datamapper4rail 0.1.0 → 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.
- data/Manifest.txt +6 -0
- data/Rakefile +14 -9
- data/generators/rspec_dm_model/rspec_dm_model_generator.rb +2 -2
- data/generators/rspec_dm_model/templates/model.rb +7 -4
- data/lib/datamapper4rails.rb +1 -53
- data/lib/datamapper4rails/adapters/restful_adapter.rb +104 -51
- data/lib/datamapper4rails/database_config.rb +7 -2
- data/lib/datamapper4rails/datamapper_store.rb +6 -5
- data/lib/datamapper4rails/identity_maps.rb +23 -0
- data/lib/datamapper4rails/preload_models.rb +26 -0
- data/lib/datamapper4rails/restful_transactions.rb +4 -3
- data/lib/datamapper4rails/version.rb +1 -1
- data/spec/datamapper_store_spec.rb +127 -0
- data/spec/restful_adapter_spec.rb +187 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +21 -0
- metadata +8 -2
data/Manifest.txt
CHANGED
@@ -18,5 +18,11 @@ lib/datamapper4rails/adapters/base_adapter.rb
|
|
18
18
|
lib/datamapper4rails/adapters/restful_adapter.rb
|
19
19
|
lib/datamapper4rails/database_config.rb
|
20
20
|
lib/datamapper4rails/datamapper_store.rb
|
21
|
+
lib/datamapper4rails/identity_maps.rb
|
22
|
+
lib/datamapper4rails/preload_models.rb
|
21
23
|
lib/datamapper4rails/restful_transactions.rb
|
22
24
|
lib/datamapper4rails/version.rb
|
25
|
+
spec/datamapper_store_spec.rb
|
26
|
+
spec/restful_adapter_spec.rb
|
27
|
+
spec/spec.opts
|
28
|
+
spec/spec_helper.rb
|
data/Rakefile
CHANGED
@@ -2,6 +2,11 @@
|
|
2
2
|
|
3
3
|
require 'rubygems'
|
4
4
|
require 'hoe'
|
5
|
+
|
6
|
+
require 'spec'
|
7
|
+
require 'spec/rake/spectask'
|
8
|
+
require 'pathname'
|
9
|
+
|
5
10
|
require './lib/datamapper4rails/version.rb'
|
6
11
|
|
7
12
|
Hoe.new('datamapper4rail', Datamapper4rails::VERSION) do |p|
|
@@ -17,16 +22,16 @@ task :install => [:clean, :package] do
|
|
17
22
|
sh "gem install --local #{gem} --no-ri --no-rdoc"
|
18
23
|
end
|
19
24
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
25
|
+
desc 'Run specifications'
|
26
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
27
|
+
if File.exists?('spec/spec.opts')
|
28
|
+
t.spec_opts << '--options' << 'spec/spec.opts'
|
29
|
+
end
|
30
|
+
t.spec_files = Pathname.glob('./spec/**/*_spec.rb')
|
31
|
+
end
|
27
32
|
|
28
|
-
|
33
|
+
require 'yard'
|
29
34
|
|
30
|
-
|
35
|
+
YARD::Rake::YardocTask.new
|
31
36
|
|
32
37
|
# vim: syntax=Ruby
|
@@ -2,13 +2,13 @@ require 'rails_generator/generators/components/model/model_generator'
|
|
2
2
|
require 'active_record'
|
3
3
|
require File.dirname(__FILE__) + '/../rspec_default_values'
|
4
4
|
|
5
|
-
class
|
5
|
+
class RspecDmModelGenerator <ModelGenerator
|
6
6
|
|
7
7
|
def manifest
|
8
8
|
record do |m|
|
9
9
|
|
10
10
|
# Check for class naming collisions.
|
11
|
-
m.class_collisions class_path, class_name
|
11
|
+
#m.class_collisions class_path, class_name
|
12
12
|
|
13
13
|
# Model, spec, and fixture directories.
|
14
14
|
m.directory File.join('app/models', class_path)
|
@@ -1,16 +1,19 @@
|
|
1
1
|
class <%= class_name %>
|
2
2
|
include DataMapper::Resource
|
3
|
+
<% if options[:add_constraints] -%>
|
4
|
+
include DataMapper::Constraints
|
5
|
+
<% end -%>
|
6
|
+
|
3
7
|
property :id, Serial
|
4
8
|
|
5
9
|
<% for attribute in attributes -%>
|
6
|
-
property :<%= attribute.name %>, <%= attribute.type.to_s.camelize %>, :nullable => false <% if attribute.type == :string or attribute.type == :text -%>, :format => /^[^<'&">]*$/<% if attribute.type == :string %>, :length =>
|
7
|
-
<% else -%>
|
10
|
+
property :<%= attribute.name %>, <%= attribute.type.to_s.camelize %>, :nullable => false <% if attribute.type == :string or attribute.type == :text -%>, :format => /^[^<'&">]*$/<% if attribute.type == :string %>, :length => 255<% end -%>
|
11
|
+
<% #else -%>
|
8
12
|
|
9
13
|
<% end -%>
|
10
14
|
<% end -%>
|
11
15
|
<% unless options[:skip_timestamps] %>
|
12
|
-
|
13
|
-
property :updated_at, DateTime, :nullable => false
|
16
|
+
timestamps :at
|
14
17
|
|
15
18
|
<% end -%>
|
16
19
|
end
|
data/lib/datamapper4rails.rb
CHANGED
@@ -1,53 +1 @@
|
|
1
|
-
require '
|
2
|
-
def config_file()
|
3
|
-
RAILS_ROOT + "/config/database.yml"
|
4
|
-
end
|
5
|
-
|
6
|
-
def create_connection()
|
7
|
-
conf = config.dup
|
8
|
-
if repositories = conf.delete(:repositories)
|
9
|
-
repositories.each do |repo, conf|
|
10
|
-
::DataMapper.setup(repo, conf) unless conf.empty?
|
11
|
-
end
|
12
|
-
else
|
13
|
-
::DataMapper.setup(:default, conf) unless conf.empty?
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
def get_config_for_environment
|
18
|
-
if hash = full_config[RAILS_ENV]
|
19
|
-
symbolize_keys(hash)
|
20
|
-
elsif hash = full_config[RAILS_ENV.to_sym]
|
21
|
-
hash
|
22
|
-
else
|
23
|
-
raise ArgumentError, "missing environment '#{RAILS_ENV}' in config file #{config_file}"
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
def full_config
|
28
|
-
@full_config ||= YAML::load(ERB.new(IO.read(config_file)).result)
|
29
|
-
end
|
30
|
-
|
31
|
-
def config
|
32
|
-
@config ||= get_config_for_environment
|
33
|
-
end
|
34
|
-
|
35
|
-
def symbolize_keys(h)
|
36
|
-
config = {}
|
37
|
-
|
38
|
-
h.each do |k, v|
|
39
|
-
if k == 'port'
|
40
|
-
config[k.to_sym] = v.to_i
|
41
|
-
elsif k == 'adapter' && v == 'postgresql'
|
42
|
-
config[k.to_sym] = 'postgres'
|
43
|
-
elsif v.is_a?(Hash)
|
44
|
-
config[k.to_sym] = symbolize_keys(v)
|
45
|
-
else
|
46
|
-
config[k.to_sym] = v
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
config
|
51
|
-
end
|
52
|
-
|
53
|
-
create_connection()
|
1
|
+
require 'datamapper4rails/database_config'
|
@@ -1,7 +1,8 @@
|
|
1
|
-
require 'adapters/
|
1
|
+
require 'datamapper4rails/adapters/base_adapter'
|
2
2
|
require 'net/http'
|
3
3
|
require 'extlib/inflection'
|
4
4
|
require 'extlib/module'
|
5
|
+
require 'dm-serializer'
|
5
6
|
|
6
7
|
module DataMapper
|
7
8
|
module Adapters
|
@@ -44,6 +45,18 @@ module DataMapper
|
|
44
45
|
raise "compound keys are not supported"
|
45
46
|
end
|
46
47
|
end
|
48
|
+
|
49
|
+
def single_entity_query?(query)
|
50
|
+
query.conditions.count {|c| c[1].key? and c[0] == :eql} == query.model.key.size
|
51
|
+
end
|
52
|
+
|
53
|
+
def attributes_to_xml(name, attributes)
|
54
|
+
xml = "<#{name}>"
|
55
|
+
attributes.each do |attr, val|
|
56
|
+
xml += "<#{attr.name}>#{val}</#{attr.name}>"
|
57
|
+
end
|
58
|
+
xml += "</#{name}>"
|
59
|
+
end
|
47
60
|
|
48
61
|
def http_get(uri)
|
49
62
|
send_request do |http|
|
@@ -66,13 +79,16 @@ module DataMapper
|
|
66
79
|
end
|
67
80
|
end
|
68
81
|
|
69
|
-
def http_put(uri, data =
|
82
|
+
def http_put(uri, data = nil)
|
70
83
|
send_request do |http|
|
71
|
-
request = Net::HTTP::Put.new(uri
|
84
|
+
request = Net::HTTP::Put.new(uri, {
|
85
|
+
'content-type' => 'application/xml',
|
86
|
+
'content-length' => data.length.to_s
|
87
|
+
})
|
72
88
|
request.basic_auth(@uri[:login],
|
73
89
|
@uri[:password]) unless @uri[:login].blank?
|
74
|
-
request.set_form_data(data)
|
75
|
-
http.request(request)
|
90
|
+
# request.set_form_data(data)
|
91
|
+
http.request(request, data)
|
76
92
|
end
|
77
93
|
end
|
78
94
|
|
@@ -112,14 +128,25 @@ module DataMapper
|
|
112
128
|
#puts
|
113
129
|
#puts "elements"
|
114
130
|
#p elements
|
131
|
+
#p query
|
132
|
+
#p model
|
115
133
|
resource = model.load(model.properties.collect do |f|
|
116
134
|
elements[f.name]
|
117
135
|
end, query)
|
118
136
|
resource.send("#{keys_from_query(query)[0].name}=".to_sym, elements[keys_from_query(query)[0].name] )
|
119
|
-
#p resource
|
120
|
-
|
121
|
-
|
137
|
+
# p resource
|
138
|
+
#p associations
|
139
|
+
associations.each do |name, association|
|
140
|
+
# puts "asso"
|
141
|
+
# p model
|
142
|
+
# p name
|
143
|
+
# p association
|
144
|
+
#p model.relationships
|
145
|
+
is_one_to_one = false
|
146
|
+
asso_model =
|
122
147
|
if rel = model.relationships[name]
|
148
|
+
#puts "rel"
|
149
|
+
#p rel
|
123
150
|
if rel.child_model == model
|
124
151
|
rel.parent_model
|
125
152
|
else
|
@@ -129,17 +156,38 @@ module DataMapper
|
|
129
156
|
#::Extlib::Inflection.constantize(::Extlib::Inflection.classify(name))
|
130
157
|
# model.find_const(::Extlib::Inflection.classify(name))
|
131
158
|
end
|
159
|
+
# p asso_model
|
132
160
|
if resource.respond_to? "#{name}=".to_sym
|
161
|
+
# puts
|
162
|
+
# puts "association"
|
163
|
+
# puts name
|
164
|
+
# p model
|
165
|
+
# p asso_model
|
133
166
|
resource.send("#{name}=".to_sym,
|
134
|
-
parse_resource(association,
|
135
|
-
::DataMapper::Query.new(query.repository,
|
167
|
+
parse_resource(association, asso_model,
|
168
|
+
::DataMapper::Query.new(query.repository, asso_model ))) unless asso_model.nil?
|
136
169
|
else
|
137
170
|
resource.send(("#{name.to_s.pluralize}<" + "<").to_sym,
|
138
|
-
parse_resource(association,
|
139
|
-
::DataMapper::Query.new(query.repository,
|
171
|
+
parse_resource(association, asso_model,
|
172
|
+
::DataMapper::Query.new(query.repository, asso_model ))) unless asso_model.nil?
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
#puts "many 2 many"
|
177
|
+
#p many_to_many
|
178
|
+
many_to_many.each do |name, many|
|
179
|
+
if model.relationships[name]
|
180
|
+
# TODO
|
181
|
+
else
|
182
|
+
# p ::Extlib::Inflection.classify(name.to_s.singularize)
|
183
|
+
many_model = Object.const_get(::Extlib::Inflection.classify(name.to_s.singularize))
|
184
|
+
resource.send(name).send(("<" + "<").to_sym,
|
185
|
+
parse_resource(many, many_model,
|
186
|
+
::DataMapper::Query.new(query.repository, many_model ))) unless many_model.nil?
|
140
187
|
end
|
141
188
|
end
|
142
189
|
resource.instance_variable_set(:@new_record, false)
|
190
|
+
#p resource
|
143
191
|
resource
|
144
192
|
end
|
145
193
|
|
@@ -168,65 +216,70 @@ module DataMapper
|
|
168
216
|
|
169
217
|
# @see BaseAdapter
|
170
218
|
def read_resource(query)
|
171
|
-
|
172
|
-
|
219
|
+
key = key_value_from_query(query)
|
220
|
+
uri = "/#{resource_name_from_query(query).pluralize}/#{key}.xml"
|
221
|
+
logger.debug { "get #{uri}" }
|
222
|
+
response = http_get(uri)
|
223
|
+
if response.kind_of?(Net::HTTPSuccess)
|
224
|
+
logger.debug { response.body.to_s }
|
225
|
+
parse_resource(REXML::Document::new(response.body).root,
|
226
|
+
query.model,
|
227
|
+
query)
|
173
228
|
else
|
174
|
-
|
175
|
-
|
229
|
+
#TODO may act on different response codes differently
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
# @see BaseAdapter
|
234
|
+
def read_resources(query)
|
235
|
+
if single_entity_query?(query)
|
236
|
+
[read_resource(query)]
|
237
|
+
else
|
238
|
+
uri = "/#{resource_name_from_query(query).pluralize}.xml"
|
176
239
|
logger.debug { "get #{uri}" }
|
177
240
|
response = http_get(uri)
|
178
241
|
if response.kind_of?(Net::HTTPSuccess)
|
179
|
-
|
180
|
-
|
181
|
-
|
242
|
+
result = []
|
243
|
+
logger.debug { response.body.to_s }
|
244
|
+
REXML::Document::new(response.body).root.each do |element|
|
245
|
+
result << parse_resource(element,
|
246
|
+
query.model,
|
247
|
+
query)
|
248
|
+
end
|
249
|
+
result
|
182
250
|
else
|
183
251
|
#TODO may act on different response codes differently
|
184
252
|
end
|
185
253
|
end
|
186
254
|
end
|
187
255
|
|
188
|
-
# @see BaseAdapter
|
189
|
-
def read_resources(query)
|
190
|
-
# raise "not implemented"
|
191
|
-
[read_resource(query)]
|
192
|
-
end
|
193
|
-
|
194
256
|
# @overwrite BaseAdapter
|
195
257
|
def update(attributes, query)
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
258
|
+
if query.limit == 1 or single_entity_query?(query)
|
259
|
+
xml = attributes_to_xml(resource_name_from_query(query), attributes)
|
260
|
+
key = key_value_from_query(query)
|
261
|
+
uri = "/#{resource_name_from_query(query).pluralize}/#{key}.xml"
|
262
|
+
logger.debug { "put #{uri}" }
|
263
|
+
response = http_put(uri, xml)
|
264
|
+
response.kind_of?(Net::HTTPSuccess)
|
265
|
+
else
|
266
|
+
super
|
200
267
|
end
|
201
|
-
key = key_value_from_query(query)
|
202
|
-
uri = "/#{name.pluralize}/#{key}.xml"
|
203
|
-
logger.debug { "put #{uri}" }
|
204
|
-
response = http_put(uri, params)
|
205
|
-
response.kind_of?(Net::HTTPSuccess)
|
206
268
|
end
|
207
269
|
|
208
270
|
# @see BaseAdapter
|
209
271
|
def update_resource(resource, attributes)
|
210
272
|
query = resource.to_query
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
attributes.each do |attr, val|
|
217
|
-
params["#{name}[#{attr.name}]"]=val
|
218
|
-
end
|
219
|
-
key = key_value_from_query(query)
|
220
|
-
logger.debug {resource.to_xml}
|
221
|
-
response = http_put("/#{resource_name_from_query(query).pluralize}/#{key}.xml", params)
|
222
|
-
response.kind_of?(Net::HTTPSuccess)
|
223
|
-
end
|
273
|
+
xml = attributes_to_xml(resource.name, attributes)
|
274
|
+
key = key_value_from_query(query)
|
275
|
+
logger.debug {resource.to_xml}
|
276
|
+
response = http_put("/#{resource_name_from_query(query).pluralize}/#{key}.xml", xml)
|
277
|
+
response.kind_of?(Net::HTTPSuccess)
|
224
278
|
end
|
225
|
-
|
279
|
+
|
226
280
|
# @overwrite BaseAdapter
|
227
281
|
def delete(query)
|
228
|
-
|
229
|
-
if query.limit == 1
|
282
|
+
if query.limit == 1 or single_entity_query?(query)
|
230
283
|
name = resource_name_from_query(query)
|
231
284
|
key = key_value_from_query(query)
|
232
285
|
uri = "/#{name.pluralize}/#{key}.xml"
|
@@ -241,7 +294,7 @@ module DataMapper
|
|
241
294
|
# @see BaseAdapter
|
242
295
|
def delete_resource(resource)
|
243
296
|
name = resource.name
|
244
|
-
key = key_value_from_query(resource.
|
297
|
+
key = key_value_from_query(resource.to_query)
|
245
298
|
uri = "/#{name.pluralize}/#{key}.xml"
|
246
299
|
logger.debug { "delete #{uri}" }
|
247
300
|
response = http_delete(uri)
|
@@ -6,8 +6,13 @@ end
|
|
6
6
|
|
7
7
|
def create_connection()
|
8
8
|
conf = config.dup
|
9
|
-
repositories = conf.delete(:repositories)
|
10
|
-
|
9
|
+
if repositories = conf.delete(:repositories)
|
10
|
+
repositories.each do |repo, conf|
|
11
|
+
::DataMapper.setup(repo, conf) unless conf.empty?
|
12
|
+
end
|
13
|
+
else
|
14
|
+
::DataMapper.setup(:default, conf) unless conf.empty?
|
15
|
+
end
|
11
16
|
end
|
12
17
|
|
13
18
|
def get_config_for_environment
|
@@ -8,8 +8,10 @@ module ActionController
|
|
8
8
|
super
|
9
9
|
if options.delete(:cache)
|
10
10
|
@@cache = {}
|
11
|
+
else
|
12
|
+
@@cache = nil unless self.class.class_variable_defined? :@@cache
|
11
13
|
end
|
12
|
-
@@session_class = ::DatamapperStore::Session
|
14
|
+
@@session_class = options.delete(:session_class) || ::DatamapperStore::Session unless (self.class.class_variable_defined? :@@session_class and @@session_class)
|
13
15
|
end
|
14
16
|
|
15
17
|
private
|
@@ -32,10 +34,8 @@ module ActionController
|
|
32
34
|
@@session_class.get(sid)
|
33
35
|
end || @@session_class.new(:session_id => sid)
|
34
36
|
session.data = session_data || {}
|
35
|
-
if session.
|
36
|
-
|
37
|
-
@@cache[sid] = session if @@cache
|
38
|
-
end
|
37
|
+
session.updated_at = Time.now if session.dirty?
|
38
|
+
@@cache[sid] = session if @@cache
|
39
39
|
session.save
|
40
40
|
end
|
41
41
|
end
|
@@ -60,6 +60,7 @@ module DatamapperStore
|
|
60
60
|
def data=(data)
|
61
61
|
attribute_set(:data, ::Base64.encode64(Marshal.dump(data)))
|
62
62
|
end
|
63
|
+
|
63
64
|
def data
|
64
65
|
Marshal.load(::Base64.decode64(attribute_get(:data)))
|
65
66
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Datamapper4rails
|
2
|
+
module IdentityMaps
|
3
|
+
|
4
|
+
module Base
|
5
|
+
def self.included(base)
|
6
|
+
base.prepend_around_filter(IdentityMapFilter)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class IdentityMapFilter
|
11
|
+
|
12
|
+
def self.filter(controller)
|
13
|
+
DataMapper.repository(:default) do |*block_args|
|
14
|
+
if block_given?
|
15
|
+
yield (*block_args)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
::ActionController::Base.send(:include, Datamapper4rails::IdentityMaps::Base)
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# load all models before each request so relations in datamapper find their classes
|
2
|
+
MODELS = []
|
3
|
+
Dir[RAILS_ROOT + "/app/models/**/*.rb"].each do |model|
|
4
|
+
model.sub!(/.*models\//, '').sub!(/.rb/, '')
|
5
|
+
m = ::Extlib::Inflection.classify(model.to_s)
|
6
|
+
MODELS << m
|
7
|
+
Object.const_get(m)
|
8
|
+
end
|
9
|
+
|
10
|
+
module ModelLoader
|
11
|
+
module Base
|
12
|
+
def self.included(base)
|
13
|
+
base.prepend_before_filter(ModelLoaderFilter)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class ModelLoaderFilter
|
18
|
+
def self.filter(controller)
|
19
|
+
MODELS.each do |model|
|
20
|
+
Object.const_get(model)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
::ActionController::Base.send(:include, ModelLoader::Base)
|
@@ -11,17 +11,18 @@ module Datamapper4rails
|
|
11
11
|
end
|
12
12
|
|
13
13
|
class TransactionFilter
|
14
|
+
|
14
15
|
def self.filter(controller)
|
15
16
|
case controller.request.method
|
16
17
|
when :post, :put, :delete then
|
17
18
|
begin
|
19
|
+
# TODO remove the :default repository and make it more general
|
18
20
|
DataMapper::Transaction.new(DataMapper.repository(:default)) do |*block_args|
|
19
21
|
if block_given?
|
20
22
|
yield (*block_args)
|
21
23
|
# added rollback for all actions which just render
|
22
|
-
# a page with validation errors and do not redirect to
|
23
|
-
# page
|
24
|
-
# restful paradigma
|
24
|
+
# a page (with validation errors) and do not redirect to
|
25
|
+
# another page
|
25
26
|
unless controller.response.redirected_to
|
26
27
|
raise Datamapper4rails::RestfulTransactions::Rollback
|
27
28
|
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
$LOAD_PATH << File.dirname(__FILE__)
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'datamapper4rails/datamapper_store'
|
4
|
+
|
5
|
+
describe DatamapperStore do
|
6
|
+
|
7
|
+
before :each do
|
8
|
+
load 'lib/datamapper4rails/datamapper_store.rb'
|
9
|
+
ActionController::Session::DatamapperStore.send(:class_variable_set, :@@session_class, nil)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should initialize with no cache and default session class' do
|
13
|
+
store = ActionController::Session::DatamapperStore.new(nil)
|
14
|
+
store.class.send(:class_variable_get, :@@cache).should be_nil
|
15
|
+
store.class.send(:class_variable_get, :@@session_class).should == DatamapperStore::Session
|
16
|
+
|
17
|
+
store = ActionController::Session::DatamapperStore.new(nil, :session_class => :some_class)
|
18
|
+
store.class.send(:class_variable_get, :@@cache).should be_nil
|
19
|
+
store.class.send(:class_variable_get, :@@session_class).should == DatamapperStore::Session
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should initialize with cache and default session class' do
|
23
|
+
store = ActionController::Session::DatamapperStore.new(nil, :cache => true)
|
24
|
+
store.class.send(:class_variable_get, :@@cache).instance_of?(Hash).should be_true
|
25
|
+
|
26
|
+
store = ActionController::Session::DatamapperStore.new(nil)
|
27
|
+
store.class.send(:class_variable_get, :@@cache).instance_of?(Hash).should be_true
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should initialize with custom session class' do
|
31
|
+
store = ActionController::Session::DatamapperStore.new(nil, :session_class => Session)
|
32
|
+
store.class.send(:class_variable_get, :@@session_class).should == Session
|
33
|
+
|
34
|
+
store = ActionController::Session::DatamapperStore.new(nil, :session_class => :some_class)
|
35
|
+
store.class.send(:class_variable_get, :@@session_class).should == Session
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe 'DatamapperStore without cache' do
|
40
|
+
|
41
|
+
def mock_session(stubs={})
|
42
|
+
@mock_session ||= mock(Session, stubs)
|
43
|
+
end
|
44
|
+
|
45
|
+
before :each do
|
46
|
+
load 'lib/datamapper4rails/datamapper_store.rb'
|
47
|
+
ActionController::Session::DatamapperStore.send(:class_variable_set, :@@cache, nil)
|
48
|
+
ActionController::Session::DatamapperStore.send(:class_variable_set, :@@session_class, nil)
|
49
|
+
@store = ActionController::Session::DatamapperStore.new(nil, :session_class => Session)
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should get the session data' do
|
53
|
+
Session.stub!(:get)
|
54
|
+
@store.send(:get_session, nil, "sid").should == ["sid",{}]
|
55
|
+
Session.stub!(:get).and_return(mock_session)
|
56
|
+
mock_session.should_receive(:data).and_return({:id => "id"})
|
57
|
+
@store.send(:get_session, nil, "sid").should == ["sid",{:id => "id"}]
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'should set the session data on new session' do
|
61
|
+
Session.should_receive(:get)
|
62
|
+
Session.should_receive(:new).with(:session_id => "sid").and_return(mock_session)
|
63
|
+
mock_session.should_receive(:data=).with({})
|
64
|
+
mock_session.should_receive(:dirty?).and_return(true)
|
65
|
+
mock_session.should_receive(:updated_at=)
|
66
|
+
mock_session.should_receive(:save).and_return(true)
|
67
|
+
@store.send(:set_session, nil, "sid", {}).should == true
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'should set the session data' do
|
71
|
+
Session.should_receive(:get).and_return(mock_session)
|
72
|
+
mock_session.should_receive(:data=).with({})
|
73
|
+
mock_session.should_receive(:dirty?).and_return(true)
|
74
|
+
mock_session.should_receive(:updated_at=)
|
75
|
+
mock_session.should_receive(:save).and_return(true)
|
76
|
+
@store.send(:set_session, nil, "sid", {}).should == true
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe 'DatamapperStore with cache' do
|
81
|
+
|
82
|
+
def mock_session(stubs={})
|
83
|
+
@mock_session ||= mock(Session, stubs)
|
84
|
+
end
|
85
|
+
|
86
|
+
before :each do
|
87
|
+
load 'lib/datamapper4rails/datamapper_store.rb'
|
88
|
+
ActionController::Session::DatamapperStore.send(:class_variable_set, :@@cache, nil)
|
89
|
+
ActionController::Session::DatamapperStore.send(:class_variable_set, :@@session_class, nil)
|
90
|
+
@store = ActionController::Session::DatamapperStore.new(nil, :cache => true, :session_class => Session)
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'should get the session data from storage' do
|
94
|
+
Session.stub!(:get)
|
95
|
+
@store.send(:get_session, nil, "sid").should == ["sid",{}]
|
96
|
+
Session.stub!(:get).and_return(mock_session)
|
97
|
+
mock_session.should_receive(:data).and_return({:id => "id"})
|
98
|
+
@store.send(:get_session, nil, "sid").should == ["sid",{:id => "id"}]
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'should get the session data from cache' do
|
102
|
+
ActionController::Session::DatamapperStore.send(:class_variable_get, :@@cache)["sid"] = mock_session
|
103
|
+
mock_session.should_receive(:data).and_return({:id => "id"})
|
104
|
+
@store.send(:get_session, nil, "sid").should == ["sid",{:id => "id"}]
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'should set the session data on new session' do
|
108
|
+
Session.should_receive(:get)
|
109
|
+
Session.should_receive(:new).with(:session_id => "sid").and_return(mock_session)
|
110
|
+
mock_session.should_receive(:data=).with({})
|
111
|
+
mock_session.should_receive(:dirty?).and_return(true)
|
112
|
+
mock_session.should_receive(:updated_at=)
|
113
|
+
mock_session.should_receive(:save).and_return(true)
|
114
|
+
@store.send(:set_session, nil, "sid", {}).should == true
|
115
|
+
ActionController::Session::DatamapperStore.send(:class_variable_get, :@@cache)["sid"].should == mock_session
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'should set the session data' do
|
120
|
+
Session.should_receive(:get).and_return(mock_session)
|
121
|
+
mock_session.should_receive(:data=).with({})
|
122
|
+
mock_session.should_receive(:dirty?).and_return(false)
|
123
|
+
mock_session.should_receive(:save).and_return(true)
|
124
|
+
@store.send(:set_session, nil, "sid", {}).should == true
|
125
|
+
ActionController::Session::DatamapperStore.send(:class_variable_get, :@@cache)["sid"].should == mock_session
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,187 @@
|
|
1
|
+
$LOAD_PATH << File.dirname(__FILE__)
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'datamapper4rails/adapters/restful_adapter'
|
4
|
+
require 'slf4r/ruby_logger'
|
5
|
+
|
6
|
+
class Item
|
7
|
+
include DataMapper::Resource
|
8
|
+
|
9
|
+
property :id, Serial
|
10
|
+
property :name, String
|
11
|
+
|
12
|
+
belongs_to :container
|
13
|
+
end
|
14
|
+
class User
|
15
|
+
include DataMapper::Resource
|
16
|
+
|
17
|
+
property :id, Serial
|
18
|
+
|
19
|
+
belongs_to :container
|
20
|
+
has n, :groups, :through => Resource
|
21
|
+
end
|
22
|
+
class Group
|
23
|
+
include DataMapper::Resource
|
24
|
+
|
25
|
+
property :id, Serial
|
26
|
+
|
27
|
+
has n, :users, :through => Resource
|
28
|
+
end
|
29
|
+
|
30
|
+
class Container
|
31
|
+
include DataMapper::Resource
|
32
|
+
|
33
|
+
property :id, Serial
|
34
|
+
|
35
|
+
has 1, :user
|
36
|
+
has n, :items
|
37
|
+
end
|
38
|
+
|
39
|
+
def mock_attribute(name)
|
40
|
+
attr = Object.new
|
41
|
+
def attr.name
|
42
|
+
@name
|
43
|
+
end
|
44
|
+
def attr.name=(name)
|
45
|
+
@name = name
|
46
|
+
end
|
47
|
+
attr.name= name
|
48
|
+
attr
|
49
|
+
end
|
50
|
+
|
51
|
+
def mock_item(stubs={})
|
52
|
+
@mock_item ||= mock(Item, stubs)
|
53
|
+
end
|
54
|
+
|
55
|
+
def mock_query(stubs={})
|
56
|
+
@mock_query ||= mock(DataMapper::Query, stubs)
|
57
|
+
end
|
58
|
+
|
59
|
+
describe DataMapper::Adapters::RestfulAdapter do
|
60
|
+
|
61
|
+
before :each do
|
62
|
+
@adapter = DataMapper::Adapters::RestfulAdapter.new(:name, "uri://")
|
63
|
+
|
64
|
+
def @adapter.key_value_from_query(query)
|
65
|
+
432
|
66
|
+
end
|
67
|
+
def @adapter.resource_name_from_query(query)
|
68
|
+
"item"
|
69
|
+
end
|
70
|
+
def @adapter.http_put(uri, data)
|
71
|
+
@uri = uri
|
72
|
+
@data = data
|
73
|
+
end
|
74
|
+
def @adapter.http_delete(uri)
|
75
|
+
@uri = uri
|
76
|
+
end
|
77
|
+
def @adapter.data
|
78
|
+
@data
|
79
|
+
end
|
80
|
+
def @adapter.uri
|
81
|
+
@uri
|
82
|
+
end
|
83
|
+
def @adapter.body=(b)
|
84
|
+
@body = b
|
85
|
+
end
|
86
|
+
def @adapter.send_request
|
87
|
+
res = Object.new
|
88
|
+
def res.body=(b)
|
89
|
+
@body = b
|
90
|
+
end
|
91
|
+
def res.body
|
92
|
+
@body
|
93
|
+
end
|
94
|
+
def res.kind_of?(clazz)
|
95
|
+
true
|
96
|
+
end
|
97
|
+
res.body= @body
|
98
|
+
res
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'should create an Item' do
|
104
|
+
@adapter.body = "<item><id>123</id><name>zappa</name></item>"
|
105
|
+
|
106
|
+
item = Item.new
|
107
|
+
@adapter.create_resource(item).should == item
|
108
|
+
item.id.should == 123
|
109
|
+
item.name.should == 'zappa'
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'should update an Item' do
|
113
|
+
mock_item.should_receive(:to_query)
|
114
|
+
mock_item.should_receive(:name).and_return("item")
|
115
|
+
mock_item.should_receive(:to_xml)
|
116
|
+
|
117
|
+
@adapter.update_resource(mock_item, mock_attribute(:name) => "frank zappa")
|
118
|
+
|
119
|
+
@adapter.data.should == "<item><name>frank zappa</name></item>"
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'should update Items' do
|
123
|
+
mock_query.should_receive(:limit).and_return(1)
|
124
|
+
@adapter.update({mock_attribute(:name) => "frank zappa"}, mock_query)
|
125
|
+
|
126
|
+
@adapter.data.should == "<item><name>frank zappa</name></item>"
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'should delete an Item' do
|
130
|
+
mock_item.should_receive(:name).and_return("item")
|
131
|
+
mock_item.should_receive(:to_query)
|
132
|
+
@adapter.delete_resource(mock_item)
|
133
|
+
@adapter.uri.should == "/items/432.xml"
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'should delete Items' do
|
137
|
+
mock_query.should_receive(:limit).and_return(1)
|
138
|
+
@adapter.delete(mock_query)
|
139
|
+
|
140
|
+
@adapter.uri.should == "/items/432.xml"
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'should read an Item' do
|
144
|
+
@adapter.body = "<item><id>123</id><name>zappa</name></item>"
|
145
|
+
|
146
|
+
query = DataMapper::Query.new(Item.new.repository, Item)
|
147
|
+
item = @adapter.read_resource(query)
|
148
|
+
item.id.should == 123
|
149
|
+
item.name.should == 'zappa'
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'should read Items' do
|
153
|
+
@adapter.body = "<items type='array'><item><id>123</id><name>zappa</name></item></items>"
|
154
|
+
|
155
|
+
query = DataMapper::Query.new(Item.new.repository, Item)
|
156
|
+
items = @adapter.read_resources(query)
|
157
|
+
items.size.should == 1
|
158
|
+
items[0].id.should == 123
|
159
|
+
items[0].name.should == 'zappa'
|
160
|
+
end
|
161
|
+
#end
|
162
|
+
|
163
|
+
|
164
|
+
#describe 'associations of ' + DataMapper::Adapters::RestfulAdapter.to_s do
|
165
|
+
it 'should read nested resource (belongs_to)' do
|
166
|
+
@adapter.body = "<item><id>123</id><name>zappa</name>" +
|
167
|
+
"<container><id>342</id>" + #<items tpye='array'><item><id>1234</id><name>frank zappa</name></item></items>" +
|
168
|
+
"</container>" +
|
169
|
+
"</item>"
|
170
|
+
|
171
|
+
query = DataMapper::Query.new(Item.new.repository, Item)
|
172
|
+
item = @adapter.read_resource(query)
|
173
|
+
item.id.should == 123
|
174
|
+
item.name.should == 'zappa'
|
175
|
+
item.container.id.should == 342
|
176
|
+
end
|
177
|
+
|
178
|
+
# it 'should read nested resource (has 1)' do
|
179
|
+
# @adapter.body = "<container><id>342</id>" +
|
180
|
+
# "<user><id>543</id></user>" +
|
181
|
+
# "</container>"
|
182
|
+
|
183
|
+
# query = DataMapper::Query.new(Container.new.repository, Container)
|
184
|
+
# c = @adapter.read_resource(query)
|
185
|
+
# c.id.should == 342
|
186
|
+
# end
|
187
|
+
end
|
data/spec/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'dm-core'
|
3
|
+
$LOAD_PATH << Pathname(__FILE__).dirname.parent.expand_path + 'lib'
|
4
|
+
|
5
|
+
# just define a empty abstract store
|
6
|
+
module ActionController
|
7
|
+
module Session
|
8
|
+
class AbstractStore
|
9
|
+
def initialize(app, options = {})
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class Session
|
16
|
+
|
17
|
+
include ::DataMapper::Resource
|
18
|
+
|
19
|
+
property :session_id, String, :key => true
|
20
|
+
|
21
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: datamapper4rail
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- mkristian
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-03-
|
12
|
+
date: 2009-03-28 00:00:00 +05:30
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -64,8 +64,14 @@ files:
|
|
64
64
|
- lib/datamapper4rails/adapters/restful_adapter.rb
|
65
65
|
- lib/datamapper4rails/database_config.rb
|
66
66
|
- lib/datamapper4rails/datamapper_store.rb
|
67
|
+
- lib/datamapper4rails/identity_maps.rb
|
68
|
+
- lib/datamapper4rails/preload_models.rb
|
67
69
|
- lib/datamapper4rails/restful_transactions.rb
|
68
70
|
- lib/datamapper4rails/version.rb
|
71
|
+
- spec/datamapper_store_spec.rb
|
72
|
+
- spec/restful_adapter_spec.rb
|
73
|
+
- spec/spec.opts
|
74
|
+
- spec/spec_helper.rb
|
69
75
|
has_rdoc: true
|
70
76
|
homepage: http://datamapper4rail.rubyforge.org
|
71
77
|
post_install_message:
|