sequel 0.1.5 → 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +22 -0
- data/Rakefile +1 -1
- data/lib/sequel/core_ext.rb +10 -0
- data/lib/sequel/dataset.rb +39 -4
- data/lib/sequel/model.rb +27 -21
- data/lib/sequel/odbc.rb +1 -1
- data/lib/sequel/pretty_table.rb +3 -3
- data/lib/sequel/sqlite.rb +4 -1
- metadata +2 -3
data/CHANGELOG
CHANGED
@@ -1,3 +1,25 @@
|
|
1
|
+
*0.1.6*
|
2
|
+
|
3
|
+
* Fixed Model#method_missing to raise for an invalid attribute.
|
4
|
+
|
5
|
+
* Fixed PrettyTable to print model objects (thanks snok.)
|
6
|
+
|
7
|
+
* Fixed ODBC timestamp conversion to return DateTime rather than Time object (thanks snok.)
|
8
|
+
|
9
|
+
* Fixed Model.method_missing (thanks snok.)
|
10
|
+
|
11
|
+
* Model.method_missing now creates stubs for calling Model.dataset methods. Methods like Model.each etc are removed.
|
12
|
+
|
13
|
+
* Changed default join type to INNER JOIN (thanks snok.)
|
14
|
+
|
15
|
+
* Added support for literal expressions, e.g. DB[:items].filter(:col1 => 'col2 - 10'.expr).
|
16
|
+
|
17
|
+
* Added Dataset#and.
|
18
|
+
|
19
|
+
* SQLite adapter opens a memory DB if no database is specified, e.g. Sequel.open 'sqlite:/'.
|
20
|
+
|
21
|
+
* Added Dataset#or, pretty nifty.
|
22
|
+
|
1
23
|
*0.1.5*
|
2
24
|
|
3
25
|
* Fixed Dataset#join to support multiple joins. Added #left_outer_join, #right_outer_join, #full_outer_join, #inner_join methods.
|
data/Rakefile
CHANGED
@@ -6,7 +6,7 @@ require 'fileutils'
|
|
6
6
|
include FileUtils
|
7
7
|
|
8
8
|
NAME = "sequel"
|
9
|
-
VERS = "0.1.
|
9
|
+
VERS = "0.1.6"
|
10
10
|
CLEAN.include ['**/.*.sw?', 'pkg/*', '.config', 'doc/*', 'coverage/*']
|
11
11
|
RDOC_OPTS = ['--quiet', '--title', "Sequel: Concise ORM for Ruby",
|
12
12
|
"--opname", "index.html",
|
data/lib/sequel/core_ext.rb
CHANGED
@@ -15,6 +15,11 @@ class Array
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
+
module Sequel
|
19
|
+
class ExpressionString < ::String
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
18
23
|
# String extensions
|
19
24
|
class String
|
20
25
|
# Converts a string into an SQL string by removing comments.
|
@@ -28,4 +33,9 @@ class String
|
|
28
33
|
def split_sql
|
29
34
|
to_sql.split(';').map {|s| s.strip}
|
30
35
|
end
|
36
|
+
|
37
|
+
# Convert a string into an Expression String
|
38
|
+
def expr
|
39
|
+
Sequel::ExpressionString.new(self)
|
40
|
+
end
|
31
41
|
end
|
data/lib/sequel/dataset.rb
CHANGED
@@ -112,6 +112,7 @@ module Sequel
|
|
112
112
|
# If an unsupported object is given, an exception is raised.
|
113
113
|
def literal(v)
|
114
114
|
case v
|
115
|
+
when ExpressionString: v
|
115
116
|
when String: "'#{v.gsub(/'/, "''")}'"
|
116
117
|
when Integer, Float: v.to_s
|
117
118
|
when NilClass: NULL
|
@@ -208,6 +209,9 @@ module Sequel
|
|
208
209
|
fmt = where.to_expressions.map {|e| format_expression(e.left, e.op, e.right)}.
|
209
210
|
join(AND_SEPARATOR)
|
210
211
|
else
|
212
|
+
# if the expression is compound, it should be parenthesized in order for
|
213
|
+
# things to be predictable (when using #or and #and.)
|
214
|
+
parenthesize |= where =~ /\).+\(/
|
211
215
|
fmt = where
|
212
216
|
end
|
213
217
|
parenthesize ? "(#{fmt})" : fmt
|
@@ -298,6 +302,32 @@ module Sequel
|
|
298
302
|
dup_merge(clause => expression_list(block || cond))
|
299
303
|
end
|
300
304
|
end
|
305
|
+
|
306
|
+
# Adds an alternate filter to an existing filter using OR. If no filter
|
307
|
+
# exists an error is raised.
|
308
|
+
def or(*cond, &block)
|
309
|
+
clause = (@opts[:group] ? :having : :where)
|
310
|
+
cond = cond.first if cond.size == 1
|
311
|
+
parenthesize = !(cond.is_a?(Hash) || cond.is_a?(Array))
|
312
|
+
if @opts[clause]
|
313
|
+
l = expression_list(@opts[clause])
|
314
|
+
r = expression_list(block || cond, parenthesize)
|
315
|
+
dup_merge(clause => "#{l} OR #{r}")
|
316
|
+
else
|
317
|
+
raise SequelError, "No existing filter found."
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
# Adds an further filter to an existing filter using AND. If no filter
|
322
|
+
# exists an error is raised. This method is identical to #filter except
|
323
|
+
# it expects an existing filter.
|
324
|
+
def and(*cond, &block)
|
325
|
+
clause = (@opts[:group] ? :having : :where)
|
326
|
+
unless @opts[clause]
|
327
|
+
raise SequelError, "No existing filter found."
|
328
|
+
end
|
329
|
+
filter(*cond, &block)
|
330
|
+
end
|
301
331
|
|
302
332
|
# Performs the inverse of Dataset#filter.
|
303
333
|
#
|
@@ -337,14 +367,20 @@ module Sequel
|
|
337
367
|
end
|
338
368
|
end
|
339
369
|
|
370
|
+
# Adds a UNION clause using a second dataset object. If all is true the
|
371
|
+
# clause used is UNION ALL, which may return duplicate rows.
|
340
372
|
def union(dataset, all = false)
|
341
373
|
dup_merge(:union => dataset, :union_all => all)
|
342
374
|
end
|
343
375
|
|
376
|
+
# Adds an INTERSECT clause using a second dataset object. If all is true
|
377
|
+
# the clause used is INTERSECT ALL, which may return duplicate rows.
|
344
378
|
def intersect(dataset, all = false)
|
345
379
|
dup_merge(:intersect => dataset, :intersect_all => all)
|
346
380
|
end
|
347
381
|
|
382
|
+
# Adds an EXCEPT clause using a second dataset object. If all is true the
|
383
|
+
# clause used is EXCEPT ALL, which may return duplicate rows.
|
348
384
|
def except(dataset, all = false)
|
349
385
|
dup_merge(:except => dataset, :except_all => all)
|
350
386
|
end
|
@@ -357,7 +393,7 @@ module Sequel
|
|
357
393
|
}
|
358
394
|
|
359
395
|
def join_expr(type, table, expr)
|
360
|
-
join_type = JOIN_TYPES[type || :
|
396
|
+
join_type = JOIN_TYPES[type || :inner]
|
361
397
|
unless join_type
|
362
398
|
raise SequelError, "Invalid join type: #{type}"
|
363
399
|
end
|
@@ -382,13 +418,12 @@ module Sequel
|
|
382
418
|
end
|
383
419
|
|
384
420
|
def left_outer_join(table, expr); join_table(:left_outer, table, expr); end
|
385
|
-
alias_method :join, :left_outer_join
|
386
421
|
def right_outer_join(table, expr); join_table(:right_outer, table, expr); end
|
387
422
|
def full_outer_join(table, expr); join_table(:full_outer, table, expr); end
|
388
423
|
def inner_join(table, expr); join_table(:inner, table, expr); end
|
424
|
+
alias_method :join, :inner_join
|
389
425
|
|
390
|
-
|
391
|
-
alias all to_a
|
426
|
+
alias_method :all, :to_a
|
392
427
|
|
393
428
|
# Maps field values for each record in the dataset (if a field name is
|
394
429
|
# given), or performs the stock mapping functionality of Enumerable.
|
data/lib/sequel/model.rb
CHANGED
@@ -21,9 +21,9 @@ module Sequel
|
|
21
21
|
def self.dataset
|
22
22
|
return @dataset if @dataset
|
23
23
|
if !table_name
|
24
|
-
raise
|
24
|
+
raise SequelError, "Table name not specified for #{self}."
|
25
25
|
elsif !db
|
26
|
-
raise
|
26
|
+
raise SequelError, "Database not specified for #{self}."
|
27
27
|
end
|
28
28
|
@dataset = db[table_name]
|
29
29
|
@dataset.model_class = self
|
@@ -190,21 +190,21 @@ module Sequel
|
|
190
190
|
|
191
191
|
def refresh
|
192
192
|
@values = self.class.dataset.naked[primary_key => @pkey] ||
|
193
|
-
(raise
|
193
|
+
(raise SequelError, "Record not found")
|
194
194
|
self
|
195
195
|
end
|
196
196
|
|
197
|
-
def self.each(&block); dataset.each(&block); end
|
198
|
-
def self.all; dataset.all; end
|
199
|
-
def self.filter(*arg, &block); dataset.filter(*arg, &block); end
|
200
|
-
def self.exclude(*arg, &block); dataset.exclude(*arg, &block); end
|
201
|
-
def self.order(*arg); dataset.order(*arg); end
|
202
|
-
def self.first(*arg); dataset.first(*arg); end
|
203
|
-
def self.count; dataset.count; end
|
204
|
-
def self.map(*arg, &block); dataset.map(*arg, &block); end
|
205
|
-
def self.hash_column(column); dataset.hash_column(primary_key, column); end
|
206
|
-
def self.join(*args); dataset.join(*args); end
|
207
|
-
def self.lock(mode, &block); dataset.lock(mode, &block); end
|
197
|
+
# def self.each(&block); dataset.each(&block); end
|
198
|
+
# def self.all; dataset.all; end
|
199
|
+
# def self.filter(*arg, &block); dataset.filter(*arg, &block); end
|
200
|
+
# def self.exclude(*arg, &block); dataset.exclude(*arg, &block); end
|
201
|
+
# def self.order(*arg); dataset.order(*arg); end
|
202
|
+
# def self.first(*arg); dataset.first(*arg); end
|
203
|
+
# def self.count; dataset.count; end
|
204
|
+
# def self.map(*arg, &block); dataset.map(*arg, &block); end
|
205
|
+
# def self.hash_column(column); dataset.hash_column(primary_key, column); end
|
206
|
+
# def self.join(*args); dataset.join(*args); end
|
207
|
+
# def self.lock(mode, &block); dataset.lock(mode, &block); end
|
208
208
|
def self.destroy_all
|
209
209
|
has_hooks?(:before_destroy) ? dataset.destroy : dataset.delete
|
210
210
|
end
|
@@ -233,7 +233,7 @@ module Sequel
|
|
233
233
|
FILTER_BY_REGEXP = /^filter_by_(.*)/.freeze
|
234
234
|
ALL_BY_REGEXP = /^all_by_(.*)/.freeze
|
235
235
|
|
236
|
-
def self.method_missing(m, *args)
|
236
|
+
def self.method_missing(m, *args, &block)
|
237
237
|
Thread.exclusive do
|
238
238
|
method_name = m.to_s
|
239
239
|
if method_name =~ FIND_BY_REGEXP
|
@@ -245,9 +245,11 @@ module Sequel
|
|
245
245
|
elsif method_name =~ ALL_BY_REGEXP
|
246
246
|
c = $1
|
247
247
|
meta_def(method_name) {|arg| filter(c => arg).all}
|
248
|
+
elsif dataset.respond_to?(m)
|
249
|
+
instance_eval("def #{m}(*args, &block); dataset.#{m}(*args, &block); end")
|
248
250
|
end
|
249
251
|
end
|
250
|
-
respond_to?(m) ? send(m, *args) : super(m, *args)
|
252
|
+
respond_to?(m) ? send(m, *args, &block) : super(m, *args)
|
251
253
|
end
|
252
254
|
|
253
255
|
def db; self.class.db; end
|
@@ -259,13 +261,17 @@ module Sequel
|
|
259
261
|
WRITE_ATTR_REGEXP = /(.*)=$/.freeze
|
260
262
|
|
261
263
|
def method_missing(m, value = nil)
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
264
|
+
write = m.to_s =~ WRITE_ATTR_REGEXP
|
265
|
+
att = write ? $1.to_sym : m
|
266
|
+
# raise unless the att is recognized or this is a new unaved record
|
267
|
+
super unless @values.include?(att) || !@pkey
|
268
|
+
|
269
|
+
write ? (self[att] = value) : self[att]
|
267
270
|
end
|
268
271
|
|
272
|
+
def each(&block); @values.each(&block); end
|
273
|
+
def keys; @values.keys; end
|
274
|
+
|
269
275
|
def id; @values[:id]; end
|
270
276
|
|
271
277
|
def save
|
data/lib/sequel/odbc.rb
CHANGED
@@ -80,7 +80,7 @@ module Sequel
|
|
80
80
|
# ODBCColumn#mapSqlTypeToGenericType and Column#klass.
|
81
81
|
case v
|
82
82
|
when ::ODBC::TimeStamp
|
83
|
-
|
83
|
+
DateTime.new(v.year, v.month, v.day, v.hour, v.minute, v.second)
|
84
84
|
when ::ODBC::Time
|
85
85
|
DateTime.now
|
86
86
|
Time.gm(now.year, now.month, now.day, v.hour, v.minute, v.second)
|
data/lib/sequel/pretty_table.rb
CHANGED
@@ -23,9 +23,9 @@ module Sequel
|
|
23
23
|
sizes[c.to_sym] = s if s > sizes[c.to_sym]
|
24
24
|
end
|
25
25
|
records.each do |r|
|
26
|
-
|
27
|
-
s =
|
28
|
-
sizes[
|
26
|
+
columns.each do |c|
|
27
|
+
s = r[c].to_s.size
|
28
|
+
sizes[c.to_sym] = s if s > sizes[c.to_sym]
|
29
29
|
end
|
30
30
|
end
|
31
31
|
sizes
|
data/lib/sequel/sqlite.rb
CHANGED
@@ -11,7 +11,10 @@ module Sequel
|
|
11
11
|
set_adapter_scheme :sqlite
|
12
12
|
|
13
13
|
def connect
|
14
|
-
|
14
|
+
if @opts[:database].empty?
|
15
|
+
@opts[:database] = ':memory:'
|
16
|
+
end
|
17
|
+
db = ::SQLite3::Database.new(@opts[:database])
|
15
18
|
db.type_translation = true
|
16
19
|
db
|
17
20
|
end
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
|
|
3
3
|
specification_version: 1
|
4
4
|
name: sequel
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.1.
|
7
|
-
date: 2007-
|
6
|
+
version: 0.1.6
|
7
|
+
date: 2007-06-01 00:00:00 +03:00
|
8
8
|
summary: Concise ORM for Ruby.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -33,7 +33,6 @@ files:
|
|
33
33
|
- README
|
34
34
|
- Rakefile
|
35
35
|
- bin/sequel
|
36
|
-
- doc/rdoc
|
37
36
|
- lib/sequel
|
38
37
|
- lib/sequel.rb
|
39
38
|
- lib/sequel/connection_pool.rb
|