hyper-model 0.6.0 → 0.99.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.gitignore +35 -41
- data/.rspec +2 -0
- data/.travis.yml +33 -0
- data/CHANGELOG.md +34 -0
- data/DOCS.md +735 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +298 -224
- data/{LICENSE → LICENSE.txt} +6 -6
- data/README.md +51 -2
- data/Rakefile +18 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/codeship.database.yml +18 -0
- data/hyper-model.gemspec +62 -36
- data/lib/active_model_client_stubs.rb +16 -0
- data/lib/active_record_base.rb +331 -0
- data/{examples/chat-app/app/assets/images/.keep → lib/acts_as_string.rb} +0 -0
- data/lib/enumerable/pluck.rb +6 -0
- data/lib/hyper-model.rb +59 -8
- data/lib/hyper_model/version.rb +3 -0
- data/lib/hyper_react/input_tags.rb +47 -0
- data/lib/hyperloop/model/load.rb +1 -1
- data/lib/kernel/itself.rb +5 -0
- data/lib/object/tap.rb +7 -0
- data/lib/opal/equality_patches.rb +15 -0
- data/lib/opal/parse_patch.rb +14 -0
- data/lib/opal/set_patches.rb +8 -0
- data/lib/reactive_record/active_record/aggregations.rb +69 -0
- data/lib/reactive_record/active_record/associations.rb +118 -0
- data/lib/reactive_record/active_record/base.rb +10 -0
- data/lib/reactive_record/active_record/class_methods.rb +406 -0
- data/lib/reactive_record/active_record/error.rb +31 -0
- data/lib/reactive_record/active_record/errors.rb +374 -0
- data/lib/reactive_record/active_record/instance_methods.rb +187 -0
- data/lib/reactive_record/active_record/public_columns_hash.rb +44 -0
- data/lib/reactive_record/active_record/reactive_record/backing_record_inspector.rb +36 -0
- data/lib/reactive_record/active_record/reactive_record/base.rb +416 -0
- data/lib/reactive_record/active_record/reactive_record/collection.rb +558 -0
- data/lib/reactive_record/active_record/reactive_record/column_types.rb +75 -0
- data/lib/reactive_record/active_record/reactive_record/dummy_value.rb +236 -0
- data/lib/reactive_record/active_record/reactive_record/getters.rb +133 -0
- data/lib/reactive_record/active_record/reactive_record/isomorphic_base.rb +576 -0
- data/lib/reactive_record/active_record/reactive_record/lookup_tables.rb +54 -0
- data/lib/reactive_record/active_record/reactive_record/operations.rb +107 -0
- data/lib/reactive_record/active_record/reactive_record/scoped_collection.rb +62 -0
- data/lib/reactive_record/active_record/reactive_record/setters.rb +194 -0
- data/lib/reactive_record/active_record/reactive_record/unscoped_collection.rb +16 -0
- data/lib/reactive_record/active_record/reactive_record/while_loading.rb +343 -0
- data/lib/reactive_record/active_record_error.rb +4 -0
- data/lib/reactive_record/broadcast.rb +223 -0
- data/lib/reactive_record/engine.rb +11 -0
- data/lib/reactive_record/interval.rb +190 -0
- data/lib/reactive_record/permissions.rb +117 -0
- data/lib/reactive_record/pry.rb +13 -0
- data/lib/reactive_record/reactive_scope.rb +18 -0
- data/lib/reactive_record/scope_description.rb +121 -0
- data/lib/reactive_record/serializers.rb +7 -0
- data/lib/reactive_record/server_data_cache.rb +478 -0
- data/path_release_steps.md +9 -0
- metadata +399 -109
- data/CODE_OF_CONDUCT.md +0 -49
- data/examples/chat-app/.gitignore +0 -21
- data/examples/chat-app/Gemfile +0 -62
- data/examples/chat-app/Gemfile.lock +0 -309
- data/examples/chat-app/README.md +0 -3
- data/examples/chat-app/Rakefile +0 -6
- data/examples/chat-app/app/assets/config/manifest.js +0 -3
- data/examples/chat-app/app/assets/javascripts/application.js +0 -3
- data/examples/chat-app/app/assets/stylesheets/application.scss +0 -33
- data/examples/chat-app/app/controllers/application_controller.rb +0 -3
- data/examples/chat-app/app/controllers/home_controller.rb +0 -5
- data/examples/chat-app/app/hyperloop/components/app.rb +0 -12
- data/examples/chat-app/app/hyperloop/components/formatted_div.rb +0 -15
- data/examples/chat-app/app/hyperloop/components/input_box.rb +0 -26
- data/examples/chat-app/app/hyperloop/components/message.rb +0 -29
- data/examples/chat-app/app/hyperloop/components/messages.rb +0 -8
- data/examples/chat-app/app/hyperloop/components/nav.rb +0 -30
- data/examples/chat-app/app/hyperloop/models/application_record.rb +0 -3
- data/examples/chat-app/app/hyperloop/models/message.rb +0 -6
- data/examples/chat-app/app/hyperloop/operations/operations.rb +0 -13
- data/examples/chat-app/app/hyperloop/stores/message_store.rb +0 -17
- data/examples/chat-app/app/policies/application_policy.rb +0 -9
- data/examples/chat-app/app/views/layouts/application.html.erb +0 -12
- data/examples/chat-app/bin/bundle +0 -3
- data/examples/chat-app/bin/rails +0 -9
- data/examples/chat-app/bin/rake +0 -9
- data/examples/chat-app/bin/setup +0 -34
- data/examples/chat-app/bin/spring +0 -17
- data/examples/chat-app/bin/update +0 -29
- data/examples/chat-app/config.ru +0 -5
- data/examples/chat-app/config/application.rb +0 -12
- data/examples/chat-app/config/boot.rb +0 -3
- data/examples/chat-app/config/cable.yml +0 -9
- data/examples/chat-app/config/database.yml +0 -25
- data/examples/chat-app/config/environment.rb +0 -5
- data/examples/chat-app/config/environments/development.rb +0 -56
- data/examples/chat-app/config/environments/production.rb +0 -86
- data/examples/chat-app/config/environments/test.rb +0 -42
- data/examples/chat-app/config/initializers/application_controller_renderer.rb +0 -6
- data/examples/chat-app/config/initializers/assets.rb +0 -11
- data/examples/chat-app/config/initializers/backtrace_silencers.rb +0 -7
- data/examples/chat-app/config/initializers/cookies_serializer.rb +0 -5
- data/examples/chat-app/config/initializers/filter_parameter_logging.rb +0 -4
- data/examples/chat-app/config/initializers/hyperloop.rb +0 -6
- data/examples/chat-app/config/initializers/inflections.rb +0 -16
- data/examples/chat-app/config/initializers/mime_types.rb +0 -4
- data/examples/chat-app/config/initializers/new_framework_defaults.rb +0 -24
- data/examples/chat-app/config/initializers/session_store.rb +0 -3
- data/examples/chat-app/config/initializers/wrap_parameters.rb +0 -14
- data/examples/chat-app/config/locales/en.yml +0 -23
- data/examples/chat-app/config/puma.rb +0 -47
- data/examples/chat-app/config/routes.rb +0 -5
- data/examples/chat-app/config/secrets.yml +0 -22
- data/examples/chat-app/config/spring.rb +0 -6
- data/examples/chat-app/db/migrate/20170319194429_create_message.rb +0 -9
- data/examples/chat-app/db/schema.rb +0 -48
- data/examples/chat-app/db/seeds.rb +0 -7
- data/examples/chat-app/lib/assets/.keep +0 -0
- data/examples/chat-app/lib/tasks/.keep +0 -0
- data/examples/chat-app/log/.keep +0 -0
- data/examples/chat-app/public/404.html +0 -67
- data/examples/chat-app/public/422.html +0 -67
- data/examples/chat-app/public/500.html +0 -66
- data/examples/chat-app/public/apple-touch-icon-precomposed.png +0 -0
- data/examples/chat-app/public/apple-touch-icon.png +0 -0
- data/examples/chat-app/public/favicon.ico +0 -0
- data/examples/chat-app/public/robots.txt +0 -5
- data/examples/chat-app/test/controllers/.keep +0 -0
- data/examples/chat-app/test/fixtures/.keep +0 -0
- data/examples/chat-app/test/fixtures/files/.keep +0 -0
- data/examples/chat-app/test/helpers/.keep +0 -0
- data/examples/chat-app/test/integration/.keep +0 -0
- data/examples/chat-app/test/mailers/.keep +0 -0
- data/examples/chat-app/test/models/.keep +0 -0
- data/examples/chat-app/test/test_helper.rb +0 -10
- data/examples/chat-app/tmp/.keep +0 -0
- data/examples/chat-app/vendor/assets/javascripts/.keep +0 -0
- data/examples/chat-app/vendor/assets/stylesheets/.keep +0 -0
- data/lib/hyperloop/model/version.rb +0 -5
|
File without changes
|
data/lib/hyper-model.rb
CHANGED
|
@@ -1,14 +1,65 @@
|
|
|
1
|
-
require
|
|
1
|
+
require 'set'
|
|
2
2
|
require 'hyperloop-config'
|
|
3
|
-
|
|
4
|
-
Hyperloop.import 'hyper-component'
|
|
5
|
-
Hyperloop.import 'hyper-model'
|
|
6
|
-
|
|
3
|
+
require 'hyper-component'
|
|
7
4
|
if RUBY_ENGINE == 'opal'
|
|
8
|
-
require 'hyper-
|
|
5
|
+
require 'hyper-operation'
|
|
6
|
+
require 'active_support'
|
|
7
|
+
require 'time'
|
|
8
|
+
require 'date'
|
|
9
|
+
require 'kernel/itself' unless Object.instance_methods.include?(:itself)
|
|
10
|
+
require 'object/tap'
|
|
11
|
+
require 'active_model_client_stubs'
|
|
12
|
+
require "reactive_record/active_record_error"
|
|
13
|
+
require "reactive_record/active_record/errors"
|
|
14
|
+
require "reactive_record/active_record/error"
|
|
15
|
+
require "reactive_record/server_data_cache"
|
|
16
|
+
require "reactive_record/active_record/reactive_record/while_loading"
|
|
17
|
+
require "reactive_record/active_record/reactive_record/operations"
|
|
18
|
+
require 'reactive_record/broadcast'
|
|
19
|
+
require "reactive_record/active_record/reactive_record/isomorphic_base"
|
|
20
|
+
require 'reactive_record/active_record/reactive_record/dummy_value'
|
|
21
|
+
require 'reactive_record/active_record/reactive_record/column_types'
|
|
22
|
+
require "reactive_record/active_record/aggregations"
|
|
23
|
+
require "reactive_record/active_record/associations"
|
|
24
|
+
require "reactive_record/active_record/reactive_record/backing_record_inspector"
|
|
25
|
+
require "reactive_record/active_record/reactive_record/getters"
|
|
26
|
+
require "reactive_record/active_record/reactive_record/setters"
|
|
27
|
+
require "reactive_record/active_record/reactive_record/lookup_tables"
|
|
28
|
+
require "reactive_record/active_record/reactive_record/base"
|
|
29
|
+
require "reactive_record/active_record/reactive_record/collection"
|
|
30
|
+
require "reactive_record/active_record/reactive_record/scoped_collection"
|
|
31
|
+
require "reactive_record/active_record/reactive_record/unscoped_collection"
|
|
32
|
+
require "reactive_record/interval"
|
|
33
|
+
require_relative 'active_record_base'
|
|
34
|
+
require_relative 'reactive_record/scope_description'
|
|
35
|
+
require "reactive_record/active_record/class_methods"
|
|
36
|
+
require "reactive_record/active_record/instance_methods"
|
|
37
|
+
require "reactive_record/active_record/base"
|
|
38
|
+
require 'hyper_react/input_tags'
|
|
9
39
|
require 'hyperloop/model/load'
|
|
40
|
+
require_relative 'hyper_model/version'
|
|
41
|
+
require_relative 'opal/parse_patch'
|
|
42
|
+
require_relative 'opal/set_patches'
|
|
43
|
+
require_relative 'opal/equality_patches'
|
|
44
|
+
React::IsomorphicHelpers.log(
|
|
45
|
+
"The gem 'hyper-mesh' is deprecated. Use gem 'hyper-model' instead.", :warning
|
|
46
|
+
) unless defined? Hyperloop::Model
|
|
10
47
|
else
|
|
11
48
|
require 'opal'
|
|
12
|
-
require 'hyper-
|
|
13
|
-
|
|
49
|
+
require 'hyper-operation'
|
|
50
|
+
require "reactive_record/permissions"
|
|
51
|
+
require "reactive_record/server_data_cache"
|
|
52
|
+
require "reactive_record/active_record/reactive_record/operations"
|
|
53
|
+
require 'reactive_record/broadcast'
|
|
54
|
+
require "reactive_record/active_record/reactive_record/isomorphic_base"
|
|
55
|
+
require "reactive_record/active_record/public_columns_hash"
|
|
56
|
+
require "reactive_record/serializers"
|
|
57
|
+
require "reactive_record/pry"
|
|
58
|
+
require_relative 'active_record_base'
|
|
59
|
+
require 'hyper_model/version'
|
|
60
|
+
|
|
61
|
+
Opal.append_path File.expand_path('../sources/', __FILE__).untaint
|
|
62
|
+
Opal.append_path File.expand_path('../', __FILE__).untaint
|
|
63
|
+
Opal.append_path File.expand_path('../../vendor', __FILE__).untaint
|
|
14
64
|
end
|
|
65
|
+
require 'enumerable/pluck'
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Special handling of input tags so they ignore defaultValue (and defaultChecked) values while loading.
|
|
2
|
+
# This is accomplished by adding a react 'key prop' that tracks whether the default value is loading.
|
|
3
|
+
# When the default value transitions from loading to loaded the key will be updated causing react to
|
|
4
|
+
# remount the component with the new default value.
|
|
5
|
+
# To handle cases where defaultValue (or defaultChecked) is an expression, a proc (or lambda) can be
|
|
6
|
+
# provided for the default value. The proc will be called, and if it raises the waiting_on_resources
|
|
7
|
+
# flag then we know that within that expression there is a value still being loaded, and the react
|
|
8
|
+
# key will be set accordingly.
|
|
9
|
+
|
|
10
|
+
module React
|
|
11
|
+
module Component
|
|
12
|
+
module Tags
|
|
13
|
+
%i[INPUT SELECT TEXTAREA].each do |component|
|
|
14
|
+
remove_method component
|
|
15
|
+
send(:remove_const, component)
|
|
16
|
+
tag = component.downcase
|
|
17
|
+
klass = Class.new(Hyperloop::Component) do
|
|
18
|
+
collect_other_params_as :opts
|
|
19
|
+
render do
|
|
20
|
+
opts = props.dup # should be opts = params.opts.dup but requires next release candiate of hyper-react
|
|
21
|
+
default_value = opts[:defaultValue] || opts[:defaultChecked]
|
|
22
|
+
if default_value.respond_to? :call
|
|
23
|
+
begin
|
|
24
|
+
saved_waiting_on_resources = React::RenderingContext.waiting_on_resources
|
|
25
|
+
React::RenderingContext.waiting_on_resources = false
|
|
26
|
+
default_value = default_value.call
|
|
27
|
+
opts[:key] = React::RenderingContext.waiting_on_resources
|
|
28
|
+
if opts[:defaultValue]
|
|
29
|
+
opts[:defaultValue] = default_value
|
|
30
|
+
else
|
|
31
|
+
opts[:defaultChecked] = default_value
|
|
32
|
+
end
|
|
33
|
+
ensure
|
|
34
|
+
React::RenderingContext.waiting_on_resources = !!saved_waiting_on_resources
|
|
35
|
+
end
|
|
36
|
+
else
|
|
37
|
+
opts[:key] = !!default_value.loading?
|
|
38
|
+
end
|
|
39
|
+
opts[:value] = opts[:value].to_s if opts.key? :value # this may not be needed
|
|
40
|
+
React::RenderingContext.render(tag, opts) { children.each(&:render) }
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
const_set component, klass
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
data/lib/hyperloop/model/load.rb
CHANGED
data/lib/object/tap.rb
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
class Date
|
|
2
|
+
alias broken_equals ==
|
|
3
|
+
def ==(other)
|
|
4
|
+
return false unless other.is_a?(Date)
|
|
5
|
+
broken_equals(other)
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
class Time
|
|
10
|
+
alias broken_equals ==
|
|
11
|
+
def ==(other)
|
|
12
|
+
return false unless other.is_a?(Time)
|
|
13
|
+
broken_equals(other)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
begin
|
|
2
|
+
JSON.parse("test")
|
|
3
|
+
rescue Exception => e
|
|
4
|
+
JSON.class_eval do
|
|
5
|
+
class << self
|
|
6
|
+
alias old_parse parse
|
|
7
|
+
end
|
|
8
|
+
def self.parse(*args, &block)
|
|
9
|
+
old_parse(*args, &block)
|
|
10
|
+
rescue Exception => e
|
|
11
|
+
raise StandardError.new e.message
|
|
12
|
+
end
|
|
13
|
+
end unless e.is_a? StandardError
|
|
14
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
module ActiveRecord
|
|
2
|
+
|
|
3
|
+
class Base
|
|
4
|
+
|
|
5
|
+
def self.reflect_on_all_aggregations
|
|
6
|
+
base_class.instance_eval { @aggregations ||= [] }
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def self.reflect_on_aggregation(attribute)
|
|
10
|
+
reflect_on_all_aggregations.detect { |aggregation| aggregation.attribute == attribute }
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
module Aggregations
|
|
16
|
+
|
|
17
|
+
class AggregationReflection
|
|
18
|
+
|
|
19
|
+
attr_reader :klass_name
|
|
20
|
+
attr_reader :attribute
|
|
21
|
+
attr_reader :mapped_attributes
|
|
22
|
+
attr_reader :constructor
|
|
23
|
+
|
|
24
|
+
def construct(args)
|
|
25
|
+
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def initialize(owner_class, macro, name, options = {})
|
|
29
|
+
owner_class.reflect_on_all_aggregations << self
|
|
30
|
+
@owner_class = owner_class
|
|
31
|
+
@constructor = options[:constructor] || :new
|
|
32
|
+
@klass_name = options[:class_name] || name.camelize
|
|
33
|
+
@attribute = name
|
|
34
|
+
if options[:mapping].respond_to? :collect
|
|
35
|
+
@mapped_attributes = options[:mapping].collect(&:last)
|
|
36
|
+
else
|
|
37
|
+
ReactiveRecord::Base.log("improper aggregate definition #{@owner_class}, :#{name}, class_name: #{@klass_name} - missing mapping", :error)
|
|
38
|
+
@mapped_attributes = []
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def klass
|
|
43
|
+
@klass ||= Object.const_get(@klass_name)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def serialize(object)
|
|
47
|
+
if object.nil?
|
|
48
|
+
object # return dummy value if that is what we got
|
|
49
|
+
else
|
|
50
|
+
@mapped_attributes.collect { |attr| object.send(attr) }
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def deserialize(array)
|
|
55
|
+
if array.nil?
|
|
56
|
+
array # return dummy value if that is what we got
|
|
57
|
+
elsif @constructor.respond_to?(:call)
|
|
58
|
+
@constructor.call(*array)
|
|
59
|
+
else
|
|
60
|
+
klass.send(@constructor, *array)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
end
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
module ActiveRecord
|
|
2
|
+
|
|
3
|
+
class Base
|
|
4
|
+
|
|
5
|
+
def self.reflect_on_all_associations
|
|
6
|
+
base_class.instance_eval { @associations ||= superclass.instance_eval { (@associations && @associations.dup) || [] } }
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def self.reflect_on_association(attr)
|
|
10
|
+
reflection_finder { |assoc| assoc.attribute == attr }
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.reflect_on_association_by_foreign_key(key)
|
|
14
|
+
reflection_finder { |assoc| assoc.association_foreign_key == key }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.reflection_finder(&block)
|
|
18
|
+
found = reflect_on_all_associations.detect do |assoc|
|
|
19
|
+
assoc.owner_class == self && yield(assoc)
|
|
20
|
+
end
|
|
21
|
+
if found
|
|
22
|
+
found
|
|
23
|
+
elsif superclass == Base
|
|
24
|
+
nil
|
|
25
|
+
else
|
|
26
|
+
superclass.reflection_finder(&block)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
module Associations
|
|
33
|
+
|
|
34
|
+
class AssociationReflection
|
|
35
|
+
|
|
36
|
+
attr_reader :association_foreign_key
|
|
37
|
+
attr_reader :attribute
|
|
38
|
+
attr_reader :macro
|
|
39
|
+
attr_reader :owner_class
|
|
40
|
+
attr_reader :source
|
|
41
|
+
|
|
42
|
+
def initialize(owner_class, macro, name, options = {})
|
|
43
|
+
owner_class.reflect_on_all_associations << self
|
|
44
|
+
@owner_class = owner_class
|
|
45
|
+
@macro = macro
|
|
46
|
+
@options = options
|
|
47
|
+
@klass_name = options[:class_name] || (collection? && name.camelize.sub(/s$/, '')) || name.camelize
|
|
48
|
+
@association_foreign_key = options[:foreign_key] || (macro == :belongs_to && "#{name}_id") || "#{@owner_class.name.underscore}_id"
|
|
49
|
+
@source = options[:source] || @klass_name.underscore if options[:through]
|
|
50
|
+
@attribute = name
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def through_association
|
|
54
|
+
return unless @options[:through]
|
|
55
|
+
@through_association ||= @owner_class.reflect_on_all_associations.detect do |association|
|
|
56
|
+
association.attribute == @options[:through]
|
|
57
|
+
end
|
|
58
|
+
raise "Through association #{@options[:through]} for "\
|
|
59
|
+
"#{@owner_class}.#{attribute} not found." unless @through_association
|
|
60
|
+
@through_association
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
alias through_association? through_association
|
|
64
|
+
|
|
65
|
+
def through_associations
|
|
66
|
+
# find all associations that use the inverse association as the through association
|
|
67
|
+
# that is find all associations that are using this association in a through relationship
|
|
68
|
+
@through_associations ||= klass.reflect_on_all_associations.select do |assoc|
|
|
69
|
+
assoc.through_association && assoc.inverse == self
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def source_associations
|
|
74
|
+
# find all associations that use this association as the source
|
|
75
|
+
# that is final all associations that are using this association as the source in a
|
|
76
|
+
# through relationship
|
|
77
|
+
@source_associations ||= owner_class.reflect_on_all_associations.collect do |sibling|
|
|
78
|
+
sibling.klass.reflect_on_all_associations.select do |assoc|
|
|
79
|
+
assoc.source == attribute
|
|
80
|
+
end
|
|
81
|
+
end.flatten
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def inverse
|
|
85
|
+
@inverse ||=
|
|
86
|
+
through_association ? through_association.inverse : find_inverse
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def inverse_of
|
|
90
|
+
@inverse_of ||= inverse.attribute
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def find_inverse
|
|
94
|
+
klass.reflect_on_all_associations.each do |association|
|
|
95
|
+
next if association.association_foreign_key != @association_foreign_key
|
|
96
|
+
next if association.klass != @owner_class
|
|
97
|
+
next if association.attribute == attribute
|
|
98
|
+
return association if klass == association.owner_class
|
|
99
|
+
end
|
|
100
|
+
raise "Association #{@owner_class}.#{attribute} "\
|
|
101
|
+
"(foreign_key: #{@association_foreign_key}) "\
|
|
102
|
+
"has no inverse in #{@klass_name}"
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def klass
|
|
106
|
+
@klass ||= Object.const_get(@klass_name)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def collection?
|
|
110
|
+
[:has_many].include? @macro
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
end
|
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
module ActiveRecord
|
|
2
|
+
|
|
3
|
+
module ClassMethods
|
|
4
|
+
|
|
5
|
+
alias _new_without_sti_type_cast new
|
|
6
|
+
|
|
7
|
+
def new(*args, &block)
|
|
8
|
+
_new_without_sti_type_cast(*args, &block).cast_to_current_sti_type
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def base_class
|
|
12
|
+
unless self < Base
|
|
13
|
+
raise ActiveRecordError, "#{name} doesn't descend from ActiveRecord"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
if superclass == Base || superclass.abstract_class?
|
|
17
|
+
self
|
|
18
|
+
else
|
|
19
|
+
superclass.base_class
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def abstract_class?
|
|
24
|
+
defined?(@abstract_class) && @abstract_class == true
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def primary_key
|
|
28
|
+
@primary_key_value ||= (self == base_class) ? :id : base_class.primary_key
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def primary_key=(val)
|
|
32
|
+
@primary_key_value = val.to_s
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def inheritance_column
|
|
36
|
+
return nil if @no_inheritance_column
|
|
37
|
+
@inheritance_column_value ||=
|
|
38
|
+
if self == base_class
|
|
39
|
+
@inheritance_column_value || 'type'
|
|
40
|
+
else
|
|
41
|
+
superclass.inheritance_column.tap { |v| @no_inheritance_column = !v }
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def inheritance_column=(name)
|
|
46
|
+
@no_inheritance_column = !name
|
|
47
|
+
@inheritance_column_value = name
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def model_name
|
|
51
|
+
@model_name ||= ActiveModel::Name.new(self)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def find(id)
|
|
55
|
+
ReactiveRecord::Base.find(self, primary_key => id)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def find_by(opts = {})
|
|
59
|
+
dealiased_opts = {}
|
|
60
|
+
opts.each { |attr, value| dealiased_opts[_dealias_attribute(attr)] = value }
|
|
61
|
+
ReactiveRecord::Base.find(self, dealiased_opts)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def enum(*args)
|
|
65
|
+
# when we implement schema validation we should also implement value checking
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def serialize(attr, *args)
|
|
69
|
+
ReactiveRecord::Base.serialized?[self][attr] = true
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def _dealias_attribute(new)
|
|
73
|
+
if self == base_class
|
|
74
|
+
_attribute_aliases[new] || new
|
|
75
|
+
else
|
|
76
|
+
_attribute_aliases[new] ||= superclass._dealias_attribute(new)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def _attribute_aliases
|
|
81
|
+
@_attribute_aliases ||= {}
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def alias_attribute(new_name, old_name)
|
|
85
|
+
['', '=', '_changed?'].each do |variant|
|
|
86
|
+
define_method("#{new_name}#{variant}") { |*args, &block| send("#{old_name}#{variant}", *args, &block) }
|
|
87
|
+
end
|
|
88
|
+
_attribute_aliases[new_name] = old_name
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# ignore any of these methods if they get called on the client. This list should be trimmed down to include only
|
|
92
|
+
# methods to be called as "macros" such as :after_create, etc...
|
|
93
|
+
SERVER_METHODS = [
|
|
94
|
+
:regulate_relationship, :regulate_scope,
|
|
95
|
+
:attribute_type_decorations, :defined_enums, :_validators, :timestamped_migrations, :lock_optimistically, :lock_optimistically=,
|
|
96
|
+
:local_stored_attributes=, :lock_optimistically?, :attribute_aliases?, :attribute_method_matchers?, :defined_enums?,
|
|
97
|
+
:has_many_without_reactive_record_add_changed_method, :has_many_with_reactive_record_add_changed_method,
|
|
98
|
+
:belongs_to_without_reactive_record_add_changed_method, :belongs_to_with_reactive_record_add_changed_method,
|
|
99
|
+
:cache_timestamp_format, :composed_of_with_reactive_record_add_changed_method, :schema_format, :schema_format=,
|
|
100
|
+
:error_on_ignored_order_or_limit, :error_on_ignored_order_or_limit=, :timestamped_migrations=, :dump_schema_after_migration,
|
|
101
|
+
:dump_schema_after_migration=, :dump_schemas, :dump_schemas=, :warn_on_records_fetched_greater_than=,
|
|
102
|
+
:belongs_to_required_by_default, :default_connection_handler, :connection_handler=, :default_connection_handler=,
|
|
103
|
+
:skip_time_zone_conversion_for_attributes, :skip_time_zone_conversion_for_attributes=, :time_zone_aware_types,
|
|
104
|
+
:time_zone_aware_types=, :protected_environments, :skip_time_zone_conversion_for_attributes?, :time_zone_aware_types?,
|
|
105
|
+
:partial_writes, :partial_writes=, :composed_of_without_reactive_record_add_changed_method, :logger, :partial_writes?,
|
|
106
|
+
:after_initialize, :record_timestamps, :record_timestamps=, :after_find, :after_touch, :before_save, :around_save,
|
|
107
|
+
:belongs_to_required_by_default=, :default_connection_handler?, :before_create, :around_create, :before_update, :around_update,
|
|
108
|
+
:after_save, :before_destroy, :around_destroy, :after_create, :after_destroy, :after_update, :_validation_callbacks,
|
|
109
|
+
:_validation_callbacks?, :_validation_callbacks=, :_initialize_callbacks, :_initialize_callbacks?, :_initialize_callbacks=,
|
|
110
|
+
:_find_callbacks, :_find_callbacks?, :_find_callbacks=, :_touch_callbacks, :_touch_callbacks?, :_touch_callbacks=, :_save_callbacks,
|
|
111
|
+
:_save_callbacks?, :_save_callbacks=, :_create_callbacks, :_create_callbacks?, :_create_callbacks=, :_update_callbacks,
|
|
112
|
+
:_update_callbacks?, :_update_callbacks=, :_destroy_callbacks, :_destroy_callbacks?, :_destroy_callbacks=, :record_timestamps?,
|
|
113
|
+
:pre_synchromesh_scope, :pre_synchromesh_default_scope, :do_not_synchronize, :do_not_synchronize?,
|
|
114
|
+
:logger=, :maintain_test_schema, :maintain_test_schema=, :scope, :time_zone_aware_attributes, :time_zone_aware_attributes=,
|
|
115
|
+
:default_timezone, :default_timezone=, :_attr_readonly, :warn_on_records_fetched_greater_than, :configurations, :configurations=,
|
|
116
|
+
:_attr_readonly?, :table_name_prefix=, :table_name_suffix=, :schema_migrations_table_name=, :internal_metadata_table_name,
|
|
117
|
+
:internal_metadata_table_name=, :primary_key_prefix_type, :_attr_readonly=, :pluralize_table_names=, :protected_environments=,
|
|
118
|
+
:ignored_columns=, :ignored_columns, :index_nested_attribute_errors, :index_nested_attribute_errors=, :primary_key_prefix_type=,
|
|
119
|
+
:table_name_prefix?, :table_name_suffix?, :schema_migrations_table_name?, :internal_metadata_table_name?, :protected_environments?,
|
|
120
|
+
:pluralize_table_names?, :ignored_columns?, :store_full_sti_class, :store_full_sti_class=, :nested_attributes_options,
|
|
121
|
+
:nested_attributes_options=, :store_full_sti_class?, :default_scopes, :default_scope_override, :default_scopes=, :default_scope_override=,
|
|
122
|
+
:nested_attributes_options?, :cache_timestamp_format=, :cache_timestamp_format?, :reactive_record_association_keys, :_validators=,
|
|
123
|
+
:has_many, :belongs_to, :composed_of, :belongs_to_without_reactive_record_add_is_method, :_rollback_callbacks, :_commit_callbacks,
|
|
124
|
+
:_before_commit_callbacks, :attribute_type_decorations=, :_commit_callbacks=, :_commit_callbacks?, :_before_commit_callbacks?,
|
|
125
|
+
:_before_commit_callbacks=, :_rollback_callbacks=, :_before_commit_without_transaction_enrollment_callbacks?,
|
|
126
|
+
:_before_commit_without_transaction_enrollment_callbacks=, :_commit_without_transaction_enrollment_callbacks,
|
|
127
|
+
:_commit_without_transaction_enrollment_callbacks?, :_commit_without_transaction_enrollment_callbacks=, :_rollback_callbacks?,
|
|
128
|
+
:_rollback_without_transaction_enrollment_callbacks?, :_rollback_without_transaction_enrollment_callbacks=,
|
|
129
|
+
:_rollback_without_transaction_enrollment_callbacks, :_before_commit_without_transaction_enrollment_callbacks, :aggregate_reflections,
|
|
130
|
+
:_reflections=, :aggregate_reflections=, :pluralize_table_names, :public_columns_hash, :attributes_to_define_after_schema_loads,
|
|
131
|
+
:attributes_to_define_after_schema_loads=, :table_name_suffix, :schema_migrations_table_name, :attribute_aliases,
|
|
132
|
+
:attribute_method_matchers, :connection_handler, :attribute_aliases=, :attribute_method_matchers=, :_validate_callbacks,
|
|
133
|
+
:_validate_callbacks?, :_validate_callbacks=, :_validators?, :_reflections?, :aggregate_reflections?, :include_root_in_json,
|
|
134
|
+
:_reflections, :include_root_in_json=, :include_root_in_json?, :local_stored_attributes, :default_scope, :table_name_prefix,
|
|
135
|
+
:attributes_to_define_after_schema_loads?, :attribute_type_decorations?, :defined_enums=, :suppress, :has_secure_token,
|
|
136
|
+
:generate_unique_secure_token, :store, :store_accessor, :_store_accessors_module, :stored_attributes, :reflect_on_aggregation,
|
|
137
|
+
:reflect_on_all_aggregations, :_reflect_on_association, :reflect_on_all_associations, :clear_reflections_cache, :reflections,
|
|
138
|
+
:reflect_on_association, :reflect_on_all_autosave_associations, :no_touching, :transaction, :after_commit, :after_rollback, :before_commit,
|
|
139
|
+
:before_commit_without_transaction_enrollment, :after_create_commit, :after_update_commit, :after_destroy_commit,
|
|
140
|
+
:after_commit_without_transaction_enrollment, :after_rollback_without_transaction_enrollment, :raise_in_transactional_callbacks,
|
|
141
|
+
:raise_in_transactional_callbacks=, :accepts_nested_attributes_for, :has_secure_password, :has_one, :has_and_belongs_to_many,
|
|
142
|
+
:before_validation, :after_validation, :serialize, :primary_key, :dangerous_attribute_method?, :get_primary_key, :quoted_primary_key,
|
|
143
|
+
:define_method_attribute, :reset_primary_key, :primary_key=, :define_method_attribute=, :attribute_names, :initialize_generated_modules,
|
|
144
|
+
:column_for_attribute, :define_attribute_methods, :undefine_attribute_methods, :instance_method_already_implemented?, :method_defined_within?,
|
|
145
|
+
:dangerous_class_method?, :class_method_defined_within?, :attribute_method?, :has_attribute?, :generated_attribute_methods,
|
|
146
|
+
:attribute_method_prefix, :attribute_method_suffix, :attribute_method_affix, :attribute_alias?, :attribute_alias, :define_attribute_method,
|
|
147
|
+
:update_counters, :locking_enabled?, :locking_column, :locking_column=, :reset_locking_column, :decorate_attribute_type,
|
|
148
|
+
:decorate_matching_attribute_types, :attribute, :define_attribute, :reset_counters, :increment_counter, :decrement_counter,
|
|
149
|
+
:validates_absence_of, :validates_length_of, :validates_size_of, :validates_presence_of, :validates_associated, :validates_uniqueness_of,
|
|
150
|
+
:validates_acceptance_of, :validates_confirmation_of, :validates_exclusion_of, :validates_format_of, :validates_inclusion_of,
|
|
151
|
+
:validates_numericality_of, :define_callbacks, :normalize_callback_params, :__update_callbacks, :get_callbacks, :set_callback,
|
|
152
|
+
:set_callbacks, :skip_callback, :reset_callbacks, :deprecated_false_terminator, :define_model_callbacks, :validate, :validators,
|
|
153
|
+
:validates_each, :validates_with, :clear_validators!, :validators_on, :validates, :_validates_default_keys, :_parse_validates_options,
|
|
154
|
+
:validates!, :_to_partial_path, :sanitize, :sanitize_sql, :sanitize_conditions, :quote_value, :sanitize_sql_for_conditions, :sanitize_sql_array,
|
|
155
|
+
:sanitize_sql_for_assignment, :sanitize_sql_hash_for_assignment, :sanitize_sql_for_order, :expand_hash_conditions_for_aggregates, :sanitize_sql_like,
|
|
156
|
+
:replace_named_bind_variables, :replace_bind_variables, :raise_if_bind_arity_mismatch, :replace_bind_variable, :quote_bound_value, :all,
|
|
157
|
+
:default_scoped, :valid_scope_name?, :scope_attributes?, :before_remove_const, :ignore_default_scope?, :unscoped, :build_default_scope,
|
|
158
|
+
:evaluate_default_scope, :ignore_default_scope=, :current_scope, :current_scope=, :scope_attributes, :base_class, :abstract_class?,
|
|
159
|
+
:finder_needs_type_condition?, :sti_name, :descends_from_active_record?, :abstract_class, :compute_type, :abstract_class=, :table_name, :columns,
|
|
160
|
+
:table_exists?, :columns_hash, :column_names, :attribute_types, :prefetch_primary_key?, :sequence_name, :quoted_table_name, :_default_attributes,
|
|
161
|
+
:type_for_attribute, :inheritance_column, :attributes_builder, :inheritance_column=, :reset_table_name, :table_name=, :reset_column_information,
|
|
162
|
+
:full_table_name_prefix, :full_table_name_suffix, :reset_sequence_name, :sequence_name=, :next_sequence_value, :column_defaults, :content_columns,
|
|
163
|
+
:readonly_attributes, :attr_readonly, :create, :create!, :instantiate, :find, :type_caster, :arel_table, :find_by, :find_by!, :initialize_find_by_cache,
|
|
164
|
+
:generated_association_methods, :arel_engine, :arel_attribute, :predicate_builder, :collection_cache_key, :relation_delegate_class,
|
|
165
|
+
:initialize_relation_delegate_cache, :enum, :collecting_queries_for_explain, :exec_explain, :i18n_scope, :lookup_ancestors, :human_attribute_name,
|
|
166
|
+
:references, :uniq, :maximum, :none, :exists?, :second, :limit, :order, :eager_load, :update, :delete_all, :destroy, :ids, :many?, :pluck, :third,
|
|
167
|
+
:delete, :fourth, :fifth, :forty_two, :second_to_last, :third_to_last, :preload, :sum, :take!, :first!, :last!, :second!, :offset, :select, :fourth!,
|
|
168
|
+
:third!, :third_to_last!, :fifth!, :where, :first_or_create, :second_to_last!, :forty_two!, :first, :having, :any?, :one?, :none?, :find_or_create_by,
|
|
169
|
+
:from, :first_or_create!, :first_or_initialize, :except, :find_or_create_by!, :find_or_initialize_by, :includes, :destroy_all, :update_all, :or,
|
|
170
|
+
:find_in_batches, :take, :joins, :find_each, :last, :in_batches, :reorder, :group, :left_joins, :left_outer_joins, :rewhere, :readonly, :create_with,
|
|
171
|
+
:distinct, :unscope, :calculate, :average, :count_by_sql, :minimum, :lock, :find_by_sql, :count, :cache, :uncached, :connection, :connection_pool,
|
|
172
|
+
:establish_connection, :connected?, :clear_cache!, :clear_reloadable_connections!, :connection_id, :connection_config, :clear_all_connections!,
|
|
173
|
+
:remove_connection, :connection_specification_name, :connection_specification_name=, :retrieve_connection, :connection_id=, :clear_active_connections!,
|
|
174
|
+
:sqlite3_connection, :direct_descendants, :benchmark, :model_name, :with_options, :attr_protected, :attr_accessible
|
|
175
|
+
]
|
|
176
|
+
|
|
177
|
+
def method_missing(name, *args, &block)
|
|
178
|
+
if args.count == 1 && name.start_with?("find_by_") && !block
|
|
179
|
+
find_by(_dealias_attribute(name.sub(/^find_by_/, "")) => args[0])
|
|
180
|
+
elsif [].respond_to?(name)
|
|
181
|
+
all.send(name, *args, &block)
|
|
182
|
+
elsif name.end_with?('!')
|
|
183
|
+
send(name.chop, *args, &block).send(:reload_from_db) rescue nil
|
|
184
|
+
elsif !SERVER_METHODS.include?(name)
|
|
185
|
+
raise "#{self.name}.#{name}(#{args}) (called class method missing)"
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# client side AR
|
|
190
|
+
|
|
191
|
+
# Any method that can be applied to an array will be applied to the result
|
|
192
|
+
# of all instead.
|
|
193
|
+
# Any method ending with ! just means apply the method after forcing a reload
|
|
194
|
+
# from the DB.
|
|
195
|
+
|
|
196
|
+
# alias pre_synchromesh_method_missing method_missing
|
|
197
|
+
#
|
|
198
|
+
# def method_missing(name, *args, &block)
|
|
199
|
+
# return all.send(name, *args, &block) if [].respond_to?(name)
|
|
200
|
+
# if name.end_with?('!')
|
|
201
|
+
# return send(name.chop, *args, &block).send(:reload_from_db) rescue nil
|
|
202
|
+
# end
|
|
203
|
+
# pre_synchromesh_method_missing(name, *args, &block)
|
|
204
|
+
# end
|
|
205
|
+
|
|
206
|
+
def create(*args, &block)
|
|
207
|
+
new(*args).save(&block)
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def scope(name, *args)
|
|
211
|
+
opts = _synchromesh_scope_args_check(args)
|
|
212
|
+
scope_description = ReactiveRecord::ScopeDescription.new(self, name, opts)
|
|
213
|
+
singleton_class.send(:define_method, name) do |*vargs|
|
|
214
|
+
all.build_child_scope(scope_description, *name, *vargs)
|
|
215
|
+
end
|
|
216
|
+
# singleton_class.send(:define_method, "#{name}=") do |_collection|
|
|
217
|
+
# raise 'NO LONGER IMPLEMENTED - DOESNT PLAY WELL WITH SYNCHROMESH'
|
|
218
|
+
# end
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def default_scope(*args, &block)
|
|
222
|
+
opts = _synchromesh_scope_args_check([*block, *args])
|
|
223
|
+
@_default_scopes ||= []
|
|
224
|
+
@_default_scopes << opts
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def all
|
|
228
|
+
ReactiveRecord::Base.default_scope[self] ||=
|
|
229
|
+
begin
|
|
230
|
+
root = ReactiveRecord::Collection
|
|
231
|
+
.new(self, nil, nil, self, 'all')
|
|
232
|
+
.extend(ReactiveRecord::UnscopedCollection)
|
|
233
|
+
(@_default_scopes || [{ client: _all_filter }]).inject(root) do |scope, opts|
|
|
234
|
+
scope.build_child_scope(ReactiveRecord::ScopeDescription.new(self, :all, opts))
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
def _all_filter
|
|
240
|
+
# provides a filter for the all scopes taking into account STI subclasses
|
|
241
|
+
# note: within the lambda `self` will be the model instance
|
|
242
|
+
defining_class_is_base_class = base_class == self
|
|
243
|
+
defining_model_name = model_name.to_s
|
|
244
|
+
lambda do
|
|
245
|
+
# have to delay computation of inheritance column since it might
|
|
246
|
+
# not be defined when class is first defined
|
|
247
|
+
ic = self.class.inheritance_column
|
|
248
|
+
defining_class_is_base_class || !ic || self[ic] == defining_model_name
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
# def all=(_collection)
|
|
253
|
+
# raise "NO LONGER IMPLEMENTED DOESNT PLAY WELL WITH SYNCHROMESH"
|
|
254
|
+
# end
|
|
255
|
+
|
|
256
|
+
def unscoped
|
|
257
|
+
ReactiveRecord::Base.unscoped[self] ||=
|
|
258
|
+
ReactiveRecord::Collection
|
|
259
|
+
.new(self, nil, nil, self, 'unscoped')
|
|
260
|
+
.extend(ReactiveRecord::UnscopedCollection)
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
def finder_method(name)
|
|
264
|
+
ReactiveRecord::ScopeDescription.new(self, "_#{name}", {})
|
|
265
|
+
[name, "#{name}!"].each do |method|
|
|
266
|
+
singleton_class.send(:define_method, method) do |*vargs|
|
|
267
|
+
all.apply_scope("_#{method}", *vargs).first
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
def abstract_class=(val)
|
|
273
|
+
@abstract_class = val
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
# def scope(name, body)
|
|
277
|
+
# singleton_class.send(:define_method, name) do | *args |
|
|
278
|
+
# args = (args.count == 0) ? name : [name, *args]
|
|
279
|
+
# ReactiveRecord::Base.class_scopes(self)[args] ||= ReactiveRecord::Collection.new(self, nil, nil, self, args)
|
|
280
|
+
# end
|
|
281
|
+
# singleton_class.send(:define_method, "#{name}=") do |collection|
|
|
282
|
+
# ReactiveRecord::Base.class_scopes(self)[name] = collection
|
|
283
|
+
# end
|
|
284
|
+
# end
|
|
285
|
+
|
|
286
|
+
# def all
|
|
287
|
+
# ReactiveRecord::Base.class_scopes(self)[:all] ||= ReactiveRecord::Collection.new(self, nil, nil, self, "all")
|
|
288
|
+
# end
|
|
289
|
+
#
|
|
290
|
+
# def all=(collection)
|
|
291
|
+
# ReactiveRecord::Base.class_scopes(self)[:all] = collection
|
|
292
|
+
# end
|
|
293
|
+
|
|
294
|
+
[:belongs_to, :has_many, :has_one].each do |macro|
|
|
295
|
+
define_method(macro) do |*args| # is this a bug in opal? saying name, scope=nil, opts={} does not work!
|
|
296
|
+
name = args.first
|
|
297
|
+
opts = (args.count > 1 and args.last.is_a? Hash) ? args.last : {}
|
|
298
|
+
assoc = Associations::AssociationReflection.new(self, macro, name, opts)
|
|
299
|
+
if macro == :has_many
|
|
300
|
+
define_method(name) { @backing_record.get_has_many(assoc, nil) }
|
|
301
|
+
define_method("#{name}=") { |val| @backing_record.set_has_many(assoc, val) }
|
|
302
|
+
else
|
|
303
|
+
define_method(name) { @backing_record.get_belongs_to(assoc, nil) }
|
|
304
|
+
define_method("#{name}=") { |val| @backing_record.set_belongs_to(assoc, val) }
|
|
305
|
+
end
|
|
306
|
+
assoc
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
def composed_of(name, opts = {})
|
|
311
|
+
reflection = Aggregations::AggregationReflection.new(base_class, :composed_of, name, opts)
|
|
312
|
+
if reflection.klass < ActiveRecord::Base
|
|
313
|
+
define_method(name) { @backing_record.get_ar_aggregate(reflection, nil) }
|
|
314
|
+
define_method("#{name}=") { |val| @backing_record.set_ar_aggregate(reflection, val) }
|
|
315
|
+
else
|
|
316
|
+
define_method(name) { @backing_record.get_non_ar_aggregate(name, nil) }
|
|
317
|
+
define_method("#{name}=") { |val| @backing_record.set_non_ar_aggregate(reflection, val) }
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
def column_names
|
|
322
|
+
ReactiveRecord::Base.public_columns_hash.keys
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
def columns_hash
|
|
326
|
+
ReactiveRecord::Base.public_columns_hash[name] || {}
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
def server_methods
|
|
330
|
+
@server_methods ||= {}
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
def server_method(name, default: nil)
|
|
334
|
+
server_methods[name] = { default: default }
|
|
335
|
+
define_method(name) do |*args|
|
|
336
|
+
vector = args.count.zero? ? name : [[name] + args]
|
|
337
|
+
@backing_record.get_server_method(vector, nil)
|
|
338
|
+
end
|
|
339
|
+
define_method("#{name}!") do |*args|
|
|
340
|
+
vector = args.count.zero? ? name : [[name] + args]
|
|
341
|
+
@backing_record.get_server_method(vector, true)
|
|
342
|
+
end
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
def define_attribute_methods
|
|
346
|
+
columns_hash.each do |name, column_hash|
|
|
347
|
+
next if name == primary_key
|
|
348
|
+
define_method(name) { @backing_record.get_attr_value(name, nil) }
|
|
349
|
+
define_method("#{name}!") { @backing_record.get_attr_value(name, true) }
|
|
350
|
+
define_method("#{name}=") { |val| @backing_record.set_attr_value(name, val) }
|
|
351
|
+
define_method("#{name}_changed?") { @backing_record.changed?(name) }
|
|
352
|
+
define_method("#{name}?") { @backing_record.get_attr_value(name, nil).present? }
|
|
353
|
+
end
|
|
354
|
+
self.inheritance_column = nil if inheritance_column && !columns_hash.key?(inheritance_column)
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
def _react_param_conversion(param, opt = nil)
|
|
358
|
+
param = Native(param)
|
|
359
|
+
param = JSON.from_object(param.to_n) if param.is_a? Native::Object
|
|
360
|
+
result =
|
|
361
|
+
if param.is_a? self
|
|
362
|
+
param
|
|
363
|
+
elsif param.is_a? Hash
|
|
364
|
+
if opt == :validate_only
|
|
365
|
+
klass = ReactiveRecord::Base.infer_type_from_hash(self, param)
|
|
366
|
+
klass == self || klass < self
|
|
367
|
+
else
|
|
368
|
+
# TODO: investigate saving .changes here and then replacing the
|
|
369
|
+
# TODO: changes after the load is complete. In other words preserve the
|
|
370
|
+
# TODO: changed values as changes while just updating the synced values.
|
|
371
|
+
target =
|
|
372
|
+
if param[primary_key]
|
|
373
|
+
find(param[primary_key])
|
|
374
|
+
else
|
|
375
|
+
new
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
associations = reflect_on_all_associations
|
|
379
|
+
|
|
380
|
+
param = param.collect do |key, value|
|
|
381
|
+
assoc = associations.detect do |association|
|
|
382
|
+
association.association_foreign_key == key
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
if assoc
|
|
386
|
+
if value
|
|
387
|
+
[assoc.attribute, { id: [value] }]
|
|
388
|
+
else
|
|
389
|
+
[assoc.attribute, [nil]]
|
|
390
|
+
end
|
|
391
|
+
else
|
|
392
|
+
[key, [value]]
|
|
393
|
+
end
|
|
394
|
+
end
|
|
395
|
+
# TODO: verify wrapping with load_data was added so broadcasting works in 1.0.0.lap28
|
|
396
|
+
ReactiveRecord::Base.load_data do
|
|
397
|
+
ReactiveRecord::ServerDataCache.load_from_json(Hash[param], target)
|
|
398
|
+
end
|
|
399
|
+
target.cast_to_current_sti_type
|
|
400
|
+
end
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
result
|
|
404
|
+
end
|
|
405
|
+
end
|
|
406
|
+
end
|