Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions spec/active_record_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,22 @@ module ActiveRecord
end
end

class PostsAuthorIdIs < NullAdapter::Query
def call(params, fields)
return false unless fields.has_key?("author_id") &&
params.has_key?("1")
actual = fields["author_id"].as(Int)
expected = params["1"].as(Int32)
actual == expected
end
end

NullAdapter.register_query("(number_of_dependents > :1) AND (number_of_dependents < :2)",
LessAndMoreDependents.new)

NullAdapter.register_query("number_of_dependents IN (:1, :2)", DependentsIn.new)

NullAdapter.register_query("posts.author_id = :1", PostsAuthorIdIs.new)
end

class Example; end
Expand All @@ -66,6 +78,8 @@ class Person < ActiveRecord::Model
field number_of_dependents : Int
field special_tax_group : Bool

has_many Post, criteria("posts.author_id") == criteria("people.id")

def get_tax_exemption
return 0.0 if number_of_dependents < 2
0.17
Expand Down Expand Up @@ -94,6 +108,7 @@ class Post < ActiveRecord::Model
field title : String
field content : String
field created_at : Time
field author_id : Int

field_level :protected

Expand Down Expand Up @@ -378,5 +393,45 @@ module ActiveRecord
FakeAdapter.instance.table_name.should eq("example_models")
end
end

describe "directive has_many" do
it "allows to join people with posts" do
# ARRANGE
person = new_person.create
first_post = Post.create({
"title" => "My first post",
"content" => "Content",
"author_id" => person.id
})
second_post = Post.create({
"title" => "My second post",
"content" => "Content",
"author_id" => person.id
})

other_person = new_other_person.create
other_post = Post.create({
"title" => "Other post",
"content" => "Content",
"author_id" => other_person.id
})

# ACT
people_joined_posts = Person.join(Post).all
actual = people_joined_posts.first.posts.map &.id

# ASSERT
expected = [first_post, second_post].map &.id
actual.should eq(expected)
end

pending "does only one query (an actual join)" do

end

pending "also allows to apply where after the join" do

end
end
end
end
31 changes: 31 additions & 0 deletions src/directives/has_many.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
module ActiveRecord::Directives
module HasMany
macro has_many(foreign_model, query)
def self.join(t : {{foreign_model}}.class)
HasManyWrapper({{MACRO_CURRENT.last.id}})
.new({{foreign_model}}.table_name_value, {{query}})
end

@cached_{{foreign_model.stringify.downcase.id}}s : Array({{foreign_model}})?

def {{foreign_model.stringify.downcase.id}}s
@cached_{{foreign_model.stringify.downcase.id}}s ||=
fetch_{{foreign_model.stringify.downcase.id}}s
end

def fetch_{{foreign_model.stringify.downcase.id}}s
query = ::Query::Equals[({{query}}).left, id]
{{foreign_model}}.where(query)
end
end

class HasManyWrapper(T)
def initialize(@foreign_table_name : String, @query : ::Query::Query)
end

def all
T.all
end
end
end
end
7 changes: 7 additions & 0 deletions src/directives/join.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module ActiveRecord::Directives
module Join
# macro def join(foreign_model)
# {{@type}}::HasMany_{{foreign_model}}
# end
end
end
6 changes: 5 additions & 1 deletion src/model.cr
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require "./criteria_helper"
require "./support"
require "./directives/*"

require "pool/connection"

Expand All @@ -15,6 +16,9 @@ module ActiveRecord
include CriteriaHelper
extend CriteriaHelper

include Directives::HasMany
extend Directives::Join

MACRO_CURRENT = [] of String

DEFAULT_CONNECTION_POOL_CAPACITY = 1
Expand Down Expand Up @@ -126,7 +130,7 @@ module ActiveRecord
@@adapter_name
end

private def self.table_name_value
def self.table_name_value
(@@table_name ||= Support.plural(name)).not_nil!
end

Expand Down