tinkit 0.0.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 (51) hide show
  1. data/LICENSE +176 -0
  2. data/README +11 -0
  3. data/Rakefile +75 -0
  4. data/lib/glue_envs/couchrest/couchrest_attachment_handler.rb +260 -0
  5. data/lib/glue_envs/couchrest/couchrest_files_mgr.rb +198 -0
  6. data/lib/glue_envs/couchrest_glue_env.rb +536 -0
  7. data/lib/glue_envs/files_mgr_base.rb +51 -0
  8. data/lib/glue_envs/filesystem/filesystem_files_mgr.rb +187 -0
  9. data/lib/glue_envs/filesystem_glue_env.rb +395 -0
  10. data/lib/glue_envs/mysql/mysql_files_mgr.rb +175 -0
  11. data/lib/glue_envs/mysql_glue_env.rb +428 -0
  12. data/lib/glue_envs/sdb_s3/sdb_s3_files_mgr.rb +314 -0
  13. data/lib/glue_envs/sdb_s3_glue_env.rb +248 -0
  14. data/lib/helpers/camel.rb +21 -0
  15. data/lib/helpers/filesystem_helpers.rb +27 -0
  16. data/lib/helpers/hash_helpers.rb +74 -0
  17. data/lib/helpers/log_helper.rb +34 -0
  18. data/lib/helpers/mime_types_new.rb +126 -0
  19. data/lib/helpers/old_more_open_struct.rb +28 -0
  20. data/lib/helpers/require_helper.rb +45 -0
  21. data/lib/helpers/tk_escape.rb +17 -0
  22. data/lib/midas/bufs_data_structure.rb +84 -0
  23. data/lib/midas/node_element_operations.rb +264 -0
  24. data/lib/tinkit.rb +38 -0
  25. data/lib/tinkit_base_node.rb +733 -0
  26. data/lib/tinkit_node_factory.rb +47 -0
  27. data/spec/couchrest_files_mgr_spec.rb +551 -0
  28. data/spec/couchrest_glue_spec.rb +246 -0
  29. data/spec/filesystem_files_mgr_spec.rb +236 -0
  30. data/spec/filesystem_glue_spec.rb +243 -0
  31. data/spec/filesystem_helpers_spec.rb +42 -0
  32. data/spec/helpers/bufs_node_builder.rb +17 -0
  33. data/spec/helpers/bufs_sample_dataset.rb +160 -0
  34. data/spec/helpers/bufs_test_environments.rb +81 -0
  35. data/spec/helpers/tmp_view_cleaner.rb +15 -0
  36. data/spec/lib_helpers/tk_escape_spec.rb +45 -0
  37. data/spec/mysql_files_mgr_spec.rb +250 -0
  38. data/spec/mysql_glue_spec.rb +214 -0
  39. data/spec/node_element_operations_spec.rb +392 -0
  40. data/spec/sdb_s3_files_mgr_spec/sdb_s3_files_mgr_spec1.rb +82 -0
  41. data/spec/sdb_s3_files_mgr_spec/sdb_s3_files_mgr_spec2.rb +68 -0
  42. data/spec/sdb_s3_files_mgr_spec/sdb_s3_files_mgr_spec3.rb +80 -0
  43. data/spec/sdb_s3_files_mgr_spec/sdb_s3_files_mgr_spec4.rb +110 -0
  44. data/spec/sdb_s3_files_mgr_spec/sdb_s3_files_mgr_spec5.rb +84 -0
  45. data/spec/sdb_s3_files_mgr_spec/sdb_s3_files_mgr_spec6.rb +83 -0
  46. data/spec/sdb_s3_files_mgr_spec/sdb_s3_files_mgr_spec7.rb +101 -0
  47. data/spec/sdb_s3_files_mgr_spec/sdb_s3_files_mgr_spec8.rb +92 -0
  48. data/spec/sdb_s3_files_mgr_spec/sdb_s3_files_mgr_spec_all.rb +266 -0
  49. data/spec/sdb_s3_glue_spec.rb +230 -0
  50. data/spec/tinkit_node_factory_spec.rb +1108 -0
  51. metadata +114 -0
@@ -0,0 +1,51 @@
1
+ #This is more of a guideline than an abstract class
2
+ #that must be inherited from.
3
+
4
+ #module <PersistentLayer>Interface
5
+ #persistent layer helper classes/modules can go here
6
+
7
+ class FilesMgrBase
8
+ #persistent layer class initialization code
9
+ #persistent layer accessors
10
+
11
+ def initialize(glue_env, node_key_value)
12
+ #persistent layer object creation
13
+ raise NotImplementedError
14
+ end
15
+
16
+ def add(node, file_datas)
17
+ raise NotImplementedError
18
+ end
19
+
20
+ def add_raw_data(node, attach_name, content_type, raw_data, file_modified_at = nil)
21
+ raise NotImplementedError
22
+ end
23
+
24
+ def get_attachments_metadata(node)
25
+ raise NotImplementedError
26
+ end
27
+
28
+ def get_raw_data(node, file_basename)
29
+ raise NotImplementedError
30
+ end
31
+
32
+ def list(node)
33
+ raise NotImplementedError
34
+ end
35
+
36
+ def subtract(node, file_basenames)
37
+ raise NotImplementedError
38
+ end
39
+
40
+ def subtract_all(node) #can be called from subtract using :all instead of a list of file_basenames
41
+ raise NotImplementedError
42
+ end
43
+
44
+ def subtract_some(node, file_basenames)
45
+ raise NotImplementedError
46
+ end
47
+
48
+ #other persistent layer methods needed
49
+
50
+ end
51
+ #end of module
@@ -0,0 +1,187 @@
1
+ require 'time'
2
+ require 'json'
3
+
4
+ #Tinkit directory organization defined in lib/helpers/require_helper
5
+ require Tinkit.helpers 'mime_types_new'
6
+ require Tinkit.helpers 'log_helper'
7
+ require Tinkit.helpers 'tk_escape' #TODO: move to helpers
8
+
9
+ #TODO: Move this into a MonkeyPatch named module (called by file glue)
10
+ # Tinkit.monkey_patch punching_dir or something
11
+ class Dir #monkey patch (duck punching?)
12
+ def self.working_entries(dir=Dir.pwd)
13
+ ignore_list = ['thumbs.db','all_child_files']
14
+ all_entries = if File.exists?(dir)
15
+ Dir.entries(dir)
16
+ else
17
+ nil
18
+ end
19
+ wgk_entries = nil
20
+ wkg_entries = all_entries.delete_if {|x| x[0] == '.'} if all_entries
21
+ wkg_entries = wkg_entries.delete_if {|x| ignore_list.include?(x.downcase)} if wkg_entries
22
+ return wkg_entries
23
+ end
24
+
25
+ #TODO: this duplicates working_entries is it needed?
26
+ def self.file_data_entries(dir=Dir.pwd)
27
+ ignore_list = ['parent_categories.txt', 'description.txt']
28
+ wkg_entries = Dir.working_entries(dir)
29
+ file_data_entries = wkg_entries.delete_if {|x| ignore_list.include?(x.downcase)}
30
+ return file_data_entries
31
+ end
32
+ end
33
+
34
+ module FilesystemInterface
35
+ class FilesMgr
36
+ #Set Logger
37
+ @@log = TinkitLog.set(self.name)
38
+
39
+ attr_accessor :attachment_location, :attachment_packages
40
+
41
+ def self.get_att_doc(node)
42
+ root_path = node.my_GlueEnv.user_datastore_location
43
+ #my_cat dependency
44
+ node_loc = node._user_data[node.my_GlueEnv.node_key]
45
+ node_path = File.join(root_path, node_loc)
46
+ model_basenames = Dir.working_entries(node_path)
47
+ filenames = model_basenames.map{|b| File.join(node_path, TkEscape.escape(b))}
48
+ end
49
+
50
+ def initialize(node_env, node_key)
51
+ #for bufs node_key is the value of :my_category
52
+ @node_key = node_key
53
+ @attachment_location = File.join(node_env.user_datastore_location, node_key)
54
+ end
55
+
56
+ #TODO: Is passing node in methods duplicative now that the moab FileMgr is bound to an env at initialization?
57
+
58
+ def add(node, file_datas)
59
+ filenames = []
60
+ file_datas.each do |file_data|
61
+ #TODO Validate file data before saving
62
+ filenames << file_data[:src_filename]
63
+ end
64
+ filenames.each do |filename|
65
+ my_dest_basename = TkEscape.escape(File.basename(filename))
66
+ node_dir = @attachment_location
67
+ #File.join(node.my_GlueEnv.user_datastore_selector, node.my_category) #TODO: this should be node id, not my cat
68
+ my_dest = File.join(node_dir, my_dest_basename)
69
+ #FIXME: obj.attached_files is broken, list_attached_files should work
70
+ #@attached_files << my_dest
71
+ same_file = filename if filename == my_dest
72
+ @@log.debug {"File model attachments:"} if @@log.debug?
73
+ @@log.debug { "Copy #{filename} to #{my_dest} if #{same_file.nil?}"} if @@log.debug?
74
+ #was breaking if the dest path didn't exist
75
+ FileUtils.mkdir_p(File.dirname(my_dest)) unless File.exist?(File.dirname(my_dest))
76
+ FileUtils.cp(filename, my_dest, :preserve => true, :verbose => false ) unless same_file
77
+ #self.file_metadata = {filename => {'file_modified' => File.mtime(filename).to_s}}
78
+ end
79
+ filenames.map {|f| TkEscape.escape(File.basename(f))} #return basenames
80
+ end
81
+
82
+ def add_raw_data(node, attach_name, content_type, raw_data, file_modified_at = nil)
83
+ raise "No Data provided for file" unless raw_data
84
+ #bia_class = @model_actor[:attachment_actor_class]
85
+ file_metadata = {}
86
+ if file_modified_at
87
+ file_metadata['file_modified'] = file_modified_at
88
+ else
89
+ file_metadata['file_modified'] = Time.now.to_s
90
+ end
91
+ file_metadata['content_type'] = content_type #TODO: is unknown content handled gracefully?
92
+ attachment_package = {}
93
+ esc_attach_name = TkEscape.escape(attach_name)
94
+ node_path = @attachment_location
95
+ FileUtils.mkdir_p(node_path) unless File.exist?(node_path)
96
+ raw_data_filename = File.join(node_path, esc_attach_name)
97
+ File.open(raw_data_filename, 'wb'){|f| f.write(raw_data)}
98
+ if file_modified_at
99
+ File.utime(Time.parse(file_modified_at), Time.parse(file_modified_at), raw_data_filename)
100
+ else
101
+ file_modified_at = File.mtime(raw_data_filename).to_s
102
+ end
103
+ [esc_attach_name]
104
+ end
105
+
106
+ #TODO Document the :all shortcut somewhere
107
+ def subtract(node, model_basenames)
108
+ if model_basenames == :all
109
+ subtract_all(node)
110
+ else
111
+ subtract_some(node, model_basenames)
112
+ end
113
+ end
114
+
115
+ #TODO: make private
116
+ def subtract_some(node, file_basenames)
117
+ file_basenames = [file_basenames].flatten
118
+ model_key = node.my_GlueEnv.model_key
119
+
120
+ node_path = @attachment_location
121
+ filenames = file_basenames.map{|b| File.join(node_path, TkEscape.escape(b))}
122
+ FileUtils.rm_f(filenames)
123
+ end
124
+ #TODO: make private
125
+ def subtract_all(node)
126
+ node_path = @attachment_location
127
+ attached_entries = Dir.working_entries(node_path)
128
+ attached_filenames = attached_entries.map{|e| File.join(node_path, e)}
129
+ FileUtils.rm(attached_filenames)
130
+ end
131
+
132
+ def get_raw_data(node, model_basename)
133
+ node_dir = @attachment_location
134
+ filename = File.join(node_dir, model_basename)
135
+ return nil unless File.exist?(filename)
136
+ File.open(filename, "r"){|f| f.read}
137
+ end
138
+
139
+ def get_attachments_metadata(node)
140
+ att_md = {}
141
+ node_dir = @attachment_location
142
+ att_basenames = Dir.working_entries(node_dir)
143
+ att_basenames.each do |att|
144
+ file_md = {}
145
+
146
+ filename = File.join(node_dir, att)
147
+ file_md[:file_modified] = File.mtime(filename).to_s
148
+ file_md[:content_type] = MimeNew.for_ofc_x(filename)
149
+ att_md[att.to_sym] = file_md
150
+ end
151
+ att_md
152
+ end
153
+
154
+ #Not used and I don't think it will work anyway
155
+ def list(node)
156
+ Dir.working_entries(@attachment_location)
157
+ end
158
+
159
+
160
+ private
161
+ =begin
162
+ def subtract_some(node, model_basenames)
163
+ if node.attached_files
164
+ #TODO: replace the duplicative namespaces with path to the node dir
165
+ root_path = node.my_GlueEnv.user_datastore_location
166
+ node_loc = node._user_data[node.my_GlueEnv.node_key]
167
+ node_path = File.join(root_path, node_loc)
168
+ filenames = model_basenames.map{|b| File.join(node_path, TkEscape.escape(b))}
169
+ #raise filenames.inspect
170
+ FileUtils.rm_f(filenames)
171
+ #subtract_all(node) if rem_atts.empty?
172
+ end
173
+ end
174
+
175
+ def subtract_all(node)
176
+ root_path = node.my_GlueEnv.user_datastore_location
177
+ node_loc = node._user_data[node.my_GlueEnv.node_key]
178
+ node_path = File.join(root_path, node_loc)
179
+ attached_entries = Dir.working_entries(node_path)
180
+ #alternate approach would be to use node.files_attached
181
+ #FIXME: What is the e for in the File.join? is it needed?
182
+ attached_filenames = attached_entries.map{|e| File.join(node_path, e)}
183
+ FileUtils.rm(attached_filenames)
184
+ end
185
+ =end
186
+ end
187
+ end
@@ -0,0 +1,395 @@
1
+ #Tinkit directory organization defined in lib/helpers/require_helper.rb
2
+ require Tinkit.midas 'bufs_data_structure'
3
+ require Tinkit.glue 'filesystem/filesystem_files_mgr'
4
+ require Tinkit.helpers 'hash_helpers'
5
+
6
+ #class ViewsMgr
7
+ module TinkitFileSystemViews
8
+ #Set Logger
9
+ @@log = TinkitLog.set(self.name, :warn)
10
+
11
+ #Dependency on TinkitInfoDocEnvMethods
12
+ attr_accessor :model_actor
13
+
14
+
15
+ #def initialize(model_actor=nil)
16
+ # @model_actor = model_actor #provides the model actor that can provide views
17
+ # @data_file = model_actor[:data_file]
18
+ #end
19
+
20
+
21
+ #TODO create an index to speed queries? sync issues?
22
+ def self.by_my_category(moab_data, user_datastore_location, match_keys)
23
+ data_file = moab_data[:moab_datastore_name]
24
+ #raise "nt: #{nodetest.my_category.inspect}" if nodetest
25
+ #raise "No category provided for search" unless my_cat
26
+ #puts "Searching for #{my_cat.inspect}"
27
+ match_keys = [match_keys].flatten
28
+ my_dir = user_datastore_location
29
+ bfss = nil
30
+ match_keys.each do |match_key|
31
+ my_cat_dir = match_key
32
+ wkg_dir = File.join(my_dir, my_cat_dir)
33
+ if File.exists?(wkg_dir)
34
+ bfss = bfss || []
35
+ data_file_path = File.join(wkg_dir, data_file)
36
+ node_data = JSON.parse(File.open(data_file_path){|f| f.read})
37
+ #bfs = self.new(node_data)
38
+ bfss << node_data #bfs
39
+ end
40
+ #return bfss #returned as an array for compatibility with other search and node types
41
+ #else
42
+ # puts "Warning: #{wkg_dir.inspect} was not found"
43
+ # return nil
44
+ end
45
+ return bfss
46
+ end
47
+
48
+ def self.by_parent_categories(moab_data, user_datastore_location, match_keys)
49
+ data_file = moab_data[:moab_datastore_name]
50
+ match_keys = [match_keys].flatten
51
+ #all_nodes = all collection method when all is moved into here
52
+ matching_node_data = []
53
+ all_wkg_entries = Dir.working_entries(user_datastore_location)
54
+ all_wkg_entries.each do |entry|
55
+ wkg_dir = File.join(user_datastore_location, entry)
56
+ if File.exists?(wkg_dir)
57
+ data_file_path = File.join(wkg_dir, data_file)
58
+ json_data = JSON.parse(File.open(data_file_path){|f| f.read})
59
+ node_data = HashKeys.str_to_sym(json_data)
60
+ match_keys.each do |k|
61
+ pc = node_data[:parent_categories]
62
+ if pc && pc.include?(k)
63
+ matching_node_data << node_data
64
+ break #we don't need to loop through each parent cat, if one already matches
65
+ end
66
+ end
67
+ end
68
+ end
69
+ #we now have all mathcing data
70
+ return matching_node_data
71
+ end
72
+ end
73
+
74
+ module FilesystemViews
75
+
76
+ def call_view(field_name, moab_data, namespace_key, user_datastore_location, match_key, view_name = nil)
77
+ data_file = moab_data[:moab_datastore_name]
78
+ matching_records = []
79
+ all_file_records = Dir.working_entries(user_datastore_location)
80
+ all_file_records.each do |file_record|
81
+ record_path = File.join(user_datastore_location, file_record)
82
+ if File.exists?(record_path)
83
+ data_file_path = File.join(record_path, data_file)
84
+ json_data = JSON.parse(File.open(data_file_path){|f| f.read})
85
+ record = HashKeys.str_to_sym(json_data)
86
+ field_data = record[field_name]
87
+ if field_data == match_key
88
+ matching_records << record
89
+ end
90
+ end
91
+ end
92
+ matching_records
93
+ end
94
+
95
+ def self.by_my_category(moab_data, user_datastore_location, match_keys)
96
+ data_file = moab_data[:moab_datastore_name]
97
+ #raise "nt: #{nodetest.my_category.inspect}" if nodetest
98
+ #raise "No category provided for search" unless my_cat
99
+ #puts "Searching for #{my_cat.inspect}"
100
+ match_keys = [match_keys].flatten
101
+ my_dir = user_datastore_location
102
+ bfss = nil
103
+ match_keys.each do |match_key|
104
+ my_cat_dir = match_key
105
+ wkg_dir = File.join(my_dir, my_cat_dir)
106
+ if File.exists?(wkg_dir)
107
+ bfss = bfss || []
108
+ data_file_path = File.join(wkg_dir, data_file)
109
+ node_data = JSON.parse(File.open(data_file_path){|f| f.read})
110
+ #bfs = self.new(node_data)
111
+ bfss << node_data #bfs
112
+ end
113
+ #return bfss #returned as an array for compatibility with other search and node types
114
+ #else
115
+ # puts "Warning: #{wkg_dir.inspect} was not found"
116
+ # return nil
117
+ end
118
+ return bfss
119
+ end
120
+ end
121
+
122
+
123
+ module FilesystemEnv
124
+ #EnvName = :filesystem_env
125
+ BADCHARS = /:/ #there's a lot more
126
+
127
+ class GlueEnv
128
+ #This class provides a generic persistence layer interface to the
129
+ #outside world that maps to the specific implementations of the
130
+ #underlying persistent layers
131
+ #Set Logger
132
+ @@log = TinkitLog.set(self.name, :warn)
133
+
134
+ include FilesystemViews
135
+
136
+ PersistLayerKey = :node_path # is the full path including node_key transform
137
+ #see mysql_glue_env to decouple persistent layer key from node key
138
+ VersionKey = :_rev #to have timestamp
139
+ NamespaceKey = :files_namespace
140
+
141
+ #FileSystemMetadataKeys = [PersistLayerKey]
142
+
143
+ MoabDataStoreDir = ".model"
144
+ MoabDatastoreName = ".node_data.json"
145
+
146
+ #include FileSystemEnv
147
+
148
+ #TODO: Rather than using File class directly, should a special class be used?
149
+ attr_accessor :user_id,
150
+ :user_datastore_location,
151
+ :metadata_keys,
152
+ :required_instance_keys,
153
+ :required_save_keys,
154
+ :node_key,
155
+ :model_key,
156
+ :version_key,
157
+ :namespace_key,
158
+ :_files_mgr_class,
159
+ :views,
160
+ :model_save_params,
161
+ :moab_data,
162
+ :persist_layer_key,
163
+ #accessors specific to this persitence model
164
+ :moab_datastore_name
165
+
166
+
167
+ def initialize(persist_env, data_model_bindings)
168
+ #TODO: determine if class_name is needed to segment cluster data within user data
169
+
170
+ #via environmental settings
171
+ filesystem_env = persist_env[:env]
172
+ #key_fields = persist_env[:key_fields]
173
+ fs_path = filesystem_env[:path]
174
+ @user_id = filesystem_env[:user_id]
175
+ @cluster_name = persist_env[:name]
176
+
177
+ #data_model_bindings from NodeElementOperations
178
+ key_fields = data_model_bindings[:key_fields]
179
+ initial_views_data = data_model_bindings[:views]
180
+
181
+ @required_instance_keys = key_fields[:required_keys] #DataStructureModels::Tinkit::RequiredInstanceKeys
182
+ @required_save_keys = key_fields[:required_keys] #DataStructureModels::Tinkit::RequiredSaveKeys
183
+ @node_key = key_fields[:primary_key] #DataStructureModels::Tinkit::NodeKey
184
+
185
+
186
+ @moab_datastore_name = MoabDatastoreName
187
+ @version_key = VersionKey #
188
+ @model_key = @node_key #ModelKey
189
+
190
+ #Change model key to persiste layer key ...
191
+ #TODO: See about not making the filesystem dependent upon the node key
192
+ @persist_layer_key = PersistLayerKey
193
+
194
+ @namespace_key = NamespaceKey
195
+ @metadata_keys = [@persist_layer_key, @version_key, @namespace_key ] #@persist_layer_key, @namespace_key]
196
+ @user_datastore_location = File.join(fs_path, @user_id, MoabDataStoreDir)
197
+
198
+
199
+
200
+ @model_save_params = {:nodes_save_path => @user_datastore_location, :data_file => @moab_datastore_name, :node_key => @node_key}
201
+ @_files_mgr_class = FilesystemInterface::FilesMgr
202
+ @views = TinkitFileSystemViews
203
+ @moab_data = {:moab_datastore_name => @moab_datastore_name}
204
+ #@views_mgr = ViewsMgr.new({:data_file => @data_file_name})
205
+
206
+ FileUtils.mkdir_p(fs_path) unless File.exists?(fs_path)
207
+ end
208
+
209
+ def query_all #TODO move to ViewsMgr
210
+ unless File.exists?(@user_datastore_location)
211
+ @@log.debug {"Warning: Can't query records. The File System Directory to work from does not exist: #{@user_datastore_location}"} if @@log.debug?
212
+ end
213
+ all_records = []
214
+ my_dir = @user_datastore_location + '/' #TODO: Can this be removed?
215
+ all_entries = Dir.working_entries(my_dir) || []
216
+ @@log.debug "querying directory: #{my_dir.inspect} and got entries: #{all_entries.inspect}"
217
+ all_entries.each do|entry|
218
+ all_records << get(entry) || {}
219
+ end
220
+ @@log.debug {"query_all returning: #{all_records.inspect}" } if @@log.debug?
221
+ return all_records
222
+ end
223
+
224
+ #TODO: reconcile raw_all with query_all, this is the only glue env using raw_all
225
+ def raw_all
226
+ query_all
227
+ =begin
228
+ @@log.debug {"Getting All (Raw) Data using "\
229
+ "data loc: #{@user_datastore_location.inspect} "\
230
+ "datastore name: #{@moab_datastore_name.inspect}" } if @@log.debug?
231
+ entries = query_all
232
+ raw_nodes = []
233
+ entries.each do |record|
234
+ data_path = File.join(record[@persist_layer_key], @moab_datastore_name)
235
+ data_json = File.open(data_path, 'r'){|f| f.read}
236
+ data = JSON.parse(data_json)
237
+ raw_nodes << data
238
+ end
239
+ raw_nodes
240
+ =end
241
+ end
242
+ #current relations supported:
243
+ # - :equals (data in the key field matches this_value)
244
+ # - :contains (this_value is contained in the key field data (same as equals for non-enumerable types )
245
+ def find_nodes_where(key, relation, this_value)
246
+ res = case relation
247
+ when :equals
248
+ find_equals(key, this_value)
249
+ when :contains
250
+ find_contains(key, this_value)
251
+ end #case
252
+ return res
253
+ end
254
+
255
+ def find_equals(key, this_value)
256
+ results =[]
257
+ query_all.each do |record|
258
+ test_val = record[key]
259
+ results << record if test_val == this_value
260
+ end
261
+ results
262
+ end
263
+
264
+ def find_contains(key, this_value)
265
+ results =[]
266
+ query_all.each do |record|
267
+ test_val = record[key]
268
+ results << record if find_contains_type_helper(test_val, this_value)
269
+ end
270
+ results
271
+ end
272
+
273
+ def find_contains_type_helper(stored_data, this_value)
274
+ #p stored_dataj
275
+ resp = nil
276
+ #stored_data = jparse(stored_dataj)
277
+ if stored_data.respond_to?(:"include?")
278
+ resp = (stored_data.include?(this_value))
279
+ else
280
+ resp = (stored_data == this_value)
281
+ end
282
+ return resp
283
+ end
284
+
285
+ def get(id)
286
+ return nil unless id
287
+ #maybe put in some validations to ensure its from the proper collection namespace?
288
+ #id may be the entry or the full path
289
+ id_path = if id.include? (@user_datastore_location)
290
+ id
291
+ else
292
+ convert_node_value_to_file_value(id)
293
+ end
294
+ #id_path = id #convert_node_value_to_file_value(id)
295
+ data_file_path = File.join(id_path, @moab_datastore_name)
296
+ rtn = if File.exists?(data_file_path)
297
+ #data_file_path = File.join(id_path, @moab_datastore_name)
298
+ json_data = File.open(data_file_path, 'r'){|f| f.read}
299
+ node_data = JSON.parse(json_data)
300
+ node_data = HashKeys.str_to_sym(node_data)
301
+ else
302
+ puts "Warning: File path doesn't exist: #{data_file_path.inspect}"
303
+ []
304
+ end
305
+ end
306
+
307
+ def save(new_data)
308
+ save_data = nil
309
+ if new_data[@persist_layer_key]
310
+ save_data = new_data
311
+ elsif new_data[@node_key]
312
+ persist_key_value = convert_node_value_to_file_value(new_data[@node_key])
313
+ save_data = new_data.merge({@persist_layer_key => persist_key_value})
314
+ else
315
+ raise "Save Data did not include any keys for saving, data: #{new_data.inspect}"
316
+ end
317
+ save_path = @user_datastore_location
318
+ save_location = save_data[@persist_layer_key]
319
+ @@log.debug {"Save Directory: #{save_location.inspect}"} if @@log.debug?
320
+ #was in FileSystemEnv mixin
321
+ #fs_save(@model_save_params, model_data)
322
+ #puts "FSG save udl: #{@user_datastore_location.inspect}"
323
+ #parent_path = @user_datastore_location
324
+ #node_key = @model_save_params[:node_key]
325
+ #node_key = @node_key
326
+ #puts "parent_path: #{parent_path.inspect}"
327
+ #puts "new data node key: #{new_data[node_key].inspect}"
328
+ #node_path = File.join(parent_path, new_data[node_key])
329
+ file_name = File.basename(@moab_datastore_name)
330
+ file_location = File.join(save_location, file_name)
331
+
332
+ #error_str = "Filesystem can't handle some characters in/
333
+ #{file_location.inspect}"
334
+ #raise error_str if new_data [node_key] =~ /::/ #FilesystemEnv::BADCHARS
335
+ @@log.info {"File Location: #{file_location.inspect}"} if @@log.info?
336
+ model_data = HashKeys.sym_to_str(save_data)
337
+
338
+ FileUtils.mkdir_p(save_location) unless File.exist?(save_location)
339
+ #raise "WTF?" unless File.exist?(save_location)
340
+ rev = Time.now.hash #<- I would use File.mtime, but how to get the mod time before saving?
341
+ model_data[@version_key] = rev
342
+ f = File.open(file_location, 'w')
343
+ f.write(model_data.to_json)
344
+ f.close
345
+ model_data['rev'] = model_data[@version_key] #TODO <-Investigate to see if it could be consistent
346
+ return model_data
347
+ end
348
+
349
+ def destroy_node(model_metadata)
350
+ #root_dir = @user_datastore_location
351
+ #model_path(model_metadata[@model_key])
352
+ node_id = model_metadata[@persist_layer_key] || generate_model_key(nil, model_metadata[@node_key])
353
+
354
+ node_dir = node_id #File.join(root_dir, node_id)
355
+
356
+ FileUtils.rm_rf(node_dir)
357
+ #node = nil
358
+ end
359
+
360
+ #namespace is used to distinguish between unique
361
+ #data sets (i.e., users) within the model
362
+ def generate_model_key(namespace, node_key_value)
363
+ #was in FileSystemEnv mixin
364
+ #fs_generate_model_key(namespace, node_key)
365
+ #TODO: Make sure namespace is portable across model migrations
366
+ file_name = convert_node_value_to_file_value(node_key_value)
367
+ #TODO: Expand bad character set
368
+ #FIXME namespace is redundant so removed it
369
+ #"#{namespace}/#{node_key}"
370
+ file_name
371
+ end
372
+
373
+ def model_path(model_key_value)
374
+ #model_key_value.gsub("::","/")
375
+ end
376
+
377
+ def destroy_bulk(list_of_native_records)
378
+ @@log.info {"Bulk Destroy: #{list_of_native_records.inspect}"} if @@log.info?
379
+ return [] unless (list_of_native_records)
380
+ list_of_native_records.each do |recs|
381
+ next unless (recs && recs.size > 0)#raise "recs not hash: #{recs}" unless recs.class == Hash
382
+ rec_id = recs[@persist_layer_key] || generate_model_key(nil, recs[@node_key])
383
+ #rec_id = File.join(@user_datastore_location, rec_id) if File.dirname(rec_id) == "."
384
+ #puts "Removing: #{r.inspect}"
385
+ FileUtils.rm_rf(rec_id)
386
+ end
387
+ end
388
+
389
+ def convert_node_value_to_file_value(node_key_value)
390
+ file_base_value = node_key_value.gsub("::", "_")
391
+ file_value = File.join(@user_datastore_location, file_base_value)
392
+ end
393
+
394
+ end
395
+ end