sequel 0.0.8 → 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +12 -0
- data/README +5 -1
- data/Rakefile +1 -1
- data/lib/sequel/dataset.rb +21 -2
- data/lib/sequel/postgres.rb +68 -23
- data/lib/sequel/sqlite.rb +1 -4
- metadata +7 -7
data/CHANGELOG
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
*0.0.9*
|
2
|
+
|
3
|
+
* Fixed Postgres::Database#tables and #locks methods.
|
4
|
+
|
5
|
+
* Added PGconn#last_insert_id method that should support all 7.x and 8.x versions of Postgresql.
|
6
|
+
|
7
|
+
* Added Dataset#exists method for EXISTS where clauses.
|
8
|
+
|
9
|
+
* Changed behavior of Dataset#literal to regard symbols as field names.
|
10
|
+
|
11
|
+
* Refactored and DRY'd Dataset#literal and overrides therof. Added support for subqueries in where clause.
|
12
|
+
|
1
13
|
*0.0.8*
|
2
14
|
|
3
15
|
* Fixed Dataset#reverse_order to provide chainability. This method can be called without arguments to invert the current order or with arguments to provide a descending order.
|
data/README
CHANGED
@@ -146,7 +146,11 @@ You can then retrieve the records by using any of the retrieval methods:
|
|
146
146
|
You can also specify a custom WHERE clause:
|
147
147
|
|
148
148
|
posts.filter('(stamp < ?) AND (author <> ?)', 3.days.ago, author_name)
|
149
|
-
|
149
|
+
|
150
|
+
Datasets can also be used as subqueries for filtering:
|
151
|
+
|
152
|
+
expensive_stuff = DB[:items].filter(:price => DB[:items].select('AVG(price) + 100'))
|
153
|
+
|
150
154
|
=== Summarizing Records
|
151
155
|
|
152
156
|
Counting records is easy:
|
data/Rakefile
CHANGED
@@ -6,7 +6,7 @@ require 'fileutils'
|
|
6
6
|
include FileUtils
|
7
7
|
|
8
8
|
NAME = "sequel"
|
9
|
-
VERS = "0.0.
|
9
|
+
VERS = "0.0.9"
|
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/dataset.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'time'
|
2
|
+
|
1
3
|
module Sequel
|
2
4
|
# A Dataset represents a view of a the data in a database, constrained by
|
3
5
|
# specific parameters such as filtering conditions, order, etc. Datasets
|
@@ -100,9 +102,13 @@ module Sequel
|
|
100
102
|
# of an SQL expression. This method is overriden in descendants.
|
101
103
|
def literal(v)
|
102
104
|
case v
|
103
|
-
when String: "'%s'" % v
|
105
|
+
when String: "'%s'" % v.gsub(/'/, "''")
|
106
|
+
when Integer, Float: v.to_s
|
107
|
+
when NilClass: NULL
|
108
|
+
when Symbol: v.to_field_name
|
104
109
|
when Array: v.empty? ? NULL : v.join(COMMA_SEPARATOR)
|
105
|
-
else
|
110
|
+
else
|
111
|
+
raise "can't express #{v.inspect}:#{v.class} as a SQL literal"
|
106
112
|
end
|
107
113
|
end
|
108
114
|
|
@@ -123,6 +129,8 @@ module Sequel
|
|
123
129
|
# BETWEEN_EXPR % [field_name(left), literal(right.begin), literal(right.end)]
|
124
130
|
when Array:
|
125
131
|
IN_EXPR % [left, literal(right)]
|
132
|
+
when self.class:
|
133
|
+
IN_EXPR % [left, right.sql]
|
126
134
|
else
|
127
135
|
EQUAL_COND % [left, literal(right)]
|
128
136
|
end
|
@@ -358,6 +366,16 @@ module Sequel
|
|
358
366
|
select(field.SUM).first.values.first
|
359
367
|
end
|
360
368
|
|
369
|
+
def avg(field)
|
370
|
+
select(field.AVG).first.values.first
|
371
|
+
end
|
372
|
+
|
373
|
+
EXISTS_EXPR = "EXISTS (%s)".freeze
|
374
|
+
|
375
|
+
def exists(opts = nil)
|
376
|
+
EXISTS_EXPR % sql({:select => 1}.merge(opts || {}))
|
377
|
+
end
|
378
|
+
|
361
379
|
LIMIT_1 = {:limit => 1}.freeze
|
362
380
|
|
363
381
|
def limit(l)
|
@@ -410,6 +428,7 @@ class Symbol
|
|
410
428
|
def MIN; "min(#{to_field_name})"; end
|
411
429
|
def MAX; "max(#{to_field_name})"; end
|
412
430
|
def SUM; "sum(#{to_field_name})"; end
|
431
|
+
def AVG; "avg(#{to_field_name})"; end
|
413
432
|
|
414
433
|
AS_REGEXP = /(.*)___(.*)/.freeze
|
415
434
|
AS_FORMAT = "%s AS %s".freeze
|
data/lib/sequel/postgres.rb
CHANGED
@@ -65,6 +65,54 @@ class PGconn
|
|
65
65
|
@transaction_in_progress = nil
|
66
66
|
end
|
67
67
|
end
|
68
|
+
|
69
|
+
SELECT_CURRVAL = "SELECT currval('%s')".freeze
|
70
|
+
|
71
|
+
def last_insert_id(table)
|
72
|
+
@table_sequences ||= {}
|
73
|
+
seq = @table_sequences[table] ||= pkey_and_sequence(table)[1]
|
74
|
+
r = async_query(SELECT_CURRVAL % seq)
|
75
|
+
r[0][0].to_i unless r.nil? || r.empty?
|
76
|
+
end
|
77
|
+
|
78
|
+
# Shamelessly appropriated from ActiveRecord's Postgresql adapter.
|
79
|
+
|
80
|
+
SELECT_PK_AND_SERIAL_SEQUENCE = <<-end_sql
|
81
|
+
SELECT attr.attname, name.nspname, seq.relname
|
82
|
+
FROM pg_class seq, pg_attribute attr, pg_depend dep,
|
83
|
+
pg_namespace name, pg_constraint cons
|
84
|
+
WHERE seq.oid = dep.objid
|
85
|
+
AND seq.relnamespace = name.oid
|
86
|
+
AND seq.relkind = 'S'
|
87
|
+
AND attr.attrelid = dep.refobjid
|
88
|
+
AND attr.attnum = dep.refobjsubid
|
89
|
+
AND attr.attrelid = cons.conrelid
|
90
|
+
AND attr.attnum = cons.conkey[1]
|
91
|
+
AND cons.contype = 'p'
|
92
|
+
AND dep.refobjid = '%s'::regclass
|
93
|
+
end_sql
|
94
|
+
|
95
|
+
SELECT_PK_AND_CUSTOM_SEQUENCE = <<-end_sql
|
96
|
+
SELECT attr.attname, name.nspname, split_part(def.adsrc, '''', 2)
|
97
|
+
FROM pg_class t
|
98
|
+
JOIN pg_namespace name ON (t.relnamespace = name.oid)
|
99
|
+
JOIN pg_attribute attr ON (t.oid = attrelid)
|
100
|
+
JOIN pg_attrdef def ON (adrelid = attrelid AND adnum = attnum)
|
101
|
+
JOIN pg_constraint cons ON (conrelid = adrelid AND adnum = conkey[1])
|
102
|
+
WHERE t.oid = '%s'::regclass
|
103
|
+
AND cons.contype = 'p'
|
104
|
+
AND def.adsrc ~* 'nextval'
|
105
|
+
end_sql
|
106
|
+
|
107
|
+
def pkey_and_sequence(table)
|
108
|
+
r = async_query(SELECT_PK_AND_SERIAL_SEQUENCE % table)
|
109
|
+
return [r[0].first, r[0].last] unless r.nil? or r.empty?
|
110
|
+
|
111
|
+
r = async_query(SELECT_PK_AND_CUSTOM_SEQUENCE % table)
|
112
|
+
return [r.first, r.last] unless r.nil? or r.empty?
|
113
|
+
rescue
|
114
|
+
nil
|
115
|
+
end
|
68
116
|
end
|
69
117
|
|
70
118
|
class String
|
@@ -130,11 +178,11 @@ module Sequel
|
|
130
178
|
|
131
179
|
|
132
180
|
def tables
|
133
|
-
|
181
|
+
dataset(RELATION_QUERY).filter(RELATION_FILTER).map(:relname)
|
134
182
|
end
|
135
183
|
|
136
184
|
def locks
|
137
|
-
|
185
|
+
dataset.from("pg_class, pg_locks").
|
138
186
|
select("pg_class.relname, pg_locks.*").
|
139
187
|
filter("pg_class.relfilenode=pg_locks.relation")
|
140
188
|
end
|
@@ -147,24 +195,10 @@ module Sequel
|
|
147
195
|
@pool.hold {|conn| conn.execute(sql).clear}
|
148
196
|
end
|
149
197
|
|
150
|
-
|
151
|
-
|
152
|
-
def execute_insert(sql)
|
198
|
+
def execute_insert(sql, table)
|
153
199
|
@pool.hold do |conn|
|
154
200
|
conn.execute(sql).clear
|
155
|
-
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
def query_single_value(sql)
|
160
|
-
@pool.hold do |conn|
|
161
|
-
result = conn.execute(sql)
|
162
|
-
begin
|
163
|
-
value = result.getvalue(0, 0)
|
164
|
-
ensure
|
165
|
-
result.clear
|
166
|
-
end
|
167
|
-
value
|
201
|
+
conn.last_insert_id(table)
|
168
202
|
end
|
169
203
|
end
|
170
204
|
|
@@ -180,11 +214,10 @@ module Sequel
|
|
180
214
|
class Dataset < Sequel::Dataset
|
181
215
|
def literal(v)
|
182
216
|
case v
|
183
|
-
when
|
217
|
+
when String, Fixnum, Float, TrueClass, FalseClass: PGconn.quote(v)
|
184
218
|
when Time: v.to_sql_timestamp
|
185
|
-
when Symbol: PGconn.quote(v.to_s)
|
186
219
|
else
|
187
|
-
|
220
|
+
super
|
188
221
|
end
|
189
222
|
end
|
190
223
|
|
@@ -267,11 +300,11 @@ module Sequel
|
|
267
300
|
end
|
268
301
|
|
269
302
|
def count(opts = nil)
|
270
|
-
|
303
|
+
query_single_value(count_sql(opts)).to_i
|
271
304
|
end
|
272
305
|
|
273
306
|
def insert(values = nil, opts = nil)
|
274
|
-
@db.execute_insert(insert_sql(values, opts))
|
307
|
+
@db.execute_insert(insert_sql(values, opts), @opts[:from])
|
275
308
|
end
|
276
309
|
|
277
310
|
def update(values, opts = nil)
|
@@ -338,6 +371,18 @@ module Sequel
|
|
338
371
|
end
|
339
372
|
end
|
340
373
|
|
374
|
+
def query_single_value(sql)
|
375
|
+
@db.synchronize do
|
376
|
+
result = @db.execute(sql)
|
377
|
+
begin
|
378
|
+
value = result.getvalue(0, 0)
|
379
|
+
ensure
|
380
|
+
result.clear
|
381
|
+
end
|
382
|
+
value
|
383
|
+
end
|
384
|
+
end
|
385
|
+
|
341
386
|
COMMA = ','.freeze
|
342
387
|
|
343
388
|
@@converters_mutex = Mutex.new
|
data/lib/sequel/sqlite.rb
CHANGED
@@ -59,12 +59,9 @@ module Sequel
|
|
59
59
|
class Dataset < Sequel::Dataset
|
60
60
|
def literal(v)
|
61
61
|
case v
|
62
|
-
when String: "'%s'" % v.gsub(/'/, "''")
|
63
62
|
when Time: literal(v.iso8601)
|
64
|
-
when Array: v.empty? ? NULL : v.join(COMMA_SEPARATOR)
|
65
|
-
when Integer, Float: v.to_s
|
66
63
|
else
|
67
|
-
|
64
|
+
super
|
68
65
|
end
|
69
66
|
end
|
70
67
|
|
metadata
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.9.
|
2
|
+
rubygems_version: 0.9.2
|
3
3
|
specification_version: 1
|
4
4
|
name: sequel
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.0.
|
7
|
-
date: 2007-03-
|
6
|
+
version: 0.0.9
|
7
|
+
date: 2007-03-25 00:00:00 +02:00
|
8
8
|
summary: Concise ORM for Ruby.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -36,15 +36,15 @@ files:
|
|
36
36
|
- doc/rdoc
|
37
37
|
- lib/sequel
|
38
38
|
- lib/sequel.rb
|
39
|
-
- lib/sequel/connection_pool.rb
|
40
|
-
- lib/sequel/core_ext.rb
|
41
|
-
- lib/sequel/database.rb
|
42
39
|
- lib/sequel/dataset.rb
|
43
40
|
- lib/sequel/model.rb
|
44
|
-
- lib/sequel/mysql.rb
|
45
41
|
- lib/sequel/postgres.rb
|
46
42
|
- lib/sequel/schema.rb
|
47
43
|
- lib/sequel/sqlite.rb
|
44
|
+
- lib/sequel/connection_pool.rb
|
45
|
+
- lib/sequel/database.rb
|
46
|
+
- lib/sequel/core_ext.rb
|
47
|
+
- lib/sequel/mysql.rb
|
48
48
|
- CHANGELOG
|
49
49
|
test_files: []
|
50
50
|
|