persistence 0.0.1.alpha → 0.0.1

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.
Files changed (138) hide show
  1. data/CHANGELOG.md +4 -0
  2. data/README.md +260 -17
  3. data/lib/namespaces.rb +55 -0
  4. data/lib/persistence.rb +38 -3
  5. data/lib/persistence/adapter/abstract.rb +22 -0
  6. data/lib/persistence/adapter/abstract/enable_disable.rb +107 -0
  7. data/lib/persistence/adapter/abstract/primary_key/id_property_string.rb +33 -0
  8. data/lib/persistence/adapter/abstract/primary_key/simple.rb +29 -0
  9. data/lib/persistence/adapter/mock.rb +9 -0
  10. data/lib/persistence/adapter/mock/adapter_interface.rb +102 -0
  11. data/lib/persistence/adapter/mock/bucket.rb +9 -0
  12. data/lib/persistence/adapter/mock/bucket/bucket_interface.rb +260 -0
  13. data/lib/persistence/adapter/mock/bucket/index.rb +9 -0
  14. data/lib/persistence/adapter/mock/bucket/index/index_interface.rb +155 -0
  15. data/lib/persistence/adapter/mock/cursor.rb +9 -0
  16. data/lib/persistence/adapter/mock/cursor/cursor_interface.rb +238 -0
  17. data/lib/persistence/cursor.rb +11 -0
  18. data/lib/persistence/cursor/atomic.rb +110 -0
  19. data/lib/persistence/cursor/cursor_interface.rb +337 -0
  20. data/lib/persistence/exception/block_required.rb +7 -0
  21. data/lib/persistence/exception/conflicting_index_already_declared.rb +7 -0
  22. data/lib/persistence/exception/duplicate_violates_unique_index.rb +7 -0
  23. data/lib/persistence/exception/explicit_index_required.rb +7 -0
  24. data/lib/persistence/exception/indexing_block_failed_to_generate_keys.rb +7 -0
  25. data/lib/persistence/exception/indexing_object_requires_keys.rb +7 -0
  26. data/lib/persistence/exception/key_value_required.rb +7 -0
  27. data/lib/persistence/exception/no_port_enabled.rb +7 -0
  28. data/lib/persistence/object.rb +21 -0
  29. data/lib/persistence/object/autodetermine.rb +74 -0
  30. data/lib/persistence/object/class_instance.rb +1884 -0
  31. data/lib/persistence/object/complex.rb +17 -0
  32. data/lib/persistence/object/complex/array.rb +14 -0
  33. data/lib/persistence/object/complex/array/class_instance.rb +37 -0
  34. data/lib/persistence/object/complex/array/object_instance.rb +54 -0
  35. data/lib/persistence/object/complex/attributes.rb +1808 -0
  36. data/lib/persistence/object/complex/attributes/attributes_array.rb +32 -0
  37. data/lib/persistence/object/complex/attributes/attributes_hash.rb +187 -0
  38. data/lib/persistence/object/complex/attributes/default_atomic_non_atomic.rb +102 -0
  39. data/lib/persistence/object/complex/attributes/hash_to_port.rb +40 -0
  40. data/lib/persistence/object/complex/class_and_object_instance.rb +132 -0
  41. data/lib/persistence/object/complex/class_instance.rb +267 -0
  42. data/lib/persistence/object/complex/complex_object.rb +111 -0
  43. data/lib/persistence/object/complex/hash.rb +14 -0
  44. data/lib/persistence/object/complex/hash/class_instance.rb +40 -0
  45. data/lib/persistence/object/complex/hash/object_instance.rb +63 -0
  46. data/lib/persistence/object/complex/index/attribute_index.rb +10 -0
  47. data/lib/persistence/object/complex/index/attribute_index/attribute_index_interface.rb +43 -0
  48. data/lib/persistence/object/complex/object_instance.rb +469 -0
  49. data/lib/persistence/object/flat.rb +17 -0
  50. data/lib/persistence/object/flat/class_instance.rb +34 -0
  51. data/lib/persistence/object/flat/file.rb +14 -0
  52. data/lib/persistence/object/flat/file/class_instance.rb +122 -0
  53. data/lib/persistence/object/flat/file/contents.rb +7 -0
  54. data/lib/persistence/object/flat/file/file_persistence.rb +147 -0
  55. data/lib/persistence/object/flat/file/object_instance.rb +116 -0
  56. data/lib/persistence/object/flat/file/path.rb +9 -0
  57. data/lib/persistence/object/flat/object_instance.rb +24 -0
  58. data/lib/persistence/object/index.rb +479 -0
  59. data/lib/persistence/object/index/block_index.rb +10 -0
  60. data/lib/persistence/object/index/block_index/block_index_interface.rb +110 -0
  61. data/lib/persistence/object/index/explicit_index.rb +10 -0
  62. data/lib/persistence/object/index/explicit_index/explicit_index_interface.rb +57 -0
  63. data/lib/persistence/object/index_hash.rb +40 -0
  64. data/lib/persistence/object/object_instance.rb +322 -0
  65. data/lib/persistence/object/parse_persistence_args.rb +145 -0
  66. data/lib/persistence/port.rb +9 -0
  67. data/lib/persistence/port/bucket.rb +9 -0
  68. data/lib/persistence/port/bucket/bucket_index.rb +9 -0
  69. data/lib/persistence/port/bucket/bucket_interface.rb +685 -0
  70. data/lib/persistence/port/controller.rb +263 -0
  71. data/lib/persistence/port/port_interface.rb +417 -0
  72. data/lib/requires.rb +146 -0
  73. data/spec/Integration_spec.rb +53 -0
  74. data/spec/Persistence_spec.rb +175 -0
  75. data/spec/example_objects.rb +6 -0
  76. data/spec/example_objects/complex_object.rb +7 -0
  77. data/spec/example_objects/complex_object/array_object.rb +7 -0
  78. data/spec/example_objects/complex_object/hash_object.rb +7 -0
  79. data/spec/example_objects/flat_object.rb +7 -0
  80. data/spec/example_objects/flat_object/file_object.rb +7 -0
  81. data/spec/persistence/adapter/enable_disable_spec.rb +29 -0
  82. data/spec/persistence/adapter/mock/cursor_spec.rb +64 -0
  83. data/spec/persistence/adapter/mock_helpers.rb +27 -0
  84. data/spec/persistence/adapter/mock_helpers/bucket.rb +10 -0
  85. data/spec/persistence/adapter/mock_helpers/integration/dictionary_hash.rb +4 -0
  86. data/spec/persistence/adapter/mock_helpers/integration/note.rb +18 -0
  87. data/spec/persistence/adapter/mock_helpers/integration/notes_array.rb +4 -0
  88. data/spec/persistence/adapter/mock_helpers/integration/user.rb +44 -0
  89. data/spec/persistence/adapter/mock_helpers/integration/user/address.rb +18 -0
  90. data/spec/persistence/adapter/mock_helpers/integration/user/dictionary_entry.rb +12 -0
  91. data/spec/persistence/adapter/mock_helpers/integration/user/sub_account.rb +15 -0
  92. data/spec/persistence/adapter/mock_helpers/object.rb +87 -0
  93. data/spec/persistence/adapter/mock_helpers/port.rb +21 -0
  94. data/spec/persistence/adapter/mock_spec.rb +211 -0
  95. data/spec/persistence/adapter/primary_key/id_property_string_spec.rb +27 -0
  96. data/spec/persistence/adapter/primary_key/simple_spec.rb +19 -0
  97. data/spec/persistence/adapter/spec_abstract/adapter_spec.rb +223 -0
  98. data/spec/persistence/adapter/spec_abstract/cursor_spec.rb +116 -0
  99. data/spec/persistence/cursor/atomic_spec.rb +86 -0
  100. data/spec/persistence/cursor/object_and_class_instance_spec.rb +73 -0
  101. data/spec/persistence/cursor_spec.rb +128 -0
  102. data/spec/persistence/object/complex/attributes/persistence_hash/array_instance_spec.rb +51 -0
  103. data/spec/persistence/object/complex/attributes/persistence_hash/hash_instance_spec.rb +56 -0
  104. data/spec/persistence/object/complex/attributes_spec.rb +1717 -0
  105. data/spec/persistence/object/complex/complex_spec.rb +922 -0
  106. data/spec/persistence/object/complex/index/attribute_index_spec.rb +76 -0
  107. data/spec/persistence/object/flat/bignum_spec.rb +33 -0
  108. data/spec/persistence/object/flat/class_instance_spec.rb +30 -0
  109. data/spec/persistence/object/flat/class_spec.rb +38 -0
  110. data/spec/persistence/object/flat/complex_spec.rb +36 -0
  111. data/spec/persistence/object/flat/false_class_spec.rb +34 -0
  112. data/spec/persistence/object/flat/file/class_instance_spec.rb +54 -0
  113. data/spec/persistence/object/flat/file/object_instance_spec.rb +143 -0
  114. data/spec/persistence/object/flat/file_spec.rb +64 -0
  115. data/spec/persistence/object/flat/fixnum_spec.rb +32 -0
  116. data/spec/persistence/object/flat/float_spec.rb +32 -0
  117. data/spec/persistence/object/flat/indexing_spec.rb +38 -0
  118. data/spec/persistence/object/flat/rational_spec.rb +33 -0
  119. data/spec/persistence/object/flat/regexp_spec.rb +32 -0
  120. data/spec/persistence/object/flat/string_spec.rb +34 -0
  121. data/spec/persistence/object/flat/symbol_spec.rb +32 -0
  122. data/spec/persistence/object/flat/true_class_spec.rb +32 -0
  123. data/spec/persistence/object/indexes/block_index_spec.rb +119 -0
  124. data/spec/persistence/object/indexes/explicit_index_spec.rb +112 -0
  125. data/spec/persistence/object/parse_persistence_args_spec.rb +65 -0
  126. data/spec/persistence/object_spec.rb +310 -0
  127. data/spec/persistence/port/bucket/bucket_interface_spec.rb +146 -0
  128. data/spec/persistence/port/bucket/index/bucket_index_spec.rb +67 -0
  129. data/spec/persistence/port/bucket_spec.rb +20 -0
  130. data/spec/persistence/port/controller_spec.rb +60 -0
  131. data/spec/persistence/port/port_interface_spec.rb +105 -0
  132. metadata +178 -21
  133. data/.gitignore +0 -17
  134. data/Gemfile +0 -4
  135. data/LICENSE +0 -22
  136. data/Rakefile +0 -2
  137. data/lib/persistence/version.rb +0 -3
  138. data/persistence.gemspec +0 -17
@@ -0,0 +1,145 @@
1
+
2
+ ###
3
+ # @private
4
+ #
5
+ # Internal helper for parsing args of the format: method, method( global_id ), method( index_name, value ),
6
+ # method( index_instance, value ), method( index_name => value ), method( index_instance => value ).
7
+ module ::Persistence::Object::ParsePersistenceArgs
8
+
9
+ #########################################
10
+ # parse_args_for_index_value_no_value #
11
+ #########################################
12
+
13
+ ###
14
+ # Parse *args for index, key_value, no_value.
15
+ #
16
+ # @param args [Array] An array of args of the format: method, method( global_id ), method( index_name, value ),
17
+ # method( index_instance, value ), method( index_name => value ), method( index_instance => value ).
18
+ #
19
+ # @param require_value [true,false] Whether key value must be provided; will throw exception if true and
20
+ # key value is not provided.
21
+ #
22
+ # @return [Array] Array containing index instance, key value, whether key value was provided.
23
+ #
24
+ def parse_args_for_index_value_no_value( args, require_value = false )
25
+
26
+ # * nil
27
+ # - Cursor to primary bucket
28
+ # * :index
29
+ # - Cursor to index
30
+ # * :index => persistence_key
31
+ # - Object(s) for indexed key value
32
+
33
+ index = nil
34
+ key_value = nil
35
+ no_value = nil
36
+ case args.count
37
+
38
+ when 0
39
+
40
+ no_value = true
41
+ if require_value
42
+ raise ::Persistence::Exception::KeyValueRequired,
43
+ 'Key value required.'
44
+ end
45
+
46
+ when 1
47
+
48
+ index_or_id = args[ 0 ]
49
+ if index_or_id.is_a?( Symbol ) or
50
+ index_or_id.is_a?( String )
51
+
52
+ index = indexes[ index_or_id ]
53
+ unless index
54
+ raise ::Persistence::Exception::ExplicitIndexRequired,
55
+ 'Explicit index ' + index_or_id.to_s + ' did not exist.'
56
+ end
57
+ no_value = true
58
+
59
+ elsif index_or_id.respond_to?( :index_object )
60
+
61
+ index = index_or_id
62
+ no_value = true
63
+
64
+ elsif index_or_id.is_a?( Hash )
65
+
66
+ key_value = index_or_id.values[ 0 ]
67
+ index_name = index_or_id.keys[ 0 ]
68
+ if index_name.is_a?( Symbol ) or
69
+ index_name.is_a?( String )
70
+
71
+ index = indexes[ index_name ]
72
+ unless index
73
+ raise ::Persistence::Exception::ExplicitIndexRequired,
74
+ 'Explicit index :' + index_name.to_s + ' did not exist.'
75
+ end
76
+
77
+ end
78
+ no_value = false
79
+
80
+ else
81
+
82
+ # persistence_id - anything other than Symbol, String, Hash
83
+ key_value = args[ 0 ]
84
+ no_value = false
85
+
86
+ end
87
+
88
+ when 2
89
+
90
+ index_or_name = args[ 0 ]
91
+
92
+ index = index_or_name.respond_to?( :index_object ) ? index_or_name : indexes[ index_or_name ]
93
+ key_value = args[ 1 ]
94
+
95
+ if ! index and ! key_value
96
+ raise ::Persistence::Exception::ExplicitIndexRequired,
97
+ 'Index ' + index_or_name.to_s + ' did not exist.'
98
+ end
99
+ no_value = false
100
+
101
+ else
102
+
103
+ raise 'Unexpected arguments ' + args.inspect + '.'
104
+
105
+ end
106
+
107
+ # if we have a file we need to persist it like we would a sub-object
108
+ if key_value.is_a?( File )
109
+ key_value = process_file_key( key_value )
110
+ end
111
+
112
+ return index, key_value, no_value
113
+
114
+ end
115
+
116
+ ######################
117
+ # process_file_key #
118
+ ######################
119
+
120
+ ###
121
+ # Internal helper method to handle instances of File as key.
122
+ #
123
+ # @param file_key [File] File instance to process as key.
124
+ #
125
+ # @return [Persistence::Object::Flat::File::Path,Persistence::Object::Flat::File::Contents] Processed key.
126
+ #
127
+ def process_file_key( file_key )
128
+
129
+ # do we have a file key? if so we need to replace it with File::Path or File::Contents
130
+
131
+ processed_key = nil
132
+
133
+ if persists_files_by_path?
134
+ processed_key = ::Persistence::Object::Flat::File::Path.new( file_key.path )
135
+ else
136
+ starting_pos = file_key.pos
137
+ processed_key = ::Persistence::Object::Flat::File::Contents.new( file_key.readlines.join )
138
+ file_key.pos = starting_pos
139
+ end
140
+
141
+ return processed_key
142
+
143
+ end
144
+
145
+ end
@@ -0,0 +1,9 @@
1
+
2
+ ###
3
+ # Public interface to storage port. Provides consist interface to adapter implementation.
4
+ #
5
+ class ::Persistence::Port
6
+
7
+ include ::Persistence::Port::PortInterface
8
+
9
+ end
@@ -0,0 +1,9 @@
1
+
2
+ ###
3
+ # Public interface to bucket in storage port. Provides consistent interface to adapter implementation.
4
+ #
5
+ class ::Persistence::Port::Bucket
6
+
7
+ include ::Persistence::Port::Bucket::BucketInterface
8
+
9
+ end
@@ -0,0 +1,9 @@
1
+
2
+ ###
3
+ # Bucket indexes run on each object inserted into bucket.
4
+ #
5
+ class ::Persistence::Port::Bucket::BucketIndex
6
+
7
+ include ::Persistence::Object::Index::BlockIndex::BlockIndexInterface
8
+
9
+ end
@@ -0,0 +1,685 @@
1
+
2
+ ###
3
+ # Interface for Bucket implementation. Provided separately for easy overriding.
4
+ #
5
+ module ::Persistence::Port::Bucket::BucketInterface
6
+
7
+ include ::Persistence::Object::Flat::File::FilePersistence
8
+
9
+ include ::Enumerable
10
+
11
+ ################
12
+ # initialize #
13
+ ################
14
+
15
+ ###
16
+ #
17
+ # @param parent_port Port where this bucket is active. Can be nil if no port is yet enabled.
18
+ #
19
+ # @param bucket_name Name of the bucket to open in port.
20
+ #
21
+ def initialize( parent_port, bucket_name )
22
+
23
+ @name = bucket_name
24
+
25
+ @indexes = { }
26
+ @pending_indexes = [ ]
27
+
28
+ if parent_port
29
+ initialize_for_port( parent_port )
30
+ end
31
+
32
+ end
33
+
34
+ #########################
35
+ # initialize_for_port #
36
+ #########################
37
+
38
+ ###
39
+ # Initialize bucket for a port that has been enabled.
40
+ #
41
+ # @param port Parent port in which to initialize bucket.
42
+ #
43
+ def initialize_for_port( port )
44
+
45
+ if port = ::Persistence.port_for_name_or_port( port ) and port.enabled?
46
+
47
+ @parent_port = ::Persistence.port_for_name_or_port( port )
48
+
49
+ if @parent_port.enabled?
50
+ @adapter_bucket = @parent_port.adapter.persistence_bucket( @name )
51
+ end
52
+
53
+ @indexes.each do |this_index_name, this_index_instance|
54
+ this_index_instance.initialize_for_bucket( self )
55
+ end
56
+
57
+ @pending_indexes.delete_if do |this_pending_index|
58
+ this_pending_index.initialize_for_bucket( self )
59
+ true
60
+ end
61
+
62
+ else
63
+
64
+ disable
65
+
66
+ end
67
+
68
+ end
69
+
70
+ ####################
71
+ # adapter_bucket #
72
+ ####################
73
+
74
+ ###
75
+ # Retrieve parallel adapter bucket instance.
76
+ #
77
+ # @return [Object] Adapter bucket instance.
78
+ #
79
+ def adapter_bucket
80
+
81
+ unless @adapter_bucket
82
+ raise 'Persistence port must be enabled first.'
83
+ end
84
+
85
+ return @adapter_bucket
86
+
87
+ end
88
+
89
+ ##########
90
+ # name #
91
+ ##########
92
+
93
+ ###
94
+ # @!attribute [accessor] Name of bucket
95
+ #
96
+ # @return [Symbol,String] Name.
97
+ #
98
+ attr_accessor :name
99
+
100
+ #################
101
+ # parent_port #
102
+ #################
103
+
104
+ attr_accessor :parent_port
105
+
106
+ #############
107
+ # disable #
108
+ #############
109
+
110
+ ###
111
+ # @private
112
+ #
113
+ # Disable bucket when port disables. Internal helper method necessary to ensure
114
+ # that old references don't stick around.
115
+ #
116
+ def disable
117
+
118
+ @adapter_bucket = nil
119
+ @parent_port = nil
120
+
121
+ @indexes.each do |this_index_name, this_index|
122
+ this_index.disable
123
+ end
124
+
125
+ end
126
+
127
+ ##################
128
+ # create_index #
129
+ ##################
130
+
131
+ ###
132
+ # Create a bucket index, which is a block index that runs on each inserted object, regardless of type.
133
+ #
134
+ def create_index( index_name, sort_by_proc = nil, & indexing_block )
135
+
136
+ return create_bucket_index( index_name, false, sort_by_proc, & indexing_block )
137
+
138
+ end
139
+
140
+ ##################################
141
+ # create_index_with_duplicates #
142
+ ##################################
143
+
144
+ ###
145
+ # Create a bucket index that permits duplicates.
146
+ #
147
+ def create_index_with_duplicates( index_name, sort_by_proc = nil, sort_duplicates_by_proc = nil, & indexing_block )
148
+
149
+ return create_bucket_index( index_name, true, sort_by_proc, sort_duplicates_by_proc, & indexing_block )
150
+
151
+ end
152
+
153
+ ################
154
+ # pend_index #
155
+ ################
156
+
157
+ ###
158
+ # @private
159
+ #
160
+ # Pend index instance for port to be enabled.
161
+ #
162
+ # @param index_instance Instance of index that is waiting for port to be enabled.
163
+ #
164
+ def pend_index( index_instance )
165
+
166
+ @pending_indexes.push( index_instance )
167
+
168
+ end
169
+
170
+ ###########
171
+ # index #
172
+ ###########
173
+
174
+ ###
175
+ # Retrieve index.
176
+ #
177
+ # @param index_name [Symbol,String] Name of index
178
+ #
179
+ # @param ensure_exists [true,false] Whether exception should be thrown if index does not exist.
180
+ #
181
+ # @return [Persistence::Object::Index] Index instance
182
+ #
183
+ def index( index_name, ensure_exists = false )
184
+
185
+ index_instance = nil
186
+
187
+ unless index_instance = @indexes[ index_name ]
188
+ if ensure_exists
189
+ raise ::ArgumentError, 'No index found by name ' << index_name.to_s + '.'
190
+ end
191
+ end
192
+
193
+ return index_instance
194
+
195
+ end
196
+
197
+ ################
198
+ # has_index? #
199
+ ################
200
+
201
+ ###
202
+ # Query whether attribute index(es) exist for object.
203
+ #
204
+ # @overload has_attribute_index?( index_name, ... )
205
+ #
206
+ # @param index_name Name of requested index.
207
+ #
208
+ # @return [true,false] Whether index(es) exist.
209
+ #
210
+ def has_index?( *indexes )
211
+
212
+ has_index = false
213
+
214
+ indexes.each do |this_index|
215
+ break unless has_index = @indexes.has_key?( index_name )
216
+ end
217
+
218
+ return has_index
219
+
220
+ end
221
+
222
+ ###########
223
+ # count #
224
+ ###########
225
+
226
+ ###
227
+ # Get the number of objects in index. See {::Enumerable}.
228
+ #
229
+ # @return [Integer] Number of objects in bucket.
230
+ #
231
+ def count( *args, & count_block )
232
+
233
+ return_value = 0
234
+
235
+ if block_given?
236
+ return_value = super( & count_block )
237
+ elsif args.empty?
238
+ return_value = adapter_bucket.count
239
+ else
240
+ return_value = super( *args )
241
+ end
242
+
243
+ return return_value
244
+
245
+ end
246
+
247
+ #############################
248
+ # delete_index_for_object #
249
+ #############################
250
+
251
+ ###
252
+ # @private
253
+ #
254
+ # Delete indexed entries for object.
255
+ #
256
+ # @param object Object that owns indexed entries.
257
+ #
258
+ # @param index_name Name of index.
259
+ #
260
+ def delete_index_for_object( object, index_name )
261
+
262
+ return delete_index_for_object_id( object.persistence_id )
263
+
264
+ end
265
+
266
+ ################################
267
+ # delete_index_for_object_id #
268
+ ################################
269
+
270
+ ###
271
+ # @private
272
+ #
273
+ # Delete indexed entries for object.
274
+ #
275
+ # @param global_id Object persistence ID that owns indexed entries.
276
+ #
277
+ # @param index_name Name of index.
278
+ #
279
+ def delete_index_for_object_id( global_id, index_name )
280
+
281
+ return adapter_bucket.delete_index_for_object_id( global_id )
282
+
283
+ end
284
+
285
+ ###################
286
+ # get_attribute #
287
+ ###################
288
+
289
+ ###
290
+ # @private
291
+ #
292
+ # Get attribute for object from port.
293
+ #
294
+ # @param object Object that owns indexed entries.
295
+ #
296
+ # @param attribute_name Name of attribute.
297
+ #
298
+ def get_attribute( object, attribute_name )
299
+
300
+ primary_key = primary_key_for_attribute_name( object, attribute_name )
301
+
302
+ attribute_value = adapter_bucket.get_attribute( object, primary_key )
303
+
304
+ if attribute_value.is_a?( ::Persistence::Object::Complex::ComplexObject )
305
+ attribute_value.persistence_port = object.persistence_port
306
+ attribute_value = attribute_value.persist
307
+ end
308
+
309
+ return attribute_value
310
+
311
+ end
312
+
313
+ ####################
314
+ # put_attribute! #
315
+ ####################
316
+
317
+ ###
318
+ # @private
319
+ #
320
+ # Put attribute for object to port.
321
+ #
322
+ # @param object Object that owns indexed entries.
323
+ #
324
+ # @param attribute_name Name of attribute.
325
+ #
326
+ # @param attribute_value Value to put.
327
+ #
328
+ def put_attribute!( object, attribute_name, attribute_value )
329
+
330
+ primary_key = primary_key_for_attribute_name( object, attribute_name )
331
+
332
+ return adapter_bucket.put_attribute!( object, primary_key, attribute_value )
333
+
334
+ end
335
+
336
+ #################
337
+ # put_object! #
338
+ #################
339
+
340
+ ###
341
+ # @private
342
+ #
343
+ # Put object properties to persistence port.
344
+ #
345
+ # @param object Object to persist to port.
346
+ #
347
+ def put_object!( object )
348
+
349
+ return adapter_bucket.put_object!( object )
350
+
351
+ end
352
+
353
+ ################
354
+ # get_object #
355
+ ################
356
+
357
+ ###
358
+ # @private
359
+ #
360
+ # Get object from persistence port.
361
+ #
362
+ # @param global_id Object persistence ID to persist from port.
363
+ #
364
+ # @return [Object] Persisted object instance.
365
+ #
366
+ def get_object( global_id )
367
+
368
+ object = nil
369
+
370
+ # get the class
371
+ if klass = @parent_port.get_class_for_object_id( global_id )
372
+
373
+ object = klass.new
374
+
375
+ object.persistence_id = global_id
376
+
377
+ # if we have non-atomic attributes, load them
378
+ unless klass.non_atomic_attribute_readers.empty?
379
+
380
+ if persistence_hash_from_port = get_object_hash( global_id )
381
+
382
+ object.load_persistence_hash( object.persistence_port, persistence_hash_from_port )
383
+
384
+ end
385
+
386
+ end
387
+
388
+ end
389
+
390
+ return object
391
+
392
+ end
393
+
394
+ #####################
395
+ # get_object_hash #
396
+ #####################
397
+
398
+ ###
399
+ # @private
400
+ #
401
+ # Get object properties from persistence port.
402
+ #
403
+ # @param global_id Object persistence ID to persist from port.
404
+ #
405
+ # @return [Hash] Persistence hash from port.
406
+ #
407
+ def get_object_hash( global_id )
408
+
409
+ return adapter_bucket.get_object( global_id )
410
+
411
+ end
412
+
413
+ #####################
414
+ # get_flat_object #
415
+ #####################
416
+
417
+ ###
418
+ # @private
419
+ #
420
+ # Get flat object from persistence port.
421
+ #
422
+ # @param global_id Object persistence ID to persist from port.
423
+ #
424
+ # @return [Object] Persisted object instance.
425
+ #
426
+ def get_flat_object( global_id )
427
+
428
+ flat_object = nil
429
+
430
+ if persistence_value_hash = adapter_bucket.get_object( global_id )
431
+
432
+ if persistence_value_key_data = persistence_value_hash.first
433
+ flat_object = persistence_value_key_data[ 1 ]
434
+ flat_object.persistence_id = global_id
435
+ end
436
+ end
437
+
438
+ return flat_object
439
+
440
+ end
441
+
442
+ ####################
443
+ # delete_object! #
444
+ ####################
445
+
446
+ ###
447
+ # @private
448
+ #
449
+ # Delete object from persistence port.
450
+ #
451
+ # @param global_id Object persistence ID to delete from port.
452
+ #
453
+ # @return [Hash] Persistence hash from port.
454
+ #
455
+ def delete_object!( global_id )
456
+
457
+ return adapter_bucket.delete_object!( global_id )
458
+
459
+ end
460
+
461
+ #######################
462
+ # delete_attribute! #
463
+ #######################
464
+
465
+ ###
466
+ # @private
467
+ #
468
+ # Delete attribute for object from port.
469
+ #
470
+ # @param object Object that owns indexed entries.
471
+ #
472
+ # @param attribute_name Name of attribute.
473
+ #
474
+ def delete_attribute!( object, attribute_name )
475
+
476
+ primary_key = primary_key_for_attribute_name( object, attribute_name )
477
+
478
+ return adapter_bucket.delete_attribute!( object, primary_key )
479
+
480
+ end
481
+
482
+ ####################################
483
+ # primary_key_for_attribute_name #
484
+ ####################################
485
+
486
+ ###
487
+ # @private
488
+ #
489
+ # Generate primary key for storage for attribute name on object.
490
+ #
491
+ # @param object Object for which attribute is being stored.
492
+ #
493
+ # @param attribute_name Name of attribute.
494
+ #
495
+ # @return [String] Primary key.
496
+ #
497
+ def primary_key_for_attribute_name( object, attribute_name )
498
+
499
+ return adapter_bucket.primary_key_for_attribute_name( object, attribute_name )
500
+
501
+ end
502
+
503
+ ################################
504
+ # persists_files_by_content? #
505
+ ################################
506
+
507
+ def persists_files_by_content?
508
+
509
+ persists_files_by_content = nil
510
+
511
+ persists_files_by_content = super
512
+
513
+ if persists_files_by_content.nil?
514
+ persists_files_by_content = parent_port.persists_files_by_content?
515
+ end
516
+
517
+ return persists_files_by_content
518
+
519
+ end
520
+
521
+ #############################
522
+ # persists_files_by_path? #
523
+ #############################
524
+
525
+ def persists_files_by_path?
526
+
527
+ persists_files_by_path = nil
528
+
529
+ persists_files_by_path = super
530
+
531
+ if persists_files_by_path.nil?
532
+ persists_files_by_path = parent_port.persists_files_by_path?
533
+ end
534
+
535
+ return persists_files_by_path
536
+
537
+ end
538
+
539
+ #####################################
540
+ # persists_file_paths_as_objects? #
541
+ #####################################
542
+
543
+ def persists_file_paths_as_objects?
544
+
545
+ persists_file_paths_as_objects = nil
546
+
547
+ persists_file_paths_as_objects = super
548
+
549
+ if persists_file_paths_as_objects.nil?
550
+ persists_file_paths_as_objects = parent_port.persists_file_paths_as_objects?
551
+ end
552
+
553
+ return persists_file_paths_as_objects
554
+
555
+ end
556
+
557
+ #####################################
558
+ # persists_file_paths_as_strings? #
559
+ #####################################
560
+
561
+ def persists_file_paths_as_strings?
562
+
563
+ persists_file_paths_as_strings = nil
564
+
565
+ persists_file_paths_as_strings = super
566
+
567
+ if persists_file_paths_as_strings.nil?
568
+ persists_file_paths_as_strings = parent_port.persists_file_paths_as_strings?
569
+ end
570
+
571
+ return persists_file_paths_as_strings
572
+
573
+ end
574
+
575
+ ############
576
+ # cursor #
577
+ ############
578
+
579
+ ###
580
+ # Create and return cursor instance for this bucket.
581
+ #
582
+ # @return [Persistence::Cursor] New cursor instance.
583
+ #
584
+ def cursor( *args, & block )
585
+
586
+ cursor_instance = ::Persistence::Cursor.new( self )
587
+
588
+ if args.count > 0
589
+ cursor_instance.persisted?( *args )
590
+ end
591
+
592
+ if block_given?
593
+ cursor_instance = cursor_instance.instance_eval( & block )
594
+ cursor_instance.close
595
+ end
596
+
597
+ return cursor_instance
598
+
599
+ end
600
+
601
+ ###################
602
+ # atomic_cursor #
603
+ ###################
604
+
605
+ ###
606
+ # Create and return cursor instance for this index enabled to load all object properties as atomic.
607
+ # See Persistence::Cursor#atomize.
608
+ #
609
+ # @return [Persistence::Cursor] New cursor instance.
610
+ #
611
+ def atomic_cursor( *args )
612
+
613
+ return cursor( *args ).atomize
614
+
615
+ end
616
+
617
+ ##########
618
+ # each #
619
+ ##########
620
+
621
+ ###
622
+ # Iterate objects in current bucket.
623
+ #
624
+ # @yield [object] Current object.
625
+ #
626
+ # @yieldparam object Object stored in bucket.
627
+ #
628
+ def each( & block )
629
+
630
+ return atomic_cursor.each( & block )
631
+
632
+ end
633
+
634
+ ##################################################################################################
635
+ private ######################################################################################
636
+ ##################################################################################################
637
+
638
+ #########################
639
+ # create_bucket_index #
640
+ #########################
641
+
642
+ ###
643
+ # Internal helper method for common code to create bucket indexs.
644
+ #
645
+ # @param index_name Name of index to create.
646
+ #
647
+ # @param permits_duplicates Whether index should permit duplicates.
648
+ #
649
+ # @param sort_by_proc [Proc] Proc to use for sorting objects.
650
+ #
651
+ # @param sort_duplicates_by_proc [Proc] Proc to use for sorting duplicate objects.
652
+ #
653
+ # @yield [object] Block to create index keys on object.
654
+ # @yieldparam object [Object] Object to index.
655
+ #
656
+ # @return [Persistence::Port::Bucket::BucketIndex]
657
+ #
658
+ def create_bucket_index( index_name,
659
+ permits_duplicates,
660
+ sort_by_proc = nil,
661
+ sort_duplicates_by_proc = nil,
662
+ & indexing_block )
663
+
664
+ if index_instance = @indexes[ index_name ] and
665
+ index_instance.permits_duplicates? != permits_duplicates
666
+
667
+ raise 'Index ' << index_name.to_s + ' has already been declared, ' <<
668
+ 'and new duplicates declaration does not match existing declaration.'
669
+
670
+ end
671
+
672
+ index_instance = ::Persistence::Port::Bucket::BucketIndex.new( index_name,
673
+ self,
674
+ permits_duplicates,
675
+ sort_by_proc,
676
+ sort_duplicates_by_proc,
677
+ & indexing_block )
678
+
679
+ @indexes[ index_name ] = index_instance
680
+
681
+ return index_instance
682
+
683
+ end
684
+
685
+ end