rtm-activerecord 0.2.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.
Files changed (38) hide show
  1. data/DISCLAIMER +13 -0
  2. data/LICENSE +201 -0
  3. data/README +4 -0
  4. data/lib/rtm/activerecord/001_initial_schema.rb +119 -0
  5. data/lib/rtm/activerecord/association_and_role.rb +54 -0
  6. data/lib/rtm/activerecord/base.rb +83 -0
  7. data/lib/rtm/activerecord/connect.rb +106 -0
  8. data/lib/rtm/activerecord/io/from_xtm2.rb +266 -0
  9. data/lib/rtm/activerecord/io/from_xtm2_libxml.rb +97 -0
  10. data/lib/rtm/activerecord/io/to_jtm.rb +141 -0
  11. data/lib/rtm/activerecord/io/to_string.rb +130 -0
  12. data/lib/rtm/activerecord/io/to_xtm1.rb +162 -0
  13. data/lib/rtm/activerecord/io/to_xtm2.rb +163 -0
  14. data/lib/rtm/activerecord/io/to_yaml.rb +132 -0
  15. data/lib/rtm/activerecord/literal_index.rb +38 -0
  16. data/lib/rtm/activerecord/locators.rb +58 -0
  17. data/lib/rtm/activerecord/merging.rb +310 -0
  18. data/lib/rtm/activerecord/name_variant_occurrence.rb +86 -0
  19. data/lib/rtm/activerecord/persistent_code_output.rb +22 -0
  20. data/lib/rtm/activerecord/quaaxtm2rtm.rb +116 -0
  21. data/lib/rtm/activerecord/quaaxtm2rtmviews.rb +137 -0
  22. data/lib/rtm/activerecord/set_wrapper.rb +101 -0
  23. data/lib/rtm/activerecord/sugar/association/hash_access.rb +22 -0
  24. data/lib/rtm/activerecord/sugar/role/counterparts.rb +56 -0
  25. data/lib/rtm/activerecord/sugar/topic/characteristics.rb +15 -0
  26. data/lib/rtm/activerecord/sugar/topic/counterparts.rb +18 -0
  27. data/lib/rtm/activerecord/sugar/topic/hash_access.rb +78 -0
  28. data/lib/rtm/activerecord/sugar/topic/identifier_direct.rb +14 -0
  29. data/lib/rtm/activerecord/sugar/topic/predefined_associations.rb +53 -0
  30. data/lib/rtm/activerecord/tm_construct.rb +66 -0
  31. data/lib/rtm/activerecord/tm_delegator.rb +417 -0
  32. data/lib/rtm/activerecord/tm_set_delegator.rb +226 -0
  33. data/lib/rtm/activerecord/tmdm.rb +309 -0
  34. data/lib/rtm/activerecord/topic.rb +204 -0
  35. data/lib/rtm/activerecord/topic_map.rb +435 -0
  36. data/lib/rtm/activerecord/traverse_associations.rb +90 -0
  37. data/lib/rtm/activerecord.rb +106 -0
  38. metadata +120 -0
@@ -0,0 +1,226 @@
1
+ # Copyright: Copyright 2009 Topic Maps Lab, University of Leipzig.
2
+ # License: Apache License, Version 2.0
3
+
4
+ module RTM::AR
5
+ class TMSetDelegator < TMDelegator
6
+ include Enumerable
7
+ # attr_reader :content_class_name
8
+ def initialize(obj,parent,type)
9
+ @obj = obj
10
+ @parent = parent
11
+ @type = type
12
+ end
13
+
14
+ # This class method wraps a Set completely while the instance method wraps one single contained object
15
+ def self.wrap(obj, parent=nil, type=nil)
16
+ return nil unless obj
17
+ raise "Double wrapping" if obj.respond_to?(:__getobj__)
18
+ self.new(obj, parent, type)
19
+ end
20
+
21
+ def add(obj)
22
+ return unless obj
23
+
24
+ old = @obj.detect { |x| x == obj } # can't that be done easier?
25
+ if old
26
+ old.merge obj
27
+ else
28
+ if obj.respond_to? :__getobj__
29
+ @obj << obj.__getobj__
30
+ else
31
+ case @type
32
+ when :Topic
33
+ @obj << @parent.topic_map.get!(obj).__getobj__
34
+ @parent.__getobj__.reload
35
+
36
+ when :ItemIdentifier
37
+ if @parent.class.name.to_s =~ /::Topic$/
38
+ tbi = @parent.topic_map._item_identifier(obj)
39
+ if tbi && tmc=tbi.topic_map_construct
40
+ if tmc.class.name =~ /::Topic$/
41
+ return @parent if tmc == @parent.__getobj__
42
+ result = Topic.wrap(tmc).merge @parent
43
+ return result
44
+ else
45
+ raise "Duplicate Item Identifier"
46
+ end
47
+ end
48
+ tbsi = @parent.topic_map._subject_identifier(obj.to_s)
49
+ if tbsi
50
+ if t=tbsi.topic
51
+ return @parent if t == @parent.__getobj__
52
+ result = Topic.wrap(t).merge @parent
53
+ # after merging, we still need to add the II
54
+ result.__getobj__.item_identifiers.create(:reference => obj.to_s, :topic_map_id => @parent.topic_map.__getobj__.id)
55
+ return result
56
+ end
57
+ end
58
+ end
59
+ result = @obj << @parent.topic_map._item_identifier!(obj.to_s)
60
+ return result
61
+
62
+ when :SubjectIdentifier
63
+ # check for existing item identifier
64
+ puts
65
+ puts "trying to add SI to a topic"
66
+ tbi = @parent.topic_map._item_identifier(obj)
67
+ if tbi && tmc=tbi.construct
68
+ puts "something with this II exists"
69
+ if tmc.class.name =~ /::Topic$/
70
+ puts "it exists as a topic"
71
+ puts tmc == @parent.__getobj__
72
+ return @parent if tmc == @parent.__getobj__
73
+
74
+ puts "trying to merge"
75
+ puts "BEFORE"
76
+ begin
77
+ result = Topic.wrap(tmc).merge(@parent)
78
+ rescue Exception => e
79
+ puts e.inspect
80
+ raise e
81
+ end
82
+ puts "AFTER"
83
+ puts "done merging, now adding SI"
84
+
85
+ #result = @parent.merge(Topic.wrap(tmc))
86
+ # after merging, we still need to add the SI
87
+ result.__getobj__.subject_identifiers.create(:reference => obj.to_s, :topic_map_id => @parent.topic_map.__getobj__.id)
88
+ puts "done adding SI, now reloading"
89
+ result.reload
90
+ puts "done reloading"
91
+ return result
92
+ else
93
+ warn("This subject identifier IRI already belongs to another topic map construct (not a topic)")
94
+ end
95
+ end
96
+ puts "checking for existing SI"
97
+ # check for existing subject identifier
98
+ tbsi = @parent.topic_map._subject_identifier(obj.to_s)
99
+ if tbsi
100
+ puts "SI exists"
101
+ if true && t=tbsi.topic #the single = is intentional, the "true &&" just makes netbeans not raise a warning
102
+ return @parent if t == @parent.__getobj__
103
+ result = Topic.wrap(t).merge @parent
104
+ return result
105
+ end
106
+ end
107
+ @obj.create(:reference => obj.to_s, :topic_map_id => @parent.topic_map.__getobj__.id)
108
+
109
+ when :SubjectLocator
110
+ tbsl = @parent.topic_map._subject_locator(obj.to_s)
111
+ if tbsl
112
+ if true && t=tbsl.topic #the single = is intentional, the "true &&" just makes netbeans not raise a warning
113
+ return @parent if t == @parent.__getobj__
114
+ result = Topic.wrap(t).merge @parent
115
+ return result
116
+ end
117
+ end
118
+ @obj.create(:reference => obj.to_s, :topic_map_id => @parent.topic_map.__getobj__.id)
119
+
120
+ end
121
+ end
122
+ end
123
+ end
124
+ alias :<< :add
125
+
126
+ def add_all(objs)
127
+ return unless objs
128
+ objs.each {|obj| add(obj)}
129
+ true
130
+ end
131
+
132
+ def each(&b)
133
+ @obj.each { |e| yield wrap(e)}
134
+ end
135
+
136
+ def size
137
+ @obj.size
138
+ end
139
+ alias :length :size
140
+
141
+ def empty?
142
+ @obj.empty?
143
+ end
144
+
145
+ def delete(obj)
146
+ obj = obj.__getobj__ if obj.respond_to? :__getobj__
147
+ case @type
148
+ when :ItemIdentifier, :SubjectIdentifier, :SubjectLocator
149
+ obj = @obj.find_by_reference(@parent.topic_map.resolve(obj.to_s)) if obj.is_a? String
150
+ when :Topic
151
+ obj = @parent.topic_map.get!(obj).__getobj__
152
+ end
153
+ @obj.delete(obj)
154
+ # item_identifiers: remove also from topicMap
155
+ #removed_event obj if respond_to? :removed_event
156
+ end
157
+ alias :remove :delete
158
+
159
+ def include?(obj)
160
+ return @obj.include?(obj.__getobj__)
161
+ #@obj.each { |e| return true if e == obj } # T#ODO support for get
162
+ #false
163
+ end
164
+
165
+ def first
166
+ wrap(@obj.entries.first)
167
+ end
168
+ def last
169
+ wrap(@obj.entries.last)
170
+ end
171
+
172
+ def to_s
173
+ "[#{@obj.entries.map { |e| wrap(e).to_s }.join(", ") }]"
174
+ end
175
+ def [](i)
176
+ wrap(@obj[i])
177
+ end
178
+
179
+ def content_class
180
+ # @content_class ||= RTM.const_get(@content_class_name)
181
+ @content_class ||= RTM.const_get("#{@content_class_name}MemImpl")
182
+ end
183
+
184
+ def find(*args)
185
+ res = @obj.find(*args)
186
+ if res.respond_to? :each
187
+ Constructs.wrap(res)
188
+ else
189
+ Construct.wrap(res)
190
+ end
191
+ end
192
+
193
+ def &(other)
194
+ @obj.to_a & other.to_a
195
+ end
196
+
197
+ alias :old_method_missing :method_missing
198
+ def method_missing(method_name, *args)
199
+ if @obj.size > 0 && first.respond_to?(method_name) && (![:__getobj__, :__setobj__].include?(method_name))
200
+ a = []
201
+ inject(a) {|all,single| all << single.send(method_name, *args)}
202
+ a
203
+ else
204
+ old_method_missing(method_name, *args)
205
+ end
206
+ end
207
+
208
+ alias :old_respond_to? :respond_to?
209
+ def respond_to?(method_name)
210
+ resp = old_respond_to?(method_name)
211
+ return resp if resp # i.e. if true
212
+ return false if [:__getobj__, :__setobj__].include?(method_name)
213
+ # ... and ask first child otherwise
214
+ @obj.size > 0 && first.respond_to?(method_name)
215
+ end
216
+
217
+ def ==(x)
218
+ self.to_a == x.to_a
219
+ end
220
+
221
+ # TMSetDelegator#to_a doesn't help as thought, but maybe we come back to that l8r...
222
+ #def to_a
223
+ # @obj.map {|o| wrap(o)}
224
+ #end
225
+ end
226
+ end
@@ -0,0 +1,309 @@
1
+ # Copyright: Copyright 2009 Topic Maps Lab, University of Leipzig.
2
+ # License: Apache License, Version 2.0
3
+
4
+ old_verbose=$VERBOSE
5
+ $VERBOSE=false
6
+ require 'active_record'
7
+ $VERBOSE=old_verbose
8
+
9
+ module RTM::AR
10
+ # The Active Record TMDM backend
11
+ module TMDM
12
+ # Moves all fields in a collection to another owner (for classes using belongs_to in AR::Base class)
13
+ module Movable
14
+ # Takes a list of [field,from, to] arguments.
15
+ # RTM::AR::TMDM::ItemIdentifier.move_all(
16
+ # ["construct_id", other.__getobj__.id, self.__getobj__.id],
17
+ # ["construct_type", other.__getobj__.class.name, self.__getobj__.class.name]
18
+ # )
19
+ # or
20
+ # RTM::AR::TMDM::Variant.move_all(["name_id", other.__getobj__.id, self.__getobj__.id])
21
+
22
+ #
23
+ def move_all(*args)
24
+ raise "All parameters must have a size of 3: [field_name, from, to]" unless args.all?{|a| a.size == 3}
25
+ set_part = ""
26
+ where_part = ""
27
+ args.each do |field, from, to|
28
+ set_part += ", " unless set_part.empty?
29
+ where_part += " and " unless where_part.empty?
30
+ from = "'#{from}'" unless from.is_a? Numeric
31
+ to = "'#{to}'" unless to.is_a? Numeric
32
+ where_part += "#{field} = #{from}"
33
+ set_part += "#{field} = #{to}"
34
+ end
35
+ #puts "setpart: #{set_part.inspect}\nwherepart: #{where_part.inspect}"
36
+ res = self.update_all(set_part, where_part)
37
+ #puts "result: #{res.inspect}"
38
+ end
39
+ end
40
+
41
+ class Construct < ActiveRecord::Base
42
+ self.store_full_sti_class = false
43
+ extend Movable
44
+ class << self
45
+ def abstract_class?
46
+ self == Construct
47
+ end
48
+ def alias_ar_relation(new,old)
49
+ alias_method new, old
50
+ alias_method "#{new}=", "#{old}="
51
+ end
52
+ alias :alias_belongs_to :alias_ar_relation
53
+ alias :alias_has_many :alias_ar_relation
54
+ def belongs_to_with_alias(name, synonym)
55
+ belongs_to name
56
+ alias_belongs_to synonym, name
57
+ end
58
+ def has_many_with_alias(name, synonym, *args)
59
+ has_many name, *args
60
+ alias_has_many synonym, name
61
+ end
62
+ def belongs_to_parent(parent)
63
+ belongs_to parent
64
+ alias_belongs_to :parent, parent
65
+ end
66
+ def this_is_a_typed_object
67
+ belongs_to :ttype, :class_name => "Topic", :foreign_key => :ttype_id
68
+ module_eval(<<-EOS, "(__RTM_AR_TMDM_TYPED_OBJECT__)", 1)
69
+ def type=(ptype)
70
+ self.ttype=ptype
71
+ end
72
+ def type
73
+ self.ttype
74
+ end
75
+ EOS
76
+ end
77
+ end
78
+ has_many :item_identifiers, :as => :construct, :dependent => :destroy
79
+ def topic_map
80
+ parent.topic_map
81
+ end
82
+ def move_to(new_parent)
83
+ self.parent = new_parent
84
+ end
85
+
86
+ end
87
+ class Reifiable < Construct
88
+ def self.abstract_class?
89
+ self == Reifiable
90
+ end
91
+ has_one :reifier, :class_name => "Topic", :as => :reified
92
+ end
93
+ class ScopedObject < Reifiable
94
+ def self.abstract_class?
95
+ self == ScopedObject
96
+ end
97
+ has_many :scoped_objects_topics, :as => :scoped_object, :dependent => :destroy
98
+ has_many :scope, :through => :scoped_objects_topics, :source => :topic
99
+ # def scope
100
+ # self.scoped_objects_topics.map { |sot| sot.topic }
101
+ # end
102
+ # def add_scoping_topic(topic) # this is not ruby-ish but at least it works, would need a complete association proxy instead...
103
+ # sot = ScopedObjectsTopic.create :topic => topic, :scoped_object => self
104
+ # self
105
+ # # sot = ScopedObjectsTopic.new :topic => topic, :scoped_object => self
106
+ # # self.scoped_objects_topics << sot
107
+ # # self
108
+ # end
109
+ # def remove_scoping_topic(topic) # this is not ruby-ish but at least it works, would need a complete association proxy instead...
110
+ # self.scoped_objects_topics.select { |sot| sot.topic == topic }.destroy
111
+ # self
112
+ # end
113
+ end
114
+ class ScopedObjectsTopic < ActiveRecord::Base
115
+ self.store_full_sti_class = false
116
+ extend Movable
117
+ belongs_to :topic, :class_name => 'RTM::AR::TMDM::Topic'
118
+ belongs_to :scoped_object, :polymorphic => true
119
+ belongs_to :association, :class_name => 'RTM::AR::TMDM::Association', :foreign_key => "scoped_object_id"
120
+ belongs_to :name, :class_name => 'RTM::AR::TMDM::Name', :foreign_key => "scoped_object_id"
121
+ belongs_to :variant, :class_name => 'RTM::AR::TMDM::Variant', :foreign_key => "scoped_object_id"
122
+ belongs_to :occurrence, :class_name => 'RTM::AR::TMDM::Occurrence', :foreign_key => "scoped_object_id"
123
+ end
124
+
125
+ class Locator < ActiveRecord::Base
126
+ self.store_full_sti_class = false
127
+ extend Movable
128
+ class << self
129
+ def abstract_class?
130
+ self == Locator
131
+ end
132
+ end
133
+ belongs_to :topic_map
134
+ end
135
+
136
+ class ItemIdentifier < Locator
137
+ belongs_to :construct, :polymorphic => true
138
+ def to_s
139
+ self.reference
140
+ end
141
+ def move_to(new_tmc)
142
+ #puts "\n\nmoving\n\t#{self.inspect}\n\nto\n\t#{new_tmc.inspect}"
143
+ #self.update_all "construct_id = #{new_tmc.id}, construct_type = '#{new_tmc.class.name}'",
144
+ #puts "changing id"
145
+ #puts self.construct_id = new_tmc.id
146
+ #puts "changing type"
147
+ #puts self.construct_type = new_tmc.class.name
148
+ self.construct = new_tmc
149
+ #puts "saving"
150
+ self.save
151
+ #
152
+ # das geht!!!
153
+ #self.class.update( self.id, "construct_id" => new_tmc.id)
154
+ end
155
+ end
156
+ class SubjectLocator < Locator
157
+ belongs_to :topic
158
+ def to_s
159
+ self.reference
160
+ end
161
+ end
162
+ class SubjectIdentifier < Locator
163
+ belongs_to :topic
164
+ def to_s
165
+ self.reference
166
+ end
167
+ end
168
+ # http://www.isotopicmaps.org/sam/sam-model/#d0e736
169
+ class Topic < Construct
170
+ belongs_to :reified, :polymorphic => true
171
+ belongs_to_parent :topic_map
172
+ has_many :subject_locators, :dependent => :destroy
173
+ has_many :subject_identifiers, :dependent => :destroy
174
+ has_many :occurrences, :dependent => :destroy
175
+ has_many_with_alias :names, :topic_names, :dependent => :destroy
176
+ has_many_with_alias :roles, :association_roles, :include => :association
177
+ has_many :associations, :through => :roles, :dependent => :destroy
178
+ #has_many :played_types, :through => :association_roles, :source => :type
179
+
180
+ has_many :typed_associations, :class_name => "Association", :foreign_key => :ttype_id
181
+ has_many :typed_roles, :class_name => "Role", :foreign_key => :ttype_id
182
+ has_many :typed_names, :class_name => "Name", :foreign_key => :ttype_id
183
+ has_many :typed_occurrences, :class_name => "Occurrence", :foreign_key => :ttype_id
184
+
185
+ has_many :scoped_objects_topics
186
+ has_many :scoped_associations, :through => :scoped_objects_topics, :source => :association,
187
+ :conditions => "scoped_objects_topics.scoped_object_type = 'RTM::AR::TMDM::Association'"
188
+ has_many :scoped_names, :through => :scoped_objects_topics, :source => :name,
189
+ :conditions => "scoped_objects_topics.scoped_object_type = 'RTM::AR::TMDM::Name'"
190
+ has_many :scoped_variants, :through => :scoped_objects_topics, :source => :variant,
191
+ :conditions => "scoped_objects_topics.scoped_object_type = 'RTM::AR::TMDM::Variant'"
192
+ has_many :scoped_occurrences, :through => :scoped_objects_topics, :source => :occurrence,
193
+ :conditions => "scoped_objects_topics.scoped_object_type = 'RTM::AR::TMDM::Occurrence'"
194
+
195
+ # def scoped_objects
196
+ # self.scoped_objects_topics.collect { |a| a.scoped_object } # temporary hack polymorphic has_many_through
197
+ # end
198
+ def scoped
199
+ scoped_associations + scoped_names + scoped_variants + scoped_occurrences
200
+ end
201
+
202
+ def typed
203
+ typed_associations + typed_roles + typed_names + typed_occurrences
204
+ end
205
+
206
+ end
207
+
208
+ class Role < Reifiable
209
+ belongs_to_parent :association
210
+ belongs_to_with_alias :topic, :player
211
+ this_is_a_typed_object
212
+ end
213
+
214
+ class Name < ScopedObject
215
+ belongs_to_parent :topic
216
+ this_is_a_typed_object
217
+ has_many :variants, :dependent => :destroy
218
+ end
219
+
220
+ class Association < ScopedObject
221
+ belongs_to_parent :topic_map
222
+ this_is_a_typed_object
223
+ has_many_with_alias :roles, :roles, :dependent => :destroy
224
+ def create_role(rplayer, ttype)
225
+ Role.create :parent => self, :player => rplayer, :ttype => ttype
226
+ end
227
+ alias :create_association_role :create_role
228
+ has_many :players, :through => :roles, :source => :topic
229
+ has_many :types, :through => :roles, :source => :ttype
230
+ end
231
+
232
+ class AssociationCache < Construct
233
+ set_table_name "associations_cache"
234
+ belongs_to_parent :topic_map
235
+ this_is_a_typed_object
236
+ has_many_with_alias :roles, :association_roles
237
+ belongs_to :role1, :class_name => "RTM::AR::TMDM::Role", :foreign_key => "role1_id"
238
+ belongs_to :player1, :class_name => "RTM::AR::TMDM::Topic", :foreign_key => "player1_id"
239
+ belongs_to :type1, :class_name => "RTM::AR::TMDM::Topic", :foreign_key => "type1_id"
240
+ belongs_to :role2, :class_name => "RTM::AR::TMDM::Role", :foreign_key => "role2_id"
241
+ belongs_to :player2, :class_name => "RTM::AR::TMDM::Topic", :foreign_key => "player2_id"
242
+ belongs_to :type2, :class_name => "RTM::AR::TMDM::Topic", :foreign_key => "type2_id"
243
+ # rolecount -> rcnt
244
+ end
245
+
246
+ class Occurrence < ScopedObject
247
+ belongs_to_parent :topic
248
+ this_is_a_typed_object
249
+ end
250
+
251
+ class Variant < ScopedObject
252
+ belongs_to_parent :name
253
+ def topic_map
254
+ parent.topic_map
255
+ end
256
+ end
257
+
258
+ class TopicMap < Reifiable
259
+ # real properties
260
+ has_many :topics, :dependent => :destroy, :include => [:subject_identifiers, :subject_locators]
261
+ has_many :associations, :dependent => :destroy, :include => :roles
262
+
263
+ # access to subproperties
264
+ has_many :locators, :class_name => "ItemIdentifier", :dependent => :destroy
265
+ has_many :subject_locators, :dependent => :destroy
266
+ has_many :subject_identifiers, :dependent => :destroy
267
+
268
+ has_many :names, :through => :topics
269
+ alias :topic_names :names
270
+
271
+ has_many :occurrences, :through => :topics
272
+ has_many :roles, :through => :associations
273
+ alias :association_roles :roles
274
+
275
+ %w[association role name occurrence].each do |m|
276
+ module_eval(<<-EOS, "(__AR_DELEGATOR_INDEX_PROPERTY_SET__)", 1)
277
+ def #{m}_types
278
+ topics.select{|t| t.#{m}s_typed.size > 0}
279
+ end
280
+ EOS
281
+ end
282
+
283
+ #typing
284
+ # has_many :association_types, :class_name => "Association", :foreign_key => :ttype_id
285
+ # has_many :role_types, :class_name => "Role", :foreign_key => :ttype_id
286
+ # has_many :name_types, :class_name => "Name", :foreign_key => :ttype_id
287
+ # has_many :occurrence_types, :class_name => "Occurrence", :foreign_key => :ttype_id
288
+
289
+ # has_many :association_types, :aka => :at, :type => :Topic, :wrap => true
290
+ # has_many :role_types, :aka => [:association_role_types,:art,:rt], :type => :Topic, :wrap => true
291
+ # has_many :name_types, :aka => [:name_types,:tnt,:nt], :type => :Topic, :wrap => true
292
+ # has_many :occurrence_types, :aka => :ot, :type => :Topic, :wrap => true
293
+
294
+
295
+ def topic_map
296
+ self
297
+ end
298
+
299
+ # # Creates a new Locator in this TopicMap
300
+ # def create_locator(reference, notation=nil)
301
+ # if notation
302
+ # ItemIdentifier.create :reference => reference, :notation => notation
303
+ # else
304
+ # ItemIdentifier.create :reference => reference # is there a better way to preserve the database default notation if none given?
305
+ # end
306
+ # end
307
+ end
308
+ end
309
+ end