sequel 0.0.8 → 0.0.9
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 +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
|
|