caruby-core 2.1.1 → 2.1.2

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.
@@ -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, :nosync,
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 the subject attribute is fetched, determined as follows:
16
- # * An attribute marked with the :fetched flag is fetched.
17
- # * An attribute marked with the :unfetched flag is not fetched.
18
- # Otherwise, a non-domain attribute is fetched, and a domain attribute is
19
- # fetched if one of the following conditions hold:
20
- # * A dependent domain attribute is fetched if it is not logical.
21
- # * An owner domain attribute is fetched by default.
22
- # * An independent domain attribute is fetched if it is abstract and not derived.
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 the attribute is fetched
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 the subject attribute is not saved.
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 the attribute is unsaved
34
- def unsaved?
35
- @flags.include?(:unsaved)
34
+ # @return [Boolean] whether this property is transient
35
+ def transient?
36
+ @flags.include?(:transient)
36
37
  end
37
-
38
- # Returns whether the subject attribute is a dependent whose value is automatically generated
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 the attribute is auto-generated
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 the subject attribute must be refetched in order to reflect
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 the subject attribute is either:
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 the attribute is an uncascaded dependent
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
- # A Java attribute is creatable if all of the following conditions hold:
70
- # * the attribute is {#saved?}
71
- # * the attribute :update_only flag is not set
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
- # A Java attribute is updatable if all of the following conditions hold:
79
- # * the attribute is {#saved?}
80
- # * the attribute :create_only flag is not set
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 the attribute is a physical dependent or the +:cascaded+ flag is set
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 the attribute cascades to crate when the owner is updated
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
- # A Java property attribute is saved if none of the following conditions hold:
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
- # * the attibute is {#nondomain?}
123
- # * the attribute is cascaded
124
- # * the attribute value is not a collection
125
- # * the attribute does not have an inverse
126
- # * the attribute :saved flag is set
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) and not proxied_save? and
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 the attribute return {#type} is a Resource class which
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
 
@@ -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::JSON::Deserializer, Jinx::Metadata
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
+
@@ -1,5 +1,5 @@
1
1
  require 'jinx/resource'
2
- require 'jinx/json/serializer'
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, Jinx::JSON::Serializer, Jinx::Resource
21
+ include CaRuby::Migratable, CaRuby::Persistable, CaRuby::JSON::Serializable, Jinx::Resource
22
22
  end
23
23
  end
24
24
 
@@ -1,3 +1,3 @@
1
1
  module CaRuby
2
- VERSION = "2.1.1"
2
+ VERSION = "2.1.2"
3
3
  end
data/lib/caruby.rb CHANGED
@@ -1,3 +1 @@
1
1
  require 'jinx'
2
- require 'jinx/helpers/log'
3
- require 'jinx/helpers/error'
@@ -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.add(b), "Cached add! did not replace existing entry")
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.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-04-13 00:00:00 -07:00
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/deserializer.rb
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.5.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