groovy 0.6.8 → 0.7.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.
- checksums.yaml +4 -4
- data/lib/groovy/model.rb +142 -36
- data/lib/groovy/query.rb +10 -4
- data/lib/groovy/schema.rb +23 -13
- data/lib/groovy/version.rb +1 -1
- data/spec/callbacks_spec.rb +2 -4
- data/spec/model_spec.rb +15 -4
- data/spec/query_spec.rb +7 -0
- data/spec/schema_spec.rb +74 -0
- data/spec/search_spec.rb +22 -1
- data/spec/spec_helper.rb +9 -0
- data/spec/vector_spec.rb +7 -0
- metadata +7 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: da506ad46a6a3aad6cd965b7fcc43079fd61903c1e1a9f0bee659342430dc9ad
|
4
|
+
data.tar.gz: 6eba099bd0552fcc3ce8aaa15a0d9fb46486a96e1c1eee8dcd427f86a7d44256
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4c26e85b1dc605632deff25150f39e3794079c75581c0098c4893d01fced0729a6f4cd99fea8cae1d840aa003b219dfc62a62acbc0fa0743514d2d4464bbf98a
|
7
|
+
data.tar.gz: 1efedf625a489694dc51442664438d8d3a1984dfa50398734f97ecccf8f8146ff4543c06f9a1a6b9a0b17c4007d4fd1baa636b5d2ade8a98b300142133e89240
|
data/lib/groovy/model.rb
CHANGED
@@ -17,6 +17,31 @@ module Groovy
|
|
17
17
|
@models ||= {}
|
18
18
|
end
|
19
19
|
|
20
|
+
module Utils
|
21
|
+
def self.singularize(str)
|
22
|
+
str.to_s.sub(/ies$/, 'y').sub(/s$/, '')
|
23
|
+
end
|
24
|
+
|
25
|
+
# category -> categories
|
26
|
+
# product -> products
|
27
|
+
def self.pluralize(str)
|
28
|
+
return str if str[-1] == 's' # already ends with s, assume already plural
|
29
|
+
str.to_s.sub(/y$/, 'ie') + 's'
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.pluralize_and_classify(str)
|
33
|
+
classify(pluralize(str))
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.underscore(str)
|
37
|
+
str.gsub(/([A-Z])/) { |x| "_#{x.downcase}" }.sub(/^_/, '')
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.classify(str)
|
41
|
+
str.to_s.gsub(/([A-Z])/, '_\1').split('_').collect! { |w| w.capitalize }.join
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
20
45
|
module Model
|
21
46
|
|
22
47
|
def self.initialize_from_record(obj)
|
@@ -30,23 +55,21 @@ module Groovy
|
|
30
55
|
# end
|
31
56
|
|
32
57
|
def self.model_from_table(table_name)
|
33
|
-
get_class(
|
58
|
+
get_class(Utils.singularize(table_name))
|
34
59
|
end
|
35
60
|
|
36
61
|
def self.included(base)
|
37
62
|
base.extend(ClassMethods)
|
38
63
|
base.include(Forwardable)
|
39
|
-
base.table_name = base.name
|
64
|
+
base.table_name = Utils.pluralize(base.name)
|
40
65
|
|
41
66
|
# add to global model list
|
42
67
|
# Groovy.models[base.name] = base
|
43
68
|
Groovy.models[base.table_name] = base
|
44
69
|
end
|
45
70
|
|
46
|
-
def self.get_class(
|
47
|
-
|
48
|
-
classified = table_name.gsub(/([A-Z])/, '_\1').split('_').collect! { |w| w.capitalize }.join
|
49
|
-
Kernel.const_get(classified)
|
71
|
+
def self.get_class(klass_name)
|
72
|
+
Kernel.const_get(Utils.classify(klass_name))
|
50
73
|
end
|
51
74
|
|
52
75
|
module ClassMethods
|
@@ -63,11 +86,15 @@ module Groovy
|
|
63
86
|
end
|
64
87
|
|
65
88
|
def underscore_name
|
66
|
-
|
89
|
+
Utils.underscore(name)
|
67
90
|
end
|
68
91
|
|
69
92
|
def attribute_names
|
70
|
-
|
93
|
+
schema.attribute_columns
|
94
|
+
end
|
95
|
+
|
96
|
+
def reference_names
|
97
|
+
schema.singular_references + schema.plural_references
|
71
98
|
end
|
72
99
|
|
73
100
|
# def singular_refs
|
@@ -87,11 +114,13 @@ module Groovy
|
|
87
114
|
self.context_name = options[:context] || Groovy.first_context_name
|
88
115
|
self.table_name = options[:table_name] if options[:table_name]
|
89
116
|
|
90
|
-
s = Schema.new(db_context, table_name,
|
117
|
+
s = Schema.new(db_context, table_name, options)
|
91
118
|
yield s if block
|
92
119
|
s.sync
|
93
120
|
|
94
|
-
|
121
|
+
include(HashTable) if table.is_a?(Groonga::Hash)
|
122
|
+
include(PatriciaTrieTable) if table.is_a?(Groonga::PatriciaTrie)
|
123
|
+
|
95
124
|
s.column_names.each { |col| add_accessors_for(col, s) }
|
96
125
|
s
|
97
126
|
end
|
@@ -118,7 +147,7 @@ module Groovy
|
|
118
147
|
elsif s.plural_references.include?(col)
|
119
148
|
add_vector_accessors(col)
|
120
149
|
else
|
121
|
-
|
150
|
+
raise "Unknown column type: #{col}"
|
122
151
|
end
|
123
152
|
end
|
124
153
|
|
@@ -147,13 +176,13 @@ module Groovy
|
|
147
176
|
end
|
148
177
|
end
|
149
178
|
|
150
|
-
def create(attributes
|
151
|
-
obj = new(attributes
|
179
|
+
def create(attributes)
|
180
|
+
obj = new(attributes)
|
152
181
|
obj.save ? obj : false
|
153
182
|
end
|
154
183
|
|
155
|
-
def create!(attributes
|
156
|
-
create(attributes
|
184
|
+
def create!(attributes)
|
185
|
+
create(attributes) or raise Error, "Invalid"
|
157
186
|
end
|
158
187
|
|
159
188
|
def update_all(attrs)
|
@@ -174,6 +203,12 @@ module Groovy
|
|
174
203
|
# Groonga["#{table_name}.#{name}"] # .search, .similar_search, etc
|
175
204
|
# end
|
176
205
|
|
206
|
+
def search_table
|
207
|
+
schema.search_table
|
208
|
+
end
|
209
|
+
|
210
|
+
def_instance_delegators :search_table, :prefix_search, :each_with_prefix # just these two for now
|
211
|
+
|
177
212
|
def index_search(column, query, options = {}, &block)
|
178
213
|
results = table.select { |rec| rec[column].match(query) }
|
179
214
|
render_results(results, &block)
|
@@ -230,6 +265,14 @@ module Groovy
|
|
230
265
|
query.where(*args, &block)
|
231
266
|
end
|
232
267
|
|
268
|
+
def each(&block)
|
269
|
+
query.each(&block)
|
270
|
+
end
|
271
|
+
|
272
|
+
def find_or_create_by(attributes)
|
273
|
+
find_by(**attributes) || create(**attributes)
|
274
|
+
end
|
275
|
+
|
233
276
|
[:first, :last, :select, :find_by, :search, :not, :sort_by, :in_batches, :limit, :offset, :paginate].each do |scope_method|
|
234
277
|
define_method scope_method do |**args, &block|
|
235
278
|
query.public_send(scope_method, **args, &block)
|
@@ -308,21 +351,80 @@ module Groovy
|
|
308
351
|
end
|
309
352
|
end
|
310
353
|
|
311
|
-
module
|
312
|
-
|
313
|
-
|
354
|
+
module PatriciaTrieTable
|
355
|
+
def self.included(base)
|
356
|
+
base.extend(ClassMethods)
|
357
|
+
end
|
358
|
+
|
359
|
+
module ClassMethods
|
360
|
+
extend Forwardable
|
361
|
+
def_instance_delegators :table, :scan, :prefix_search, :open_prefix_cursor, \
|
362
|
+
:suffix_search, :open_near_cursor, :tag_keys
|
314
363
|
|
315
|
-
|
316
|
-
|
317
|
-
|
364
|
+
def each_with_prefix(prefix, options = {}, &block)
|
365
|
+
table.open_prefix_cursor(prefix, options) do |cursor|
|
366
|
+
cursor.each { |r| yield r }
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
370
|
+
def each_near(str, options = {}, &block)
|
371
|
+
table.open_near_cursor(str, options) do |cursor|
|
372
|
+
cursor.each { |r| yield r }
|
373
|
+
end
|
318
374
|
end
|
319
375
|
end
|
320
376
|
end
|
321
377
|
|
378
|
+
module HashTable
|
379
|
+
def self.included(base)
|
380
|
+
base.extend(ClassMethods)
|
381
|
+
end
|
382
|
+
|
383
|
+
module ClassMethods
|
384
|
+
def find(key)
|
385
|
+
if record = table[key.to_s] and record.record_id
|
386
|
+
new_from_record(record)
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
def new_from_record(record)
|
391
|
+
# new(record.attributes, record)
|
392
|
+
new(record._key, nil, record)
|
393
|
+
end
|
394
|
+
|
395
|
+
def create(key, attributes)
|
396
|
+
obj = new(key, attributes)
|
397
|
+
obj.save ? obj : false
|
398
|
+
end
|
399
|
+
|
400
|
+
def create!(key, attributes)
|
401
|
+
create(key, attributes) or raise Error, "Invalid"
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
405
|
+
def initialize(key, attrs = nil, record = nil)
|
406
|
+
@key = key
|
407
|
+
super(attrs, record)
|
408
|
+
end
|
409
|
+
|
410
|
+
def load_record
|
411
|
+
self.class.table[key]
|
412
|
+
end
|
413
|
+
|
414
|
+
# def new_record?
|
415
|
+
# key.nil?
|
416
|
+
# end
|
417
|
+
|
418
|
+
def key
|
419
|
+
@key || (record ? record._key : nil)
|
420
|
+
end
|
421
|
+
|
422
|
+
end
|
423
|
+
|
322
424
|
attr_reader :id, :record, :changes
|
323
425
|
|
324
|
-
def initialize(attrs = nil, record = nil
|
325
|
-
@attributes, @vectors
|
426
|
+
def initialize(attrs = nil, record = nil)
|
427
|
+
@attributes, @vectors = {}, {}
|
326
428
|
@foreign_refs_to_update = {}
|
327
429
|
|
328
430
|
if set_record(record)
|
@@ -344,9 +446,9 @@ module Groovy
|
|
344
446
|
|
345
447
|
# get reference to the actual record in the Groonga table,
|
346
448
|
# not the temporary one we get as part of a search result.
|
347
|
-
|
348
|
-
|
349
|
-
|
449
|
+
def load_record
|
450
|
+
self.class.table[id]
|
451
|
+
end
|
350
452
|
|
351
453
|
def attributes
|
352
454
|
load_attributes_from_record # populate missing
|
@@ -356,7 +458,7 @@ module Groovy
|
|
356
458
|
alias_method :attrs, :attributes
|
357
459
|
|
358
460
|
def inspect
|
359
|
-
"#<#{self.class.name} id:#{id.inspect} attributes:[#{self.class.attribute_names.join(', ')}]>"
|
461
|
+
"#<#{self.class.name} id:#{id.inspect} attributes:[#{self.class.attribute_names.join(', ')}] references:[#{self.class.reference_names.join(', ')}]>"
|
360
462
|
end
|
361
463
|
|
362
464
|
def dump
|
@@ -365,7 +467,6 @@ module Groovy
|
|
365
467
|
|
366
468
|
def new_record?
|
367
469
|
id.nil?
|
368
|
-
# _key.nil?
|
369
470
|
end
|
370
471
|
|
371
472
|
def persisted?
|
@@ -427,6 +528,9 @@ module Groovy
|
|
427
528
|
update_attributes(obj) or raise "Invalid!"
|
428
529
|
end
|
429
530
|
|
531
|
+
alias_method :update, :update_attributes
|
532
|
+
alias_method :update!, :update_attributes!
|
533
|
+
|
430
534
|
def save(options = {})
|
431
535
|
return false if respond_to?(:invalid?) and invalid?
|
432
536
|
if new_record?
|
@@ -455,7 +559,7 @@ module Groovy
|
|
455
559
|
unless new_record?
|
456
560
|
# raise RecordNotPersisted if id.nil?
|
457
561
|
# ensure_persisted!
|
458
|
-
rec =
|
562
|
+
rec = load_record
|
459
563
|
set_record(rec)
|
460
564
|
# load_attributes_from_record
|
461
565
|
end
|
@@ -494,11 +598,6 @@ module Groovy
|
|
494
598
|
return val.to_i == 0 ? nil : val
|
495
599
|
end
|
496
600
|
|
497
|
-
# def _key
|
498
|
-
# return unless record
|
499
|
-
# record.respond_to?(:_key) ? record._key : id
|
500
|
-
# end
|
501
|
-
|
502
601
|
def load_attributes_from_record
|
503
602
|
self.class.attribute_names.each do |col|
|
504
603
|
public_send("#{col}=", get_record_attribute(col)) unless @attributes.key?(col)
|
@@ -533,7 +632,14 @@ module Groovy
|
|
533
632
|
if record.nil? # not persisted yet
|
534
633
|
set_attribute(name, obj.id) # obj should be a groovy model or groonga record
|
535
634
|
else
|
536
|
-
val = obj.
|
635
|
+
val = if obj.is_a?(Groovy::Model)
|
636
|
+
obj.id
|
637
|
+
elsif obj.respond_to?(:record)
|
638
|
+
# obj.record.record_id
|
639
|
+
obj.record
|
640
|
+
else
|
641
|
+
obj
|
642
|
+
end
|
537
643
|
record[name] = val
|
538
644
|
end
|
539
645
|
end
|
@@ -545,7 +651,7 @@ module Groovy
|
|
545
651
|
|
546
652
|
def create
|
547
653
|
fire_callbacks(:before_create)
|
548
|
-
set_record(self.class.insert(@attributes, @
|
654
|
+
set_record(self.class.insert(@attributes, @key))
|
549
655
|
update_foreign_refs
|
550
656
|
fire_callbacks(:after_create)
|
551
657
|
self
|
data/lib/groovy/query.rb
CHANGED
@@ -80,20 +80,26 @@ module Groovy
|
|
80
80
|
add_param(AND + "(#{map_operator(handle_timestamps(conditions))})")
|
81
81
|
when Hash # { foo: 'bar' } or { views: 1..100 }
|
82
82
|
conditions.each do |key, val|
|
83
|
-
|
83
|
+
case val
|
84
|
+
when Model
|
85
|
+
raise "Object not persisted yet!" unless val.persisted?
|
86
|
+
str = "#{key}:#{val.id}"
|
87
|
+
add_param(AND + str)
|
88
|
+
|
89
|
+
when Range
|
84
90
|
add_param(AND + [key, val.min].join(':>=')) if val.min # lte
|
85
91
|
add_param(AND + [key, val.max].join(':<=')) if val.max # gte
|
86
92
|
|
87
|
-
|
93
|
+
when Regexp
|
88
94
|
str = val.source.gsub('/', '_slash_').gsub('(', '_openp_').gsub(')', '_closep_').gsub(REMOVE_INVALID_CHARS_REGEX, '')
|
89
95
|
param = val.source[0] == '^' ? ':^' : val.source[-1] == '$' ? ':$' : ':~' # starts with or regexp
|
90
96
|
add_param(AND + [key, str.downcase].join(param)) # regex must be downcase
|
91
97
|
|
92
|
-
|
98
|
+
when Array # { foo: [1,2,3] }
|
93
99
|
str = "#{key}:#{val.join(" OR #{key}:")}"
|
94
100
|
add_param(AND + str)
|
95
101
|
|
96
|
-
|
102
|
+
when Time
|
97
103
|
# The second, specify the timestamp as string in following format:
|
98
104
|
# “(YEAR)/(MONTH)/(DAY) (HOUR):(MINUTE):(SECOND)”
|
99
105
|
|
data/lib/groovy/schema.rb
CHANGED
@@ -4,6 +4,14 @@ module Groovy
|
|
4
4
|
class Schema
|
5
5
|
|
6
6
|
SEARCH_TABLE_NAME = 'Terms'.freeze
|
7
|
+
|
8
|
+
SEARCH_TABLE_OPTIONS = {
|
9
|
+
type: :patricia_trie,
|
10
|
+
normalizer: :NormalizerAuto,
|
11
|
+
key_type: "ShortText",
|
12
|
+
default_tokenizer: "TokenBigram"
|
13
|
+
}.freeze
|
14
|
+
|
7
15
|
COLUMN_DEFAULTS = {
|
8
16
|
compress: :zstandard
|
9
17
|
}.freeze
|
@@ -33,6 +41,10 @@ module Groovy
|
|
33
41
|
@table ||= context[table_name]
|
34
42
|
end
|
35
43
|
|
44
|
+
def table_type
|
45
|
+
(@opts[:type] || :array).to_sym
|
46
|
+
end
|
47
|
+
|
36
48
|
# def [](key)
|
37
49
|
# # @spec[key.to_sym]
|
38
50
|
# table.columns.select { |c| c.column? && c.name.to_s == "#{table_name}.#{key.to_s}" }
|
@@ -115,11 +127,11 @@ module Groovy
|
|
115
127
|
end
|
116
128
|
|
117
129
|
def reference(name, table_name = nil, options = {})
|
118
|
-
table_name =
|
130
|
+
table_name = Utils.pluralize_and_classify(name) if table_name.nil?
|
119
131
|
|
120
132
|
unless context[table_name]
|
121
133
|
log "Table #{table_name} doesn't exist yet! Creating now..."
|
122
|
-
create_table!(table_name)
|
134
|
+
create_table!(table_name, nil)
|
123
135
|
end
|
124
136
|
|
125
137
|
refs_by_table[table_name] = name.to_sym
|
@@ -174,19 +186,17 @@ module Groovy
|
|
174
186
|
name_col = [table_name, col].join('.')
|
175
187
|
log "Adding index on #{name_col}"
|
176
188
|
Groonga::Schema.change_table(SEARCH_TABLE_NAME, context: context) do |table|
|
177
|
-
#
|
178
|
-
|
189
|
+
if opts[:search] # search column requires with_position: true
|
190
|
+
table.index(name_col, name: name_col, with_position: true, with_section: true)
|
191
|
+
else
|
192
|
+
table.index(name_col, name: name_col.sub('.', '_'))
|
193
|
+
end
|
179
194
|
end
|
180
195
|
end
|
181
196
|
|
182
197
|
def ensure_search_table!
|
183
198
|
return if search_table
|
184
|
-
opts = (@opts[:search_table] || {}).merge(
|
185
|
-
type: :patricia_trie,
|
186
|
-
normalizer: :NormalizerAuto,
|
187
|
-
key_type: "ShortText",
|
188
|
-
default_tokenizer: "TokenBigram"
|
189
|
-
})
|
199
|
+
opts = (@opts[:search_table] || {}).merge(SEARCH_TABLE_OPTIONS)
|
190
200
|
log("Creating search table with options: #{opts.inspect}")
|
191
201
|
Groonga::Schema.create_table(SEARCH_TABLE_NAME, opts.merge(context: context))
|
192
202
|
end
|
@@ -225,9 +235,9 @@ module Groovy
|
|
225
235
|
end
|
226
236
|
end
|
227
237
|
|
228
|
-
def create_table!(name = table_name)
|
229
|
-
log "Creating table #{name}!"
|
230
|
-
Groonga::Schema.create_table(name, context: context)
|
238
|
+
def create_table!(name = table_name, type = table_type)
|
239
|
+
log "Creating table #{name} with type #{type.inspect}!"
|
240
|
+
Groonga::Schema.create_table(name, context: context, type: type)
|
231
241
|
end
|
232
242
|
|
233
243
|
def remove_table!(name = table_name)
|
data/lib/groovy/version.rb
CHANGED
data/spec/callbacks_spec.rb
CHANGED
@@ -4,14 +4,14 @@ describe Groovy::Model do
|
|
4
4
|
|
5
5
|
before :all do
|
6
6
|
Groovy.open('tmp/callbacks', 'callbacks_spec')
|
7
|
-
|
7
|
+
load_test_schema!
|
8
8
|
end
|
9
9
|
|
10
10
|
after :all do
|
11
11
|
Groovy.close('callbacks_spec')
|
12
12
|
end
|
13
13
|
|
14
|
-
def
|
14
|
+
def load_test_schema!
|
15
15
|
klass = Class.new
|
16
16
|
Object.const_set("User", klass)
|
17
17
|
User.class_eval do
|
@@ -35,8 +35,6 @@ describe Groovy::Model do
|
|
35
35
|
# puts "updated"
|
36
36
|
end
|
37
37
|
end
|
38
|
-
|
39
|
-
User.add_reference :comments, "Comments", type: :vector
|
40
38
|
end
|
41
39
|
|
42
40
|
it 'fires created callbacks' do
|
data/spec/model_spec.rb
CHANGED
@@ -15,7 +15,6 @@ describe Groovy::Model do
|
|
15
15
|
end
|
16
16
|
|
17
17
|
describe '.scope' do
|
18
|
-
|
19
18
|
before :all do
|
20
19
|
TestProduct.class_eval do
|
21
20
|
scope :with_name, -> (name) { where(name: name) if name }
|
@@ -120,6 +119,21 @@ describe Groovy::Model do
|
|
120
119
|
end
|
121
120
|
|
122
121
|
describe '#update_attributes' do
|
122
|
+
|
123
|
+
it 'allows setting references out of searches' do
|
124
|
+
cat = TestCategory.create!(name: 'A category')
|
125
|
+
cat2 = TestCategory.create!(name: 'Another category')
|
126
|
+
|
127
|
+
prod = TestProduct.create!(name: 'A product', price: 100)
|
128
|
+
prod.update_attributes(test_category: cat)
|
129
|
+
|
130
|
+
last = TestCategory.last
|
131
|
+
expect(last).to eq(cat2)
|
132
|
+
puts "last: #{last.inspect}"
|
133
|
+
prod.update_attributes(test_category: last)
|
134
|
+
expect(prod.reload.test_category).to eq(cat2)
|
135
|
+
end
|
136
|
+
|
123
137
|
end
|
124
138
|
|
125
139
|
describe '#save' do
|
@@ -147,15 +161,12 @@ describe Groovy::Model do
|
|
147
161
|
end
|
148
162
|
|
149
163
|
describe 'attributes accessors' do
|
150
|
-
|
151
164
|
end
|
152
165
|
|
153
166
|
describe 'singular refs' do
|
154
|
-
|
155
167
|
end
|
156
168
|
|
157
169
|
describe 'plural refs' do
|
158
|
-
|
159
170
|
end
|
160
171
|
|
161
172
|
end
|
data/spec/query_spec.rb
CHANGED
@@ -16,6 +16,13 @@ describe Groovy::Query do
|
|
16
16
|
Groovy.close('query_spec')
|
17
17
|
end
|
18
18
|
|
19
|
+
# describe '#first' do
|
20
|
+
# it 'returns a valid object' do
|
21
|
+
# res = TestProduct.first
|
22
|
+
# expect(res.record.table.name).to eq(TestProduct.table.name)
|
23
|
+
# end
|
24
|
+
# end
|
25
|
+
|
19
26
|
describe '#where' do
|
20
27
|
describe 'boolean value' do
|
21
28
|
it 'finds expected records' do
|
data/spec/schema_spec.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
require_relative './spec_helper'
|
2
|
+
|
3
|
+
describe Groovy::Model do
|
4
|
+
|
5
|
+
CONTEXT_NAME = 'schema_spec'
|
6
|
+
|
7
|
+
before :all do
|
8
|
+
Groovy.open('tmp/' + CONTEXT_NAME, CONTEXT_NAME)
|
9
|
+
load_test_schema!
|
10
|
+
end
|
11
|
+
|
12
|
+
after :all do
|
13
|
+
Groovy.close(CONTEXT_NAME)
|
14
|
+
end
|
15
|
+
|
16
|
+
def load_test_schema!
|
17
|
+
klass = Class.new
|
18
|
+
Object.const_set("Product", klass)
|
19
|
+
Product.class_eval do
|
20
|
+
include Groovy::Model
|
21
|
+
|
22
|
+
schema(type: 'hash', context: CONTEXT_NAME) do |t|
|
23
|
+
t.string :name
|
24
|
+
t.many :categories
|
25
|
+
t.timestamps
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
klass = Class.new
|
30
|
+
Object.const_set("Category", klass)
|
31
|
+
Category.class_eval do
|
32
|
+
include Groovy::Model
|
33
|
+
|
34
|
+
schema(context: CONTEXT_NAME) do |t|
|
35
|
+
t.many :products, "Products"
|
36
|
+
t.string :name
|
37
|
+
t.timestamps
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe 'hash table' do
|
43
|
+
|
44
|
+
it 'creates, updates and finds records as expected' do
|
45
|
+
product = Product.new('ipod-mini', name: 'iPod Mini')
|
46
|
+
expect(product.new_record?).to eq(true)
|
47
|
+
|
48
|
+
expect(product.name).to eq('iPod Mini')
|
49
|
+
expect(product.save).to eq(true)
|
50
|
+
expect(product.persisted?).to eq(true)
|
51
|
+
expect(product.key).to eq('ipod-mini')
|
52
|
+
|
53
|
+
expect(product.update_attributes(name: 'iPod Mini 2nd Generation'))
|
54
|
+
expect(product.name).to eq('iPod Mini 2nd Generation')
|
55
|
+
|
56
|
+
expect(Product.find('ipod-mini')).to eq(product)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'works with references too' do
|
60
|
+
product = Product.new('ipod-mini', name: 'iPod Mini')
|
61
|
+
expect(product.save).to eq(true)
|
62
|
+
|
63
|
+
category = Category.new(name: 'iPods')
|
64
|
+
expect(category.save).to eq(true)
|
65
|
+
|
66
|
+
category.products << product
|
67
|
+
product.categories << category
|
68
|
+
|
69
|
+
expect(product.reload.categories).to eq([category])
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
data/spec/search_spec.rb
CHANGED
@@ -6,7 +6,7 @@ describe Groovy::Model, 'searching' do
|
|
6
6
|
Groovy.open('tmp/search', 'search_spec')
|
7
7
|
load_schema! 'search_spec'
|
8
8
|
|
9
|
-
TestProduct.add_column :description, :string, index: true
|
9
|
+
TestProduct.add_column :description, :string, index: true #, search: true
|
10
10
|
|
11
11
|
TestProduct.create!(name: 'First product', description: 'Lorem ipsum dolor sit amet')
|
12
12
|
TestProduct.create!(name: 'Second product', description: 'Lorea el ipsum poh loco')
|
@@ -51,4 +51,25 @@ describe Groovy::Model, 'searching' do
|
|
51
51
|
expect(res.first.name).to eq('Second product')
|
52
52
|
end
|
53
53
|
end
|
54
|
+
|
55
|
+
describe 'prefix search' do
|
56
|
+
it 'returns results' do
|
57
|
+
res = TestProduct.prefix_search('Lore')
|
58
|
+
expect(res.count).to eq(0)
|
59
|
+
|
60
|
+
res = TestProduct.prefix_search('lore')
|
61
|
+
expect(res.count).to eq(2)
|
62
|
+
expect(res.first).to be_a(Groonga::Record)
|
63
|
+
parts = res.map { |rec| rec['._key'] }
|
64
|
+
expect(parts).to eq(['lorem', 'lorea'])
|
65
|
+
end
|
66
|
+
|
67
|
+
# it 'works with each_with_prefix too' do
|
68
|
+
# parts = []
|
69
|
+
# res = TestProduct.each_with_prefix('lore') do |rec|
|
70
|
+
# parts.push(rec['._key'])
|
71
|
+
# end
|
72
|
+
# expect(parts).to eq(['lorem', 'lorea'])
|
73
|
+
# end
|
74
|
+
end
|
54
75
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -16,12 +16,21 @@ RSpec.configure do |config|
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
+
class TestCategory
|
20
|
+
include Groovy::Model
|
21
|
+
end
|
22
|
+
|
19
23
|
class TestProduct
|
20
24
|
include Groovy::Model
|
21
25
|
end
|
22
26
|
|
23
27
|
def load_schema!(context_name)
|
28
|
+
TestCategory.load_schema context: context_name do |t|
|
29
|
+
t.string :name
|
30
|
+
end
|
31
|
+
|
24
32
|
TestProduct.load_schema context: context_name do |t|
|
33
|
+
t.one :test_category
|
25
34
|
t.boolean :visible
|
26
35
|
t.string :name
|
27
36
|
t.integer :price
|
data/spec/vector_spec.rb
CHANGED
@@ -63,6 +63,13 @@ describe Groovy::Model do
|
|
63
63
|
expect(user2.reload.comments).to eq([])
|
64
64
|
end
|
65
65
|
|
66
|
+
it 'finds records using relations too' do
|
67
|
+
user = User.create(name: 'John')
|
68
|
+
comment = Comment.create(author: user, content: 'Hello there!')
|
69
|
+
|
70
|
+
expect(Comment.find_by(author: user)).to eq(comment)
|
71
|
+
end
|
72
|
+
|
66
73
|
end
|
67
74
|
|
68
75
|
end
|
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.7.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tomás Pollak
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-07-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rroonga
|
@@ -101,13 +101,14 @@ files:
|
|
101
101
|
- spec/groovy_spec.rb
|
102
102
|
- spec/model_spec.rb
|
103
103
|
- spec/query_spec.rb
|
104
|
+
- spec/schema_spec.rb
|
104
105
|
- spec/search_spec.rb
|
105
106
|
- spec/spec_helper.rb
|
106
107
|
- spec/vector_spec.rb
|
107
108
|
homepage: https://github.com/tomas/groovy
|
108
109
|
licenses: []
|
109
110
|
metadata: {}
|
110
|
-
post_install_message:
|
111
|
+
post_install_message:
|
111
112
|
rdoc_options: []
|
112
113
|
require_paths:
|
113
114
|
- lib
|
@@ -122,8 +123,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
122
123
|
- !ruby/object:Gem::Version
|
123
124
|
version: '0'
|
124
125
|
requirements: []
|
125
|
-
rubygems_version: 3.4.
|
126
|
-
signing_key:
|
126
|
+
rubygems_version: 3.4.6
|
127
|
+
signing_key:
|
127
128
|
specification_version: 4
|
128
129
|
summary: A wrapper around Groonga/Rroonga
|
129
130
|
test_files: []
|