dm-redis-adapter 0.0.11 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.textile CHANGED
@@ -2,23 +2,30 @@ h1. dm-redis-adapter
2
2
 
3
3
  This is a <a href="http://datamapper.org">DataMapper</a> adapter for the <a href="http://github.com/antirez/redis/">Redis</a> key-value database.
4
4
 
5
- Redis is a very fast key-value store with some interesting data structures added. You can have a key that is a SET, LIST, or a STRING that is binary safe. Data structures like SET and LIST allow for even more interesting things. Redis is a fabulous and fast engine for data structures, and you can read more about it here: <a href="http://code.google.com/p/redis/">redis</a>. Redis is also a persistent data store, and can be used in large-scale environments with master-slave replication and consistent hashing on the client side.
5
+ Redis is a very fast key-value store with some interesting data structures added. You can have a key that is a SET, LIST, STRING or HASH that is binary safe. Data structures like SET and LIST allow for even more interesting things. Redis is a fabulous and fast engine for data structures, and you can read more about it here: <a href="http://code.google.com/p/redis/">redis</a>. Redis is also a persistent data store, and can be used in large-scale environments with master-slave replication and consistent hashing on the client side.
6
6
 
7
7
  <a href="http://datamapper.org">DataMapper</a> is a brilliant ORM that is based on the <a href="http://www.martinfowler.com/eaaCatalog/identityMap.html">IdentityMap</a> pattern. Usage of DataMapper resembles that of ActiveRecord, the popular ORM bundled with Ruby on Rails, but with some very important differences. A quote from the DM wiki: "One row in the database should equal one object reference. Pretty simple idea. Pretty profound impact." Having an identity map allows for very efficient queries to the database, as well as interesting forms of lazy loading of attributes or associations.
8
8
 
9
9
  Marrying DataMapper to Redis allows for schema-less models, you can add fields at any time without having to create a migration. DataMapper also allows us to store non-native Redis types in the db, like Date fields.
10
10
 
11
+ h1. Upgrading
12
+
13
+ > v0.1 is not compatible with data created with previous versions! The new storage schema is designed to be more VM friendly. I won't be releasing a gem version of v0.1 until a stable version of redis that includes hash support has been released.
14
+
11
15
  h1. Changelog
12
16
 
17
+ * v0.2.1 Fixes to sorting
18
+ * v0.1.1 Update to redis-rb v2.0.0
19
+ * v0.1 Update to store records as redis hash values
13
20
  * v0.0.11 Updates to support newer versions of the redis client, support for JSON datatypes
14
21
 
15
22
  h1. Install
16
23
 
17
24
  Prerequisites:
18
25
  * Redis:
19
- ** <a href="http://code.google.com/p/redis/">Redis, v1.3.8</a>
26
+ ** <a href="http://code.google.com/p/redis/">Redis, v2.0.x RC series</a>
20
27
  * Gems:
21
- ** <a href="http://github.com/datamapper/dm-core/">dm-core</a> v0.10.2
28
+ ** <a href="http://github.com/datamapper/dm-core/">dm-core</a> v1.0.0
22
29
 
23
30
  Install the dm-redis adapter:
24
31
  <pre>
@@ -89,5 +96,5 @@ h1. Badass contributors
89
96
 
90
97
  * <a href="http://github.com/aeden">Anthony Eden (aeden)</a> Gem cleanup, update to jeweler
91
98
  * <a href="http://github.com/sr">Simon Roset (sr)</a> Fixes for edge dm-core
92
- * <a href="http://github.com/cehoffman">Chris Hoffman (cehoffman)</a> Fixes for Ruby 1.9, bundler for development deps
93
- * <a href="http://github.com/bpo">brian p o'rourke (bpo)</a> Updates for newer versions of redis client and DM JSON type support
99
+ * <a href="http://github.com/cehoffman">Chris Hoffman (cehoffman)</a> Fixes for Ruby 1.9, bundler for development deps, fixes for sorting
100
+ * <a href="http://github.com/bpo">brian p o'rourke (bpo)</a> Updates for newer versions of redis client and DM JSON type support, move to hash storage
data/Rakefile CHANGED
@@ -26,13 +26,13 @@ begin
26
26
  gemspec.homepage = HOMEPAGE
27
27
  gemspec.description = SUMMARY
28
28
  gemspec.authors = AUTHORS
29
- gemspec.add_dependency "dm-core", ">= 0.10.2"
30
- gemspec.add_dependency "dm-types", ">= 0.10.2"
31
- gemspec.add_dependency "redis"
29
+ gemspec.add_dependency "dm-core", ">= 1.0.0"
30
+ gemspec.add_dependency "dm-types", ">= 1.0.0"
31
+ gemspec.add_dependency "redis", ">= 2.0.3"
32
32
  gemspec.files = %w(MIT-LICENSE README.textile Rakefile) + Dir.glob("{lib,spec}/**/*")
33
- gemspec.has_rdoc = true
33
+ gemspec.has_rdoc = false
34
34
  gemspec.extra_rdoc_files = ["MIT-LICENSE"]
35
- end
35
+ end
36
36
  rescue LoadError
37
37
  puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
38
38
  end
@@ -36,18 +36,19 @@ module DataMapper
36
36
  # @api semipublic
37
37
  def read(query)
38
38
  records = records_for(query).each do |record|
39
+ record_data = @redis.hgetall( "#{query.model.to_s.downcase}:#{record[redis_key_for(query.model)]}" )
40
+
39
41
  query.fields.each do |property|
40
42
  next if query.model.key.include?(property)
41
43
 
44
+ name = property.name.to_s
45
+ value = record_data[name]
46
+
42
47
  # Integers are stored as Strings in Redis. If there's a
43
48
  # string coming out that should be an integer, convert it
44
49
  # now. All other typecasting is handled by datamapper
45
50
  # separately.
46
- if property.primitive == Integer
47
- record[property.name.to_s] = property.typecast(@redis["#{query.model.to_s.downcase}:#{record[redis_key_for(query.model)]}:#{property.name}"])
48
- else
49
- record[property.name.to_s] = @redis["#{query.model.to_s.downcase}:#{record[redis_key_for(query.model)]}:#{property.name}"]
50
- end
51
+ record[name] = [Integer, Date].include?(property.primitive) ? property.typecast( value ) : value
51
52
  end
52
53
  end
53
54
  records = query.match_records(records)
@@ -88,9 +89,7 @@ module DataMapper
88
89
  # @api semipublic
89
90
  def delete(collection)
90
91
  records_for(collection.query).each do |record|
91
- collection.query.model.properties.each do |p|
92
- @redis.del("#{collection.query.model.to_s.downcase}:#{record[redis_key_for(collection.query.model)]}:#{p.name}")
93
- end
92
+ @redis.del("#{collection.query.model.to_s.downcase}:#{record[redis_key_for(collection.query.model)]}")
94
93
  @redis.srem(key_set_for(collection.query.model), record[redis_key_for(collection.query.model)])
95
94
  collection.query.model.properties.select {|p| p.index}.each do |p|
96
95
  @redis.srem("#{collection.query.model.to_s.downcase}:#{p.name}:#{encode(record[p.name])}", record[redis_key_for(collection.query.model)])
@@ -116,11 +115,22 @@ module DataMapper
116
115
  @redis.sadd("#{resource.model.to_s.downcase}:#{property.name}:#{encode(resource[property.name.to_s])}", resource.key)
117
116
  end
118
117
 
119
- model.properties(self.name).each do |property|
120
- next unless attributes.key?(property)
118
+ properties_to_set = []
119
+ properties_to_del = []
120
+
121
+ fields = model.properties(self.name).select {|property| attributes.key?(property) }
122
+ fields.each do |property|
121
123
  value = attributes[property]
122
- @redis["#{resource.model.to_s.downcase}:#{resource.key.join}:#{property.name}"] = value unless value.nil?
124
+ if value.nil?
125
+ properties_to_del << property.name
126
+ else
127
+ properties_to_set << property.name << attributes[property]
128
+ end
123
129
  end
130
+
131
+ hash_key = "#{resource.model.to_s.downcase}:#{resource.key.join}"
132
+ properties_to_del.each {|prop| @redis.hdel(hash_key, prop) }
133
+ @redis.hmset(hash_key, *properties_to_set) unless properties_to_set.empty?
124
134
  end
125
135
  end
126
136
 
@@ -147,9 +157,17 @@ module DataMapper
147
157
  keys << {"#{redis_key_for(query.model)}" => k, "#{o.subject.name}" => o.value}
148
158
  end
149
159
  end
150
-
151
- if query.limit
152
- @redis.sort(key_set_for(query.model), :limit => [query.offset, query.limit]).each do |val|
160
+
161
+ if query.order || query.limit
162
+ params = {}
163
+ params[:limit] = [query.offset, query.limit] if query.limit
164
+
165
+ if query.order
166
+ order = query.order.first
167
+ params[:order] = order.operator.to_s
168
+ end
169
+
170
+ @redis.sort(key_set_for(query.model), params).each do |val|
153
171
  keys << {"#{redis_key_for(query.model)}" => val.to_i}
154
172
  end
155
173
  end
@@ -0,0 +1,14 @@
1
+ require 'dm-redis-adapter'
2
+ require 'dm-core/spec/setup'
3
+
4
+ module DataMapper
5
+ module Spec
6
+ module Adapters
7
+
8
+ class RedisAdapter < Adapter
9
+ end
10
+
11
+ use RedisAdapter
12
+ end
13
+ end
14
+ end
@@ -0,0 +1 @@
1
+ require 'dm-redis-adapter/adapter'
@@ -1,7 +1,11 @@
1
- require File.expand_path("../spec_helper", __FILE__)
2
- require 'redis'
1
+ require 'spec_helper'
3
2
 
4
- require 'dm-core/spec/adapter_shared_spec'
3
+ require 'dm-core'
4
+ require 'dm-core/spec/shared/adapter_spec'
5
+ require 'dm-redis-adapter/spec/setup'
6
+
7
+ ENV['ADAPTER'] = 'redis'
8
+ ENV['ADAPTER_SUPPORTS'] = 'all'
5
9
 
6
10
  describe DataMapper::Adapters::RedisAdapter do
7
11
  before(:all) do
@@ -9,12 +13,13 @@ describe DataMapper::Adapters::RedisAdapter do
9
13
  :adapter => "redis",
10
14
  :db => 15
11
15
  })
16
+ @repository = DataMapper.repository(@adapter.name)
12
17
  end
13
18
 
19
+ it_should_behave_like 'An Adapter'
20
+
14
21
  after(:all) do
15
22
  redis = Redis.new(:db => 15)
16
23
  redis.flushdb
17
24
  end
18
-
19
- it_should_behave_like 'An Adapter'
20
- end
25
+ end
@@ -1,22 +1,21 @@
1
1
  require File.expand_path("../spec_helper", __FILE__)
2
- require 'redis'
3
- require 'rubygems'
4
2
  require 'dm-validations'
5
3
  require 'dm-types'
6
- require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib/dm_redis.rb'))
4
+ require 'logger'
7
5
 
8
6
  describe DataMapper::Adapters::RedisAdapter do
9
7
  before(:all) do
10
8
  @adapter = DataMapper.setup(:default, {
11
9
  :adapter => "redis",
12
- :db => 15
10
+ :db => 15,
11
+ # :logger => Logger.new(STDOUT)
13
12
  })
14
13
  end
15
14
 
16
15
  it "should validate unique entries that are indexed" do
17
16
  class Crumblecake
18
17
  include DataMapper::Resource
19
- validates_is_unique :flavor
18
+ validates_uniqueness_of :flavor
20
19
 
21
20
  property :id, Serial
22
21
  property :flavor, String, :index => true
@@ -33,7 +32,7 @@ describe DataMapper::Adapters::RedisAdapter do
33
32
 
34
33
  property :id, Serial
35
34
  property :name, String
36
- property :env, DataMapper::Types::Json, :default => lambda { {} }
35
+ property :env, DataMapper::Property::Json, :default => lambda { {} }
37
36
  end
38
37
  end
39
38
 
@@ -52,8 +51,50 @@ describe DataMapper::Adapters::RedisAdapter do
52
51
  end
53
52
  end
54
53
 
54
+ it "should allow me to delete properties" do
55
+ class User
56
+ include DataMapper::Resource
57
+
58
+ property :id, Serial
59
+ property :name, String
60
+ end
61
+
62
+ u = User.create :name => "bpo"
63
+ u.reload.name.should == "bpo"
64
+ u.name = nil
65
+ u.save
66
+ u.reload.name.should == nil
67
+ end
68
+
69
+ it "should store Date fields" do
70
+ class Post
71
+ include DataMapper::Resource
72
+
73
+ property :id, Serial
74
+ property :posted_at, Date
75
+ end
76
+
77
+ Post.create :posted_at => Date.today
78
+ Post.first.posted_at.should be_a(Date)
79
+ end
80
+
81
+ it "should get the first and last model inserted" do
82
+ class GangMember
83
+ include DataMapper::Resource
84
+
85
+ property :id, Serial
86
+ property :nickname, String
87
+ end
88
+
89
+ joey = GangMember.create(:nickname => "Joey 'two-times'")
90
+ bobby = GangMember.create(:nickname => "Bobby 'three-fingers'")
91
+
92
+ GangMember.first.should == joey
93
+ GangMember.last.should == bobby
94
+ end
95
+
55
96
  after(:all) do
56
97
  redis = Redis.new(:db => 15)
57
98
  redis.flushdb
58
99
  end
59
- end
100
+ end
data/spec/spec_helper.rb CHANGED
@@ -8,6 +8,4 @@ rescue LoadError
8
8
  Bundler.setup
9
9
  end
10
10
 
11
- require 'dm-core'
12
-
13
- require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib/dm_redis'))
11
+ require 'dm-core'
metadata CHANGED
@@ -1,12 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dm-redis-adapter
3
3
  version: !ruby/object:Gem::Version
4
+ hash: 21
4
5
  prerelease: false
5
6
  segments:
6
7
  - 0
7
- - 0
8
- - 11
9
- version: 0.0.11
8
+ - 2
9
+ - 1
10
+ version: 0.2.1
10
11
  platform: ruby
11
12
  authors:
12
13
  - Dan Herrera
@@ -14,47 +15,55 @@ autorequire:
14
15
  bindir: bin
15
16
  cert_chain: []
16
17
 
17
- date: 2010-04-26 00:00:00 -07:00
18
+ date: 2010-07-12 00:00:00 -07:00
18
19
  default_executable:
19
20
  dependencies:
20
21
  - !ruby/object:Gem::Dependency
21
22
  name: dm-core
22
23
  prerelease: false
23
24
  requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
24
26
  requirements:
25
27
  - - ">="
26
28
  - !ruby/object:Gem::Version
29
+ hash: 23
27
30
  segments:
31
+ - 1
28
32
  - 0
29
- - 10
30
- - 2
31
- version: 0.10.2
33
+ - 0
34
+ version: 1.0.0
32
35
  type: :runtime
33
36
  version_requirements: *id001
34
37
  - !ruby/object:Gem::Dependency
35
38
  name: dm-types
36
39
  prerelease: false
37
40
  requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
38
42
  requirements:
39
43
  - - ">="
40
44
  - !ruby/object:Gem::Version
45
+ hash: 23
41
46
  segments:
47
+ - 1
42
48
  - 0
43
- - 10
44
- - 2
45
- version: 0.10.2
49
+ - 0
50
+ version: 1.0.0
46
51
  type: :runtime
47
52
  version_requirements: *id002
48
53
  - !ruby/object:Gem::Dependency
49
54
  name: redis
50
55
  prerelease: false
51
56
  requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
52
58
  requirements:
53
59
  - - ">="
54
60
  - !ruby/object:Gem::Version
61
+ hash: 9
55
62
  segments:
63
+ - 2
56
64
  - 0
57
- version: "0"
65
+ - 3
66
+ version: 2.0.3
58
67
  type: :runtime
59
68
  version_requirements: *id003
60
69
  description: DataMapper adapter for the Redis key-value database
@@ -69,7 +78,9 @@ files:
69
78
  - MIT-LICENSE
70
79
  - README.textile
71
80
  - Rakefile
72
- - lib/dm_redis.rb
81
+ - lib/dm-redis-adapter.rb
82
+ - lib/dm-redis-adapter/adapter.rb
83
+ - lib/dm-redis-adapter/spec/setup.rb
73
84
  - spec/dm_redis_spec.rb
74
85
  - spec/dm_redis_validations_spec.rb
75
86
  - spec/spec_helper.rb
@@ -77,29 +88,33 @@ has_rdoc: true
77
88
  homepage: http://github.com/whoahbot/dm-redis-adapter
78
89
  licenses: []
79
90
 
80
- post_install_message:
91
+ post_install_message: "\n !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n (!!) U P G R A D I N G (!!)\n\n WAAAAAAAAAAAAAAAAAAAAAAAIT!\n Earlier versions of dm-redis-adapter\n use a different method of storing properties\n which means that this version of dm-redis-adapter\n won't read them properly.\n\n !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n "
81
92
  rdoc_options:
82
93
  - --charset=UTF-8
83
94
  require_paths:
84
95
  - lib
85
96
  required_ruby_version: !ruby/object:Gem::Requirement
97
+ none: false
86
98
  requirements:
87
99
  - - ">="
88
100
  - !ruby/object:Gem::Version
101
+ hash: 3
89
102
  segments:
90
103
  - 0
91
104
  version: "0"
92
105
  required_rubygems_version: !ruby/object:Gem::Requirement
106
+ none: false
93
107
  requirements:
94
108
  - - ">="
95
109
  - !ruby/object:Gem::Version
110
+ hash: 3
96
111
  segments:
97
112
  - 0
98
113
  version: "0"
99
114
  requirements: []
100
115
 
101
116
  rubyforge_project:
102
- rubygems_version: 1.3.6
117
+ rubygems_version: 1.3.7
103
118
  signing_key:
104
119
  specification_version: 3
105
120
  summary: DataMapper adapter for the Redis key-value database