doeskeyvalue 0.2.2 → 0.9.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.
@@ -0,0 +1,25 @@
1
+ # AWEXOME LABS
2
+ # DoesKeyValue
3
+
4
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
6
+
7
+ require "rubygems"
8
+ require "bundler"
9
+ Bundler.setup(:default, :development)
10
+
11
+ require "active_record"
12
+ require "active_support"
13
+ require "doeskeyvalue"
14
+ require "rspec"
15
+ require "rspec/autorun"
16
+
17
+ root = File.expand_path(File.join(File.dirname(__FILE__), ".."))
18
+ ActiveRecord::Base.establish_connection(
19
+ :adapter => "sqlite3",
20
+ :database => ":memory:"
21
+ # :database => "#{root}/db/safeattributes.db"
22
+ )
23
+
24
+ RSpec.configure do |config|
25
+ end
metadata CHANGED
@@ -1,62 +1,154 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: doeskeyvalue
3
- version: !ruby/object:Gem::Version
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.0
4
5
  prerelease:
5
- version: 0.2.2
6
6
  platform: ruby
7
- authors:
7
+ authors:
8
8
  - Awexome Labs
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
-
13
- date: 2011-06-29 00:00:00 -04:00
14
- default_executable:
15
- dependencies:
16
- - !ruby/object:Gem::Dependency
12
+ date: 2012-12-30 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activesupport
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 3.2.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 3.2.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: activerecord
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 3.2.0
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 3.2.0
46
+ - !ruby/object:Gem::Dependency
17
47
  name: hashie
18
- requirement: &id001 !ruby/object:Gem::Requirement
48
+ requirement: !ruby/object:Gem::Requirement
19
49
  none: false
20
- requirements:
21
- - - ">="
22
- - !ruby/object:Gem::Version
23
- version: "0"
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 1.2.0
24
54
  type: :runtime
25
55
  prerelease: false
26
- version_requirements: *id001
27
- - !ruby/object:Gem::Dependency
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 1.2.0
62
+ - !ruby/object:Gem::Dependency
28
63
  name: bundler
29
- requirement: &id002 !ruby/object:Gem::Requirement
64
+ requirement: !ruby/object:Gem::Requirement
30
65
  none: false
31
- requirements:
66
+ requirements:
32
67
  - - ~>
33
- - !ruby/object:Gem::Version
34
- version: 1.0.0
68
+ - !ruby/object:Gem::Version
69
+ version: 1.1.0
35
70
  type: :development
36
71
  prerelease: false
37
- version_requirements: *id002
38
- - !ruby/object:Gem::Dependency
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: 1.1.0
78
+ - !ruby/object:Gem::Dependency
39
79
  name: jeweler
40
- requirement: &id003 !ruby/object:Gem::Requirement
80
+ requirement: !ruby/object:Gem::Requirement
41
81
  none: false
42
- requirements:
82
+ requirements:
43
83
  - - ~>
44
- - !ruby/object:Gem::Version
45
- version: 1.5.2
84
+ - !ruby/object:Gem::Version
85
+ version: 1.8.4
46
86
  type: :development
47
87
  prerelease: false
48
- version_requirements: *id003
49
- description: Bring the fun of NoSQL into your SQL-backed Active Record objects in a compartmentalized way. Turns any text field on your objects into a schema-less key value store.
50
- email: gems@awexomelabs.com
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ version: 1.8.4
94
+ - !ruby/object:Gem::Dependency
95
+ name: rdoc
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ~>
100
+ - !ruby/object:Gem::Version
101
+ version: '3.12'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ~>
108
+ - !ruby/object:Gem::Version
109
+ version: '3.12'
110
+ - !ruby/object:Gem::Dependency
111
+ name: rspec
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: 2.11.0
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: 2.11.0
126
+ - !ruby/object:Gem::Dependency
127
+ name: sqlite3
128
+ requirement: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: 1.3.6
134
+ type: :development
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ! '>='
140
+ - !ruby/object:Gem::Version
141
+ version: 1.3.6
142
+ description: NoSQL-like key value stores in SQL-backed ActiveRecord objects. Arbitrary
143
+ keys behave like dynamic, indexable, searchable first-order attributes.
144
+ email: engineering@awexomelabs.com
51
145
  executables: []
52
-
53
146
  extensions: []
54
-
55
- extra_rdoc_files:
147
+ extra_rdoc_files:
56
148
  - LICENSE.txt
57
149
  - README.rdoc
58
- files:
59
- - .document
150
+ files:
151
+ - .rspec
60
152
  - Gemfile
61
153
  - Gemfile.lock
62
154
  - LICENSE.txt
@@ -65,42 +157,44 @@ files:
65
157
  - VERSION
66
158
  - doeskeyvalue.gemspec
67
159
  - lib/doeskeyvalue.rb
68
- - lib/doeskeyvalue/indexes.rb
69
- - lib/doeskeyvalue/key_manager.rb
70
- - lib/doeskeyvalue/keys.rb
160
+ - lib/doeskeyvalue/accessors.rb
161
+ - lib/doeskeyvalue/column_storage.rb
162
+ - lib/doeskeyvalue/configuration.rb
163
+ - lib/doeskeyvalue/index.rb
164
+ - lib/doeskeyvalue/state.rb
165
+ - lib/doeskeyvalue/table_storage.rb
71
166
  - lib/doeskeyvalue/util.rb
72
167
  - lib/generators/doeskeyvalue/doeskeyvalue_generator.rb
73
168
  - lib/generators/doeskeyvalue/templates/create_key_value_index.rb
74
- has_rdoc: true
169
+ - spec/doeskeyvalue/column_storage_spec.rb
170
+ - spec/doeskeyvalue/table_storage_spec.rb
171
+ - spec/spec_helper.rb
75
172
  homepage: http://github.com/awexome/doeskeyvalue
76
- licenses:
173
+ licenses:
77
174
  - MIT
78
175
  post_install_message:
79
176
  rdoc_options: []
80
-
81
- require_paths:
177
+ require_paths:
82
178
  - lib
83
- required_ruby_version: !ruby/object:Gem::Requirement
179
+ required_ruby_version: !ruby/object:Gem::Requirement
84
180
  none: false
85
- requirements:
86
- - - ">="
87
- - !ruby/object:Gem::Version
88
- hash: -3792581262529831668
89
- segments:
181
+ requirements:
182
+ - - ! '>='
183
+ - !ruby/object:Gem::Version
184
+ version: '0'
185
+ segments:
90
186
  - 0
91
- version: "0"
92
- required_rubygems_version: !ruby/object:Gem::Requirement
187
+ hash: 2971647915141782582
188
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
189
  none: false
94
- requirements:
95
- - - ">="
96
- - !ruby/object:Gem::Version
97
- version: "0"
190
+ requirements:
191
+ - - ! '>='
192
+ - !ruby/object:Gem::Version
193
+ version: '0'
98
194
  requirements: []
99
-
100
195
  rubyforge_project:
101
- rubygems_version: 1.5.2
196
+ rubygems_version: 1.8.24
102
197
  signing_key:
103
198
  specification_version: 3
104
- summary: Add schema-less NoSQL-like key values to any ActiveRecord class
199
+ summary: NoSQL-like key value stores in SQL-backed ActiveRecord objects.
105
200
  test_files: []
106
-
data/.document DELETED
@@ -1,5 +0,0 @@
1
- lib/**/*.rb
2
- bin/*
3
- -
4
- features/**/*.feature
5
- LICENSE.txt
@@ -1,104 +0,0 @@
1
- # AWEXOME LABS
2
- # DoesKeyValue
3
- #
4
- # Indexes -- ActiveRecord::Base methods for settings and retrieval of values based
5
- # on key indexes
6
-
7
- module DoesKeyValue
8
- module Indexes
9
-
10
- def declare_index(key_value_column, key_name, opts={})
11
- raise DoesKeyValue::NoColumnNameSpecified unless key_value_column
12
- raise DoesKeyValue::NoKeyNameSpecified unless key_name
13
- raise DoesKeyValue::KeyAndIndexOptionsMustBeHash unless opts.is_a?(Hash)
14
-
15
- search_key = "#{key_value_column}.#{key_name}"
16
- # TODO: raise DoesKeyValue::NoKeyForThatIndex if !self.respond_to?(key_name) || !self.respond_to?("#{key_name}=")
17
-
18
- class_name = self.name.underscore
19
- class_table_name = self.table_name
20
- index_table_name = "key_value_index"
21
-
22
- # INDEX TABLE: key_value_index
23
- # id:int
24
- # key_name:string
25
- # value:string
26
- # obj_type:string
27
- # obj_id:int
28
-
29
- # Define finders that leverage the custom index table:
30
- instance_eval <<-EOS
31
- def find_all_by_#{key_value_column}_#{key_name}(value)
32
- find(
33
- :all,
34
- :select=>"*",
35
- :from=>"#{index_table_name}",
36
- :conditions=>["`#{index_table_name}`.obj_type = ? AND `#{index_table_name}`.key_name = ? AND `#{index_table_name}`.value = ?", self.to_s, "#{search_key}", value],
37
- :joins => "LEFT JOIN `#{class_table_name}` ON `#{class_table_name}`.id = `#{index_table_name}`.obj_id"
38
- )
39
- end
40
-
41
- def find_all_by_#{key_name}(value)
42
- find_all_by_#{key_value_column}_#{key_name}(value)
43
- end
44
-
45
- def find_all_with_#{key_value_column}(opts={})
46
- conds = Array.new
47
- opts.each do |k, v|
48
- conds.add_condition(["`#{index_table_name}`.obj_type = ? AND `#{index_table_name}`.key_name = ? AND `#{index_table_name}`.value = ?", self.to_s, "#{search_key}", v])
49
- end
50
- find(
51
- :all,
52
- :select=>"*",
53
- :from=>"#{index_table_name}",
54
- :conditions=>conds,
55
- :joins=>"LEFT JOIN `#{class_table_name}` ON `#{class_table_name}`.id = `#{index_table_name}`.obj_id"
56
- )
57
- end
58
- EOS
59
-
60
- # Provide a callback after save which updates the index
61
- define_method("update_index_#{key_value_column}_#{key_name}_after_save") do
62
- class_name = self.class.name.underscore
63
- class_table_name = self.class.table_name
64
- index_table_name = "key_value_index"
65
-
66
- # TODO: Restrict value to 255 characters, the table-enforced limit
67
-
68
- # TODO: Serialize value in such a nils to be properly represented
69
- # Sample JSON Serialization: tab.to_json
70
- # Sample JSON Reconstruction: Tab.new( JSON.parse(tab.to_json)["tab"] )
71
-
72
- new_value = self.send(key_name)
73
- up_count = ActiveRecord::Base.connection.update("
74
- UPDATE `#{index_table_name}` SET `value` = \"#{new_value}\", `updated_at` = NOW()
75
- WHERE `obj_type`=\"#{self.class}\" AND `obj_id`=#{self.id} AND `key_name`=\"#{search_key}\"
76
- ")
77
- if !new_value.nil? && up_count == 0
78
- idx_id = ActiveRecord::Base.connection.insert(
79
- "INSERT INTO `#{index_table_name}` (`obj_type`,`obj_id`,`key_name`,`value`,`created_at`,`updated_at`) VALUES (\"#{self.class}\", #{self.id}, \"#{search_key}\", \"#{new_value}\", NOW(), NOW())
80
- ")
81
- return idx_id
82
- end
83
-
84
- end
85
- after_save "update_index_#{key_value_column}_#{key_name}_after_save"
86
-
87
- # Provide a callback after destroy to likewise update the index
88
- define_method("update_index_#{key_value_column}_#{key_name}_after_destroy") do
89
- class_name = self.class.name.underscore
90
- class_table_name = self.class.table_name
91
- index_table_name = "key_value_index"
92
- num_del = ActiveRecord::Base.connection.delete("DELETE FROM `#{index_table_name}` WHERE `obj_type` = \"#{self.class}\" AND `obj_id` = #{self.id}")
93
- end
94
- after_destroy "update_index_#{key_value_column}_#{key_name}_after_destroy"
95
-
96
-
97
- # Add the index to the key and column manager:
98
- DoesKeyValue::KeyManager.instance.declare_index(self, key_value_column, key_name, opts)
99
-
100
- end
101
-
102
-
103
- end # Indexes
104
- end # DoesKeyValue
@@ -1,116 +0,0 @@
1
- # AWEXOME LABS
2
- # DoesKeyValue
3
- #
4
- # KeyManager -- Holds and maintains key_value configuration for all
5
- # classes and blob-containers implementing DoesKeyValue
6
-
7
- module DoesKeyValue
8
- class KeyManager
9
-
10
- # There can be only one:
11
- include Singleton
12
-
13
-
14
- # Return the Hash of known columns, organized by declaring class
15
- def columns
16
- @columns ||= Hashie::Mash.new
17
- end
18
-
19
- # Declare a key_value columns' existing in a given class
20
- def declare_column(klass, column_name)
21
- @columns ||= Hashie::Mash.new
22
- if @columns[klass].nil?
23
- @columns[klass] = [column_name]
24
- else
25
- @columns[klass] << column_name
26
- end
27
- @columns[klass]
28
- end
29
-
30
- # Return the key columns present on a specific class
31
- def columns_for(klass)
32
- columns_this_klass = columns[klass]
33
- columns_lineage = [ columns_this_klass ]
34
- if ancestor = klass.ancestors[1]
35
- unless ancestor == ActiveRecord::Base
36
- columns_lineage << columns_for(ancestor)
37
- end
38
- end
39
- columns_lineage.reject{|i| i.nil? }.flatten
40
- end
41
-
42
-
43
- # Return the Hash of known keys, organized by the declaring class
44
- def keys
45
- @keys ||= Hashie::Mash.new
46
- end
47
-
48
- # Declare a key in a specific column set for a specific class
49
- def declare_key(klass, column_name, key, opts={})
50
- # TODO: Store the key options in the manager
51
- column_name = column_name.to_sym
52
- @keys ||= Hashie::Mash.new
53
- if klass_keys = @keys[klass]
54
- if column_keys = klass_keys[column_name]
55
- column_keys << key
56
- else
57
- klass_keys[column_name] = [key]
58
- end
59
- else
60
- @keys[klass] = {column_name => [key]}
61
- end
62
- @keys[klass][column_name]
63
- end
64
-
65
- # Return the keys present for the given column on a specific class
66
- def keys_for(klass, column_name)
67
- keys_this_klass = keys[klass][column_name] rescue []
68
- keys_lineage = [ keys_this_klass ]
69
- if ancestor = klass.ancestors[1]
70
- unless ancestor == ActiveRecord::Base
71
- keys_lineage << keys_for(ancestor, column_name)
72
- end
73
- end
74
- keys_lineage.flatten.reject{|i| i.nil?}
75
- end
76
-
77
-
78
-
79
- # Return the Hash of known Indexes, organized by the declaring class
80
- def indexes
81
- @indexes ||= Hashie::Mash.new
82
- end
83
-
84
- # Declare an index in a specific column set for a specific class
85
- def declare_index(klass, column_name, key, opts={})
86
- # TODO: Store the index options in the manager
87
- column_name = column_name.to_sym
88
- @indexes ||= Hashie::Mash.new
89
- if klass_indexes = @indexes[klass]
90
- if column_indexes = klass_indexes[column_name]
91
- column_indexes << key
92
- else
93
- klass_indexes[column_name] = [key]
94
- end
95
- else
96
- @indexes[klass] = {@column_name => [key]}
97
- end
98
- @indexes[klass][column_name]
99
- end
100
-
101
- # Return the indexes present for the given column on a specific class
102
- def indexes_for(klass, column_name)
103
- indexes_this_klass = indexes[klass][column_name] rescue []
104
- indexes_lineage = [ indexes_this_klass ]
105
- if ancestor = klass.ancestors[1]
106
- unless ancestor == ActiveRecord::Base
107
- indexes_lineage << indexes_for(ancestor, column_name)
108
- end
109
- end
110
- indexes_lineage.flatten.reject{|i| i.nil? }
111
- end
112
-
113
-
114
-
115
- end # KeyManager
116
- end # DoesKeyValue