groovy 0.4.5 → 0.5.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.
- checksums.yaml +4 -4
- data/README.md +3 -0
- data/example/Gemfile.lock +1 -1
- data/example/basic.rb +15 -1
- data/example/relations.rb +1 -0
- data/lib/groovy/model.rb +34 -28
- data/lib/groovy/query.rb +45 -24
- data/lib/groovy/schema.rb +14 -14
- data/lib/groovy/vector.rb +21 -0
- data/lib/groovy/version.rb +1 -1
- data/spec/model_spec.rb +22 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 334e9f5cb0dffab38a1bcd065ba7bedd4d4382ad79cc8c572044ebb0fd6f3586
|
4
|
+
data.tar.gz: 6fae9ad07b1e8316594e320da974d5aee980deaaca717c729a260004a221d8a8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fa11b79ead949a9f3595459a5b8b7baecb48ac30769e0586627f1d9753ec991a7e2a4a3f20e8cef12bf7f474e02fa30f8b347b9a7330db26fe39462496ed12a5
|
7
|
+
data.tar.gz: 113348c59d32fcefab72dfa707ce97e6972294454b5afb84e5e9e72bfe6c26538e6236161353d915827ae9962291437ac821d59c5d81ee86276a88d8630c7306
|
data/README.md
CHANGED
data/example/Gemfile.lock
CHANGED
data/example/basic.rb
CHANGED
@@ -28,4 +28,18 @@ populate if Product.count == 0
|
|
28
28
|
|
29
29
|
# 50_000 products: 50M
|
30
30
|
# 100_000 products: 50M
|
31
|
-
# 500_000 products: 62M
|
31
|
+
# 500_000 products: 62M
|
32
|
+
|
33
|
+
module MemInfo
|
34
|
+
KERNEL_PAGE_SIZE = `getconf PAGESIZE`.chomp.to_i rescue 4096
|
35
|
+
STATM_PATH = "/proc/#{Process.pid}/statm"
|
36
|
+
STATM_FOUND = File.exist?(STATM_PATH)
|
37
|
+
def self.rss
|
38
|
+
STATM_FOUND ? (File.read(STATM_PATH).split(' ')[1].to_i * KERNEL_PAGE_SIZE) / 1024 : 0
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
puts MemInfo.rss
|
43
|
+
prices = Product.all.map { |x| x.price }
|
44
|
+
puts prices.inspect
|
45
|
+
puts MemInfo.rss
|
data/example/relations.rb
CHANGED
data/lib/groovy/model.rb
CHANGED
@@ -26,7 +26,7 @@ module Groovy
|
|
26
26
|
# end
|
27
27
|
|
28
28
|
def self.model_from_table(table_name)
|
29
|
-
Kernel.const_get(table_name.sub(/ies$/, 'y').sub(/s$/, '').
|
29
|
+
Kernel.const_get(table_name.to_s.sub(/ies$/, 'y').sub(/s$/, '').classify)
|
30
30
|
end
|
31
31
|
|
32
32
|
def self.included(base)
|
@@ -150,7 +150,6 @@ module Groovy
|
|
150
150
|
# Groonga["#{table_name}.#{name}"] # .search, .similar_search, etc
|
151
151
|
# end
|
152
152
|
|
153
|
-
|
154
153
|
def index_search(column, query, options = {}, &block)
|
155
154
|
results = table.select { |rec| rec[column].match(query) }
|
156
155
|
render_results(results, &block)
|
@@ -187,28 +186,23 @@ module Groovy
|
|
187
186
|
query
|
188
187
|
end
|
189
188
|
|
190
|
-
def first(num = 1)
|
191
|
-
arr = limit(num)
|
192
|
-
num == 1 ? arr.first : arr
|
193
|
-
end
|
194
|
-
|
195
|
-
def last(num = 1)
|
196
|
-
arr = all.sort_by(_id: :desc).limit(num)
|
197
|
-
num == 1 ? arr.first : arr
|
198
|
-
end
|
199
|
-
|
200
189
|
def query
|
201
190
|
query_class.new(self, table)
|
202
191
|
end
|
203
192
|
|
193
|
+
def scopes
|
194
|
+
@scopes ||= []
|
195
|
+
end
|
196
|
+
|
204
197
|
def scope(name, obj)
|
198
|
+
scopes.push(name)
|
205
199
|
query_class.add_scope(name, obj)
|
206
200
|
define_singleton_method(name) do |*args|
|
207
201
|
query.public_send(name, *args)
|
208
202
|
end
|
209
203
|
end
|
210
204
|
|
211
|
-
[:
|
205
|
+
[:first, :last, :select, :find_by, :search, :where, :not, :sort_by, :limit, :offset, :paginate, :in_batches].each do |scope_method|
|
212
206
|
define_method scope_method do |*args, &block|
|
213
207
|
query.public_send(scope_method, *args, &block)
|
214
208
|
end
|
@@ -293,13 +287,13 @@ module Groovy
|
|
293
287
|
end
|
294
288
|
end
|
295
289
|
|
296
|
-
attr_reader :id, :
|
290
|
+
attr_reader :id, :record, :changes
|
297
291
|
|
298
292
|
def initialize(attrs = nil, record = nil, key = nil)
|
299
293
|
@attributes, @vectors, @_key = {}, {}, key # key is used on creation only
|
300
294
|
|
301
295
|
if set_record(record)
|
302
|
-
|
296
|
+
# load_attributes_from_record(record)
|
303
297
|
else
|
304
298
|
attrs ||= {}
|
305
299
|
unless attrs.is_a?(Hash)
|
@@ -317,8 +311,13 @@ module Groovy
|
|
317
311
|
|
318
312
|
# get reference to the actual record in the Groonga table,
|
319
313
|
# not the temporary one we get as part of a search result.
|
320
|
-
def load_record
|
321
|
-
|
314
|
+
# def load_record
|
315
|
+
# self.class.table[id]
|
316
|
+
# end
|
317
|
+
|
318
|
+
def attributes
|
319
|
+
load_attributes_from_record # populate missing
|
320
|
+
@attributes
|
322
321
|
end
|
323
322
|
|
324
323
|
def inspect
|
@@ -331,7 +330,9 @@ module Groovy
|
|
331
330
|
end
|
332
331
|
|
333
332
|
def [](key)
|
334
|
-
|
333
|
+
k = key.to_sym
|
334
|
+
@attributes[k] = get_record_attribute(k) unless @attributes.key?(k)
|
335
|
+
@attributes[k]
|
335
336
|
end
|
336
337
|
|
337
338
|
def []=(key, val)
|
@@ -392,11 +393,15 @@ module Groovy
|
|
392
393
|
end
|
393
394
|
|
394
395
|
def reload
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
396
|
+
unless new_record?
|
397
|
+
# raise RecordNotPersisted if id.nil?
|
398
|
+
# ensure_persisted!
|
399
|
+
rec = self.class.table[id] # _key
|
400
|
+
set_record(rec)
|
401
|
+
# load_attributes_from_record
|
402
|
+
end
|
403
|
+
|
404
|
+
@attributes = {}
|
400
405
|
@changes = {}
|
401
406
|
self
|
402
407
|
end
|
@@ -416,6 +421,7 @@ module Groovy
|
|
416
421
|
private
|
417
422
|
|
418
423
|
def get_record_attribute(key)
|
424
|
+
return if record.nil?
|
419
425
|
val = record[key]
|
420
426
|
if self.class.schema.time_columns.include?(key)
|
421
427
|
fix_time_value(val)
|
@@ -433,15 +439,15 @@ module Groovy
|
|
433
439
|
# record.respond_to?(:_key) ? record._key : id
|
434
440
|
# end
|
435
441
|
|
436
|
-
def
|
442
|
+
def load_attributes_from_record
|
437
443
|
self.class.attribute_names.each do |col|
|
438
|
-
public_send("#{col}=", get_record_attribute(col))
|
444
|
+
public_send("#{col}=", get_record_attribute(col)) unless @attributes.key?(col)
|
439
445
|
end
|
440
446
|
end
|
441
447
|
|
442
448
|
def set_attribute(key, val)
|
443
|
-
changes[key.to_sym] = [self[key], val] if changes # nil
|
444
|
-
attributes[key.to_sym] = val
|
449
|
+
changes[key.to_sym] = [self[key], val] if changes # nil before initializing
|
450
|
+
@attributes[key.to_sym] = val
|
445
451
|
end
|
446
452
|
|
447
453
|
def get_ref(name)
|
@@ -466,7 +472,7 @@ module Groovy
|
|
466
472
|
|
467
473
|
def create
|
468
474
|
fire_callbacks(:before_create)
|
469
|
-
set_record(self.class.insert(attributes, @_key))
|
475
|
+
set_record(self.class.insert(@attributes, @_key))
|
470
476
|
fire_callbacks(:after_create)
|
471
477
|
self
|
472
478
|
end
|
data/lib/groovy/query.rb
CHANGED
@@ -3,6 +3,7 @@ module Groovy
|
|
3
3
|
class Query
|
4
4
|
|
5
5
|
include Enumerable
|
6
|
+
|
6
7
|
AND = '+'.freeze
|
7
8
|
NOT = '-'.freeze
|
8
9
|
PER_PAGE = 50.freeze
|
@@ -61,13 +62,13 @@ module Groovy
|
|
61
62
|
where(conditions).limit(1).first
|
62
63
|
end
|
63
64
|
|
64
|
-
def find_each(opts = {}, &block)
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
end
|
65
|
+
# def find_each(opts = {}, &block)
|
66
|
+
# count = 0
|
67
|
+
# in_batches({ of: 10 }.merge(opts)) do |group|
|
68
|
+
# group.each { |item| count += 1; yield(item) }
|
69
|
+
# end
|
70
|
+
# count
|
71
|
+
# end
|
71
72
|
|
72
73
|
# http://groonga.org/docs/reference/grn_expr/query_syntax.html
|
73
74
|
# TODO: support match_columns (search value in two or more columns)
|
@@ -138,12 +139,12 @@ module Groovy
|
|
138
139
|
end
|
139
140
|
|
140
141
|
def limit(num)
|
141
|
-
|
142
|
+
sorting[:limit] = num
|
142
143
|
self
|
143
144
|
end
|
144
145
|
|
145
146
|
def offset(num)
|
146
|
-
|
147
|
+
sorting[:offset] = num
|
147
148
|
self
|
148
149
|
end
|
149
150
|
|
@@ -155,8 +156,8 @@ module Groovy
|
|
155
156
|
|
156
157
|
# sort_by(title: :asc)
|
157
158
|
def sort_by(hash)
|
158
|
-
if hash.is_a?(String) || hash.is_a?(Symbol) # e.g. 'title.desc' or :title (asc by default)
|
159
|
-
param, dir = hash.to_s.split(
|
159
|
+
if hash.is_a?(String) || hash.is_a?(Symbol) # e.g. 'title.desc', 'title desc' or :title (asc by default)
|
160
|
+
param, dir = hash.to_s.split(/\s|\./)
|
160
161
|
hash = {}
|
161
162
|
hash[param] = dir || 'asc'
|
162
163
|
end
|
@@ -191,11 +192,16 @@ module Groovy
|
|
191
192
|
end
|
192
193
|
|
193
194
|
def [](index)
|
194
|
-
|
195
|
+
if r = results[index]
|
196
|
+
model.new_from_record(r)
|
197
|
+
end
|
195
198
|
end
|
196
199
|
|
197
200
|
def each(&block)
|
198
|
-
records.each { |r| block.call(r) }
|
201
|
+
# records.each { |r| block.call(r) }
|
202
|
+
results.each_with_index do |r, index|
|
203
|
+
yield model.new_from_record(r)
|
204
|
+
end
|
199
205
|
end
|
200
206
|
|
201
207
|
def update_all(attrs)
|
@@ -207,35 +213,50 @@ module Groovy
|
|
207
213
|
@total_entries
|
208
214
|
end
|
209
215
|
|
210
|
-
def
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
216
|
+
def first(num = 1)
|
217
|
+
limit(num)
|
218
|
+
num == 1 ? records.first : records
|
219
|
+
end
|
220
|
+
|
221
|
+
def last(num = 1)
|
222
|
+
if sorting[:by]
|
223
|
+
get_last(num)
|
224
|
+
else # no sorting, so
|
225
|
+
sort_by(_id: :desc).limit(num)
|
226
|
+
# if last(2) or more, then re-sort by ascending ID
|
227
|
+
num == 1 ? records.first : records.sort { |a,b| a.id <=> b.id }
|
215
228
|
end
|
216
229
|
end
|
217
230
|
|
218
231
|
def in_batches(of: 1000, from: nil, &block)
|
219
|
-
|
220
|
-
|
232
|
+
sorting[:limit] = of
|
233
|
+
sorting[:offset] = from || 0
|
221
234
|
|
222
235
|
while results.any?
|
223
236
|
yield to_a
|
224
237
|
break if results.size < of
|
225
238
|
|
226
|
-
|
239
|
+
sorting[:offset] += of
|
227
240
|
@records = @results = nil # reset
|
228
241
|
end
|
229
242
|
end
|
230
243
|
|
244
|
+
private
|
245
|
+
attr_reader :model, :table, :options, :select_block
|
246
|
+
|
231
247
|
def records
|
232
248
|
@records ||= results.map do |r|
|
233
249
|
model.new_from_record(r)
|
234
250
|
end
|
235
251
|
end
|
236
252
|
|
237
|
-
|
238
|
-
|
253
|
+
def get_last(count = 1)
|
254
|
+
if count > 1
|
255
|
+
records[(size-count)..-1]
|
256
|
+
else
|
257
|
+
records[size-1]
|
258
|
+
end
|
259
|
+
end
|
239
260
|
|
240
261
|
def add_param(param)
|
241
262
|
raise "Select block already given!" if select_block
|
@@ -265,7 +286,7 @@ module Groovy
|
|
265
286
|
|
266
287
|
@total_entries = set.size
|
267
288
|
|
268
|
-
debug "Sorting with #{sort_key_and_order}
|
289
|
+
debug "Sorting with #{sort_key_and_order} (options: #{sorting.inspect})"
|
269
290
|
set = set.sort(sort_key_and_order, {
|
270
291
|
limit: sorting[:limit],
|
271
292
|
offset: sorting[:offset], # [sorting[:offset], @total_entries].min
|
data/lib/groovy/schema.rb
CHANGED
@@ -26,6 +26,7 @@ module Groovy
|
|
26
26
|
def initialize(context, table_name, opts = {})
|
27
27
|
@context, @table_name, @opts = context, table_name, opts || {}
|
28
28
|
@spec, @index_columns = {}, []
|
29
|
+
@cache = {}
|
29
30
|
end
|
30
31
|
|
31
32
|
def table
|
@@ -33,47 +34,44 @@ module Groovy
|
|
33
34
|
end
|
34
35
|
|
35
36
|
def search_table
|
36
|
-
@search_table ||= context[SEARCH_TABLE_NAME]
|
37
|
+
@cache[:search_table] ||= context[SEARCH_TABLE_NAME]
|
37
38
|
end
|
38
39
|
|
39
40
|
def column_names
|
40
|
-
get_names
|
41
|
+
@cache[:column_names] ||= get_names(table.columns)
|
41
42
|
end
|
42
43
|
|
43
44
|
def singular_references
|
44
|
-
|
45
|
-
get_names(table.columns.select(&:reference_column?).reject(&:vector?))
|
45
|
+
@cache[:singular_references] ||= get_names(table.columns.select(&:reference_column?).reject(&:vector?))
|
46
46
|
end
|
47
47
|
|
48
48
|
def plural_references
|
49
|
-
|
50
|
-
get_names(table.columns.select(&:vector?))
|
49
|
+
@cache[:plural_references] ||= get_names(table.columns.select(&:vector?))
|
51
50
|
end
|
52
51
|
|
53
52
|
def attribute_columns
|
54
|
-
|
55
|
-
get_names(table.columns.select { |c| c.column? && !c.reference_column? && !c.vector? })
|
53
|
+
@cache[:attribute_columns] ||= get_names(table.columns.select { |c| c.column? && !c.reference_column? && !c.vector? })
|
56
54
|
end
|
57
55
|
|
58
56
|
def time_columns
|
59
|
-
columns_by_type('Time')
|
57
|
+
@cache[:time_columns] ||= columns_by_type('Time')
|
60
58
|
end
|
61
59
|
|
62
60
|
def integer_columns
|
63
|
-
columns_by_type('Int32')
|
61
|
+
@cache[:integer_columns] ||= columns_by_type('Int32')
|
64
62
|
end
|
65
63
|
|
66
64
|
def boolean_columns
|
67
|
-
columns_by_type('Bool')
|
65
|
+
@cache[:boolean_columns] ||= columns_by_type('Bool')
|
68
66
|
end
|
69
67
|
|
70
68
|
def columns_by_type(type)
|
71
69
|
get_names(table.columns.select { |c| c.column? && c.range.name == type })
|
72
70
|
end
|
73
71
|
|
74
|
-
|
75
|
-
|
76
|
-
|
72
|
+
def reload
|
73
|
+
@cache = {}
|
74
|
+
end
|
77
75
|
|
78
76
|
def rebuild!
|
79
77
|
log("Rebuilding!")
|
@@ -116,6 +114,8 @@ module Groovy
|
|
116
114
|
@index_columns.each do |col|
|
117
115
|
add_index_on(col)
|
118
116
|
end
|
117
|
+
|
118
|
+
reload
|
119
119
|
self
|
120
120
|
end
|
121
121
|
|
data/lib/groovy/vector.rb
CHANGED
@@ -74,9 +74,30 @@ module Groovy
|
|
74
74
|
|
75
75
|
alias_method :<<, :push
|
76
76
|
|
77
|
+
[:first, :last, :find_by, :search, :where, :not, :sort_by, :limit, :offset, :paginate, :in_batches].each do |scope_method|
|
78
|
+
define_method scope_method do |*args, &block|
|
79
|
+
query.public_send(scope_method, *args, &block)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
77
83
|
private
|
78
84
|
attr_reader :obj, :key
|
79
85
|
|
86
|
+
def query
|
87
|
+
model = Model.model_from_table(key.capitalize)
|
88
|
+
obj_name = obj.class.name.downcase
|
89
|
+
model.query.where(obj_name => obj.id)
|
90
|
+
end
|
91
|
+
|
92
|
+
def method_missing(name, *args, &block)
|
93
|
+
model = Model.model_from_table(key.capitalize)
|
94
|
+
if model.scopes.include?(name)
|
95
|
+
query.send(name)
|
96
|
+
else
|
97
|
+
super
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
80
101
|
def remove_record(rec)
|
81
102
|
recs = obj.record[key].delete_if { |r| r == rec }
|
82
103
|
obj.record[key] = recs
|
data/lib/groovy/version.rb
CHANGED
data/spec/model_spec.rb
CHANGED
@@ -86,6 +86,28 @@ describe Groovy::Model do
|
|
86
86
|
end
|
87
87
|
|
88
88
|
describe '#[]' do
|
89
|
+
it 'reads value from record' do
|
90
|
+
prod = TestProduct.create!(name: 'A product', price: 100)
|
91
|
+
expect(prod.name).to eq('A product')
|
92
|
+
expect(prod['name']).to eq('A product')
|
93
|
+
expect(prod[:name]).to eq('A product')
|
94
|
+
|
95
|
+
prod = TestProduct.find(prod.id)
|
96
|
+
expect(prod.name).to eq('A product')
|
97
|
+
expect(prod['name']).to eq('A product')
|
98
|
+
expect(prod[:name]).to eq('A product')
|
99
|
+
|
100
|
+
prod = TestProduct.new
|
101
|
+
expect(prod.name).to eq(nil)
|
102
|
+
prod.name = 'Another product'
|
103
|
+
expect(prod.name).to eq('Another product')
|
104
|
+
prod.reload
|
105
|
+
expect(prod.name).to eq(nil)
|
106
|
+
prod.name = 'Another product'
|
107
|
+
prod.save
|
108
|
+
prod.reload
|
109
|
+
expect(prod.name).to eq('Another product')
|
110
|
+
end
|
89
111
|
end
|
90
112
|
|
91
113
|
describe '#[]=' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: groovy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tomás Pollak
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-07-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rroonga
|