groovy 0.1.3 → 0.1.4

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: 4a5a7078b71e609451ea64d58ee47e7573f7570563118c1b1fdf62078617ce8d
4
- data.tar.gz: 7444d38fc53884cb3540c0ab73efd91f296fcfa96828890cc29509831e6ae656
3
+ metadata.gz: e12ec33808ce635a4cc1d18432daab18f075fdd6112d41be94c4b3d81039cfb9
4
+ data.tar.gz: 72fc2666d2c87469399e7c3297fa69a613e194f95ba22a51f1f4306a7123b36d
5
5
  SHA512:
6
- metadata.gz: c20a741e4074aae0e28164ed307080229257d9c1fb6e00bd9fbe50f7b558b0189c1172cadc0ecd9b56484724b442a9bdd5bd59e67fbf748bdee9f4c39642fbd0
7
- data.tar.gz: e6481be3ce2ae9fc87071bf1865e1672e7da9b3af0eee39a69dc718be6c4ef39b5dbb942cdd466fe26ccc2035fa5aba70037c12a2f373b44de42d88e3d7cc4b6
6
+ metadata.gz: 31599509b743b69e7b0da3f1348da0bbd029b81003685bddc3ce6b95100e8c11f7ad2524ba7b3600925cbd50b5468bae09eba0126d5e8b0072dc032e990be9f4
7
+ data.tar.gz: 0f73afaab9eb391731d864aaace675755c713ef32bfa2c045bc1760d5eda25cd67d3f2b395562d31a5bbf7affff0e50ec9c5d923a8f222516a21dec4dfef34f6
data/.gitignore CHANGED
@@ -4,3 +4,5 @@ test
4
4
  log
5
5
  pkg
6
6
  example/db
7
+ tmp
8
+ Gemfile.lock
data/example/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- groovy (0.1.2)
4
+ groovy (0.1.3)
5
5
  rroonga (~> 7.1)
6
6
 
7
7
  GEM
data/example/basic.rb CHANGED
@@ -11,6 +11,9 @@ class Product
11
11
  t.integer :price
12
12
  t.timestamps
13
13
  end
14
+
15
+ scope :by_price, -> { sort_by(price: :asc) }
16
+ scope :named, -> (name) { where(name: name) if name }
14
17
  end
15
18
 
16
19
  def populate
data/example/relations.rb CHANGED
@@ -23,6 +23,8 @@ class Category
23
23
  t.string :name
24
24
  t.timestamps
25
25
  end
26
+
27
+ scope :named, -> (name) { where(name: name) if name }
26
28
  end
27
29
 
28
30
  class Place
@@ -34,6 +36,8 @@ class Place
34
36
  t.string :description, index: true
35
37
  t.timestamps
36
38
  end
39
+
40
+ scope :recent, -> { sort_by(created_at: :desc) }
37
41
  end
38
42
 
39
43
  class Location
data/groovy.gemspec CHANGED
@@ -14,9 +14,12 @@ Gem::Specification.new do |s|
14
14
  # s.required_rubygems_version = ">= 1.3.6"
15
15
  # s.rubyforge_project = "groovy"
16
16
 
17
- s.add_development_dependency "bundler", ">= 1.0.0"
18
17
  s.add_runtime_dependency "rroonga", "~> 7.1"
19
18
 
19
+ s.add_development_dependency "bundler", ">= 1.0.0"
20
+ s.add_development_dependency "rspec", '~> 3.0', '>= 3.0.0'
21
+ s.add_development_dependency "fuubar", '>= 2.3.2'
22
+
20
23
  s.files = `git ls-files`.split("\n")
21
24
  s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
22
25
  s.require_path = 'lib'
data/lib/groovy.rb CHANGED
@@ -3,14 +3,18 @@ require File.expand_path(File.dirname(__FILE__)) + '/groovy/model'
3
3
 
4
4
  module Groovy
5
5
 
6
+ class Error < StandardError; end
7
+ class ContextNotFound < Error; end
8
+ class ContextAlreadyClosed < Error; end
9
+
6
10
  class << self
7
11
 
8
12
  def contexts
9
13
  @contexts ||= {}
10
14
  end
11
15
 
12
- def [](key)
13
- contexts[key.to_sym]
16
+ def [](name)
17
+ contexts[name.to_sym]
14
18
  end
15
19
 
16
20
  def first_context_name
@@ -18,7 +22,14 @@ module Groovy
18
22
  end
19
23
 
20
24
  def open(db_path, name = :default, opts = {})
21
- raise "Context already defined: #{name}" if contexts[name.to_sym]
25
+ unless db_path.is_a?(String)
26
+ raise ArgumentError, "Invalid db_path: #{db_path}"
27
+ end
28
+
29
+ if contexts[name.to_sym]
30
+ raise ArgumentError, "Context already defined: #{name}"
31
+ end
32
+
22
33
  contexts[name.to_sym] = if name == :default
23
34
  Groonga::Context.default.tap { |ctx| open_or_create_db(ctx, db_path) }
24
35
  else
@@ -26,6 +37,14 @@ module Groovy
26
37
  end
27
38
  end
28
39
 
40
+ def close(name = :default)
41
+ ctx = contexts[name.to_sym] or raise ContextNotFound.new(name)
42
+ contexts.delete(name.to_sym)
43
+ ctx.close
44
+ rescue Groonga::Closed => e
45
+ raise ContextAlreadyClosed
46
+ end
47
+
29
48
  def logger=(obj)
30
49
  @logger = obj
31
50
  end
data/lib/groovy/model.rb CHANGED
@@ -39,6 +39,7 @@ module Groovy
39
39
  end
40
40
 
41
41
  def table
42
+ # raise "Table name not set: #{table_name}" if table_name.nil?
42
43
  db_context[table_name]
43
44
  end
44
45
 
@@ -47,7 +48,11 @@ module Groovy
47
48
  end
48
49
 
49
50
  def schema(options = {}, &block)
50
- @schema ||= begin
51
+ @schema ||= load_schema(options, &block)
52
+ end
53
+
54
+ def load_schema(options = {}, &block)
55
+ @schema = begin
51
56
  self.context_name = options[:context] || Groovy.first_context_name
52
57
  self.table_name = options[:table_name] if options[:table_name]
53
58
 
@@ -66,7 +71,8 @@ module Groovy
66
71
  def scope(name, obj)
67
72
  define_singleton_method(name) do |*args|
68
73
  res = obj.respond_to?(:call) ? obj.call(*args) : obj
69
- self
74
+ # res = obj.respond_to?(:call) ? self.instance_exec(*args) { |a| obj.call(*a) } : obj
75
+ self # return self instead of query, so we can call other scopes
70
76
  end
71
77
  end
72
78
 
@@ -75,6 +81,19 @@ module Groovy
75
81
  new(record.attributes, record)
76
82
  end
77
83
 
84
+ def find_and_init_record(id)
85
+ if found = table[id]
86
+ new_from_record(found)
87
+ end
88
+ end
89
+
90
+ def find_records(&block)
91
+ records = table.select(&block)
92
+ records.map do|r|
93
+ find_and_init_record(r.attributes['_key']['_id'])
94
+ end
95
+ end
96
+
78
97
  def find(id)
79
98
  if record = table[id] and record.id
80
99
  new_from_record(record)
@@ -109,9 +128,10 @@ module Groovy
109
128
  # table.select("#{col}:#{q}", operator: Groonga::Operation::SIMILAR)
110
129
  end
111
130
 
112
- def unique_values_for(column, limit: -1)
131
+ def unique_values_for(column, limit: -1, cache: false)
113
132
  cols = [column]
114
133
  opts = { drill_down: cols, drill_down_limit: limit, drilldown_sortby: '_key' }
134
+ opts[:cache] = cache ? 'yes' : 'no'
115
135
  resp = table.context.select(table_name, opts) # drill_down_output_columns: cols
116
136
  arr = resp.body[1] # or resp.drilldowns
117
137
  arr.slice(2..-1) # .flatten
@@ -143,11 +163,11 @@ module Groovy
143
163
  where(params).limit(1).first
144
164
  end
145
165
 
146
- def in_batches(of: 1000, from: nil, &block)
147
- all.in_batches(of: of, from: from, &block)
148
- end
166
+ # def in_batches(of: 1000, from: nil, &block)
167
+ # all.in_batches(of: of, from: from, &block)
168
+ # end
149
169
 
150
- [:search, :where, :not, :sort_by, :limit, :offset].each do |scope_method|
170
+ [:search, :where, :not, :sort_by, :limit, :offset, :paginate, :in_batches].each do |scope_method|
151
171
  define_method scope_method do |*args|
152
172
  query.public_send(scope_method, *args)
153
173
  end
@@ -179,7 +199,7 @@ module Groovy
179
199
  private
180
200
 
181
201
  def db_context
182
- Groovy.contexts[context_name] or raise "Context not defined: #{context_name}"
202
+ Groovy.contexts[context_name.to_sym] or raise "Context not defined: #{context_name}"
183
203
  end
184
204
 
185
205
  def add_attr_accessors(col)
@@ -269,11 +289,16 @@ module Groovy
269
289
 
270
290
  def update_attributes(obj)
271
291
  set_attributes(obj)
292
+ return false if respond_to?(:invalid?) and invalid?
272
293
  update
273
294
  end
274
295
 
296
+ def update_attributes!(obj)
297
+ update_attributes or raise "Invalid!"
298
+ end
299
+
275
300
  def save(options = {})
276
- return false if respond_to?(:invalid) and invalid?
301
+ return false if respond_to?(:invalid?) and invalid?
277
302
  new_record? ? create : update
278
303
  end
279
304
 
@@ -304,6 +329,10 @@ module Groovy
304
329
  attributes
305
330
  end
306
331
 
332
+ def ==(other)
333
+ self.id == other.id
334
+ end
335
+
307
336
  private
308
337
 
309
338
  # def _key
data/lib/groovy/query.rb CHANGED
@@ -17,9 +17,12 @@ module Groovy
17
17
  end
18
18
 
19
19
  def merge_with!(another)
20
+ # puts "merging #{parameters.inspect} with #{another.parameters.inspect}"
20
21
  # parameters.merge!(another.parameters)
21
- parameters.concat(another.parameters)
22
- sorting.merge!(another.sorting)
22
+ @parameters = another.parameters
23
+ @sorting = another.sorting
24
+ # parameters.concat(another.parameters)
25
+ # sorting.merge!(another.sorting)
23
26
  self
24
27
  end
25
28
 
@@ -42,21 +45,25 @@ module Groovy
42
45
  def where(conditions = nil)
43
46
  case conditions
44
47
  when String # "foo:bar"
45
- parameters.push(AND + "(#{map_operator(conditions)})")
48
+ add_param(AND + "(#{map_operator(conditions)})")
46
49
  when Hash # { foo: 'bar' } or { views: 1..100 }
47
50
  conditions.each do |key, val|
48
51
  if val.is_a?(Range)
49
- parameters.push(AND + [key, val.min].join(':>=')) if val.min # lte
50
- parameters.push(AND + [key, val.max].join(':<=')) if val.max # gte
52
+ add_param(AND + [key, val.min].join(':>=')) if val.min # lte
53
+ add_param(AND + [key, val.max].join(':<=')) if val.max # gte
54
+
51
55
  elsif val.is_a?(Regexp)
52
- str = val.source.gsub(/[^a-z]/, '')
53
- param = val.source[0] == '^' ? ':^' : ':~' # starts with or regexp
54
- parameters.push(AND + [key, str].join(param))
56
+ str = val.source.gsub(/[^a-zA-Z0-9\s_\.,-]/, '')
57
+ param = val.source[0] == '^' ? ':^' : val.source[-1] == '$' ? ':$' : ':~' # starts with or regexp
58
+ add_param(AND + [key, str.downcase].join(param)) # regex must be downcase
59
+
55
60
  elsif val.is_a?(Array) # { foo: [1,2,3] }
56
61
  str = "#{key}:#{val.join(" OR #{key}:")}"
57
- parameters.push(AND + str)
62
+ add_param(AND + str)
63
+
58
64
  else
59
- parameters.push(AND + [key, val.to_s].join(':'))
65
+ str = val.nil? || val.to_s.strip == '' ? '\\' : val.to_s
66
+ add_param(AND + [key, str].join(':'))
60
67
  end
61
68
  end
62
69
  # when Array # ["foo:?", val]
@@ -76,13 +83,21 @@ module Groovy
76
83
  when Hash # { foo: 'bar' }
77
84
  conditions.each do |key, val|
78
85
  if val.is_a?(Range)
79
- parameters.push(AND + [key, val.min].join(':<=')) if val.min > 0 # gte
80
- parameters.push(AND + [key, val.max].join(':>=')) if val.max # lte, nil if range.max is -1
86
+ add_param(AND + [key, val.min].join(':<=')) if val.min > 0 # gte
87
+ add_param(AND + [key, val.max].join(':>=')) if val.max # lte, nil if range.max is -1
88
+
89
+ elsif val.is_a?(Regexp)
90
+ str = val.source.gsub(/[^a-zA-Z0-9\s_\.,-]/, '')
91
+ param = val.source[0] == '^' ? ':^' : val.source[-1] == '$' ? ':$' : ':~' # starts with or regexp
92
+ add_param(NOT + [key, str.downcase].join(param)) # regex must be downcase
93
+
81
94
  elsif val.is_a?(Array) # { foo: [1,2,3] }
82
- str = "#{key}:!#{val.join(" OR #{key}:!")}"
83
- parameters.push(AND + str)
95
+ str = "#{key}:!#{val.join(" #{AND}#{key}:!")}"
96
+ add_param(AND + str)
97
+
84
98
  else
85
- parameters.push(AND + [key, val.to_s].join(':!')) # not
99
+ str = val.nil? || val.to_s.strip == '' ? '\\' : val.to_s
100
+ add_param(AND + [key, str].join(':!')) # not
86
101
  end
87
102
  end
88
103
  # when Array # ["foo:?", val]
@@ -171,11 +186,10 @@ module Groovy
171
186
  end
172
187
 
173
188
  def records
174
- @records ||= results.map do |r|
189
+ @records ||= results.map do |r|
175
190
  # FIXME: figure out the right way to do this.
176
- # model.new(r.value.attributes['_key'], r)
177
191
  id = r.attributes['_value']['_key']['_id']
178
- model.new_from_record(table[id])
192
+ model.find_and_init_record(id)
179
193
  end
180
194
  end
181
195
 
@@ -186,6 +200,11 @@ module Groovy
186
200
  model.clear_query # sets @query to nil
187
201
  end
188
202
 
203
+ def add_param(param)
204
+ raise "Duplicate param: #{param}" if parameters.include?(param)
205
+ parameters.push(param)
206
+ end
207
+
189
208
  def results
190
209
  @results ||= execute
191
210
  rescue Groonga::TooLargeOffset
@@ -198,12 +217,14 @@ module Groovy
198
217
  def execute
199
218
  set = if parameters.any?
200
219
  query = prepare_query
201
- puts query if ENV['DEBUG']
220
+ puts "Finding records with query: #{query}" if ENV['DEBUG']
202
221
  table.select(query, options)
203
222
  else
204
223
  table.select(options)
205
224
  end
206
225
 
226
+ puts set.expression.inspect
227
+
207
228
  @total_entries = set.size
208
229
 
209
230
  puts "Sorting with #{sort_key_and_order}, #{sorting.inspect}" if ENV['DEBUG']
@@ -232,7 +253,7 @@ module Groovy
232
253
  def prepare_query
233
254
  query = parameters.join(" ").split(/ or /i).map do |part|
234
255
  part.gsub(/\s(\w)/, '\ \1')
235
- end.join(' OR ')
256
+ end.join(' OR ').sub(/^-/, '_id:>0 -') #.gsub(' OR -', ' -')
236
257
  end
237
258
 
238
259
  def method_missing(name, *args)
@@ -1,3 +1,3 @@
1
1
  module Groovy
2
- VERSION = '0.1.3'.freeze
2
+ VERSION = '0.1.4'.freeze
3
3
  end
data/spec/groovy_spec.rb CHANGED
@@ -1,61 +1,66 @@
1
- require './lib/groovy'
2
- require 'rspec/mocks'
3
-
4
- describe Groovy::Model do
5
-
6
- describe '.schema' do
7
- end
8
-
9
- describe '.scope' do
10
- end
11
-
12
- describe '.create' do
13
- end
14
-
15
- describe '.find' do
16
- end
17
-
18
- describe '.find_by' do
19
- end
20
-
21
- describe '.delete_all' do
22
- end
23
-
24
- describe '#[]' do
25
- end
26
-
27
- describe '#[]=' do
28
- end
29
-
30
- describe '#increment' do
31
- end
32
-
33
- describe '#dirty' do
34
- end
35
-
36
- describe '#update_attributes' do
37
- end
38
-
39
- describe '#save' do
40
- end
41
-
42
- describe '#delete' do
43
- end
44
-
45
- describe '#reload' do
46
- end
47
-
48
- describe 'attributes accessors' do
49
-
50
- end
51
-
52
- describe 'singular refs' do
53
-
54
- end
55
-
56
- describe 'plural refs' do
57
-
58
- end
59
-
60
- end
61
-
1
+ require_relative './spec_helper'
2
+
3
+ describe Groovy do
4
+ before :each do
5
+ Groonga::Context.default = nil
6
+ end
7
+
8
+ describe '.open' do
9
+ it 'explodes if called with no params' do
10
+ expect do
11
+ Groovy.open
12
+ end.to raise_error(ArgumentError)
13
+ end
14
+
15
+ it 'explodes if called with nil db_path' do
16
+ expect do
17
+ Groovy.open(nil)
18
+ end.to raise_error(ArgumentError)
19
+ end
20
+
21
+ context 'if no context given' do
22
+ it 'sets up database for default context' do
23
+ expect(Groonga::Context.default.database).to be_nil
24
+ Groovy.open('tmp/foo1')
25
+ expect(Groonga::Context.default.database).to be_a(Groonga::Database)
26
+ Groovy.close # default
27
+ end
28
+ end
29
+
30
+ context 'if context given' do
31
+ it 'sets up database for default context' do
32
+ expect(Groonga::Context.default.database).to be_nil
33
+ Groovy.open('tmp/foo2', :test)
34
+ expect(Groonga::Context.default.database).to be_nil
35
+
36
+ expect(Groovy['test']).to be_a(Groonga::Context)
37
+ expect(Groovy[:test].database).to be_a(Groonga::Database)
38
+
39
+ Groovy.close(:test)
40
+ end
41
+ end
42
+ end
43
+
44
+ describe '.close' do
45
+ it 'thows if not opened (default)' do
46
+ expect { Groovy.close }.to raise_error(Groovy::ContextNotFound)
47
+ end
48
+
49
+ it 'thows if context does not exist' do
50
+ expect { Groovy.close(:foo) }.to raise_error(Groovy::ContextNotFound)
51
+ end
52
+
53
+ it 'thows if already closed' do
54
+ Groovy.open('tmp/foo')
55
+ Groovy.close
56
+ expect do
57
+ Groovy.close
58
+ end.to raise_error(Groovy::ContextNotFound)
59
+ end
60
+
61
+ it 'works if ctx exists and open' do
62
+ Groovy.open('tmp/foo', :test)
63
+ expect(Groovy.close(:test)).to eq(nil)
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,104 @@
1
+ require_relative './spec_helper'
2
+
3
+ describe Groovy::Model do
4
+
5
+ before :all do
6
+ Groovy.open('tmp/model', 'model_spec')
7
+ load_schema! 'model_spec'
8
+ end
9
+
10
+ after :all do
11
+ Groovy.close('model_spec')
12
+ end
13
+
14
+ after :each do
15
+ TestProduct.clear_query # otherwise next test will fail
16
+ end
17
+
18
+ describe '.schema' do
19
+ end
20
+
21
+ describe '.scope' do
22
+
23
+ before :all do
24
+ TestProduct.class_eval do
25
+ scope :with_name, -> (name) { where(name: name) if name }
26
+ scope :by_price_asc, -> { sort_by(price: :asc) }
27
+ scope :cheapest, -> { by_price_asc }
28
+ end
29
+ end
30
+
31
+ it 'does not perform query by default' do
32
+ expect(TestProduct.table).not_to receive(:select)
33
+ TestProduct.with_name('foo')
34
+ end
35
+
36
+ describe 'chaining' do
37
+
38
+ it 'allow chaining (even if methods dont return the query)' do
39
+ expect do
40
+ TestProduct.with_name('foo').by_price_asc.cheapest
41
+ end.not_to raise_error
42
+ end
43
+
44
+ it 'does not duplicate params' do
45
+ res = TestProduct.with_name('foo').by_price_asc.cheapest
46
+ res.query
47
+ expect(res.query.parameters).to eq(["+name:foo"])
48
+ expect(res.query.sorting).to eq(:by=>[{:key=>"price", :order=>:asc}], :limit=>-1, :offset=>0)
49
+ end
50
+
51
+ end
52
+
53
+ end
54
+
55
+ describe '.create' do
56
+ end
57
+
58
+ describe '.find' do
59
+ end
60
+
61
+ describe '.find_by' do
62
+ end
63
+
64
+ describe '.delete_all' do
65
+ end
66
+
67
+ describe '#[]' do
68
+ end
69
+
70
+ describe '#[]=' do
71
+ end
72
+
73
+ describe '#increment' do
74
+ end
75
+
76
+ describe '#dirty' do
77
+ end
78
+
79
+ describe '#update_attributes' do
80
+ end
81
+
82
+ describe '#save' do
83
+ end
84
+
85
+ describe '#delete' do
86
+ end
87
+
88
+ describe '#reload' do
89
+ end
90
+
91
+ describe 'attributes accessors' do
92
+
93
+ end
94
+
95
+ describe 'singular refs' do
96
+
97
+ end
98
+
99
+ describe 'plural refs' do
100
+
101
+ end
102
+
103
+ end
104
+
@@ -0,0 +1,204 @@
1
+ require_relative './spec_helper'
2
+
3
+ describe Groovy::Query do
4
+
5
+ before :all do
6
+ Groovy.open('tmp/querying', 'query_spec')
7
+ load_schema! 'query_spec'
8
+ @p1 = TestProduct.create!(name: "Product 1", visible: true, price: 10, tag_list: 'one, number two, and three')
9
+ @p2 = TestProduct.create!(name: "Product 2", visible: false, price: 20, tag_list: 'number two, three')
10
+ @p3 = TestProduct.create!(name: "Product 3", visible: true, price: 30, tag_list: nil)
11
+ @p4 = TestProduct.create!(name: "Product 4", visible: false, price: 40, tag_list: 'one, number two')
12
+ @p5 = TestProduct.create!(name: "Product 5", visible: true, price: 50, tag_list: '')
13
+ end
14
+
15
+ after :all do
16
+ Groovy.close('query_spec')
17
+ end
18
+
19
+ describe '#where' do
20
+ describe 'nil value' do
21
+ it 'finds expected records' do
22
+ res = TestProduct.where(tag_list: nil)
23
+ expect(res.map(&:id)).to eq([@p3.id, @p5.id])
24
+ end
25
+ it 'works with other args too' do
26
+ res = TestProduct.where(name: 'Product 5').where(tag_list: nil)
27
+ expect(res.map(&:id)).to eq([@p5.id])
28
+ end
29
+ end
30
+
31
+ describe 'empty string value' do
32
+ it 'finds expected records' do
33
+ res = TestProduct.where(tag_list: '')
34
+ expect(res.map(&:id)).to eq([@p3.id, @p5.id])
35
+ end
36
+ it 'works with other args too' do
37
+ res = TestProduct.where(name: 'Product 5').where(tag_list: '')
38
+ expect(res.map(&:id)).to eq([@p5.id])
39
+ end
40
+ end
41
+
42
+ describe 'exact search' do
43
+ it 'finds expected records' do
44
+ res = TestProduct.where(name: 'Product 2')
45
+ expect(res.map(&:id)).to eq([@p2.id])
46
+ end
47
+ end
48
+
49
+ context 'basic regex' do
50
+ it 'finds expected records' do
51
+ res = TestProduct.where(tag_list: /two/)
52
+ expect(res.map(&:id)).to eq([@p1.id, @p2.id, @p4.id])
53
+ end
54
+
55
+ it 'is not case-sensitive' do
56
+ res = TestProduct.where(tag_list: /TWO/)
57
+ expect(res.map(&:id)).to eq([@p1.id, @p2.id, @p4.id])
58
+ end
59
+ end
60
+
61
+ describe 'starts with regex' do
62
+ it 'finds expected records' do
63
+ res = TestProduct.where(name: /^product/)
64
+ # expect(res.map(&:id)).to eq([])
65
+ expect(res.map(&:id)).to eq([@p1.id, @p2.id, @p3.id, @p4.id, @p5.id])
66
+
67
+ res = TestProduct.where(name: /^Product/)
68
+ # expect(res.map(&:id)).to eq([])
69
+ expect(res.map(&:id)).to eq([@p1.id, @p2.id, @p3.id, @p4.id, @p5.id])
70
+ end
71
+ end
72
+
73
+ describe 'ends with regex' do
74
+ it 'finds expected records' do
75
+ res = TestProduct.where(tag_list: /three$/)
76
+ expect(res.map(&:id)).to eq([@p1.id, @p2.id])
77
+
78
+ # res = TestProduct.where(name: /THREE$/)
79
+ # expect(res.map(&:id)).to eq([])
80
+ # expect(res.map(&:id)).to eq([@p1.id, @p2.id, @p3.id])
81
+ # expect(res.map(&:id)).to eq([@p1.id, @p2.id, @p3.id, @p4.id, @p5.id])
82
+ end
83
+ end
84
+
85
+ context 'regex with spaces' do
86
+ it 'finds expected records' do
87
+ res = TestProduct.where(tag_list: /number two/)
88
+ expect(res.map(&:id)).to eq([@p1.id, @p2.id, @p4.id])
89
+ end
90
+
91
+ xit 'handles escaped chars correctly' do
92
+ res = TestProduct.where(tag_list: /number\stwo/)
93
+ expect(res.map(&:id)).to eq([@p1.id, @p2.id, @p4.id])
94
+ end
95
+ end
96
+
97
+ context 'array value' do
98
+ it 'finds expected records' do
99
+ res = TestProduct.where(_id: [@p1.id, @p3.id, @p5.id])
100
+ expect(res.map(&:id)).to eq([@p1.id, @p3.id, @p5.id])
101
+ end
102
+ end
103
+ end
104
+
105
+ describe '#not' do
106
+ describe 'nil value' do
107
+ it 'finds expected records' do
108
+ res = TestProduct.where.not(tag_list: nil)
109
+ expect(res.map(&:id)).to eq([@p1.id, @p2.id, @p4.id])
110
+ end
111
+ it 'works with other args too' do
112
+ res = TestProduct.where.not(name: 'Product 2').where.not(tag_list: nil)
113
+ expect(res.map(&:id)).to eq([@p1.id, @p4.id])
114
+ end
115
+ end
116
+
117
+ describe 'empty string value' do
118
+ it 'finds expected records' do
119
+ res = TestProduct.where.not(tag_list: '')
120
+ expect(res.map(&:id)).to eq([@p1.id, @p2.id, @p4.id])
121
+ end
122
+ it 'works with other args too' do
123
+ res = TestProduct.where.not(name: 'Product 2').where.not(tag_list: '')
124
+ expect(res.map(&:id)).to eq([@p1.id, @p4.id])
125
+ end
126
+ end
127
+
128
+ describe 'exact search' do
129
+ it 'finds expected records' do
130
+ res = TestProduct.not(name: 'Product 2')
131
+ expect(res.map(&:id)).to eq([@p1.id, @p3.id, @p4.id, @p5.id])
132
+ end
133
+ end
134
+
135
+ context 'basic regex' do
136
+ it 'finds expected records' do
137
+ res = TestProduct.not(tag_list: /two/)
138
+ expect(res.map(&:id)).to eq([@p3.id, @p5.id])
139
+ end
140
+
141
+ it 'is not case-sensitive' do
142
+ res = TestProduct.not(tag_list: /TWO/)
143
+ expect(res.map(&:id)).to eq([@p3.id, @p5.id])
144
+ end
145
+ end
146
+
147
+ describe 'starts with regex' do
148
+ it 'finds expected records' do
149
+ res = TestProduct.not(name: /^product/)
150
+ expect(res.map(&:id)).to eq([])
151
+
152
+ res = TestProduct.not(name: /^Product/)
153
+ expect(res.map(&:id)).to eq([])
154
+ end
155
+ end
156
+
157
+ describe 'ends with regex' do
158
+ it 'finds expected records' do
159
+ res = TestProduct.not(tag_list: /three$/)
160
+ expect(res.map(&:id)).to eq([@p3.id, @p4.id, @p5.id])
161
+
162
+ # res = TestProduct.where(name: /THREE$/)
163
+ # expect(res.map(&:id)).to eq([])
164
+ # expect(res.map(&:id)).to eq([@p1.id, @p2.id, @p3.id])
165
+ # expect(res.map(&:id)).to eq([@p1.id, @p2.id, @p3.id, @p4.id, @p5.id])
166
+ end
167
+ end
168
+
169
+ context 'regex with spaces' do
170
+ it 'finds expected records' do
171
+ res = TestProduct.not(tag_list: /number two/)
172
+ expect(res.map(&:id)).to eq([@p3.id, @p5.id])
173
+ end
174
+
175
+ xit 'handles escaped chars correctly' do
176
+ res = TestProduct.not(tag_list: /number\stwo/)
177
+ expect(res.map(&:id)).to eq([@p1.id, @p2.id, @p4.id])
178
+ end
179
+ end
180
+
181
+ context 'array value' do
182
+ it 'finds expected records' do
183
+ res = TestProduct.not(_id: [@p1.id, @p3.id, @p5.id])
184
+ expect(res.map(&:id)).to eq([@p2.id, @p4.id])
185
+ end
186
+ end
187
+ end
188
+
189
+ describe '#limit' do
190
+ end
191
+
192
+ describe '#offset' do
193
+ end
194
+
195
+ describe '#in_batches' do
196
+ end
197
+
198
+ describe '#paginate' do
199
+ end
200
+
201
+ describe '#sort_by' do
202
+ end
203
+
204
+ end
@@ -0,0 +1,29 @@
1
+ require 'bundler'
2
+ Bundler.require(:default, :test)
3
+
4
+ require 'rspec/core'
5
+ require './lib/groovy'
6
+
7
+ RSpec.configure do |config|
8
+ config.before(:each) do
9
+ # Groonga::Context.default = nil
10
+ end
11
+ config.after(:suite) do
12
+ FileUtils.rm_rf('tmp')
13
+ end
14
+ end
15
+
16
+ class TestProduct
17
+ include Groovy::Model
18
+ end
19
+
20
+ def load_schema!(context_name)
21
+ TestProduct.load_schema context: context_name do |t|
22
+ t.boolean :visible
23
+ t.string :name
24
+ t.integer :price
25
+ t.string :tag_list
26
+ end
27
+ end
28
+
29
+ # load_schema!
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: groovy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
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: 2019-05-03 00:00:00.000000000 Z
11
+ date: 2019-05-09 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rroonga
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '7.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '7.1'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: bundler
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -25,19 +39,39 @@ dependencies:
25
39
  - !ruby/object:Gem::Version
26
40
  version: 1.0.0
27
41
  - !ruby/object:Gem::Dependency
28
- name: rroonga
42
+ name: rspec
29
43
  requirement: !ruby/object:Gem::Requirement
30
44
  requirements:
31
45
  - - "~>"
32
46
  - !ruby/object:Gem::Version
33
- version: '7.1'
34
- type: :runtime
47
+ version: '3.0'
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: 3.0.0
51
+ type: :development
35
52
  prerelease: false
36
53
  version_requirements: !ruby/object:Gem::Requirement
37
54
  requirements:
38
55
  - - "~>"
39
56
  - !ruby/object:Gem::Version
40
- version: '7.1'
57
+ version: '3.0'
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: 3.0.0
61
+ - !ruby/object:Gem::Dependency
62
+ name: fuubar
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: 2.3.2
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: 2.3.2
41
75
  description: Allows using Groonga in your models a-la ActiveRecord.
42
76
  email:
43
77
  - tomas@forkhq.com
@@ -63,6 +97,9 @@ files:
63
97
  - lib/groovy/vector.rb
64
98
  - lib/groovy/version.rb
65
99
  - spec/groovy_spec.rb
100
+ - spec/model_spec.rb
101
+ - spec/query_spec.rb
102
+ - spec/spec_helper.rb
66
103
  homepage: https://github.com/tomas/groovy
67
104
  licenses: []
68
105
  metadata: {}