doeskeyvalue 0.2.2 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile CHANGED
@@ -1,13 +1,23 @@
1
- # AWEXOME LABS
1
+ # DOES KEY VALUE
2
2
  # Gemfile
3
3
 
4
4
  source "http://rubygems.org"
5
5
 
6
6
  # Runtime dependencies:
7
- gem "hashie"
7
+
8
+ # The gem extends ActiveRecord:
9
+ gem "activesupport", "~> 3.2.0"
10
+ gem "activerecord", "~> 3.2.0"
11
+
12
+ # And has additional dependencies:
13
+ gem "hashie", "~> 1.2.0"
8
14
 
9
15
  # Development dependencies:
10
16
  group :development do
11
- gem "bundler", "~> 1.0.0"
12
- gem "jeweler", "~> 1.5.2"
17
+ gem "bundler", "~> 1.1.0"
18
+ gem "jeweler", "~> 1.8.4"
19
+ gem "rdoc", "~> 3.12"
20
+ gem "rspec", ">= 2.11.0"
21
+
22
+ gem "sqlite3", ">= 1.3.6"
13
23
  end
data/Gemfile.lock CHANGED
@@ -1,18 +1,53 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
+ activemodel (3.2.8)
5
+ activesupport (= 3.2.8)
6
+ builder (~> 3.0.0)
7
+ activerecord (3.2.8)
8
+ activemodel (= 3.2.8)
9
+ activesupport (= 3.2.8)
10
+ arel (~> 3.0.2)
11
+ tzinfo (~> 0.3.29)
12
+ activesupport (3.2.8)
13
+ i18n (~> 0.6)
14
+ multi_json (~> 1.0)
15
+ arel (3.0.2)
16
+ builder (3.0.3)
17
+ diff-lcs (1.1.3)
4
18
  git (1.2.5)
5
- hashie (1.0.0)
6
- jeweler (1.5.2)
7
- bundler (~> 1.0.0)
19
+ hashie (1.2.0)
20
+ i18n (0.6.1)
21
+ jeweler (1.8.4)
22
+ bundler (~> 1.0)
8
23
  git (>= 1.2.5)
9
24
  rake
10
- rake (0.8.7)
25
+ rdoc
26
+ json (1.7.5)
27
+ multi_json (1.3.6)
28
+ rake (0.9.2.2)
29
+ rdoc (3.12)
30
+ json (~> 1.4)
31
+ rspec (2.11.0)
32
+ rspec-core (~> 2.11.0)
33
+ rspec-expectations (~> 2.11.0)
34
+ rspec-mocks (~> 2.11.0)
35
+ rspec-core (2.11.1)
36
+ rspec-expectations (2.11.3)
37
+ diff-lcs (~> 1.1.3)
38
+ rspec-mocks (2.11.2)
39
+ sqlite3 (1.3.6)
40
+ tzinfo (0.3.33)
11
41
 
12
42
  PLATFORMS
13
43
  ruby
14
44
 
15
45
  DEPENDENCIES
16
- bundler (~> 1.0.0)
17
- hashie
18
- jeweler (~> 1.5.2)
46
+ activerecord (~> 3.2.0)
47
+ activesupport (~> 3.2.0)
48
+ bundler (~> 1.1.0)
49
+ hashie (~> 1.2.0)
50
+ jeweler (~> 1.8.4)
51
+ rdoc (~> 3.12)
52
+ rspec (>= 2.11.0)
53
+ sqlite3 (>= 1.3.6)
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2011 Awexome Labs, LLC
1
+ Copyright (c) 2012 Awexome Labs, LLC
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.rdoc CHANGED
@@ -1,104 +1,139 @@
1
1
  = DoesKeyValue
2
2
 
3
- Bring the fun of NoSQL into your SQL-backed Active Record objects in a compartmentalized way. Turns
4
- any text field on your objects into a schema-less key value store.
3
+ NoSQL-like key value stores in SQL-backed ActiveRecord objects. Arbitrary keys behave
4
+ like dynamic, indexable, searchable first-order attributes.
5
+
6
+ == Deprecation Notice
7
+
8
+ DoesKeyValue is undergoing a substantial API change in order to better support new features
9
+ and alter the approach to previously-included features. The "old" gem versions will have
10
+ number in the v0.2.* series and are maintained (though only for major bugfixes) on the
11
+ {"albus" branch}[https://github.com/awexome/doeskeyvalue/tree/albus] in the repository.
12
+ Going forward, new work on the gem will be of the v0.9.* version series and will be
13
+ completed in {"bellatrix" branch}[https://github.com/awexome/doeskeyvalue/tree/bellatrix]
14
+ and made available in master.
15
+
16
+ When ready, the new "bellatrix" API will be released as a public gem with v0.9.0, but until
17
+ then, users can live on the edge by referencing this repository (master or bellatrix branches)
18
+ in their Gemfiles.
19
+
20
+ This documentation refers to only the new/v0.9+ branch and its corresponding API.
5
21
 
6
22
 
7
23
  == Installation
8
24
 
9
- Do the usual, of course:
25
+ Tried and true:
10
26
 
11
27
  gem install doeskeyvalue
12
28
 
13
29
  And add a gem dependency to your Gemfile:
14
30
 
15
- gem "doeskeyvalue", ">=0.1.0"
31
+ gem "doeskeyvalue"
16
32
 
17
33
 
18
- == Example
34
+ == Column-Based Storage Example
19
35
 
20
- Quick and simple. First, add the declaration to your ActiveRecord model:
36
+ In any ActiveRecord model in which you'd like to have key-value support, you simply
37
+ declare your intention to declare keys:
21
38
 
22
- doeskeyvalue :settings
39
+ does_keys :column=>"settings"
23
40
 
24
- In this invocation, "settings" is the name of TEXT or BLOB field on your model's database table. Think
25
- of it as something you'd typically serialize, but would prefer solid accessor and finding behavior on.
41
+ In this invocation, "settings" is the name of TEXT or BLOB field on your model's database
42
+ table. Think of it as something you'd typically serialize, but would prefer solid accessor
43
+ and finding behavior on.
26
44
 
27
- To add keys to your document, using the name of the field you provided, before (in this case
28
- "settings"), add keys individually like so:
45
+ Add keys to your document field individually like so:
29
46
 
30
- settings_key :uid
31
- settings_key :email
32
- settings_key :name
33
-
34
- This adds a uid, email, and name field to your record. You can use these fields just like regular
35
- columns on your ActiveRecord object, but they're happily stored within your TEXT/BLOB column at the
36
- database level. Check it out:
47
+ has_key :email # Default type is string
48
+ has_key :uid, :type=>:integer # But type can be overidden easily
49
+ has_key :city, :default=>"Awesomeville" # You can also declare default values
50
+
51
+ This adds email, uid, and city fields to your record. You can use these fields just like regular
52
+ columns on your ActiveRecord object, but they're happily stored within your TEXT/BLOB column at
53
+ the database level. Check it out:
37
54
 
38
55
  mod = Model.new
56
+ mod.email = "me@awexo.me"
57
+ => "me@awexo.me"
58
+ mod.email
59
+ => "me@awexo.me"
39
60
 
40
- mod.uid = "mccolin"
41
- => "mccolin"
42
-
43
- mod.uid
44
- => "mccolin"
45
-
46
- You can see the serialized key-value structure at any time, as well. Just access your old filed:
61
+ You can see the serialized key-value structure at any time, as well. Just access your old field:
47
62
 
48
63
  mod.settings
49
- => {:uid=>"mccolin"}
50
-
51
- At this point, we have a fancy serialized Hash on our hands. What we really want to be able to do is
52
- search for objects of type Model that have certain values. That's possible, too. First, generate the
53
- necessary migration:
64
+ => {:email=>"me@awexo.me"}
54
65
 
55
- rails g doeskeyvalue
56
-
57
- This creates db/migrate/XXX_create_key_value_index.rb for you. Migrate your database:
58
66
 
59
- rake db:migrate
60
-
61
- Now, you can declare keys that you'd like to be searchable within Model like so:
67
+ === Indexes and Searchability
62
68
 
63
- settings_index :uid
64
- settings_index :email
65
-
66
- Now, you've added powerful finders to your objects. As your objects are created, accessed, and updated,
67
- metadata in your index table will be updated that allows you to search against those objects similarly
68
- to how you'd perform lookups with a regular finder. Like so:
69
+ By default, all keys specified in column-based storage also have indexes which provide scopes
70
+ and searchability. This behavior, however, requires the addition of an key index database table,
71
+ which you can generate on the command line:
69
72
 
70
- Model.find_all_by_uid(123)
71
- => [#<Model:0x000001016b51a0 @settings=>{:uid=>123}>, #<Model:0x000001016b51a0 @settings=>{:uid=>123}>, ...]
72
-
73
- Model.find_all_with_settings(:email=>"foo@bar.com")
74
- => [#<Model:0x000001016b51a0 @settings=>{:email=>"foo@bar"}>, ...]
73
+ > rails generate doeskeyvalue
74
+ > rake db:migrate
75
75
 
76
- You can only run finds on keys for which you've added an index, but you can add and remove indexes as
77
- necessary simply by removing the index declaration from your model.
76
+ This will add a +key_value_index+ table to your database, which will serve as an application-wide
77
+ index and cache of your declared keys. Key values you modify on your objects are stored/cached
78
+ within the +key_value_index+ table, which is used in lookups.
78
79
 
79
- Likewise, you can remove keys from any model by removing the key declaration. This allows you to add
80
- and remove keys from every ActiveRecord object at will, without having to build any migrations, but you
81
- can still reap the benefits of whatever SQL-backed relational database you've chosen for the bulk of
82
- your application's heavy lifting.
80
+ For each key, a default scope of the form "with_KEYNAME" is provided for your use:
83
81
 
82
+ Model.with_email("foo@bar.com")
83
+ => []
84
+ Model.with_email("me@awexo.me")
85
+ => [#<User id: 1, ..., settings: {"email"=>"me@awexo.me"}, ...>]
84
86
 
85
- == Prior Versions
87
+ If you'd prefer to not have this searchability, you can forgo the creation of an index and related
88
+ scope for any of your keys, like so:
86
89
 
87
- DoesKeyValue is a much newer and cleaner version of the old "do_document_fields" plugin for prior versions
88
- of Rails. Check that out at http://github.com/mccolin/do_document_fields
90
+ has_key :email, :index=>false # Deny index creation (default setting for index is true)
89
91
 
92
+ Naturally, if all of your keys omit an index, you will not require the +key_value_index+ table in
93
+ your project.
90
94
 
91
- == Contributions
92
-
93
- * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
94
- * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
95
- * Fork the project
96
- * Start a feature/bugfix branch
97
- * Commit and push until you are happy with your contribution
98
- * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
99
- * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
100
95
 
101
- == Copyright
96
+ == Table-Based Storage Example
97
+
98
+ For larger key sets, you may find it advantageous to move your key-value storage into a separate
99
+ database table altogether, instead of the baked-in serialized TEXT/BLOB column. You can do this
100
+ quite easily by using a different flag in your initialization call:
101
+
102
+ does_keys :table=>"user_preferences"
103
+
104
+ In this example, we're storing our key-value pairs as their own independent rows within the
105
+ user_preferences database table. You declare keys and manipulate values in exactly the same way
106
+ as before:
107
+
108
+ has_key :bgcolor, :default=>"blue"
109
+ has_key :birthday, :type=>:datetime
110
+ has_key :likes_ice_cream, :type=>:boolean, :default=>true
111
+
112
+ mod.likes_ice_cream
113
+ => true
114
+ mod.likes_ice_cream = false
115
+ => false
116
+ mod.bgcolor
117
+ => "blue"
118
+
119
+ However, unlike with column-based storage, these values are immediately written to the table
120
+ specified in the invocation (in this case, +user_preferences+).
102
121
 
103
- Copyright (c) 2011 Awexome Labs, LLC. http://awexomelabs.com/
122
+ You will need to generate your separate key value indexes using the generator, while providing
123
+ a table name:
124
+
125
+ > rails generate doeskeyvalue user_preferences
126
+ > rake db:migrate
127
+
128
+ All keys using the separate table-based storage approach are automatically indexed. Values are
129
+ read directly from the supporting index table.
130
+
131
+ If desired, multiple models can freely store their values in a single table. This may be desired
132
+ for locality of all settings across a varieties of classes. You could, for instance, create one
133
+ +preferences+ table, which collects key values from User, Account, and Post models. For each class,
134
+ the invocation to +does_keys+ is the same. Simple!
135
+
136
+
137
+ == Copyright
104
138
 
139
+ Copyright (c) 2012 Awexome Labs, LLC. http://awexomelabs.com/
data/Rakefile CHANGED
@@ -1,8 +1,7 @@
1
- # AWEXOME LABS
2
- # Rakefile
1
+ # encoding: utf-8
3
2
 
4
- require 'rubygems'
5
- require 'bundler'
3
+ require "rubygems"
4
+ require "bundler"
6
5
  begin
7
6
  Bundler.setup(:default, :development)
8
7
  rescue Bundler::BundlerError => e
@@ -10,31 +9,56 @@ rescue Bundler::BundlerError => e
10
9
  $stderr.puts "Run `bundle install` to install missing gems"
11
10
  exit e.status_code
12
11
  end
13
- require 'rake'
12
+ require "rake"
14
13
 
15
- require 'jeweler'
14
+ require "jeweler"
16
15
  Jeweler::Tasks.new do |gem|
17
16
  # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
18
17
  gem.name = "doeskeyvalue"
19
18
  gem.homepage = "http://github.com/awexome/doeskeyvalue"
20
19
  gem.license = "MIT"
21
- gem.summary = %Q{Add schema-less NoSQL-like key values to any ActiveRecord class}
22
- gem.description = %Q{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.}
23
- gem.email = "gems@awexomelabs.com"
20
+ gem.summary = %Q{NoSQL-like key value stores in SQL-backed ActiveRecord objects.}
21
+ gem.description = %Q{NoSQL-like key value stores in SQL-backed ActiveRecord objects. Arbitrary keys behave like dynamic, indexable, searchable first-order attributes.}
22
+ gem.email = "engineering@awexomelabs.com"
24
23
  gem.authors = ["Awexome Labs"]
25
-
26
- # Internal Gem Dependencies:
27
- # gem.add_runtime_dependency 'jabber4r', '> 0.1'
28
- # gem.add_development_dependency 'rspec', '> 1.2.3'
24
+ # dependencies defined in Gemfile
29
25
  end
30
26
  Jeweler::RubygemsDotOrgTasks.new
31
27
 
32
- require 'rake/rdoctask'
28
+ require "rspec/core"
29
+ require "rspec/core/rake_task"
30
+ RSpec::Core::RakeTask.new(:spec) do |spec|
31
+ end
32
+
33
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
34
+ spec.rcov = true
35
+ end
36
+
37
+ task :default => :spec
38
+
39
+ # require "rake/testtask"
40
+ # Rake::TestTask.new(:test) do |test|
41
+ # test.libs << "lib" << "test"
42
+ # test.pattern = "test/**/test_*.rb"
43
+ # test.verbose = true
44
+ # end
45
+
46
+ # require "rcov/rcovtask"
47
+ # Rcov::RcovTask.new do |test|
48
+ # test.libs << "test"
49
+ # test.pattern = "test/**/test_*.rb"
50
+ # test.verbose = true
51
+ # test.rcov_opts << "--exclude "gems/*""
52
+ # end
53
+
54
+ # task :default => :test
55
+
56
+ require "rdoc/task"
33
57
  Rake::RDocTask.new do |rdoc|
34
- version = File.exist?('VERSION') ? File.read('VERSION') : ""
58
+ version = File.exist?("VERSION") ? File.read("VERSION") : ""
35
59
 
36
- rdoc.rdoc_dir = 'rdoc'
37
- rdoc.title = "doeskeyvalue #{version}"
38
- rdoc.rdoc_files.include('README*')
39
- rdoc.rdoc_files.include('lib/**/*.rb')
60
+ rdoc.rdoc_dir = "rdoc"
61
+ rdoc.title = "DoesKeyValue #{version}"
62
+ rdoc.rdoc_files.include("README*")
63
+ rdoc.rdoc_files.include("lib/**/*.rb")
40
64
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.2
1
+ 0.9.0
data/doeskeyvalue.gemspec CHANGED
@@ -4,20 +4,20 @@
4
4
  # -*- encoding: utf-8 -*-
5
5
 
6
6
  Gem::Specification.new do |s|
7
- s.name = %q{doeskeyvalue}
8
- s.version = "0.2.2"
7
+ s.name = "doeskeyvalue"
8
+ s.version = "0.9.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Awexome Labs"]
12
- s.date = %q{2011-06-29}
13
- s.description = %q{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.}
14
- s.email = %q{gems@awexomelabs.com}
12
+ s.date = "2012-12-30"
13
+ s.description = "NoSQL-like key value stores in SQL-backed ActiveRecord objects. Arbitrary keys behave like dynamic, indexable, searchable first-order attributes."
14
+ s.email = "engineering@awexomelabs.com"
15
15
  s.extra_rdoc_files = [
16
16
  "LICENSE.txt",
17
17
  "README.rdoc"
18
18
  ]
19
19
  s.files = [
20
- ".document",
20
+ ".rspec",
21
21
  "Gemfile",
22
22
  "Gemfile.lock",
23
23
  "LICENSE.txt",
@@ -26,35 +26,56 @@ Gem::Specification.new do |s|
26
26
  "VERSION",
27
27
  "doeskeyvalue.gemspec",
28
28
  "lib/doeskeyvalue.rb",
29
- "lib/doeskeyvalue/indexes.rb",
30
- "lib/doeskeyvalue/key_manager.rb",
31
- "lib/doeskeyvalue/keys.rb",
29
+ "lib/doeskeyvalue/accessors.rb",
30
+ "lib/doeskeyvalue/column_storage.rb",
31
+ "lib/doeskeyvalue/configuration.rb",
32
+ "lib/doeskeyvalue/index.rb",
33
+ "lib/doeskeyvalue/state.rb",
34
+ "lib/doeskeyvalue/table_storage.rb",
32
35
  "lib/doeskeyvalue/util.rb",
33
36
  "lib/generators/doeskeyvalue/doeskeyvalue_generator.rb",
34
- "lib/generators/doeskeyvalue/templates/create_key_value_index.rb"
37
+ "lib/generators/doeskeyvalue/templates/create_key_value_index.rb",
38
+ "spec/doeskeyvalue/column_storage_spec.rb",
39
+ "spec/doeskeyvalue/table_storage_spec.rb",
40
+ "spec/spec_helper.rb"
35
41
  ]
36
- s.homepage = %q{http://github.com/awexome/doeskeyvalue}
42
+ s.homepage = "http://github.com/awexome/doeskeyvalue"
37
43
  s.licenses = ["MIT"]
38
44
  s.require_paths = ["lib"]
39
- s.rubygems_version = %q{1.5.2}
40
- s.summary = %q{Add schema-less NoSQL-like key values to any ActiveRecord class}
45
+ s.rubygems_version = "1.8.24"
46
+ s.summary = "NoSQL-like key value stores in SQL-backed ActiveRecord objects."
41
47
 
42
48
  if s.respond_to? :specification_version then
43
49
  s.specification_version = 3
44
50
 
45
51
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
46
- s.add_runtime_dependency(%q<hashie>, [">= 0"])
47
- s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
48
- s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
52
+ s.add_runtime_dependency(%q<activesupport>, ["~> 3.2.0"])
53
+ s.add_runtime_dependency(%q<activerecord>, ["~> 3.2.0"])
54
+ s.add_runtime_dependency(%q<hashie>, ["~> 1.2.0"])
55
+ s.add_development_dependency(%q<bundler>, ["~> 1.1.0"])
56
+ s.add_development_dependency(%q<jeweler>, ["~> 1.8.4"])
57
+ s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
58
+ s.add_development_dependency(%q<rspec>, [">= 2.11.0"])
59
+ s.add_development_dependency(%q<sqlite3>, [">= 1.3.6"])
49
60
  else
50
- s.add_dependency(%q<hashie>, [">= 0"])
51
- s.add_dependency(%q<bundler>, ["~> 1.0.0"])
52
- s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
61
+ s.add_dependency(%q<activesupport>, ["~> 3.2.0"])
62
+ s.add_dependency(%q<activerecord>, ["~> 3.2.0"])
63
+ s.add_dependency(%q<hashie>, ["~> 1.2.0"])
64
+ s.add_dependency(%q<bundler>, ["~> 1.1.0"])
65
+ s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
66
+ s.add_dependency(%q<rdoc>, ["~> 3.12"])
67
+ s.add_dependency(%q<rspec>, [">= 2.11.0"])
68
+ s.add_dependency(%q<sqlite3>, [">= 1.3.6"])
53
69
  end
54
70
  else
55
- s.add_dependency(%q<hashie>, [">= 0"])
56
- s.add_dependency(%q<bundler>, ["~> 1.0.0"])
57
- s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
71
+ s.add_dependency(%q<activesupport>, ["~> 3.2.0"])
72
+ s.add_dependency(%q<activerecord>, ["~> 3.2.0"])
73
+ s.add_dependency(%q<hashie>, ["~> 1.2.0"])
74
+ s.add_dependency(%q<bundler>, ["~> 1.1.0"])
75
+ s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
76
+ s.add_dependency(%q<rdoc>, ["~> 3.12"])
77
+ s.add_dependency(%q<rspec>, [">= 2.11.0"])
78
+ s.add_dependency(%q<sqlite3>, [">= 1.3.6"])
58
79
  end
59
80
  end
60
81