Skip to content

Commit

Permalink
#236 - Make it possible to initialize new Model instances from query …
Browse files Browse the repository at this point in the history
…sets
  • Loading branch information
ellmetha committed Jun 10, 2024
1 parent c11a15c commit 2485429
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 0 deletions.
18 changes: 18 additions & 0 deletions docs/docs/models-and-databases/reference/query-set.md
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,24 @@ electronic_products = Product.filter(category: "Electronics")
average_rating = electronic_products.average(:rating)
```

### `build`

Initializes a new model instance.

This method allows initializing a new model instance using the arguments defined in the passed double splat argument.

```crystal
new_post = Post.all.build(title: "My blog post")
```

This method can also be called with a block that is executed for the new object:

```crystal
new_post = Post.all.build(title: "My blog post") do |p|
p.complex_attribute = compute_complex_attribute
end
```

### `bulk_create`

Bulk inserts the passed model instances into the database.
Expand Down
28 changes: 28 additions & 0 deletions spec/marten/db/query/related_set_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,34 @@ describe Marten::DB::Query::RelatedSet do
end
end

describe "#build" do
it "initializes a new record with the related field set" do
user = TestUser.create!(username: "jd1", email: "[email protected]", first_name: "John", last_name: "Doe")

qset = Marten::DB::Query::RelatedSet(Post).new(user, "author_id")

new_post = qset.build(title: "Post")

new_post.persisted?.should be_false
new_post.author.should eq user
new_post.title.should eq "Post"
end

it "initializes a new record with the related field set when a block is used" do
user = TestUser.create!(username: "jd1", email: "[email protected]", first_name: "John", last_name: "Doe")

qset = Marten::DB::Query::RelatedSet(Post).new(user, "author_id")

new_post = qset.build do |p|
p.title = "Post"
end

new_post.persisted?.should be_false
new_post.author.should eq user
new_post.title.should eq "Post"
end
end

describe "#create" do
it "creates a new record with the related field set" do
user = TestUser.create!(username: "jd1", email: "[email protected]", first_name: "John", last_name: "Doe")
Expand Down
19 changes: 19 additions & 0 deletions spec/marten/db/query/set_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -767,6 +767,25 @@ describe Marten::DB::Query::Set do
end
end

describe "#build" do
it "returns the non-persisted model instance initialized from the specified parameters" do
tag = Marten::DB::Query::Set(Tag).new.build(name: "New tag")

tag.persisted?.should be_false
tag.name.should eq "New tag"
end

it "returns the non-persisted model instance initialized from the specified parameters and block" do
tag = Marten::DB::Query::Set(Tag).new.build(is_active: true) do |o|
o.name = "New tag"
end

tag.persisted?.should be_false
tag.is_active.should be_true
tag.name.should eq "New tag"
end
end

describe "#create" do
it "returns the non-persisted model instance if it is invalid" do
tag = Marten::DB::Query::Set(Tag).new.create(name: nil)
Expand Down
27 changes: 27 additions & 0 deletions src/marten/db/query/set.cr
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,33 @@ module Marten
@query.average(field.try(&.to_s))
end

# Initializes a new model instance.
#
# The new model instance is initialized by using the attributes defined in the `kwargs` double splat argument.
#
# ```
# new_post = Post.all.build(title: "My blog post")
# ```
def build(**kwargs)
build_record(**kwargs)
end

# Initializes a new model instance.
#
# This method provides the exact same behaviour as `#build` with the ability to define a block that is executed
# for the new object. This block can be used to directly initialize the new model instance.
#
# ```
# new_post = Post.all.build(title: "My blog post") do |p|
# p.complex_attribute = compute_complex_attribute
# end
# ```
def build(**kwargs, &)
object = build_record(**kwargs)
yield object
object
end

# Bulk inserts the passed model instances into the database.
#
# This method allows to insert multiple model instances into the database in a single query. This can be useful
Expand Down

0 comments on commit 2485429

Please sign in to comment.