groovy 0.4.5 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f2e7655a8fefa2f17295105acb6ba387f275eb158c0babed04675d566f736766
4
- data.tar.gz: 5a9b94a767f58b033a11044d3b7992911a6cde0ad068955c76d85bdd2c0464b9
3
+ metadata.gz: 334e9f5cb0dffab38a1bcd065ba7bedd4d4382ad79cc8c572044ebb0fd6f3586
4
+ data.tar.gz: 6fae9ad07b1e8316594e320da974d5aee980deaaca717c729a260004a221d8a8
5
5
  SHA512:
6
- metadata.gz: 2c8813e0920559c6422f8129ca40e51c42a6db26efc65c9f2d9a1d47d8f5f6d5638f9677f970a38d36a180c93cf610b99b7adc372579eaff92ae4d8bd9aa41ae
7
- data.tar.gz: d12ed329507b8a5c191308e198a5434f8226fd24bf4f25c8b2b8d64a832c05df39ff9946dddd53b7da5df11c2d14bc9ab97e4dcf84d67e60c9c2811d0c0122b6
6
+ metadata.gz: fa11b79ead949a9f3595459a5b8b7baecb48ac30769e0586627f1d9753ec991a7e2a4a3f20e8cef12bf7f474e02fa30f8b347b9a7330db26fe39462496ed12a5
7
+ data.tar.gz: 113348c59d32fcefab72dfa707ce97e6972294454b5afb84e5e9e72bfe6c26538e6236161353d915827ae9962291437ac821d59c5d81ee86276a88d8630c7306
data/README.md CHANGED
@@ -2,4 +2,7 @@
2
2
 
3
3
  An ORM for Groonga.
4
4
 
5
+ # TODO:
6
+
7
+ - [ ] Allow using scopes/queries through Vector class.
5
8
 
data/example/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- groovy (0.4.3)
4
+ groovy (0.4.6)
5
5
  rroonga (= 9.0.3)
6
6
 
7
7
  GEM
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
@@ -21,6 +21,7 @@ class Category
21
21
 
22
22
  schema do |t|
23
23
  t.string :name
24
+ t.reference :place, "Places"
24
25
  t.timestamps
25
26
  end
26
27
 
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$/, '').capitalize)
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
- [:select, :find_each, :find_by, :search, :where, :not, :sort_by, :limit, :offset, :paginate, :in_batches].each do |scope_method|
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, :attributes, :record, :changes
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
- set_attributes_from_record(record)
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
- self.class.table[id]
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
- attributes[key.to_sym]
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
- raise RecordNotPersisted if id.nil?
396
- ensure_persisted!
397
- rec = self.class.table[id] # _key
398
- # set_record(rec)
399
- set_attributes_from_record(rec)
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 set_attributes_from_record(rec)
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 when initializing
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
- count = 0
66
- in_batches({ of: 10 }.merge(opts)) do |group|
67
- group.each { |item| count += 1; yield(item) }
68
- end
69
- count
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
- @sorting[:limit] = num
142
+ sorting[:limit] = num
142
143
  self
143
144
  end
144
145
 
145
146
  def offset(num)
146
- @sorting[:offset] = num
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
- records[index]
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 last(count = 1)
211
- if count > 1
212
- records[(size-count)..-1]
213
- else
214
- records[size-1]
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
- @sorting[:limit] = of
220
- @sorting[:offset] = from || 0
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
- @sorting[:offset] += of
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
- private
238
- attr_reader :model, :table, :options, :select_block
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}, #{sorting.inspect}"
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 table.columns
41
+ @cache[:column_names] ||= get_names(table.columns)
41
42
  end
42
43
 
43
44
  def singular_references
44
- # @singular_references ||=
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
- # @plural_references ||=
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
- # @attribute_columns ||=
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
- # def time_column?(name)
75
- # time_columns.include?(name)
76
- # end
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
@@ -1,3 +1,3 @@
1
1
  module Groovy
2
- VERSION = '0.4.5'.freeze
2
+ VERSION = '0.5.0'.freeze
3
3
  end
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.5
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: 2020-10-13 00:00:00.000000000 Z
11
+ date: 2022-07-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rroonga