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 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