Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implements ReactiveRecord::Collection#create #407

Open
wants to merge 1 commit into
base: edge
Choose a base branch
from
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
Original file line number Diff line number Diff line change
Expand Up @@ -116,32 +116,28 @@ def to_s
end

class << self
attr_accessor :broadcast_updated_at

=begin
sync_scopes takes a newly broadcasted record change and updates all relevant currently active scopes
This is particularly hard when the client proc is specified. For example consider this scope:

class TestModel < ApplicationRecord
scope :quicker, -> { where(completed: true) }, client: -> { completed }
end

and this slice of reactive code:
# sync_scopes takes a newly broadcasted record change and updates all relevant currently active scopes
# This is particularly hard when the client proc is specified. For example consider this scope:

DIV { "quicker.count = #{TestModel.quicker.count}" }
# class TestModel < ApplicationRecord
# scope :quicker, -> { where(completed: true) }, client: -> { completed }
# end

then on the server this code is executed:
# and this slice of reactive code:

TestModel.last.update(completed: false)
# DIV { "quicker.count = #{TestModel.quicker.count}" }

This will result in the changes being broadcast to the client, which may cauase the value of
TestModel.quicker.count to increase or decrease. Of course we may not actually have the all the records,
perhaps we just have the aggregate count.
# then on the server this code is executed:

To determine this sync_scopes first asks if the record being changed is in the scope given its value
# TestModel.last.update(completed: false)

# This will result in the changes being broadcast to the client, which may cauase the value of
# TestModel.quicker.count to increase or decrease. Of course we may not actually have the all the records,
# perhaps we just have the aggregate count.

=end
attr_accessor :broadcast_updated_at
# To determine this sync_scopes first asks if the record being changed is in the scope given its value

def sync_scopes(broadcast)
self.broadcast_updated_at = broadcast.updated_at
Expand Down Expand Up @@ -503,6 +499,33 @@ def force_push(item)
notify_of_change self
end

def create(attributes = nil)
raise "You cannot call create unless the parent is saved" if @owner.new_record?

attributes = [attributes] unless attributes.is_a?(Array)

records = attributes.map { |a| build_record(a) }

Promise.new.tap do |promise|
Promise.when(*records.map(&:save)).then do
promise.resolve(records)

yield(*records) if block_given?
end
end
end

def build_record(attributes = {})
if (through_association = @association&.through_association)
through_association.klass.new(
@association.inverse_of => @owner,
@association.source => @association.klass.new(attributes)
)
else
@association.klass.new(attributes).tap { |r| _internal_push(r) }
end
end

# [:first, :last].each do |method|
# define_method method do |*args|
# if args.count == 0
Expand Down
79 changes: 79 additions & 0 deletions ruby/hyper-model/spec/batch1/reactive_record/collection_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# frozen_string_literal: true

require "spec_helper"

describe "ReactiveRecord::Collection", js: true do
context "#create" do
before(:each) { policy_allows_all }

it "should not create any records if the parent is not saved" do
expect_promise do
error = nil

user = User.new(first_name: "foo")

begin
user.comments.create(comment: "foobar")
rescue StandardError => e
error = e
end

error
end.to eq("You cannot call create unless the parent is saved")

expect(Comment.count).to eq(0)
end

it "should create a new record in a has many association" do
user = FactoryBot.create(:user, first_name: "foo")

expect_promise do
user = User.find_by_first_name("foo")

user.comments.create(comment: "foobar")
end

expect(user.comments.count).to eq(1)
end

it "should create multiple new records in a has many association" do
user = FactoryBot.create(:user, first_name: "foo")

expect_promise do
user = User.find_by_first_name("foo")

user.comments.create([{ comment: "foobar" }, { comment: "barfoo" }])
end

expect(user.comments.count).to eq(2)
end

it "should create a new record and a join record in a has many through association" do
user = FactoryBot.create(:user, first_name: "foo")

expect_promise do
user = User.find_by_first_name("foo")

user.commented_on_items.create(title: "foo", description: "bar")
end

expect(user.commented_on_items.count).to eq(1)
expect(user.comments.count).to eq(1)
end

it "should create a multiple new records and join records in a has many through association" do
user = FactoryBot.create(:user, first_name: "foo")

expect_promise do
user = User.find_by_first_name("foo")

user.commented_on_items.create(
[{ title: "foo", description: "bar" }, { title: "foo", description: "bar" }]
)
end

expect(user.commented_on_items.count).to eq(2)
expect(user.comments.count).to eq(2)
end
end
end