caruby-core 2.1.1 → 2.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -0
- data/History.md +5 -1
- data/lib/caruby/database/cache.rb +20 -9
- data/lib/caruby/database/lazy_loader.rb +1 -1
- data/lib/caruby/database/operation.rb +2 -0
- data/lib/caruby/database/persistable.rb +19 -13
- data/lib/caruby/database/persistence_service.rb +14 -38
- data/lib/caruby/database/persistifier.rb +86 -37
- data/lib/caruby/database/reader.rb +87 -87
- data/lib/caruby/database/reader_template_builder.rb +7 -4
- data/lib/caruby/database/sql_executor.rb +32 -15
- data/lib/caruby/database/writer.rb +20 -12
- data/lib/caruby/database/writer_template_builder.rb +10 -6
- data/lib/caruby/database.rb +97 -55
- data/lib/caruby/helpers/coordinate.rb +4 -4
- data/lib/caruby/helpers/person.rb +2 -2
- data/lib/caruby/helpers/properties.rb +4 -4
- data/lib/caruby/helpers/roman.rb +2 -2
- data/lib/caruby/helpers/version.rb +1 -1
- data/lib/caruby/json/serializable.rb +17 -0
- data/lib/caruby/metadata/propertied.rb +8 -1
- data/lib/caruby/metadata/property_characteristics.rb +41 -46
- data/lib/caruby/metadata.rb +1 -2
- data/lib/caruby/migration/migrator.rb +108 -0
- data/lib/caruby/resource.rb +2 -2
- data/lib/caruby/version.rb +1 -1
- data/lib/caruby.rb +0 -2
- data/test/lib/caruby/database/cache_test.rb +1 -3
- metadata +6 -8
- data/lib/caruby/caruby-src.tar.gz +0 -0
- data/lib/caruby/json/deserializer.rb +0 -15
- data/lib/caruby/json/serializer.rb +0 -69
@@ -9,37 +9,38 @@ module CaRuby
|
|
9
9
|
# +:autogenerated+ flag.
|
10
10
|
SUPPORTED_FLAGS = [
|
11
11
|
:autogenerated, :logical, :cascaded, :no_cascade_update_to_create, :saved, :unsaved, :fetched,
|
12
|
-
:unfetched, :include_in_save_template, :fetch_saved, :create_only, :update_only,
|
13
|
-
:volatile].to_set
|
12
|
+
:unfetched, :transient, :include_in_save_template, :fetch_saved, :create_only, :update_only,
|
13
|
+
:nosync, :volatile].to_set
|
14
14
|
|
15
|
-
# Returns whether
|
16
|
-
# *
|
17
|
-
# *
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
15
|
+
# Returns whether this property is fetched, determined as follows:
|
16
|
+
# * this property is marked with the +:fetched+ flag
|
17
|
+
# * this property is not marked with the +:transient+ or +:unfetched+ flag
|
18
|
+
# * otherwise, this is a non-domain property
|
19
|
+
# * otherwise, this is a domain property and one of the following conditions hold:
|
20
|
+
# * this is a non-logical dependent domain property
|
21
|
+
# * this is an owner property
|
22
|
+
# * this is an abstract, non-derived independent property
|
23
23
|
#
|
24
|
-
# @return [Boolean] whether
|
24
|
+
# @return [Boolean] whether this property is fetched
|
25
25
|
def fetched?
|
26
26
|
return true if @flags.include?(:fetched)
|
27
|
-
return false if @flags.include?(:unfetched)
|
27
|
+
return false if @flags.include?(:transient) or @flags.include?(:unfetched)
|
28
28
|
nondomain? or dependent? ? fetched_dependent? : fetched_independent?
|
29
29
|
end
|
30
|
-
|
31
|
-
# Returns whether
|
30
|
+
|
31
|
+
# Returns whether this property is unfetched, unsaved and should not be
|
32
|
+
# lazy-loaded, determined by whether it is marked with the +:transient+ flag.
|
32
33
|
#
|
33
|
-
# @return [Boolean] whether
|
34
|
-
def
|
35
|
-
@flags.include?(:
|
34
|
+
# @return [Boolean] whether this property is transient
|
35
|
+
def transient?
|
36
|
+
@flags.include?(:transient)
|
36
37
|
end
|
37
|
-
|
38
|
-
# Returns whether
|
38
|
+
|
39
|
+
# Returns whether this property is a dependent whose value is automatically generated
|
39
40
|
# with place-holder domain objects when the parent is created. An attribute is auto-generated
|
40
41
|
# if the +:autogenerated+ flag is set.
|
41
42
|
#
|
42
|
-
# @return [Boolean] whether
|
43
|
+
# @return [Boolean] whether this property is auto-generated
|
43
44
|
def autogenerated?
|
44
45
|
@flags.include?(:autogenerated)
|
45
46
|
end
|
@@ -50,34 +51,34 @@ module CaRuby
|
|
50
51
|
# * it is {#cascaded?} and marked with the +:unfetched+ flag
|
51
52
|
# * it is marked with the +:fetch_saved+ flag
|
52
53
|
#
|
53
|
-
# @return [Boolean] whether
|
54
|
+
# @return [Boolean] whether this property must be refetched in order to reflect
|
54
55
|
# the database content
|
55
56
|
def fetch_saved?
|
56
57
|
@flags.include?(:fetch_saved) or autogenerated? or (cascaded? and @flags.include?(:unfetched))
|
57
58
|
end
|
58
59
|
|
59
|
-
# Returns whether
|
60
|
+
# Returns whether this property is either:
|
60
61
|
# 1. an owner attribute which does not automatically cascade application service creation
|
61
62
|
# or update to the referenced dependent, or
|
62
63
|
# 2. the dependent attribute whose inverse is a logical owner attribute
|
63
64
|
#
|
64
|
-
# @return [Boolean] whether
|
65
|
+
# @return [Boolean] whether this property is an uncascaded dependent
|
65
66
|
def logical?
|
66
67
|
@flags.include?(:logical) or (owner? and inverse_property and inverse_property.logical?)
|
67
68
|
end
|
68
69
|
|
69
|
-
#
|
70
|
-
# *
|
71
|
-
# * the
|
70
|
+
# This property is creatable if all of the following conditions hold:
|
71
|
+
# * it is {#saved?}
|
72
|
+
# * the +:update_only+ flag is not set
|
72
73
|
#
|
73
74
|
# @return [Boolean] whether this attribute is saved in a create operation
|
74
75
|
def creatable?
|
75
76
|
saved? and not @flags.include?(:update_only)
|
76
77
|
end
|
77
78
|
|
78
|
-
#
|
79
|
-
# *
|
80
|
-
# * the
|
79
|
+
# This property is updatable if all of the following conditions hold:
|
80
|
+
# * it is {#saved?}
|
81
|
+
# * the +:create_only+ flag is not set
|
81
82
|
#
|
82
83
|
# @return [Boolean] whether this attribute is saved in a update operation
|
83
84
|
def updatable?
|
@@ -86,7 +87,7 @@ module CaRuby
|
|
86
87
|
|
87
88
|
# Indicates whether this reference propery is saved when its owner is saved.
|
88
89
|
#
|
89
|
-
# @return [Boolean] whether
|
90
|
+
# @return [Boolean] whether this property is a physical dependent or the +:cascaded+ flag is set
|
90
91
|
def cascaded?
|
91
92
|
(dependent? and not logical?) or @flags.include?(:cascaded)
|
92
93
|
end
|
@@ -110,25 +111,23 @@ module CaRuby
|
|
110
111
|
# The given object has a null identifier:
|
111
112
|
# followed by the attribute type name.
|
112
113
|
#
|
113
|
-
# @return [Boolean] whether
|
114
|
+
# @return [Boolean] whether this property cascades to crate when the owner is updated
|
114
115
|
def cascade_update_to_create?
|
115
116
|
cascaded? and not @flags.include?(:no_cascade_update_to_create)
|
116
117
|
end
|
117
118
|
|
118
|
-
#
|
119
|
-
# * the attribute :unsaved flag is set
|
120
|
-
# * the attribute is {#proxied_save?}
|
119
|
+
# This property is saved if it is a Java property that is not {#unsaved} or {#proxied_save?}
|
121
120
|
# and any of the following conditions hold:
|
122
|
-
# *
|
123
|
-
# *
|
124
|
-
# *
|
125
|
-
# *
|
126
|
-
# *
|
121
|
+
# * it is {#nondomain?}
|
122
|
+
# * it is {#cascaded?}
|
123
|
+
# * it is not a {#collection?}
|
124
|
+
# * it does not have an inverse
|
125
|
+
# * it is a {#unidirectional_java_dependent?}
|
127
126
|
#
|
128
127
|
# @return [Boolean] whether this attribute is saved in a create or update operation
|
129
128
|
def saved?
|
130
129
|
@flags.include?(:saved) or
|
131
|
-
(java_property? and not @flags.include?(:unsaved)
|
130
|
+
(java_property? and not (@flags.include?(:unsaved) or transient? or proxied_save?) and
|
132
131
|
(nondomain? or cascaded? or not collection? or inverse.nil? or unidirectional_java_dependent?))
|
133
132
|
end
|
134
133
|
|
@@ -143,7 +142,7 @@ module CaRuby
|
|
143
142
|
not saved?
|
144
143
|
end
|
145
144
|
|
146
|
-
# @return [Boolean] whether
|
145
|
+
# @return [Boolean] whether this property return {#type} is a Resource class which
|
147
146
|
# implements the saver_proxy method
|
148
147
|
def proxied_save?
|
149
148
|
domain? and type.method_defined?(:saver_proxy)
|
@@ -163,11 +162,6 @@ module CaRuby
|
|
163
162
|
inv_prop = inverse_property
|
164
163
|
inv_prop.nil? or inv_prop.collection?
|
165
164
|
end
|
166
|
-
|
167
|
-
# @return [Boolean] whether the subject attribute is not saved
|
168
|
-
def transient?
|
169
|
-
not saved?
|
170
|
-
end
|
171
165
|
|
172
166
|
# @return [Boolean] whether this is a non-collection Java attribute
|
173
167
|
def searchable?
|
@@ -176,6 +170,7 @@ module CaRuby
|
|
176
170
|
|
177
171
|
# @return [Boolean] whether this attribute is set by the server
|
178
172
|
def volatile?
|
173
|
+
# TODO - subsume by autogenerated?
|
179
174
|
to_sym == :identifier or @flags.include?(:volatile)
|
180
175
|
end
|
181
176
|
|
data/lib/caruby/metadata.rb
CHANGED
@@ -1,10 +1,9 @@
|
|
1
|
-
require 'jinx/json/deserializer'
|
2
1
|
require 'caruby/metadata/propertied'
|
3
2
|
|
4
3
|
module CaRuby
|
5
4
|
# The metadata persistence mix-in.
|
6
5
|
module Metadata
|
7
|
-
include Propertied, Jinx::
|
6
|
+
include Propertied, Jinx::Metadata
|
8
7
|
|
9
8
|
private
|
10
9
|
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'jinx/helpers/stopwatch'
|
2
|
+
require 'jinx/migration/migrator'
|
3
|
+
|
4
|
+
module CaRuby
|
5
|
+
class Migrator < Jinx::Migrator
|
6
|
+
# Creates a new Migrator with the given options.
|
7
|
+
#
|
8
|
+
# The migration configuration must provide sufficient information to build a well-formed migration
|
9
|
+
# target object. For example, if the target object is a new +CaTissue::SpecimenCollectionGroup+,
|
10
|
+
# then the migrator must build that SCG's required +CollectionProtocolRegistration+. The CPR in
|
11
|
+
# turn must either exist in the database or the migrator must build the required CPR
|
12
|
+
# +participant+ and +collection_protocol+.
|
13
|
+
#
|
14
|
+
# @option (see Jinx::Migrator#initialize)
|
15
|
+
# @option opts [Database] :database the target application database
|
16
|
+
# @see #migrate_to_database
|
17
|
+
def initialize(opts={})
|
18
|
+
super
|
19
|
+
@database = opts[:database]
|
20
|
+
end
|
21
|
+
|
22
|
+
# Imports this migrator's file into the database with the given connect options.
|
23
|
+
# This method creates or updates the domain objects mapped from the migration source.
|
24
|
+
# If a block is given to this method, then the block is called on each migrated
|
25
|
+
# target object.
|
26
|
+
#
|
27
|
+
# The target object is saved in the database. Every referenced migrated object is created,
|
28
|
+
# if necessary. Finally, a migration target owner object is created, if necessary.
|
29
|
+
#
|
30
|
+
# For example, suppose a migration configuration specifies the following:
|
31
|
+
# * the target is a +CaTissue::SpecimenCollectionGroup+
|
32
|
+
# * the field mapping specifies a +Participant+ MRN,
|
33
|
+
# * the defaults specify a +CollectionProtocol+ title and a +Site+ name
|
34
|
+
#
|
35
|
+
# The migrator attempts to fetch the protocol and site from the database. If they do not
|
36
|
+
# exist, then they are created. In order to create the protocol and site, the migration
|
37
|
+
# configuration must specify sufficient information to validate the objects before creation,
|
38
|
+
# as described in {#initialize}. Finally, the SCG +CollectionProtocolRegistration+ owner
|
39
|
+
# is created. This CPR references the migration protocol and site.
|
40
|
+
#
|
41
|
+
# If the +:create+ option is set, then an input record for a target object which already
|
42
|
+
# exists in the database is noted in a debug log message and ignored rather than updated.
|
43
|
+
#
|
44
|
+
# @yield [target, row] operates on the migration target
|
45
|
+
# @yieldparam [Resource] target the migrated target domain object
|
46
|
+
# @yieldparam [{Symbol => Object}] row the migration source record
|
47
|
+
def migrate_to_database(&block)
|
48
|
+
# migrate with save
|
49
|
+
tm = Jinx::Stopwatch.measure { execute_save(&block) }.elapsed
|
50
|
+
logger.debug { format_migration_time_log_message(tm) }
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
# {#migrate} with a {#save} block on the migration target. Each migrated object
|
56
|
+
# is created, if necessary, after the target save.
|
57
|
+
def execute_save
|
58
|
+
if @database.nil? then
|
59
|
+
raise MigrationError.new("Migrator cannot save records since the database option was not specified.")
|
60
|
+
end
|
61
|
+
@database.open do |db|
|
62
|
+
migrate do |tgt, rec|
|
63
|
+
# Save the target object.
|
64
|
+
save(tgt, db)
|
65
|
+
# Ensure that each migrated object is created if necessary.
|
66
|
+
@migrated.each { |obj| create(obj, db) unless db.exists?(obj) }
|
67
|
+
yield(tgt, rec) if block_given?
|
68
|
+
db.clear
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# @param [Resource] obj the domain object to save in the database
|
74
|
+
# @return [Resource, nil] obj if the save is successful, nil otherwise
|
75
|
+
def save(obj, database)
|
76
|
+
if @create then
|
77
|
+
create(obj, database)
|
78
|
+
else
|
79
|
+
logger.debug { "Migrator saving #{obj}..." }
|
80
|
+
database.save(obj)
|
81
|
+
logger.debug { "Migrator saved #{obj}." }
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# @param [Resource] obj the domain object to create in the database
|
86
|
+
# @return [Resource, nil] obj if the create is successful, nil otherwise
|
87
|
+
def create(obj, database)
|
88
|
+
logger.debug { "Migrator creating #{obj}..." }
|
89
|
+
database.create(obj)
|
90
|
+
logger.debug { "Migrator created #{obj}." }
|
91
|
+
end
|
92
|
+
|
93
|
+
# @return [String] a log message for the given migration time in seconds
|
94
|
+
def format_migration_time_log_message(time)
|
95
|
+
# the database execution time
|
96
|
+
dt = @database.execution_time
|
97
|
+
if time > 120 then
|
98
|
+
time /= 60
|
99
|
+
dt /= 60
|
100
|
+
unit = "minutes"
|
101
|
+
else
|
102
|
+
unit = "seconds"
|
103
|
+
end
|
104
|
+
"Migration took #{'%.2f' % time} #{unit}, of which #{'%.2f' % dt} were database operations."
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
data/lib/caruby/resource.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'jinx/resource'
|
2
|
-
require '
|
2
|
+
require 'caruby/json/serializable'
|
3
3
|
require 'caruby/migration/migratable'
|
4
4
|
require 'caruby/database/persistable'
|
5
5
|
|
@@ -18,7 +18,7 @@ module CaRuby
|
|
18
18
|
# @metadata_module = CaRuby::Metadata
|
19
19
|
# end
|
20
20
|
module Resource
|
21
|
-
include CaRuby::Migratable, CaRuby::Persistable,
|
21
|
+
include CaRuby::Migratable, CaRuby::Persistable, CaRuby::JSON::Serializable, Jinx::Resource
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
data/lib/caruby/version.rb
CHANGED
data/lib/caruby.rb
CHANGED
@@ -12,8 +12,6 @@ class CacheTest < Test::Unit::TestCase
|
|
12
12
|
b = Item.new(:a)
|
13
13
|
assert_equal(a, cache[b], "Cached equivalent not found")
|
14
14
|
assert_equal(a, cache.add(b), "Cached add replaced existing entry")
|
15
|
-
cache.add!(b)
|
16
|
-
assert_equal(b, cache.add(b), "Cached add! did not replace existing entry")
|
17
15
|
end
|
18
16
|
|
19
17
|
def test_add!
|
@@ -22,7 +20,7 @@ class CacheTest < Test::Unit::TestCase
|
|
22
20
|
cache.add(a)
|
23
21
|
b = Item.new(:a)
|
24
22
|
cache.add!(b)
|
25
|
-
assert_equal(b, cache
|
23
|
+
assert_equal(b, cache[a], "Cached add! did not replace existing entry")
|
26
24
|
end
|
27
25
|
|
28
26
|
def test_clear
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: caruby-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 2.1.
|
5
|
+
version: 2.1.2
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- OHSU
|
@@ -10,8 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2012-
|
14
|
-
default_executable:
|
13
|
+
date: 2012-06-12 00:00:00 Z
|
15
14
|
dependencies:
|
16
15
|
- !ruby/object:Gem::Dependency
|
17
16
|
name: bundler
|
@@ -111,7 +110,6 @@ extra_rdoc_files: []
|
|
111
110
|
|
112
111
|
files:
|
113
112
|
- lib/caruby.rb
|
114
|
-
- lib/caruby/caruby-src.tar.gz
|
115
113
|
- lib/caruby/database.rb
|
116
114
|
- lib/caruby/metadata.rb
|
117
115
|
- lib/caruby/resource.rb
|
@@ -141,13 +139,13 @@ files:
|
|
141
139
|
- lib/caruby/helpers/properties.rb
|
142
140
|
- lib/caruby/helpers/roman.rb
|
143
141
|
- lib/caruby/helpers/version.rb
|
144
|
-
- lib/caruby/json/
|
145
|
-
- lib/caruby/json/serializer.rb
|
142
|
+
- lib/caruby/json/serializable.rb
|
146
143
|
- lib/caruby/metadata/java_property.rb
|
147
144
|
- lib/caruby/metadata/propertied.rb
|
148
145
|
- lib/caruby/metadata/property.rb
|
149
146
|
- lib/caruby/metadata/property_characteristics.rb
|
150
147
|
- lib/caruby/migration/migratable.rb
|
148
|
+
- lib/caruby/migration/migrator.rb
|
151
149
|
- lib/caruby/rdbi/driver/jdbc.rb
|
152
150
|
- History.md
|
153
151
|
- LEGAL
|
@@ -161,7 +159,6 @@ files:
|
|
161
159
|
- test/lib/caruby/helpers/properties_test.rb
|
162
160
|
- test/lib/caruby/helpers/roman_test.rb
|
163
161
|
- test/lib/caruby/helpers/version_test.rb
|
164
|
-
has_rdoc: yard
|
165
162
|
homepage: http://caruby.rubyforge.org
|
166
163
|
licenses:
|
167
164
|
- MIT
|
@@ -185,7 +182,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
185
182
|
requirements: []
|
186
183
|
|
187
184
|
rubyforge_project: caruby
|
188
|
-
rubygems_version: 1.
|
185
|
+
rubygems_version: 1.8.15
|
189
186
|
signing_key:
|
190
187
|
specification_version: 3
|
191
188
|
summary: Ruby facade for caBIG applications.
|
@@ -197,3 +194,4 @@ test_files:
|
|
197
194
|
- test/lib/caruby/helpers/properties_test.rb
|
198
195
|
- test/lib/caruby/helpers/roman_test.rb
|
199
196
|
- test/lib/caruby/helpers/version_test.rb
|
197
|
+
has_rdoc: yard
|
Binary file
|
@@ -1,15 +0,0 @@
|
|
1
|
-
require 'json'
|
2
|
-
|
3
|
-
module CaRuby
|
4
|
-
module JSON
|
5
|
-
# JSON => {Jinx::Resource} deserializer.
|
6
|
-
module Deserializer
|
7
|
-
# @param [String] json the JSON to deserialize
|
8
|
-
# @return [Jinx::Resource] the deserialized object
|
9
|
-
def json_create(json)
|
10
|
-
# Make the new object from the json data attribute => value hash.
|
11
|
-
new(json['data'])
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
@@ -1,69 +0,0 @@
|
|
1
|
-
module CaRuby
|
2
|
-
module JSON
|
3
|
-
# {Jinx::Resource} => JSON serializer.
|
4
|
-
module Serializer
|
5
|
-
# @param args the JSON serialization options
|
6
|
-
# @return [String] the JSON representation of this {Jinx::Resource}
|
7
|
-
def to_json(*args)
|
8
|
-
database.lazy_loader.disable do
|
9
|
-
{
|
10
|
-
'json_class' => json_class_name,
|
11
|
-
'data' => json_value_hash
|
12
|
-
}.to_json(*args)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
private
|
17
|
-
|
18
|
-
# The JSON class name must be scoped by the Resource package module, not the
|
19
|
-
# Java package, in order to recognize the Jinx::Resource JSON hooks.
|
20
|
-
#
|
21
|
-
# @return [String] the class name qualified by the Resource package module name context
|
22
|
-
def json_class_name
|
23
|
-
[self.class.domain_module, self.class.name.demodulize].join('::')
|
24
|
-
end
|
25
|
-
|
26
|
-
# Builds a serializable attribute => value hash. An independent or owner attribute
|
27
|
-
# value is a copy of the referenced domain object consisting of only the key attributes.
|
28
|
-
#
|
29
|
-
# @return [{Symbol => Object}] the serializable value hash
|
30
|
-
def json_value_hash
|
31
|
-
vh = value_hash(self.class.nondomain_attributes)
|
32
|
-
vh.merge!(value_hash(self.class.dependent_attributes))
|
33
|
-
self.class.independent_attributes.each do |oa|
|
34
|
-
value = send(oa) || next
|
35
|
-
vh[oa] = owner.copy(owner.class.all_key_attributes)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def json_independent_reference(ref)
|
40
|
-
return ref.map { |item| json_independent_reference(item) } if ref.collection?
|
41
|
-
ref.copy(json_foreign_key_value_hash(ref))
|
42
|
-
end
|
43
|
-
|
44
|
-
def json_foreign_key_value_hash(ref)
|
45
|
-
json_key_value_hash(ref, ref.class.primary_key_attributes) or
|
46
|
-
json_key_value_hash(ref, ref.class.secondary_key_attributes) or
|
47
|
-
json_key_value_hash(ref, ref.class.alternate_key_attributes)
|
48
|
-
Hash::EMPTY_HASH
|
49
|
-
end
|
50
|
-
|
51
|
-
def json_key_value_hash(ref, attributes)
|
52
|
-
attributes.to_compact_hash { |ka| json_foreign_key_value(ref, ka) || return }
|
53
|
-
end
|
54
|
-
|
55
|
-
def json_foreign_key_value(ref, attribute)
|
56
|
-
value = ref.send(attribute) || return
|
57
|
-
Jinx::Resource === value ? json_foreign_key_value_hash(value) : value
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
module Enumerable
|
64
|
-
# @param args the JSON serialization options
|
65
|
-
# @return [String] the JSON representation of this Enumerable as an array
|
66
|
-
def to_json(*args)
|
67
|
-
to_a.to_json(*args)
|
68
|
-
end
|
69
|
-
end
|