groovy 0.4.1 → 0.4.6
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/lib/groovy.rb +8 -0
- data/lib/groovy/model.rb +17 -15
- data/lib/groovy/query.rb +47 -20
- data/lib/groovy/schema.rb +15 -4
- data/lib/groovy/version.rb +1 -1
- data/spec/model_spec.rb +9 -1
- data/spec/query_spec.rb +13 -1
- 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: 2569117dfa3663d6c60ed950be2972c58116e7eaf6d21f5c6640cb91642fee4f
|
4
|
+
data.tar.gz: 33e1651825dd626dab979e9c504d5de1b7d8162363d42cbeca43873e370cad04
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 66b311fe79a3f9c8467ddbe9f863a2fd731b9c7dd9df2dbeb49fc1b8d62f4b7b506b2e0ca1f05c6ad7766ede89df0a26cb4a8eae8f96097ff613ab17cadde593
|
7
|
+
data.tar.gz: c1dbb4f84dfdb79d870a0e498acbc63d7e1268f5cfd1f0951fd16cc7d890b68a6d3679e903eb703b8de4a44b6765070594df0eb53b8cfbeb7ac9fb1499f5dd3f
|
data/lib/groovy.rb
CHANGED
@@ -1,6 +1,14 @@
|
|
1
1
|
require 'groonga'
|
2
2
|
require File.expand_path(File.dirname(__FILE__)) + '/groovy/model'
|
3
3
|
|
4
|
+
# overwrite Groonga::Record#inspect because the #attributes part is
|
5
|
+
# making debugging take ages
|
6
|
+
class Groonga::Record
|
7
|
+
def inspect
|
8
|
+
super
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
4
12
|
module Groovy
|
5
13
|
|
6
14
|
class Error < StandardError; end
|
data/lib/groovy/model.rb
CHANGED
@@ -187,16 +187,6 @@ module Groovy
|
|
187
187
|
query
|
188
188
|
end
|
189
189
|
|
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
190
|
def query
|
201
191
|
query_class.new(self, table)
|
202
192
|
end
|
@@ -208,7 +198,7 @@ module Groovy
|
|
208
198
|
end
|
209
199
|
end
|
210
200
|
|
211
|
-
[:find_each, :find_by, :search, :where, :not, :sort_by, :limit, :offset, :paginate, :in_batches].each do |scope_method|
|
201
|
+
[:first, :last, :select, :find_each, :find_by, :search, :where, :not, :sort_by, :limit, :offset, :paginate, :in_batches].each do |scope_method|
|
212
202
|
define_method scope_method do |*args, &block|
|
213
203
|
query.public_send(scope_method, *args, &block)
|
214
204
|
end
|
@@ -221,6 +211,12 @@ module Groovy
|
|
221
211
|
set_timestamp(attributes, :created_at)
|
222
212
|
set_timestamp(attributes, :updated_at)
|
223
213
|
|
214
|
+
# remove nil attributes for integer columns, otherwise
|
215
|
+
# we get a TypeError (no implicit conversion from nil to integer)
|
216
|
+
attributes.each do |k, v|
|
217
|
+
attributes.delete(k) if v.nil? # && schema.integer_columns.include?(k)
|
218
|
+
end
|
219
|
+
|
224
220
|
if table.support_key?
|
225
221
|
raise "Key required" if key.nil?
|
226
222
|
table.add(key, attributes)
|
@@ -297,7 +293,7 @@ module Groovy
|
|
297
293
|
else
|
298
294
|
attrs ||= {}
|
299
295
|
unless attrs.is_a?(Hash)
|
300
|
-
raise ArgumentError.new("Attributes should be a Hash")
|
296
|
+
raise ArgumentError.new("Attributes should be a Hash, not a #{attrs.class}")
|
301
297
|
end
|
302
298
|
|
303
299
|
# don't call set_attributes since we don't want to call
|
@@ -309,6 +305,12 @@ module Groovy
|
|
309
305
|
@changes = {}
|
310
306
|
end
|
311
307
|
|
308
|
+
# get reference to the actual record in the Groonga table,
|
309
|
+
# not the temporary one we get as part of a search result.
|
310
|
+
def load_record
|
311
|
+
self.class.table[id]
|
312
|
+
end
|
313
|
+
|
312
314
|
def inspect
|
313
315
|
"#<#{self.class.name} id:#{id.inspect} attributes:[#{self.class.attribute_names.join(', ')}]>"
|
314
316
|
end
|
@@ -394,18 +396,18 @@ module Groovy
|
|
394
396
|
end
|
395
397
|
|
396
398
|
def ==(other)
|
397
|
-
self.id == other.id
|
399
|
+
self.class == other.class && self.id == other.id
|
398
400
|
end
|
399
401
|
|
400
402
|
def <=>(other)
|
401
|
-
self.id <=> other.id
|
403
|
+
self.class == other.class && self.id <=> other.id
|
402
404
|
end
|
403
405
|
|
404
406
|
private
|
405
407
|
|
406
408
|
def get_record_attribute(key)
|
407
409
|
val = record[key]
|
408
|
-
if self.class.schema.
|
410
|
+
if self.class.schema.time_columns.include?(key)
|
409
411
|
fix_time_value(val)
|
410
412
|
else
|
411
413
|
val
|
data/lib/groovy/query.rb
CHANGED
@@ -3,9 +3,11 @@ 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
|
10
|
+
# ESCAPE_CHARS_REGEX = /([\(\)\/\\])/.freeze
|
9
11
|
VALID_QUERY_CHARS = 'a-zA-Z0-9_\.,&-'.freeze
|
10
12
|
REMOVE_INVALID_CHARS_REGEX = Regexp.new('[^\s' + VALID_QUERY_CHARS + ']').freeze
|
11
13
|
|
@@ -47,6 +49,11 @@ module Groovy
|
|
47
49
|
self
|
48
50
|
end
|
49
51
|
|
52
|
+
def select(&block)
|
53
|
+
@select_block = block
|
54
|
+
self
|
55
|
+
end
|
56
|
+
|
50
57
|
def find(id)
|
51
58
|
find_by(_id: id)
|
52
59
|
end
|
@@ -76,7 +83,7 @@ module Groovy
|
|
76
83
|
add_param(AND + [key, val.max].join(':<=')) if val.max # gte
|
77
84
|
|
78
85
|
elsif val.is_a?(Regexp)
|
79
|
-
str = val.source.gsub(REMOVE_INVALID_CHARS_REGEX, '')
|
86
|
+
str = val.source.gsub('/', '_slash_').gsub('(', '_openp_').gsub(')', '_closep_').gsub(REMOVE_INVALID_CHARS_REGEX, '')
|
80
87
|
param = val.source[0] == '^' ? ':^' : val.source[-1] == '$' ? ':$' : ':~' # starts with or regexp
|
81
88
|
add_param(AND + [key, str.downcase].join(param)) # regex must be downcase
|
82
89
|
|
@@ -110,7 +117,7 @@ module Groovy
|
|
110
117
|
add_param(AND + [key, val.max].join(':>=')) if val.max # lte, nil if range.max is -1
|
111
118
|
|
112
119
|
elsif val.is_a?(Regexp)
|
113
|
-
str = val.source.gsub(REMOVE_INVALID_CHARS_REGEX, '')
|
120
|
+
str = val.source.gsub('/', '_slash_').gsub('(', '_openp_').gsub(')', '_closep_').gsub(REMOVE_INVALID_CHARS_REGEX, '')
|
114
121
|
param = val.source[0] == '^' ? ':^' : val.source[-1] == '$' ? ':$' : ':~' # starts with or regexp
|
115
122
|
add_param(NOT + [key, str.downcase].join(param)) # regex must be downcase
|
116
123
|
|
@@ -132,25 +139,25 @@ module Groovy
|
|
132
139
|
end
|
133
140
|
|
134
141
|
def limit(num)
|
135
|
-
|
142
|
+
sorting[:limit] = num
|
136
143
|
self
|
137
144
|
end
|
138
145
|
|
139
146
|
def offset(num)
|
140
|
-
|
147
|
+
sorting[:offset] = num
|
141
148
|
self
|
142
149
|
end
|
143
150
|
|
144
|
-
def paginate(page = 1)
|
151
|
+
def paginate(page = 1, per_page: PER_PAGE)
|
145
152
|
page = 1 if page.to_i < 1
|
146
|
-
offset = ((page.to_i)-1) *
|
147
|
-
offset(offset).limit(
|
153
|
+
offset = ((page.to_i)-1) * per_page
|
154
|
+
offset(offset).limit(per_page) # returns self
|
148
155
|
end
|
149
156
|
|
150
157
|
# sort_by(title: :asc)
|
151
158
|
def sort_by(hash)
|
152
|
-
if hash.is_a?(String) || hash.is_a?(Symbol) # e.g. 'title.desc' or :title (asc by default)
|
153
|
-
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|\./)
|
154
161
|
hash = {}
|
155
162
|
hash[param] = dir || 'asc'
|
156
163
|
end
|
@@ -201,23 +208,30 @@ module Groovy
|
|
201
208
|
@total_entries
|
202
209
|
end
|
203
210
|
|
204
|
-
def
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
211
|
+
def first(num = 1)
|
212
|
+
limit(num)
|
213
|
+
num == 1 ? records.first : records
|
214
|
+
end
|
215
|
+
|
216
|
+
def last(num = 1)
|
217
|
+
if sorting[:by]
|
218
|
+
get_last(num)
|
219
|
+
else # no sorting, so
|
220
|
+
sort_by(_id: :desc).limit(num)
|
221
|
+
# if last(2) or more, then re-sort by ascending ID
|
222
|
+
num == 1 ? records.first : records.sort { |a,b| a.id <=> b.id }
|
209
223
|
end
|
210
224
|
end
|
211
225
|
|
212
226
|
def in_batches(of: 1000, from: nil, &block)
|
213
|
-
|
214
|
-
|
227
|
+
sorting[:limit] = of
|
228
|
+
sorting[:offset] = from || 0
|
215
229
|
|
216
230
|
while results.any?
|
217
231
|
yield to_a
|
218
232
|
break if results.size < of
|
219
233
|
|
220
|
-
|
234
|
+
sorting[:offset] += of
|
221
235
|
@records = @results = nil # reset
|
222
236
|
end
|
223
237
|
end
|
@@ -229,9 +243,18 @@ module Groovy
|
|
229
243
|
end
|
230
244
|
|
231
245
|
private
|
232
|
-
attr_reader :model, :table, :options
|
246
|
+
attr_reader :model, :table, :options, :select_block
|
247
|
+
|
248
|
+
def get_last(count = 1)
|
249
|
+
if count > 1
|
250
|
+
records[(size-count)..-1]
|
251
|
+
else
|
252
|
+
records[size-1]
|
253
|
+
end
|
254
|
+
end
|
233
255
|
|
234
256
|
def add_param(param)
|
257
|
+
raise "Select block already given!" if select_block
|
235
258
|
raise "Duplicate param: #{param}" if parameters.include?(param)
|
236
259
|
parameters.push(param)
|
237
260
|
end
|
@@ -244,7 +267,10 @@ module Groovy
|
|
244
267
|
end
|
245
268
|
|
246
269
|
def execute
|
247
|
-
set = if
|
270
|
+
set = if select_block
|
271
|
+
debug "Finding records with select block"
|
272
|
+
table.select { |record| select_block.call(record) }
|
273
|
+
elsif parameters.any?
|
248
274
|
query = prepare_query
|
249
275
|
debug "Finding records with query: #{query}"
|
250
276
|
table.select(query, options)
|
@@ -255,7 +281,7 @@ module Groovy
|
|
255
281
|
|
256
282
|
@total_entries = set.size
|
257
283
|
|
258
|
-
debug "Sorting with #{sort_key_and_order}
|
284
|
+
debug "Sorting with #{sort_key_and_order} (options: #{sorting.inspect})"
|
259
285
|
set = set.sort(sort_key_and_order, {
|
260
286
|
limit: sorting[:limit],
|
261
287
|
offset: sorting[:offset], # [sorting[:offset], @total_entries].min
|
@@ -287,6 +313,7 @@ module Groovy
|
|
287
313
|
query = parameters.join(' ').split(/ or /i).map do |part|
|
288
314
|
part.gsub(' ', ' ') # replace double with single spaces
|
289
315
|
.gsub(space_regex, '\ \1') # escape spaces before word letters
|
316
|
+
.gsub('_slash_', '\/').gsub('_openp_', '\(').gsub('_closep_', '\)')
|
290
317
|
.gsub(/(\d\d):(\d\d):(\d\d)/, '\1\:\2\:\3') # escape hh:mm:ss in timestamps
|
291
318
|
end.join(' OR ').sub(/^-/, '_id:>0 -') #.gsub(' OR -', ' -')
|
292
319
|
end
|
data/lib/groovy/schema.rb
CHANGED
@@ -56,14 +56,25 @@ module Groovy
|
|
56
56
|
end
|
57
57
|
|
58
58
|
def time_columns
|
59
|
-
|
60
|
-
get_names(table.columns.select { |c| c.column? && c.range.name == 'Time' })
|
59
|
+
columns_by_type('Time')
|
61
60
|
end
|
62
61
|
|
63
|
-
def
|
64
|
-
|
62
|
+
def integer_columns
|
63
|
+
columns_by_type('Int32')
|
65
64
|
end
|
66
65
|
|
66
|
+
def boolean_columns
|
67
|
+
columns_by_type('Bool')
|
68
|
+
end
|
69
|
+
|
70
|
+
def columns_by_type(type)
|
71
|
+
get_names(table.columns.select { |c| c.column? && c.range.name == type })
|
72
|
+
end
|
73
|
+
|
74
|
+
# def time_column?(name)
|
75
|
+
# time_columns.include?(name)
|
76
|
+
# end
|
77
|
+
|
67
78
|
def rebuild!
|
68
79
|
log("Rebuilding!")
|
69
80
|
# remove_table! if table
|
data/lib/groovy/version.rb
CHANGED
data/spec/model_spec.rb
CHANGED
@@ -17,7 +17,7 @@ describe Groovy::Model do
|
|
17
17
|
describe '.scope' do
|
18
18
|
|
19
19
|
before :all do
|
20
|
-
TestProduct.class_eval do
|
20
|
+
TestProduct.class_eval do
|
21
21
|
scope :with_name, -> (name) { where(name: name) if name }
|
22
22
|
scope :by_price_asc, -> { sort_by(price: :asc) }
|
23
23
|
scope :cheapest, -> { by_price_asc }
|
@@ -49,6 +49,13 @@ describe Groovy::Model do
|
|
49
49
|
end
|
50
50
|
|
51
51
|
describe '.create' do
|
52
|
+
|
53
|
+
it 'does not explode when inserting nil values for columns' do
|
54
|
+
expect do
|
55
|
+
TestProduct.create({ price: nil })
|
56
|
+
end.not_to raise_error
|
57
|
+
end
|
58
|
+
|
52
59
|
end
|
53
60
|
|
54
61
|
describe '.find' do
|
@@ -60,6 +67,7 @@ describe Groovy::Model do
|
|
60
67
|
describe '.delete_all' do
|
61
68
|
|
62
69
|
before do
|
70
|
+
TestProduct.delete_all
|
63
71
|
@first = TestProduct.create!(name: 'A product', price: 100)
|
64
72
|
@second = TestProduct.create!(name: 'Another product', price: 200)
|
65
73
|
expect(TestProduct.count).to eq(2)
|
data/spec/query_spec.rb
CHANGED
@@ -8,7 +8,7 @@ describe Groovy::Query do
|
|
8
8
|
@p1 = TestProduct.create!(name: "Product 1", visible: true, price: 10, tag_list: 'one, number two & three')
|
9
9
|
@p2 = TestProduct.create!(name: "Product 2", visible: false, price: 20, tag_list: 'number two, three')
|
10
10
|
@p3 = TestProduct.create!(name: "Product 3: The Best", visible: true, price: 30, tag_list: nil)
|
11
|
-
@p4 = TestProduct.create!(name: "Product 4", visible: false, price: 40, tag_list: 'one, number two')
|
11
|
+
@p4 = TestProduct.create!(name: "Product 4", visible: false, price: 40, tag_list: 'one, number two / something')
|
12
12
|
@p5 = TestProduct.create!(name: "Product 5", visible: true, price: 50, tag_list: '')
|
13
13
|
end
|
14
14
|
|
@@ -124,6 +124,12 @@ describe Groovy::Query do
|
|
124
124
|
res = TestProduct.where(tag_list: /two & three/)
|
125
125
|
expect(res.map(&:id)).to eq([@p1.id])
|
126
126
|
end
|
127
|
+
|
128
|
+
it 'works with slashes' do
|
129
|
+
str = 'two / something'
|
130
|
+
res = TestProduct.where(tag_list: /#{str}/)
|
131
|
+
expect(res.map(&:id)).to eq([@p4.id])
|
132
|
+
end
|
127
133
|
end
|
128
134
|
|
129
135
|
describe 'starts with regex' do
|
@@ -253,6 +259,12 @@ describe Groovy::Query do
|
|
253
259
|
res = TestProduct.not(tag_list: /two & three/)
|
254
260
|
expect(res.map(&:id)).to eq([@p2.id, @p3.id, @p4.id, @p5.id])
|
255
261
|
end
|
262
|
+
|
263
|
+
it 'works with slashes' do
|
264
|
+
str = 'two / something'
|
265
|
+
res = TestProduct.not(tag_list: /#{str}/)
|
266
|
+
expect(res.map(&:id)).to eq([@p1.id, @p2.id, @p3.id, @p5.id])
|
267
|
+
end
|
256
268
|
end
|
257
269
|
|
258
270
|
describe 'starts with regex' 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.
|
4
|
+
version: 0.4.6
|
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-
|
11
|
+
date: 2020-10-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rroonga
|