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 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.8"
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",
@@ -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 v.to_s
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
@@ -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
- query(RELATION_QUERY).filter(RELATION_FILTER).map(:relname)
181
+ dataset(RELATION_QUERY).filter(RELATION_FILTER).map(:relname)
134
182
  end
135
183
 
136
184
  def locks
137
- query.from("pg_class, pg_locks").
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
- SELECT_LASTVAL = 'SELECT lastval()'.freeze
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
- query_single_value(SELECT_LASTVAL)
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 Array: super
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
- PGconn.quote(v)
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
- @db.query_single_value(count_sql(opts)).to_i
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
@@ -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
- raise "can't express #{v.inspect}:#{v.class} as a SQL literal"
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.0
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.8
7
- date: 2007-03-24 00:00:00 +02:00
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