sequel_core 1.0.10 → 1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|