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 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