sequel_core 1.0.10 → 1.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.
- data/CHANGELOG +18 -0
- data/Rakefile +1 -1
- data/lib/sequel_core/adapters/mysql.rb +4 -27
- data/lib/sequel_core/adapters/postgres.rb +21 -1
- data/lib/sequel_core/database.rb +11 -0
- data/lib/sequel_core/dataset/convenience.rb +43 -18
- data/lib/sequel_core/dataset/sql.rb +30 -3
- data/spec/adapters/mysql_spec.rb +15 -0
- data/spec/adapters/postgres_spec.rb +34 -1
- data/spec/database_spec.rb +22 -0
- data/spec/dataset_spec.rb +145 -14
- metadata +2 -2
data/CHANGELOG
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
=== 1.1 (2008-02-15)
|
2
|
+
|
3
|
+
* Fixed Dataset#join_table to support joining of datasets (#156).
|
4
|
+
|
5
|
+
* Changed Dataset#empty? to use EXISTS condition instead of counting records, for much better performance (#158).
|
6
|
+
|
7
|
+
* Implemented insertion of multiple records in a single statement for postgres adapter. This feature is available only in postgres 8.2 and newer.
|
8
|
+
|
9
|
+
* Implemented Postgres::Database#server_version.
|
10
|
+
|
11
|
+
* Implemented Database#get, short for dataset.get(...).
|
12
|
+
|
13
|
+
* Refactored Dataset#multi_insert, added #import alias, added support for calling #multi_insert using array of columns and array of value arrays (thanks David Lee).
|
14
|
+
|
15
|
+
* Implemented Dataset#get, a replacement for select(column).first[column].
|
16
|
+
|
17
|
+
* Implemented Dataset#grep method, poor man's text search.
|
18
|
+
|
1
19
|
=== 1.0.10 (2008-02-13)
|
2
20
|
|
3
21
|
* Fixed Datset#group_and_count to work inside a query block (#152).
|
data/Rakefile
CHANGED
@@ -9,7 +9,7 @@ include FileUtils
|
|
9
9
|
# Configuration
|
10
10
|
##############################################################################
|
11
11
|
NAME = "sequel_core"
|
12
|
-
VERS = "1.
|
12
|
+
VERS = "1.1"
|
13
13
|
CLEAN.include ["**/.*.sw?", "pkg/*", ".config", "doc/*", "coverage/*"]
|
14
14
|
RDOC_OPTS = [
|
15
15
|
"--quiet",
|
@@ -358,33 +358,10 @@ module Sequel
|
|
358
358
|
self
|
359
359
|
end
|
360
360
|
|
361
|
-
def multi_insert_sql(
|
362
|
-
|
363
|
-
|
364
|
-
"INSERT INTO #{@opts[:from]} (#{columns}) VALUES #{values}"
|
365
|
-
end
|
366
|
-
|
367
|
-
# Inserts multiple records into the associated table. This method can be
|
368
|
-
# to efficiently insert a large amounts of records into a table. Inserts
|
369
|
-
# are automatically wrapped in a transaction. If the :commit_every
|
370
|
-
# option is specified, the method will generate a separate transaction
|
371
|
-
# for each batch of records, e.g.:
|
372
|
-
#
|
373
|
-
# dataset.multi_insert(list, :commit_every => 1000)
|
374
|
-
def multi_insert(list, opts = {})
|
375
|
-
keys = list.first.keys
|
376
|
-
|
377
|
-
if every = (opts[:commit_every] || opts[:slice])
|
378
|
-
list.each_slice(every) do |s|
|
379
|
-
@db.transaction do
|
380
|
-
@db.execute(multi_insert_sql(keys, s))
|
381
|
-
end
|
382
|
-
end
|
383
|
-
else
|
384
|
-
@db.transaction do
|
385
|
-
@db.execute(multi_insert_sql(keys, list))
|
386
|
-
end
|
387
|
-
end
|
361
|
+
def multi_insert_sql(columns, values)
|
362
|
+
columns = literal(columns)
|
363
|
+
values = values.map {|r| "(#{literal(r)})"}.join(COMMA_SEPARATOR)
|
364
|
+
["INSERT INTO #{@opts[:from]} (#{columns}) VALUES #{values}"]
|
388
365
|
end
|
389
366
|
end
|
390
367
|
end
|
@@ -263,6 +263,17 @@ module Sequel
|
|
263
263
|
end
|
264
264
|
end
|
265
265
|
|
266
|
+
def server_version
|
267
|
+
@server_version ||= pool.hold do |conn|
|
268
|
+
if conn.respond_to?(:server_version)
|
269
|
+
pool.hold {|c| c.server_version}
|
270
|
+
else
|
271
|
+
get(:version[]) =~ /PostgreSQL (\d+)\.(\d+)\.(\d+)/
|
272
|
+
($1.to_i * 10000) + ($2.to_i * 100) + $3.to_i
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
266
277
|
def execute_insert(sql, table, values)
|
267
278
|
@logger.info(sql) if @logger
|
268
279
|
@pool.hold do |conn|
|
@@ -428,7 +439,16 @@ module Sequel
|
|
428
439
|
end
|
429
440
|
end
|
430
441
|
end
|
431
|
-
|
442
|
+
|
443
|
+
def multi_insert_sql(columns, values)
|
444
|
+
return super if @db.server_version < 80200
|
445
|
+
|
446
|
+
# postgresql 8.2 introduces support for insert
|
447
|
+
columns = literal(columns)
|
448
|
+
values = values.map {|r| "(#{literal(r)})"}.join(COMMA_SEPARATOR)
|
449
|
+
["INSERT INTO #{@opts[:from]} (#{columns}) VALUES #{values}"]
|
450
|
+
end
|
451
|
+
|
432
452
|
def insert(*values)
|
433
453
|
@db.execute_insert(insert_sql(*values), @opts[:from],
|
434
454
|
values.size == 1 ? values.first : values)
|
data/lib/sequel_core/database.rb
CHANGED
@@ -135,6 +135,17 @@ module Sequel
|
|
135
135
|
(String === args.first) ? fetch(*args) : from(*args)
|
136
136
|
end
|
137
137
|
|
138
|
+
# Returns a single value from the database, e.g.:
|
139
|
+
#
|
140
|
+
# # SELECT 1
|
141
|
+
# DB.get(1) #=> 1
|
142
|
+
#
|
143
|
+
# # SELECT version()
|
144
|
+
# DB.get(:version[]) #=> ...
|
145
|
+
def get(expr)
|
146
|
+
dataset.get(expr)
|
147
|
+
end
|
148
|
+
|
138
149
|
# Raises a Sequel::Error::NotImplemented. This method is overriden in descendants.
|
139
150
|
def execute(sql)
|
140
151
|
raise NotImplementedError, "#execute should be overriden by adapters"
|
@@ -8,9 +8,10 @@ module Sequel
|
|
8
8
|
each {|a| block[a.to_hash]}
|
9
9
|
end
|
10
10
|
|
11
|
-
# Returns true if
|
11
|
+
# Returns true if no records exists in the dataset
|
12
12
|
def empty?
|
13
|
-
|
13
|
+
db.dataset.where(exists).get(1) == nil
|
14
|
+
# count == 0
|
14
15
|
end
|
15
16
|
|
16
17
|
# Returns the first record in the dataset.
|
@@ -29,6 +30,10 @@ module Sequel
|
|
29
30
|
each(opts) {|r| @columns = nil; return r.values.first}
|
30
31
|
nil
|
31
32
|
end
|
33
|
+
|
34
|
+
def get(column)
|
35
|
+
select(column).single_value
|
36
|
+
end
|
32
37
|
|
33
38
|
# Returns the first record in the dataset. If the num argument is specified,
|
34
39
|
# an array is returned with the first <i>num</i> records.
|
@@ -217,29 +222,49 @@ module Sequel
|
|
217
222
|
records.each {|r| csv << "#{r.join(COMMA_SEPARATOR)}\r\n"}
|
218
223
|
csv
|
219
224
|
end
|
220
|
-
|
225
|
+
|
221
226
|
# Inserts multiple records into the associated table. This method can be
|
222
227
|
# to efficiently insert a large amounts of records into a table. Inserts
|
223
|
-
# are automatically wrapped in a transaction.
|
224
|
-
#
|
225
|
-
#
|
228
|
+
# are automatically wrapped in a transaction.
|
229
|
+
#
|
230
|
+
# This method can be called either with an array of hashes:
|
231
|
+
#
|
232
|
+
# dataset.multi_insert({:x => 1}, {:x => 2})
|
226
233
|
#
|
227
|
-
#
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
234
|
+
# Or with a columns array and an array of value arrays:
|
235
|
+
#
|
236
|
+
# dataset.multi_insert([:x, :y], [[1, 2], [3, 4]])
|
237
|
+
#
|
238
|
+
# The method also accepts a :slice or :commit_every option that specifies
|
239
|
+
# the number of records to insert per transaction. This is useful especially
|
240
|
+
# when inserting a large number of records, e.g.:
|
241
|
+
#
|
242
|
+
# # this will commit every 50 records
|
243
|
+
# dataset.multi_insert(lots_of_records, :slice => 50)
|
244
|
+
def multi_insert(*args)
|
245
|
+
if args[0].is_a?(Array) && args[1].is_a?(Array)
|
246
|
+
columns, values, opts = *args
|
236
247
|
else
|
237
|
-
|
238
|
-
|
239
|
-
|
248
|
+
# we assume that an array of hashes is given
|
249
|
+
hashes, opts = *args
|
250
|
+
columns = hashes.first.keys
|
251
|
+
# convert the hashes into arrays
|
252
|
+
values = hashes.map {|h| columns.map {|c| h[c]}}
|
253
|
+
end
|
254
|
+
|
255
|
+
slice_size = opts && (opts[:commit_every] || opts[:slice])
|
256
|
+
|
257
|
+
if slice_size
|
258
|
+
values.each_slice(slice_size) do |slice|
|
259
|
+
statements = multi_insert_sql(columns, slice)
|
260
|
+
@db.transaction {statements.each {|st| @db.execute(st)}}
|
240
261
|
end
|
262
|
+
else
|
263
|
+
statements = multi_insert_sql(columns, values)
|
264
|
+
@db.transaction {statements.each {|st| @db.execute(st)}}
|
241
265
|
end
|
242
266
|
end
|
267
|
+
alias_method :import, :multi_insert
|
243
268
|
|
244
269
|
module QueryBlockCopy #:nodoc:
|
245
270
|
def each(*args); raise Error, "#each cannot be invoked inside a query block."; end
|
@@ -18,7 +18,9 @@ module Sequel
|
|
18
18
|
if s =~ QUALIFIED_REGEXP
|
19
19
|
return column
|
20
20
|
else
|
21
|
-
if (
|
21
|
+
if table.is_a?(Dataset)
|
22
|
+
table = :t1
|
23
|
+
elsif (table =~ ALIASED_REGEXP)
|
22
24
|
table = $2
|
23
25
|
end
|
24
26
|
Sequel::SQL::QualifiedColumnRef.new(table, column)
|
@@ -341,6 +343,14 @@ module Sequel
|
|
341
343
|
filter(*cond, &block)
|
342
344
|
end
|
343
345
|
end
|
346
|
+
|
347
|
+
def grep(cols, terms)
|
348
|
+
conds = [];
|
349
|
+
cols = [cols] unless cols.is_a?(Array)
|
350
|
+
terms = [terms] unless terms.is_a?(Array)
|
351
|
+
cols.each {|c| terms.each {|t| conds << match_expr(c, t)}}
|
352
|
+
filter(conds.join(' OR '))
|
353
|
+
end
|
344
354
|
|
345
355
|
# Adds a UNION clause using a second dataset object. If all is true the
|
346
356
|
# clause used is UNION ALL, which may return duplicate rows.
|
@@ -380,6 +390,9 @@ module Sequel
|
|
380
390
|
v = qualified_column_name(v, @opts[:last_joined_table] || first_source) if v.is_a?(Symbol)
|
381
391
|
join_conditions[k] = v
|
382
392
|
end
|
393
|
+
if table.is_a?(Dataset)
|
394
|
+
table = "(#{table.sql}) t1"
|
395
|
+
end
|
383
396
|
" #{join_type} #{table} ON #{expression_list(join_conditions)}"
|
384
397
|
end
|
385
398
|
|
@@ -524,6 +537,19 @@ module Sequel
|
|
524
537
|
end
|
525
538
|
end
|
526
539
|
end
|
540
|
+
|
541
|
+
# Returns an array of insert statements for inserting multiple records.
|
542
|
+
# This method is used by #multi_insert to format insert statements and
|
543
|
+
# expects a keys array and and an array of value arrays.
|
544
|
+
#
|
545
|
+
# This method may be overriden by descendants.
|
546
|
+
def multi_insert_sql(columns, values)
|
547
|
+
table = @opts[:from]
|
548
|
+
columns = literal(columns)
|
549
|
+
values.map do |r|
|
550
|
+
"INSERT INTO #{table} (#{columns}) VALUES (#{literal(r)})"
|
551
|
+
end
|
552
|
+
end
|
527
553
|
|
528
554
|
# Formats an UPDATE statement using the given values.
|
529
555
|
#
|
@@ -600,9 +626,10 @@ module Sequel
|
|
600
626
|
|
601
627
|
# Returns an EXISTS clause for the dataset.
|
602
628
|
#
|
603
|
-
#
|
629
|
+
# DB.select(1).where(DB[:items].exists).sql
|
630
|
+
# #=> "SELECT 1 WHERE EXISTS (SELECT * FROM items)"
|
604
631
|
def exists(opts = nil)
|
605
|
-
"EXISTS (#{
|
632
|
+
"EXISTS (#{select_sql(opts)})"
|
606
633
|
end
|
607
634
|
|
608
635
|
# If given an integer, the dataset will contain only the first l results.
|
data/spec/adapters/mysql_spec.rb
CHANGED
@@ -537,4 +537,19 @@ context "MySQL::Dataset#multi_insert" do
|
|
537
537
|
{:name => nil, :value => 4}
|
538
538
|
]
|
539
539
|
end
|
540
|
+
|
541
|
+
specify "should support inserting using columns and values arrays" do
|
542
|
+
@d.multi_insert([:name, :value], [['abc', 1], ['def', 2]])
|
543
|
+
|
544
|
+
MYSQL_DB.sqls.should == [
|
545
|
+
'BEGIN',
|
546
|
+
"INSERT INTO items (`name`, `value`) VALUES ('abc', 1), ('def', 2)",
|
547
|
+
'COMMIT'
|
548
|
+
]
|
549
|
+
|
550
|
+
@d.all.should == [
|
551
|
+
{:name => 'abc', :value => 1},
|
552
|
+
{:name => 'def', :value => 2}
|
553
|
+
]
|
554
|
+
end
|
540
555
|
end
|
@@ -24,6 +24,10 @@ context "A PostgreSQL database" do
|
|
24
24
|
@db.disconnect
|
25
25
|
@db.pool.size.should == 0
|
26
26
|
end
|
27
|
+
|
28
|
+
specify "should provide the server version" do
|
29
|
+
@db.server_version.should > 70000
|
30
|
+
end
|
27
31
|
end
|
28
32
|
|
29
33
|
context "A PostgreSQL dataset" do
|
@@ -246,7 +250,7 @@ context "A PostgreSQL database" do
|
|
246
250
|
end
|
247
251
|
end
|
248
252
|
|
249
|
-
context "A
|
253
|
+
context "A PostgreSQL database" do
|
250
254
|
setup do
|
251
255
|
end
|
252
256
|
|
@@ -284,4 +288,33 @@ context "A PostgreSSQL database" do
|
|
284
288
|
PGSQL_DB[:posts].full_text_search(:title, 'ruby', :language => 'french').sql.should ==
|
285
289
|
"SELECT * FROM posts WHERE (to_tsvector('french', \"title\") @@ to_tsquery('french', 'ruby'))"
|
286
290
|
end
|
291
|
+
end
|
292
|
+
|
293
|
+
context "Postgres::Dataset#multi_insert_sql / #import" do
|
294
|
+
setup do
|
295
|
+
@ds = PGSQL_DB[:test]
|
296
|
+
end
|
297
|
+
|
298
|
+
specify "should return separate insert statements if server_version < 80200" do
|
299
|
+
@ds.db.meta_def(:server_version) {80199}
|
300
|
+
|
301
|
+
@ds.multi_insert_sql([:x, :y], [[1, 2], [3, 4]]).should == [
|
302
|
+
'INSERT INTO test ("x", "y") VALUES (1, 2)',
|
303
|
+
'INSERT INTO test ("x", "y") VALUES (3, 4)'
|
304
|
+
]
|
305
|
+
end
|
306
|
+
|
307
|
+
specify "should a single insert statement if server_version >= 80200" do
|
308
|
+
@ds.db.meta_def(:server_version) {80200}
|
309
|
+
|
310
|
+
@ds.multi_insert_sql([:x, :y], [[1, 2], [3, 4]]).should == [
|
311
|
+
'INSERT INTO test ("x", "y") VALUES (1, 2), (3, 4)'
|
312
|
+
]
|
313
|
+
|
314
|
+
@ds.db.meta_def(:server_version) {80201}
|
315
|
+
|
316
|
+
@ds.multi_insert_sql([:x, :y], [[1, 2], [3, 4]]).should == [
|
317
|
+
'INSERT INTO test ("x", "y") VALUES (1, 2), (3, 4)'
|
318
|
+
]
|
319
|
+
end
|
287
320
|
end
|
data/spec/database_spec.rb
CHANGED
@@ -846,4 +846,26 @@ context "Database#inspect" do
|
|
846
846
|
specify "should include the class name and the connection url" do
|
847
847
|
@db.inspect.should == '#<DummyDatabase: "blah://blahblah/blah">'
|
848
848
|
end
|
849
|
+
end
|
850
|
+
|
851
|
+
context "Database#get" do
|
852
|
+
setup do
|
853
|
+
@c = Class.new(DummyDatabase) do
|
854
|
+
def dataset
|
855
|
+
ds = super
|
856
|
+
ds.meta_def(:get) {|c| @db.execute select(c).sql; c}
|
857
|
+
ds
|
858
|
+
end
|
859
|
+
end
|
860
|
+
|
861
|
+
@db = @c.new
|
862
|
+
end
|
863
|
+
|
864
|
+
specify "should use Dataset#get to get a single value" do
|
865
|
+
@db.get(1).should == 1
|
866
|
+
@db.sqls.last.should == 'SELECT 1'
|
867
|
+
|
868
|
+
@db.get(:version[])
|
869
|
+
@db.sqls.last.should == 'SELECT version()'
|
870
|
+
end
|
849
871
|
end
|
data/spec/dataset_spec.rb
CHANGED
@@ -342,7 +342,7 @@ context "Dataset#where" do
|
|
342
342
|
specify "should accept a subquery for an EXISTS clause" do
|
343
343
|
a = @dataset.filter {:price < 100}
|
344
344
|
@dataset.filter(a.exists).sql.should ==
|
345
|
-
'SELECT * FROM test WHERE EXISTS (SELECT
|
345
|
+
'SELECT * FROM test WHERE EXISTS (SELECT * FROM test WHERE (price < 100))'
|
346
346
|
end
|
347
347
|
|
348
348
|
specify "should accept proc expressions" do
|
@@ -1048,22 +1048,34 @@ context "Dataset#group_and_count" do
|
|
1048
1048
|
end
|
1049
1049
|
|
1050
1050
|
context "Dataset#empty?" do
|
1051
|
-
specify "should return true if
|
1052
|
-
@
|
1053
|
-
|
1054
|
-
|
1051
|
+
specify "should return true if records exist in the dataset" do
|
1052
|
+
@db = Sequel::Database.new
|
1053
|
+
@db.meta_def(:execute) {|sql| puts "blah";@sqls ||=[]; @sqls << sql}
|
1054
|
+
@db.meta_def(:sqls) {@sqls ||= []}
|
1055
|
+
|
1056
|
+
$cccc = Class.new(Sequel::Dataset) do
|
1057
|
+
def fetch_rows(sql)
|
1058
|
+
@db.execute(sql)
|
1059
|
+
yield(:x => 'blah')
|
1055
1060
|
end
|
1056
1061
|
end
|
1057
|
-
|
1058
|
-
@dataset
|
1059
|
-
|
1060
|
-
@c = Class.new(Sequel::Dataset) do
|
1061
|
-
def count
|
1062
|
-
1
|
1063
|
-
end
|
1062
|
+
|
1063
|
+
@db.meta_def(:dataset) do
|
1064
|
+
$cccc.new(self)
|
1064
1065
|
end
|
1065
|
-
|
1066
|
-
@dataset.
|
1066
|
+
|
1067
|
+
@dataset = Sequel::Dataset.new(@db).from(:test)
|
1068
|
+
|
1069
|
+
@dataset.should_not be_empty
|
1070
|
+
@db.sqls.last.should == 'SELECT 1 WHERE EXISTS (SELECT * FROM test)'
|
1071
|
+
|
1072
|
+
@db.meta_def(:dataset) do
|
1073
|
+
ds = $cccc.new(self)
|
1074
|
+
ds.meta_def(:get) {|c| nil}
|
1075
|
+
ds
|
1076
|
+
end
|
1077
|
+
|
1078
|
+
@dataset.should be_empty
|
1067
1079
|
end
|
1068
1080
|
end
|
1069
1081
|
|
@@ -1170,6 +1182,17 @@ context "Dataset#join_table" do
|
|
1170
1182
|
should raise_error(Sequel::Error)
|
1171
1183
|
end
|
1172
1184
|
|
1185
|
+
specify "should support joining datasets" do
|
1186
|
+
ds = Sequel::Dataset.new(nil).from(:categories)
|
1187
|
+
|
1188
|
+
@d.join_table(:left_outer, ds, :item_id => :id).sql.should ==
|
1189
|
+
'SELECT * FROM items LEFT OUTER JOIN (SELECT * FROM categories) t1 ON (t1.item_id = items.id)'
|
1190
|
+
|
1191
|
+
ds.filter!(:active => true)
|
1192
|
+
|
1193
|
+
@d.join_table(:left_outer, ds, :item_id => :id).sql.should ==
|
1194
|
+
'SELECT * FROM items LEFT OUTER JOIN (SELECT * FROM categories WHERE (active = \'t\')) t1 ON (t1.item_id = items.id)'
|
1195
|
+
end
|
1173
1196
|
end
|
1174
1197
|
|
1175
1198
|
context "Dataset#[]=" do
|
@@ -1575,7 +1598,34 @@ context "Dataset#single_value" do
|
|
1575
1598
|
specify "should return nil" do
|
1576
1599
|
@e.single_value.should be_nil
|
1577
1600
|
end
|
1601
|
+
end
|
1578
1602
|
|
1603
|
+
context "Dataset#get" do
|
1604
|
+
setup do
|
1605
|
+
@c = Class.new(Sequel::Dataset) do
|
1606
|
+
attr_reader :last_sql
|
1607
|
+
|
1608
|
+
def fetch_rows(sql)
|
1609
|
+
@last_sql = sql
|
1610
|
+
yield(:name => sql)
|
1611
|
+
end
|
1612
|
+
end
|
1613
|
+
|
1614
|
+
@d = @c.new(nil).from(:test)
|
1615
|
+
end
|
1616
|
+
|
1617
|
+
specify "should select the specified column and fetch its value" do
|
1618
|
+
@d.get(:name).should == "SELECT name FROM test"
|
1619
|
+
@d.get(:abc).should == "SELECT abc FROM test" # the first available value is returned always
|
1620
|
+
end
|
1621
|
+
|
1622
|
+
specify "should work with filters" do
|
1623
|
+
@d.filter(:id => 1).get(:name).should == "SELECT name FROM test WHERE (id = 1)"
|
1624
|
+
end
|
1625
|
+
|
1626
|
+
specify "should work with aliased fields" do
|
1627
|
+
@d.get(:x__b.as(:name)).should == "SELECT x.b AS name FROM test"
|
1628
|
+
end
|
1579
1629
|
end
|
1580
1630
|
|
1581
1631
|
context "Dataset#set_row_proc" do
|
@@ -2085,6 +2135,42 @@ context "Dataset#multi_insert" do
|
|
2085
2135
|
'COMMIT'
|
2086
2136
|
]
|
2087
2137
|
end
|
2138
|
+
|
2139
|
+
specify "should accept a columns array and a values array" do
|
2140
|
+
@ds.multi_insert([:x, :y], [[1, 2], [3, 4]])
|
2141
|
+
@db.sqls.should == [
|
2142
|
+
'BEGIN',
|
2143
|
+
"INSERT INTO items (x, y) VALUES (1, 2)",
|
2144
|
+
"INSERT INTO items (x, y) VALUES (3, 4)",
|
2145
|
+
'COMMIT'
|
2146
|
+
]
|
2147
|
+
end
|
2148
|
+
|
2149
|
+
specify "should accept a columns array and a values array with slice option" do
|
2150
|
+
@ds.multi_insert([:x, :y], [[1, 2], [3, 4], [5, 6]], :slice => 2)
|
2151
|
+
@db.sqls.should == [
|
2152
|
+
'BEGIN',
|
2153
|
+
"INSERT INTO items (x, y) VALUES (1, 2)",
|
2154
|
+
"INSERT INTO items (x, y) VALUES (3, 4)",
|
2155
|
+
'COMMIT',
|
2156
|
+
'BEGIN',
|
2157
|
+
"INSERT INTO items (x, y) VALUES (5, 6)",
|
2158
|
+
'COMMIT'
|
2159
|
+
]
|
2160
|
+
end
|
2161
|
+
|
2162
|
+
specify "should be aliased by #import" do
|
2163
|
+
@ds.import([:x, :y], [[1, 2], [3, 4], [5, 6]], :slice => 2)
|
2164
|
+
@db.sqls.should == [
|
2165
|
+
'BEGIN',
|
2166
|
+
"INSERT INTO items (x, y) VALUES (1, 2)",
|
2167
|
+
"INSERT INTO items (x, y) VALUES (3, 4)",
|
2168
|
+
'COMMIT',
|
2169
|
+
'BEGIN',
|
2170
|
+
"INSERT INTO items (x, y) VALUES (5, 6)",
|
2171
|
+
'COMMIT'
|
2172
|
+
]
|
2173
|
+
end
|
2088
2174
|
end
|
2089
2175
|
|
2090
2176
|
context "Dataset#query" do
|
@@ -2698,3 +2784,48 @@ context "Dataset#all" do
|
|
2698
2784
|
a.should == [1, 3, "SELECT * FROM items"]
|
2699
2785
|
end
|
2700
2786
|
end
|
2787
|
+
|
2788
|
+
context "Dataset#grep" do
|
2789
|
+
setup do
|
2790
|
+
@ds = Sequel::Dataset.new(nil).from(:posts)
|
2791
|
+
end
|
2792
|
+
|
2793
|
+
specify "should format a SQL filter correctly" do
|
2794
|
+
@ds.grep(:title, 'ruby').sql.should ==
|
2795
|
+
"SELECT * FROM posts WHERE (title LIKE 'ruby')"
|
2796
|
+
end
|
2797
|
+
|
2798
|
+
specify "should support multiple columns" do
|
2799
|
+
@ds.grep([:title, :body], 'ruby').sql.should ==
|
2800
|
+
"SELECT * FROM posts WHERE ((title LIKE 'ruby') OR (body LIKE 'ruby'))"
|
2801
|
+
end
|
2802
|
+
|
2803
|
+
specify "should support multiple search terms" do
|
2804
|
+
@ds.grep(:title, ['abc', 'def']).sql.should ==
|
2805
|
+
"SELECT * FROM posts WHERE ((title LIKE 'abc') OR (title LIKE 'def'))"
|
2806
|
+
end
|
2807
|
+
|
2808
|
+
specify "should support multiple columns and search terms" do
|
2809
|
+
@ds.grep([:title, :body], ['abc', 'def']).sql.should ==
|
2810
|
+
"SELECT * FROM posts WHERE ((title LIKE 'abc') OR (title LIKE 'def') OR (body LIKE 'abc') OR (body LIKE 'def'))"
|
2811
|
+
end
|
2812
|
+
|
2813
|
+
specify "should support regexps if the dataset allows it" do
|
2814
|
+
@ds.meta_def(:match_expr) do |l, r|
|
2815
|
+
case r
|
2816
|
+
when String
|
2817
|
+
"(#{literal(l)} LIKE #{literal(r)})"
|
2818
|
+
when Regexp
|
2819
|
+
"(#{literal(l)} =~ #{literal(r.source)})"
|
2820
|
+
else
|
2821
|
+
raise Sequel::Error, "Unsupported match pattern class (#{r.class})."
|
2822
|
+
end
|
2823
|
+
end
|
2824
|
+
|
2825
|
+
@ds.grep(:title, /ruby/).sql.should ==
|
2826
|
+
"SELECT * FROM posts WHERE (title =~ 'ruby')"
|
2827
|
+
|
2828
|
+
@ds.grep(:title, [/^ruby/, 'ruby']).sql.should ==
|
2829
|
+
"SELECT * FROM posts WHERE ((title =~ '^ruby') OR (title LIKE 'ruby'))"
|
2830
|
+
end
|
2831
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sequel_core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: "1.1"
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sharon Rosner
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-02-
|
12
|
+
date: 2008-02-15 00:00:00 +02:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|