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.
@@ -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