joffice_redis 0.1.1
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/.gitignore +1 -0
- data/LICENSE-2.0.txt +202 -0
- data/README.markdown +11 -0
- data/Rakefile +29 -0
- data/lib/joffice_redis.rb +35 -0
- data/lib/joffice_redis/cache_model.rb +205 -0
- data/lib/joffice_redis/hash_table.rb +73 -0
- data/lib/joffice_redis/marshal.rb +65 -0
- data/lib/joffice_redis/model_factory.rb +417 -0
- data/lib/joffice_redis/redis_client_base.rb +121 -0
- data/lib/joffice_redis/redis_manager.rb +213 -0
- data/lib/joffice_redis/redis_method_factory.rb +445 -0
- data/lib/joffice_redis/storages/presence_redis.rb +80 -0
- metadata +132 -0
@@ -0,0 +1,73 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
=begin
|
3
|
+
Copyright 2010 Denis Kokorin <[email protected]>
|
4
|
+
|
5
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
you may not use this file except in compliance with the License.
|
7
|
+
You may obtain a copy of the License at
|
8
|
+
|
9
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
|
11
|
+
Unless required by applicable law or agreed to in writing, software
|
12
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
See the License for the specific language governing permissions and
|
15
|
+
limitations under the License.
|
16
|
+
=end
|
17
|
+
|
18
|
+
|
19
|
+
module JOffice::Redis
|
20
|
+
class HashTable
|
21
|
+
attr_reader :redis
|
22
|
+
|
23
|
+
def initialize(id, redis)
|
24
|
+
@id, @redis, @_attributes=id, redis,{}
|
25
|
+
end
|
26
|
+
|
27
|
+
def [](key)
|
28
|
+
get(key)
|
29
|
+
end
|
30
|
+
|
31
|
+
def get(key)
|
32
|
+
@_attributes[key]||=((v=redis.get(hash_key(key))) ? Marshal.load(v) : v)
|
33
|
+
end
|
34
|
+
|
35
|
+
def []=(key, value)
|
36
|
+
set(key, value)
|
37
|
+
end
|
38
|
+
|
39
|
+
def set(key, value, expire=nil)
|
40
|
+
if value
|
41
|
+
@_attributes[key]=value unless expire
|
42
|
+
k=hash_key(key)
|
43
|
+
redis.set(k, Marshal.dump(value))
|
44
|
+
redis.expire(k, expire) if expire
|
45
|
+
else
|
46
|
+
redis.del(hash_key(key))
|
47
|
+
@_attributes.delete(key)
|
48
|
+
end
|
49
|
+
value
|
50
|
+
end
|
51
|
+
|
52
|
+
def hash_key(key)
|
53
|
+
"#{@id}:#{key}".force_encoding('ASCII-8BIT')
|
54
|
+
end
|
55
|
+
|
56
|
+
def exists?(key)
|
57
|
+
k=hash_key(key)
|
58
|
+
(@_attributes.has_key?(k) || redis.exists?(k))
|
59
|
+
end
|
60
|
+
|
61
|
+
def delete(key)
|
62
|
+
redis.del(hash_key(key))
|
63
|
+
@_attributes.delete(key)
|
64
|
+
end
|
65
|
+
|
66
|
+
class << self
|
67
|
+
def keys(id, redis)
|
68
|
+
(r=redis.keys("#{id}:*")) ? r : []
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
=begin
|
3
|
+
Copyright 2010 Denis Kokorin <[email protected]>
|
4
|
+
|
5
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
you may not use this file except in compliance with the License.
|
7
|
+
You may obtain a copy of the License at
|
8
|
+
|
9
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
|
11
|
+
Unless required by applicable law or agreed to in writing, software
|
12
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
See the License for the specific language governing permissions and
|
15
|
+
limitations under the License.
|
16
|
+
=end
|
17
|
+
|
18
|
+
|
19
|
+
require 'msgpack'
|
20
|
+
|
21
|
+
module JOffice::Redis
|
22
|
+
module MarshalValue
|
23
|
+
|
24
|
+
def unbox_object(value)
|
25
|
+
value.blank? ? value : Marshal.load(value)
|
26
|
+
end
|
27
|
+
module_function :unbox_object
|
28
|
+
|
29
|
+
def box_object(value)
|
30
|
+
value.blank? ? value : Marshal.dump(value)
|
31
|
+
end
|
32
|
+
module_function :box_object
|
33
|
+
|
34
|
+
def unbox_string(value)
|
35
|
+
value.blank? ? '' : MessagePack.unpack(value).encode2utf8
|
36
|
+
end
|
37
|
+
module_function :unbox_string
|
38
|
+
|
39
|
+
def box_string(value)
|
40
|
+
(value || '').to_s.to_msgpack
|
41
|
+
end
|
42
|
+
module_function :box_string
|
43
|
+
|
44
|
+
def unbox_integer(value)
|
45
|
+
value.to_i
|
46
|
+
end
|
47
|
+
module_function :unbox_integer
|
48
|
+
|
49
|
+
def box_integer(value)
|
50
|
+
value ? value.to_s : '0'
|
51
|
+
end
|
52
|
+
module_function :box_integer
|
53
|
+
|
54
|
+
def unbox_boolean(value)
|
55
|
+
'1' == value
|
56
|
+
end
|
57
|
+
module_function :unbox_boolean
|
58
|
+
|
59
|
+
def box_boolean(value)
|
60
|
+
value ? '1' : '0'
|
61
|
+
end
|
62
|
+
module_function :box_boolean
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,417 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
=begin
|
3
|
+
Copyright 2010 Denis Kokorin <[email protected]>
|
4
|
+
|
5
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
you may not use this file except in compliance with the License.
|
7
|
+
You may obtain a copy of the License at
|
8
|
+
|
9
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
|
11
|
+
Unless required by applicable law or agreed to in writing, software
|
12
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
See the License for the specific language governing permissions and
|
15
|
+
limitations under the License.
|
16
|
+
=end
|
17
|
+
|
18
|
+
|
19
|
+
require 'fileutils'
|
20
|
+
require 'digest/sha1'
|
21
|
+
|
22
|
+
module JOffice::Redis
|
23
|
+
class ModelFactory
|
24
|
+
attr_reader :parent
|
25
|
+
attr_reader :attributes
|
26
|
+
attr_reader :attributes_hash
|
27
|
+
attr_reader :attribute_lists
|
28
|
+
attr_reader :unique_indexes
|
29
|
+
attr_accessor :prefix
|
30
|
+
attr_reader :logger
|
31
|
+
attr_reader :class_module_name
|
32
|
+
attr_reader :instance_module_name
|
33
|
+
|
34
|
+
def initialize(parent, logger)
|
35
|
+
@parent=parent
|
36
|
+
@logger=logger
|
37
|
+
@consts=[]
|
38
|
+
@static_methods=[]
|
39
|
+
@instance_methods=[]
|
40
|
+
@indexes={}
|
41
|
+
@composite_indexes={}
|
42
|
+
@static_alias=[]
|
43
|
+
@index_by_field={}
|
44
|
+
@attributes,@attributes_hash,@attribute_lists,@unique_indexes = {},{},{},{}
|
45
|
+
|
46
|
+
yield self if block_given?
|
47
|
+
|
48
|
+
#@class_name="CS#{Digest::SHA1.hexdigest(parent.name)}"
|
49
|
+
@class_name="CS#{class_table}_#{prefix}"
|
50
|
+
@class_module_name="JOffice::Redis::Metadata::#{@class_name}::ClassMethods"
|
51
|
+
@instance_module_name="JOffice::Redis::Metadata::#{@class_name}::InstanceMethods"
|
52
|
+
|
53
|
+
generate
|
54
|
+
|
55
|
+
|
56
|
+
#@buffer=["", "", "module JOffice::Redis","module Metadata","# Metadata for class #{parent.name}", "module #{@class_name}"]
|
57
|
+
#@buffer << "module ClassMethods"
|
58
|
+
@buffer = ["class << self"]
|
59
|
+
@buffer << "include JOffice::Redis::MarshalValue"
|
60
|
+
@buffer+=@consts
|
61
|
+
@buffer << ""
|
62
|
+
@buffer+=@static_methods.map{|v| " #{v}"}
|
63
|
+
@buffer<< @static_alias.join("\n")
|
64
|
+
@buffer << "end"
|
65
|
+
|
66
|
+
#@buffer << "module InstanceMethods"
|
67
|
+
@buffer << ""
|
68
|
+
@buffer+=@instance_methods.map{|v| " #{v}"}
|
69
|
+
@buffer << ""
|
70
|
+
#@buffer << "end"
|
71
|
+
#@buffer << "#{parent.name}.send(:include, InstanceMethods)"
|
72
|
+
####@buffer << "#{parent.name}.send(:extend, JOffice::Redis::CacheModelClassMethods)"
|
73
|
+
#@buffer << "#{parent.name}.send(:extend, ClassMethods)"
|
74
|
+
#@buffer+=["end","end","end"]
|
75
|
+
parent.class_eval @buffer.join("\n")
|
76
|
+
#save_and_include
|
77
|
+
end
|
78
|
+
|
79
|
+
def save_and_include
|
80
|
+
dir=File.join(File.absolute_path(File.dirname(__FILE__)),'metadata')
|
81
|
+
FileUtils.mkdir_p(dir)
|
82
|
+
|
83
|
+
path=File.join(dir, "#{@class_name}.rb")
|
84
|
+
f=File.open(path,'w')
|
85
|
+
f.write(@buffer.join("\n"))
|
86
|
+
f.close
|
87
|
+
#require path
|
88
|
+
end
|
89
|
+
|
90
|
+
def attribute(name, options={})
|
91
|
+
unique=options[:unique]
|
92
|
+
key_name=(options[:key_name] || name)
|
93
|
+
attributes[name.to_sym]=[options[:type] || :object, unique, key_name]
|
94
|
+
unique_indexes[name]=key_name if unique
|
95
|
+
end
|
96
|
+
|
97
|
+
def attribute_list(name, options={})
|
98
|
+
attribute_lists[name]=options
|
99
|
+
end
|
100
|
+
|
101
|
+
def hash(name, options={})
|
102
|
+
attributes_hash[name]=options
|
103
|
+
end
|
104
|
+
|
105
|
+
def index(name, field)
|
106
|
+
(@indexes[name]||=[]) << field
|
107
|
+
@index_by_field[field]=name
|
108
|
+
end
|
109
|
+
|
110
|
+
def composite_index(name, *fields)
|
111
|
+
options=fields.extract_options!
|
112
|
+
@composite_indexes[name]=[fields.flatten, options]
|
113
|
+
end
|
114
|
+
|
115
|
+
def set_table_name(name)
|
116
|
+
@class_table=name
|
117
|
+
end
|
118
|
+
|
119
|
+
private
|
120
|
+
def generate_unbox_value(value_name, type)
|
121
|
+
case type
|
122
|
+
when :boolean then "('1'==#{value_name})"
|
123
|
+
when :integer then "#{value_name}.to_i"
|
124
|
+
when :string then "JOffice::Redis::MarshalValue.unbox_string(#{value_name})"
|
125
|
+
else "JOffice::Redis::MarshalValue.unbox_object(#{value_name})"
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def const(name, value)
|
130
|
+
@consts << "#{name}=#{value}"
|
131
|
+
end
|
132
|
+
|
133
|
+
def method(name, args=nil, static=false, log=true, block=false)
|
134
|
+
buf=[]
|
135
|
+
buf << ("JOffice::Redis::CacheModel.logger.info('Redis[#{class_table}]'){'#{name}('+[#{args}].flatten.inspect+')'}") if logger && log
|
136
|
+
yield buf
|
137
|
+
args="#{args}, &block" if block
|
138
|
+
buf=buf.map{|v| " #{v}"}.join("\n")
|
139
|
+
signature=(args ? "#{name}(#{args})" : name)
|
140
|
+
buf=["def #{signature}\n#{buf}","end"]
|
141
|
+
buf << "public :#{name}" if static
|
142
|
+
static ? (@static_methods << buf.join("\n")) : (@instance_methods << buf.join("\n"))
|
143
|
+
end
|
144
|
+
|
145
|
+
def class_table
|
146
|
+
@class_table||[email protected]
|
147
|
+
end
|
148
|
+
|
149
|
+
def key_id_set
|
150
|
+
":'"+((prefix ? "#{prefix}::" : '') +"id").gsub(/ /,'%20')+"'"
|
151
|
+
end
|
152
|
+
|
153
|
+
def define_db
|
154
|
+
method('db', nil, true, false) do |m|
|
155
|
+
m << "@@db||=JOffice::RedisManager.instance.open_db_em('#{class_table}')"
|
156
|
+
end
|
157
|
+
|
158
|
+
method('db=', 'value', true, false) do |m|
|
159
|
+
m << "@@db=value"
|
160
|
+
end
|
161
|
+
|
162
|
+
method('db', nil, false, false) do |m|
|
163
|
+
m << "self.class.db"
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def generate_key
|
168
|
+
const("ALL_MODEL_ATTRIBUTES_KEYS",attributes.keys.inspect)
|
169
|
+
const("PREFIX", ":'#{prefix}'") unless prefix.blank?
|
170
|
+
|
171
|
+
method('all_attributes',nil, true, false) do |m|
|
172
|
+
m << "#{@class_module_name}::ALL_MODEL_ATTRIBUTES_KEYS"
|
173
|
+
end
|
174
|
+
|
175
|
+
method('all_attributes', nil, false, false) do |m|
|
176
|
+
m << "#{@class_module_name}::ALL_MODEL_ATTRIBUTES_KEYS"
|
177
|
+
end
|
178
|
+
|
179
|
+
method('key_id_set',nil, true, false) do |m|
|
180
|
+
m << ":'"+(prefix ? "#{prefix}::" : '') +"id'"
|
181
|
+
end
|
182
|
+
|
183
|
+
method('prefix',nil, true, false) do |m|
|
184
|
+
m << 'PREFIX'
|
185
|
+
end unless prefix.blank?
|
186
|
+
|
187
|
+
method('prefix', nil, false, false) do |m|
|
188
|
+
m << 'PREFIX'
|
189
|
+
end if prefix && !prefix.empty?
|
190
|
+
|
191
|
+
method('key','*args', true, false) do |m|
|
192
|
+
m << "args.#{prefix ? 'unshift(prefix).' : ''}join(':').gsub(/ /,'%20').force_encoding('ASCII-8BIT')"
|
193
|
+
end
|
194
|
+
|
195
|
+
method('keys_cache', nil, false, false) do |m|
|
196
|
+
m << "@keys_cache||={}"
|
197
|
+
end
|
198
|
+
|
199
|
+
method('key','*args', false, false) do |m|
|
200
|
+
if prefix
|
201
|
+
s='([prefix, id]+args)'
|
202
|
+
else
|
203
|
+
s='args.unshift(id)'
|
204
|
+
end
|
205
|
+
m << s+".join(':').gsub(/ /,'%20').force_encoding('ASCII-8BIT')"
|
206
|
+
end
|
207
|
+
|
208
|
+
if prefix
|
209
|
+
build_key_by_id_name='"'+prefix+':#{id}:#{name}"'
|
210
|
+
else
|
211
|
+
build_key_by_id_name='"#{id}:#{name}"'
|
212
|
+
end
|
213
|
+
build_key_by_id_name+=".gsub(/ /,'%20').force_encoding('ASCII-8BIT')"
|
214
|
+
|
215
|
+
method "key_name", "id, name", true, false do |m|
|
216
|
+
m << build_key_by_id_name
|
217
|
+
end
|
218
|
+
|
219
|
+
method "key_name", "name", false do |m|
|
220
|
+
m << "keys_cache[name]||=" + build_key_by_id_name
|
221
|
+
end
|
222
|
+
|
223
|
+
method "key2id", "key", true, false do |m|
|
224
|
+
m << (prefix ? "key[#{prefix.length+1}..key.length] if key" : "key")
|
225
|
+
end
|
226
|
+
|
227
|
+
end
|
228
|
+
|
229
|
+
def generate_attributes
|
230
|
+
attributes.each do |name, options|
|
231
|
+
unique_key_name=options[2]
|
232
|
+
|
233
|
+
method name do |m|
|
234
|
+
m << "@#{name}||="+generate_unbox_value("db.get(key_name(:#{name}))", options[0])
|
235
|
+
end
|
236
|
+
|
237
|
+
method "#{name}=","value" do |m|
|
238
|
+
m << "db.set(key_name(:#{name}),JOffice::Redis::MarshalValue.box_#{options[0]}(@#{name}=value))"
|
239
|
+
m << "db.set(self.class.key_name(:#{unique_key_name},value), id)" if options[1]
|
240
|
+
m << "db.set_add(self.class.key_name(:#{@index_by_field[name]}, value), id)" if @index_by_field.has_key?(name)
|
241
|
+
end
|
242
|
+
|
243
|
+
@static_alias << "alias :unbox_value_#{name} :unbox_#{options[0]}"
|
244
|
+
|
245
|
+
if options[1]
|
246
|
+
method "find_by_#{unique_key_name}","value, select=[]", true do |m|
|
247
|
+
m << "id=db.get(key_name(:#{unique_key_name}, value))"
|
248
|
+
if unique_key_name==name
|
249
|
+
m << "id ? new(:id=>id, :#{name}=>value).ensure_attributes(select) : nil"
|
250
|
+
else
|
251
|
+
m << "id ? new(:id=>id).ensure_attributes(select) : nil"
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
if @index_by_field.has_key?(name)
|
257
|
+
index_name=@index_by_field[name]
|
258
|
+
method "find_all_by_#{index_name}", "value, select=[]", true do |m|
|
259
|
+
m << "ids=db.set_members(key_name(:#{index_name}, value))"
|
260
|
+
m << "ids ? load_by_ids(ids, select) : []"
|
261
|
+
end
|
262
|
+
|
263
|
+
method "find_all_id_by_#{name}", "value", true do |m|
|
264
|
+
m << "db.set_members(key_name(:#{index_name}, value))"
|
265
|
+
end
|
266
|
+
|
267
|
+
method "count_by_#{name}", "value", true do |m|
|
268
|
+
m << "db.scard(key_name(:#{index_name}, value))"
|
269
|
+
end
|
270
|
+
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
def generate_hash_attributes
|
276
|
+
attributes_hash.each do |name, options|
|
277
|
+
method name do |m|
|
278
|
+
m << "@#{name}||=JOffice::Redis::HashTable.new(key_name(:'#{name}'), db)"
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
def generate_save_composite_index
|
284
|
+
method "save_composite_index" do |m|
|
285
|
+
@composite_indexes.each do |index_name, d|
|
286
|
+
fields,options=*d
|
287
|
+
if options[:unique]
|
288
|
+
m << "db.set(self.class.key(:#{index_name}, #{fields.join(',')}), id)"
|
289
|
+
else
|
290
|
+
m << "db.set_add(self.class.key(:#{index_name}, #{fields.join(',')}), id)"
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
@composite_indexes.each do |index_name, d|
|
296
|
+
fields,options=*d
|
297
|
+
fields_map=fields.map{|v| ":#{v}=>#{v}"}.join(',')
|
298
|
+
fields_sym_array=":#{fields.join(',:')}"
|
299
|
+
if options[:unique]
|
300
|
+
method "find_by_#{fields.join('_and_')}","#{fields.join(',')}, select=[]", true do |m|
|
301
|
+
m << "id=db.get(key(:#{index_name}, #{fields.join(',')}))"
|
302
|
+
m << "select=select.map{|v| v.to_sym}-[#{fields_sym_array}] if select && !select.empty?"
|
303
|
+
m << "id ? new({:id=>id, #{fields_map}}).ensure_attributes(select) : nil"
|
304
|
+
end
|
305
|
+
|
306
|
+
method "exists_by_#{fields.join('_and_')}?", fields.join(','), true do |m|
|
307
|
+
m << "db.exists(key(:#{index_name}, #{fields.join(',')}))"
|
308
|
+
end
|
309
|
+
else
|
310
|
+
method "find_all_by_#{fields.join('_and_')}", "#{fields.join(',')}, select=[]", true, true, true do |m|
|
311
|
+
m << "find_by_batch_set(key(:#{index_name}, #{fields.join(',')}), {:select=>select,:default=>{#{fields_map}}}, &block)"
|
312
|
+
end
|
313
|
+
|
314
|
+
method "exists_by_#{fields.join('_and_')}?", fields.join(','), true do |m|
|
315
|
+
m << "db.exists(key(:#{index_name}, #{fields.join(',')}))"
|
316
|
+
end
|
317
|
+
|
318
|
+
method "count_by_#{fields.join('_and_')}", fields.join(','), true do |m|
|
319
|
+
m << "db.scard(key(:#{index_name}, #{fields.join(',')}))"
|
320
|
+
end
|
321
|
+
end
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
def generate_clone_method
|
326
|
+
method "clone", "v, id=nil", true do |m|
|
327
|
+
m << "item=new(:id=>(id ? id : v.id))"
|
328
|
+
m << "db.bulk_set do"
|
329
|
+
attributes.each do |name, options|
|
330
|
+
m << "item.#{name}=v.#{name}"
|
331
|
+
end
|
332
|
+
m << ""
|
333
|
+
m << "item.save_custom" if parent.instance_methods.index('save_custom')
|
334
|
+
m << "item.save"
|
335
|
+
m << "db.set_add(#{key_id_set}, item.id)"
|
336
|
+
m << "end"
|
337
|
+
m << "item"
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
def generate_exists
|
342
|
+
|
343
|
+
method 'exists?','id', true do |m|
|
344
|
+
m << "db.sismember(#{key_id_set}, id) if id"
|
345
|
+
end
|
346
|
+
|
347
|
+
method "exists?" do |m|
|
348
|
+
m << "self.class.exists?(id)"
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
def generate_delete_method
|
353
|
+
|
354
|
+
method "delete" do |m|
|
355
|
+
m << "return unless exists?"
|
356
|
+
m << "key_to_delete=#{@class_module_name}::ALL_MODEL_ATTRIBUTES_KEYS.map{|name| key_name( name) }"
|
357
|
+
keys_to_ensure=[]
|
358
|
+
[email protected] if @indexes.size>0
|
359
|
+
keys_to_ensure+=@composite_indexes.values.map{|v| v[0]} if @composite_indexes.size>0
|
360
|
+
m << "ensure_attributes(#{keys_to_ensure.flatten.uniq.map{|v| v.to_sym}.inspect})" unless keys_to_ensure.empty?
|
361
|
+
|
362
|
+
@composite_indexes.each do |index_name, d|
|
363
|
+
fields,options=*d
|
364
|
+
if options[:unique]
|
365
|
+
m << "key_to_delete << self.class.key(:#{index_name}, #{fields.join(',')})"
|
366
|
+
else
|
367
|
+
m << "db.set_remove_if_empty(self.class.key(:#{index_name}, #{fields.join(',')}), id)"
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
if unique_indexes.size>0
|
372
|
+
unique_indexes.each do |name, index|
|
373
|
+
m << "key_to_delete << self.class.key_name(:#{index}, #{name})"
|
374
|
+
end
|
375
|
+
end
|
376
|
+
if attributes_hash.size>0
|
377
|
+
m << "key_to_delete+=(db.keys(key_name('*')) || [])"
|
378
|
+
end
|
379
|
+
m << "key_to_delete+=delete_custom" if parent.instance_methods.index('delete_custom')
|
380
|
+
|
381
|
+
@indexes.each do |index, fields|
|
382
|
+
fields.each do |field|
|
383
|
+
m << "db.set_remove_if_empty(self.class.key_name(:#{index}, #{field}), id)"
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
387
|
+
m << "db.del(key_to_delete)"
|
388
|
+
m << "db.set_remove(#{key_id_set}, id)"
|
389
|
+
end
|
390
|
+
|
391
|
+
method "delete", nil, true do |m|
|
392
|
+
m << "new(:id=>id).delete"
|
393
|
+
end
|
394
|
+
|
395
|
+
end
|
396
|
+
|
397
|
+
def generate_save
|
398
|
+
generate_save_composite_index
|
399
|
+
|
400
|
+
method "save" do |m|
|
401
|
+
#m << "db.set_add(#{key_id_set}, id)"
|
402
|
+
m << "save_composite_index" if @composite_indexes.size>0
|
403
|
+
end
|
404
|
+
end
|
405
|
+
|
406
|
+
def generate
|
407
|
+
define_db
|
408
|
+
generate_key
|
409
|
+
generate_exists
|
410
|
+
generate_attributes
|
411
|
+
generate_hash_attributes
|
412
|
+
generate_clone_method
|
413
|
+
generate_delete_method
|
414
|
+
generate_save
|
415
|
+
end
|
416
|
+
end
|
417
|
+
end
|