sequel 0.1.9.5 → 0.1.9.6

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,4 +1,12 @@
1
- === SVN
1
+ === 0.2 (2007-08-13)
2
+
3
+ * Refactored schema definition code. Gets rid of famous primary_key problem as well as other issues (e.g. issue #22).
4
+
5
+ * Added #pagination_record_count, #page_range and #current_page_record_range for paginated datasets.
6
+
7
+ * Changed MySQL adapter to automatically reconnect (issue #26).
8
+
9
+ * Changed Sequel() to acccept variable arity.
2
10
 
3
11
  * Added :elements option to column definition, in order to support ENUM and SET types.
4
12
 
data/Rakefile CHANGED
@@ -6,7 +6,7 @@ require 'fileutils'
6
6
  include FileUtils
7
7
 
8
8
  NAME = "sequel"
9
- VERS = "0.1.9.5"
9
+ VERS = "0.1.9.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.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  require 'metaid'
2
2
 
3
3
  files = %w[
4
- core_ext error database connection_pool pretty_table expressions
5
- dataset schema migration model
4
+ core_ext error schema database connection_pool pretty_table expressions
5
+ dataset migration model
6
6
  ]
7
7
  dir = File.join(File.dirname(__FILE__), 'sequel')
8
8
  files.each {|f| require(File.join(dir, f))}
@@ -31,7 +31,7 @@ module Sequel #:nodoc:
31
31
  end
32
32
 
33
33
  class Object
34
- def Sequel(uri)
35
- Sequel.connect(uri)
34
+ def Sequel(*args)
35
+ Sequel.connect(*args)
36
36
  end
37
37
  end
@@ -110,6 +110,38 @@ module Sequel
110
110
  true
111
111
  end
112
112
 
113
+ include Schema::SQL
114
+
115
+ NULL = "NULL".freeze
116
+ TIMESTAMP_FORMAT = "TIMESTAMP '%Y-%m-%d %H:%M:%S'".freeze
117
+ DATE_FORMAT = "DATE '%Y-%m-%d'".freeze
118
+ TRUE = "'t'".freeze
119
+ FALSE = "'f'".freeze
120
+
121
+ # default literal implementation for use in schema definitions
122
+ def literal(v)
123
+ case v
124
+ when ExpressionString: v
125
+ when String: "'#{v.gsub(/'/, "''")}'"
126
+ when Integer, Float: v.to_s
127
+ when NilClass: NULL
128
+ when TrueClass: TRUE
129
+ when FalseClass: FALSE
130
+ when Symbol: v.to_field_name
131
+ when Array: v.empty? ? NULL : v.map {|i| literal(i)}.join(COMMA_SEPARATOR)
132
+ when Time: v.strftime(TIMESTAMP_FORMAT)
133
+ when Date: v.strftime(DATE_FORMAT)
134
+ when Dataset: "(#{v.sql})"
135
+ else
136
+ raise SequelError, "can't express #{v.inspect} as a SQL literal"
137
+ end
138
+ end
139
+
140
+ # default serial primary key definition. this should be overriden for each adapter.
141
+ def serial_primary_key_options
142
+ {:primary_key => true, :type => :integer, :auto_increment => true}
143
+ end
144
+
113
145
  # Creates a table. The easiest way to use this method is to provide a
114
146
  # block:
115
147
  # DB.create_table :posts do
@@ -119,16 +151,13 @@ module Sequel
119
151
  # index :title
120
152
  # end
121
153
  def create_table(name, &block)
122
- schema = Schema.new
123
- schema.create_table(name, &block)
124
- schema.create(self)
154
+ g = Schema::Generator.new(self, name, &block)
155
+ execute(create_table_sql(*g.create_info))
125
156
  end
126
157
 
127
158
  # Drops a table.
128
159
  def drop_table(*names)
129
- transaction do
130
- execute(names.map {|n| Schema.drop_table_sql(n)}.join)
131
- end
160
+ execute(names.map {|n| drop_table_sql(n)}.join)
132
161
  end
133
162
 
134
163
  # Performs a brute-force check for the existance of a table. This method is
@@ -171,7 +200,7 @@ module Sequel
171
200
  end
172
201
  end
173
202
  end
174
-
203
+
175
204
  @@adapters = Hash.new
176
205
 
177
206
  # Sets the adapter scheme for the Database class. Call this method in
@@ -80,19 +80,27 @@ module Sequel
80
80
  end
81
81
  end
82
82
 
83
- # returns a paginated dataset. The resulting dataset also provides the
83
+ # Returns a paginated dataset. The resulting dataset also provides the
84
84
  # total number of pages (Dataset#page_count) and the current page number
85
85
  # (Dataset#current_page), as well as Dataset#prev_page and Dataset#next_page
86
86
  # for implementing pagination controls.
87
87
  def paginate(page_no, page_size)
88
- total_pages = (count / page_size.to_f).ceil
88
+ record_count = count
89
+ total_pages = (record_count / page_size.to_f).ceil
89
90
  paginated = limit(page_size, (page_no - 1) * page_size)
90
- paginated.current_page = page_no
91
- paginated.page_count = total_pages
91
+ paginated.set_pagination_info(page_no, page_size, record_count)
92
92
  paginated
93
93
  end
94
+
95
+ # Sets the pagination info
96
+ def set_pagination_info(page_no, page_size, record_count)
97
+ @current_page = page_no
98
+ @page_size = page_size
99
+ @pagination_record_count = record_count
100
+ @page_count = (record_count / page_size.to_f).ceil
101
+ end
94
102
 
95
- attr_accessor :page_count, :current_page
103
+ attr_accessor :page_size, :page_count, :current_page, :pagination_record_count
96
104
 
97
105
  # Returns the previous page number or nil if the current page is the first
98
106
  def prev_page
@@ -103,6 +111,21 @@ module Sequel
103
111
  def next_page
104
112
  current_page < page_count ? (current_page + 1) : nil
105
113
  end
114
+
115
+ # Returns the page range
116
+ def page_range
117
+ 1..page_count
118
+ end
119
+
120
+ # Returns the record range for the current page
121
+ def current_page_record_range
122
+ return nil if @current_page > @page_count
123
+
124
+ a = 1 + (@current_page - 1) * @page_size
125
+ b = a + @page_size - 1
126
+ b = @pagination_record_count if b > @pagination_record_count
127
+ a..b
128
+ end
106
129
 
107
130
  # Returns the minimum value for the given field.
108
131
  def min(field)
@@ -44,6 +44,8 @@ module Sequel
44
44
  NULL = "NULL".freeze
45
45
  TIMESTAMP_FORMAT = "TIMESTAMP '%Y-%m-%d %H:%M:%S'".freeze
46
46
  DATE_FORMAT = "DATE '%Y-%m-%d'".freeze
47
+ TRUE = "'t'".freeze
48
+ FALSE = "'f'".freeze
47
49
 
48
50
  # Returns a literal representation of a value to be used as part
49
51
  # of an SQL expression. The stock implementation supports literalization
@@ -64,8 +66,8 @@ module Sequel
64
66
  when String: "'#{v.gsub(/'/, "''")}'"
65
67
  when Integer, Float: v.to_s
66
68
  when NilClass: NULL
67
- when TrueClass: 't'
68
- when FalseClass: 'f'
69
+ when TrueClass: TRUE
70
+ when FalseClass: FALSE
69
71
  when Symbol: v.to_field_name
70
72
  when Array: v.empty? ? NULL : v.map {|i| literal(i)}.join(COMMA_SEPARATOR)
71
73
  when Time: v.strftime(TIMESTAMP_FORMAT)
@@ -106,6 +106,7 @@ module Sequel
106
106
  target ||= latest_migration_version(directory)
107
107
  raise SequelError, "No current version available" if current.nil?
108
108
  raise SequelError, "No target version available" if target.nil?
109
+
109
110
  direction = current < target ? :up : :down
110
111
 
111
112
  classes = migration_classes(directory, target, current, direction)
@@ -121,9 +122,14 @@ module Sequel
121
122
  def self.migration_classes(directory, target, current, direction)
122
123
  range = direction == :up ?
123
124
  (current + 1)..target : (target + 1)..current
124
-
125
- # load migration files
125
+
126
+ # Remove class definitions
127
+ Migration.descendants.each do |c|
128
+ Object.send(:remove_const, c.to_s) rescue nil
129
+ end
126
130
  Migration.descendants.clear # remove any defined migration classes
131
+
132
+ # load migration files
127
133
  migration_files(directory, range).each {|fn| load(fn)}
128
134
 
129
135
  # get migration classes
data/lib/sequel/mysql.rb CHANGED
@@ -55,10 +55,21 @@ module Sequel
55
55
  class Database < Sequel::Database
56
56
  set_adapter_scheme :mysql
57
57
 
58
+ def serial_primary_key_options
59
+ {:primary_key => true, :type => :integer, :auto_increment => true}
60
+ end
61
+
62
+ AUTO_INCREMENT = 'AUTO_INCREMENT'.freeze
63
+
64
+ def auto_increment_sql
65
+ AUTO_INCREMENT
66
+ end
67
+
58
68
  def connect
59
69
  conn = Mysql.real_connect(@opts[:host], @opts[:user], @opts[:password],
60
70
  @opts[:database], @opts[:port])
61
71
  conn.query_with_result = false
72
+ conn.reconnect = true
62
73
  conn
63
74
  end
64
75
 
@@ -159,7 +159,6 @@ module Sequel
159
159
  RELATION_FILTER = "(relkind = 'r') AND (relname !~ '^pg|sql')".freeze
160
160
  SYSTEM_TABLE_REGEXP = /^pg|sql/.freeze
161
161
 
162
-
163
162
  def tables
164
163
  dataset(RELATION_QUERY).filter(RELATION_FILTER).map {|r| r[:relname].to_sym}
165
164
  end
@@ -265,6 +264,13 @@ module Sequel
265
264
  end
266
265
  end
267
266
 
267
+ def serial_primary_key_options
268
+ {:primary_key => true, :type => :serial}
269
+ end
270
+
271
+ def drop_table_sql(name)
272
+ "DROP TABLE #{name} CASCADE;"
273
+ end
268
274
  end
269
275
 
270
276
  class Dataset < Sequel::Dataset
data/lib/sequel/schema.rb CHANGED
@@ -1,183 +1,8 @@
1
1
  module Sequel
2
- class Schema
3
- class << self
4
- include Dataset::SQL
5
- end
6
-
7
- COMMA_SEPARATOR = ', '.freeze
8
- COLUMN_DEF = '%s %s'.freeze
9
- COLUMN_MEMBERS_DEF = '(%d)'.freeze
10
- UNIQUE = ' UNIQUE'.freeze
11
- NOT_NULL = ' NOT NULL'.freeze
12
- DEFAULT = ' DEFAULT %s'.freeze
13
- PRIMARY_KEY = ' PRIMARY KEY'.freeze
14
- REFERENCES = ' REFERENCES %s'.freeze
15
- ON_DELETE = ' ON DELETE %s'.freeze
16
- AUTOINCREMENT = ' AUTOINCREMENT'.freeze
17
-
18
- RESTRICT = 'RESTRICT'.freeze
19
- CASCADE = 'CASCADE'.freeze
20
- NO_ACTION = 'NO ACTION'.freeze
21
- SET_NULL = 'SET NULL'.freeze
22
- SET_DEFAULT = 'SET DEFAULT'.freeze
23
-
24
- TYPES = Hash.new {|h, k| k}
25
- TYPES[:double] = 'double precision'
26
-
27
- def self.on_delete_action(action)
28
- case action
29
- when :restrict: RESTRICT
30
- when :cascade: CASCADE
31
- when :set_null: SET_NULL
32
- when :set_default: SET_DEFAULT
33
- else NO_ACTION
34
- end
35
- end
36
-
37
- def self.column_definition(column)
38
- c = COLUMN_DEF % [column[:name], TYPES[column[:type]]]
39
- column[:size] ||= 255 if column[:type] == :varchar
40
- atts = column[:size] || column[:elements]
41
- c << COLUMN_MEMBERS_DEF % literal(atts) if atts
42
- c << UNIQUE if column[:unique]
43
- c << NOT_NULL if column[:null] == false
44
- c << DEFAULT % literal(column[:default]) if column.include?(:default)
45
- c << PRIMARY_KEY if column[:primary_key]
46
- c << REFERENCES % column[:table] if column[:table]
47
- c << ON_DELETE % on_delete_action(column[:on_delete]) if
48
- column[:on_delete]
49
- c << AUTOINCREMENT if column[:auto_increment]
50
- c
51
- end
52
-
53
- def self.create_table_column_list(columns)
54
- columns.map {|c| column_definition(c)}.join(COMMA_SEPARATOR)
55
- end
56
-
57
- CREATE_INDEX = 'CREATE INDEX %s ON %s (%s);'.freeze
58
- CREATE_UNIQUE_INDEX = 'CREATE UNIQUE INDEX %s ON %s (%s);'.freeze
59
- INDEX_NAME = '%s_%s_index'.freeze
60
- UNDERSCORE = '_'.freeze
61
-
62
- def self.index_definition(table_name, index)
63
- fields = index[:columns].join(COMMA_SEPARATOR)
64
- index_name = index[:name] || INDEX_NAME %
65
- [table_name, index[:columns].join(UNDERSCORE)]
66
- (index[:unique] ? CREATE_UNIQUE_INDEX : CREATE_INDEX) %
67
- [index_name, table_name, fields]
68
- end
69
-
70
- def self.create_indexes_sql(table_name, indexes)
71
- indexes.map {|i| index_definition(table_name, i)}.join
72
- end
73
-
74
- CREATE_TABLE = "CREATE TABLE %s (%s);".freeze
75
-
76
- def self.create_table_sql(name, columns, indexes = nil)
77
- sql = CREATE_TABLE % [name, create_table_column_list(columns)]
78
- sql << create_indexes_sql(name, indexes) if indexes && !indexes.empty?
79
- sql
80
- end
81
-
82
- DROP_TABLE = "DROP TABLE %s CASCADE;".freeze
83
-
84
- def self.drop_table_sql(name)
85
- DROP_TABLE % name
86
- end
87
-
88
- class Generator
89
- attr_reader :table_name
90
-
91
- def initialize(table_name, auto_primary_key = nil, &block)
92
- @table_name = table_name
93
- @primary_key = auto_primary_key
94
- @columns = []
95
- @indexes = []
96
- instance_eval(&block)
97
- end
98
-
99
- def method_missing(type, name = nil, opts = nil)
100
- return super unless name
101
- column(name, type, opts)
102
- end
103
-
104
- def primary_key(name, type = nil, opts = nil)
105
- @primary_key = {
106
- :name => name,
107
- :type => type || :serial,
108
- :primary_key => true
109
- }.merge(opts || {})
110
- end
111
-
112
- def primary_key_name
113
- @primary_key && @primary_key[:name]
114
- end
115
-
116
- def column(name, type, opts = nil)
117
- @columns << {:name => name, :type => type}.merge(opts || {})
118
- end
119
-
120
- def foreign_key(name, opts)
121
- @columns << {:name => name, :type => :integer}.merge(opts || {})
122
- end
123
-
124
- def has_column?(name)
125
- @columns.each {|c| return true if c[:name] == name}
126
- false
127
- end
128
-
129
- def index(columns, opts = nil)
130
- columns = [columns] unless columns.is_a?(Array)
131
- @indexes << {:columns => columns}.merge(opts || {})
132
- end
133
-
134
- def create_sql
135
- if @primary_key && !has_column?(@primary_key[:name])
136
- @columns.unshift(@primary_key)
137
- end
138
- Schema.create_table_sql(@table_name, @columns, @indexes)
139
- end
140
-
141
- def drop_sql
142
- Schema.drop_table_sql(@table_name)
143
- end
144
- end
145
-
146
- attr_reader :instructions
147
-
148
- def initialize(&block)
149
- @instructions = []
150
- instance_eval(&block) if block
151
- end
152
-
153
- def auto_primary_key(name, type = nil, opts = nil)
154
- @auto_primary_key = {
155
- :name => name,
156
- :type => type || :serial,
157
- :primary_key => true
158
- }.merge(opts || {})
159
- end
160
-
161
- def create_table(table_name, &block)
162
- @instructions << Generator.new(table_name, @auto_primary_key, &block)
163
- end
164
-
165
- def create(db)
166
- @instructions.each do |s|
167
- db.execute(s.create_sql)
168
- end
169
- end
170
-
171
- def drop(db)
172
- @instructions.reverse_each do |s|
173
- db.execute(s.drop_sql) if db.table_exists?(s.table_name)
174
- end
175
- end
176
-
177
- def recreate(db)
178
- drop(db)
179
- create(db)
180
- end
2
+ module Schema
181
3
  end
182
4
  end
183
5
 
6
+ require File.join(File.dirname(__FILE__), 'schema/schema_sql')
7
+ require File.join(File.dirname(__FILE__), 'schema/schema_generator')
8
+
@@ -0,0 +1,53 @@
1
+ module Sequel
2
+ module Schema
3
+ class Generator
4
+ def initialize(db, table_name, &block)
5
+ @db = db
6
+ @table_name = table_name
7
+ @columns = []
8
+ @indexes = []
9
+ instance_eval(&block)
10
+ end
11
+
12
+ def method_missing(type, name = nil, opts = nil)
13
+ return super unless name
14
+ column(name, type, opts)
15
+ end
16
+
17
+ def primary_key(name, type = nil, opts = nil)
18
+ @primary_key = @db.serial_primary_key_options.merge({
19
+ :name => name
20
+ })
21
+ @primary_key.merge!({:type => type}) if type
22
+ @primary_key.merge!(opts) if opts
23
+ @primary_key
24
+ end
25
+
26
+ def column(name, type, opts = nil)
27
+ @columns << {:name => name, :type => type}.merge(opts || {})
28
+ end
29
+
30
+ def foreign_key(name, opts)
31
+ @columns << {:name => name, :type => :integer}.merge(opts || {})
32
+ end
33
+
34
+ def has_column?(name)
35
+ @columns.each {|c| return true if c[:name] == name}
36
+ false
37
+ end
38
+
39
+ def index(columns, opts = nil)
40
+ columns = [columns] unless columns.is_a?(Array)
41
+ @indexes << {:columns => columns}.merge(opts || {})
42
+ end
43
+
44
+ def create_info
45
+ if @primary_key && !has_column?(@primary_key[:name])
46
+ @columns.unshift(@primary_key)
47
+ end
48
+ [@table_name, @columns, @indexes]
49
+ end
50
+ end
51
+ end
52
+ end
53
+
@@ -0,0 +1,85 @@
1
+ module Sequel
2
+ module Schema
3
+ module SQL
4
+ RESTRICT = 'RESTRICT'.freeze
5
+ CASCADE = 'CASCADE'.freeze
6
+ NO_ACTION = 'NO ACTION'.freeze
7
+ SET_NULL = 'SET NULL'.freeze
8
+ SET_DEFAULT = 'SET DEFAULT'.freeze
9
+
10
+ def on_delete_clause(action)
11
+ case action
12
+ when :restrict: RESTRICT
13
+ when :cascade: CASCADE
14
+ when :set_null: SET_NULL
15
+ when :set_default: SET_DEFAULT
16
+ else NO_ACTION
17
+ end
18
+ end
19
+
20
+ AUTOINCREMENT = 'AUTOINCREMENT'.freeze
21
+
22
+ def auto_increment_sql
23
+ AUTOINCREMENT
24
+ end
25
+
26
+ COMMA_SEPARATOR = ', '.freeze
27
+ UNIQUE = ' UNIQUE'.freeze
28
+ NOT_NULL = ' NOT NULL'.freeze
29
+ PRIMARY_KEY = ' PRIMARY KEY'.freeze
30
+
31
+ TYPES = Hash.new {|h, k| k}
32
+ TYPES[:double] = 'double precision'
33
+
34
+ def column_definition_sql(column)
35
+ sql = "#{column[:name]} #{TYPES[column[:type]]}"
36
+ column[:size] ||= 255 if column[:type] == :varchar
37
+ elements = column[:size] || column[:elements]
38
+ sql << "(#{literal(elements)})" if elements
39
+ sql << UNIQUE if column[:unique]
40
+ sql << NOT_NULL if column[:null] == false
41
+ sql << " DEFAULT #{literal(column[:default])}" if column.include?(:default)
42
+ sql << PRIMARY_KEY if column[:primary_key]
43
+ sql << " REFERENCES #{column[:table]}" if column[:table]
44
+ sql << " ON DELETE #{on_delete_clause(column[:on_delete])}" if column[:on_delete]
45
+ sql << " #{auto_increment_sql}" if column[:auto_increment]
46
+ sql
47
+ end
48
+
49
+ def column_list_sql(columns)
50
+ columns.map {|c| column_definition_sql(c)}.join(COMMA_SEPARATOR)
51
+ end
52
+
53
+ UNDERSCORE = '_'.freeze
54
+
55
+ def default_index_name(table_name, columns)
56
+ "#{table_name}_#{columns.join(UNDERSCORE)}_index"
57
+ end
58
+
59
+ def index_definition_sql(table_name, index)
60
+ fields = index[:columns].join(COMMA_SEPARATOR)
61
+ index_name = index[:name] || default_index_name(table_name, index[:columns])
62
+ if index[:unique]
63
+ "CREATE UNIQUE INDEX #{index_name} ON #{table_name} (#{fields});"
64
+ else
65
+ "CREATE INDEX #{index_name} ON #{table_name} (#{fields});"
66
+ end
67
+ end
68
+
69
+ def index_list_sql(table_name, indexes)
70
+ indexes.map {|i| index_definition_sql(table_name, i)}.join
71
+ end
72
+
73
+ def create_table_sql(name, columns, indexes = nil)
74
+ sql = "CREATE TABLE #{name} (#{column_list_sql(columns)});"
75
+ sql << index_list_sql(name, indexes) if indexes && !indexes.empty?
76
+ sql
77
+ end
78
+
79
+ def drop_table_sql(name)
80
+ "DROP TABLE #{name};"
81
+ end
82
+ end
83
+ end
84
+ end
85
+
data/lib/sequel/sqlite.rb CHANGED
@@ -9,6 +9,10 @@ module Sequel
9
9
  class Database < Sequel::Database
10
10
  set_adapter_scheme :sqlite
11
11
 
12
+ def serial_primary_key_options
13
+ {:primary_key => true, :type => :integer, :auto_increment => true}
14
+ end
15
+
12
16
  def connect
13
17
  if @opts[:database].empty?
14
18
  @opts[:database] = ':memory:'
@@ -182,6 +182,7 @@ end
182
182
  class DummyDatabase < Sequel::Database
183
183
  attr_reader :sql
184
184
  def execute(sql); @sql = sql; end
185
+ def transaction; yield; end
185
186
 
186
187
  def dataset
187
188
  DummyDataset.new(self)
@@ -200,7 +201,7 @@ context "Database#create_table" do
200
201
  index :name, :unique => true
201
202
  end
202
203
  @db.sql.should ==
203
- 'CREATE TABLE test (id integer NOT NULL PRIMARY KEY, name text);CREATE UNIQUE INDEX test_name_index ON test (name);'
204
+ 'CREATE TABLE test (id integer NOT NULL PRIMARY KEY AUTOINCREMENT, name text);CREATE UNIQUE INDEX test_name_index ON test (name);'
204
205
  end
205
206
  end
206
207
 
@@ -218,13 +219,13 @@ context "Database#drop_table" do
218
219
  specify "should construct proper SQL" do
219
220
  @db.drop_table :test
220
221
  @db.sql.should ==
221
- 'DROP TABLE test CASCADE;'
222
+ 'DROP TABLE test;'
222
223
  end
223
224
 
224
225
  specify "should accept multiple table names" do
225
226
  @db.drop_table :a, :bb, :ccc
226
227
  @db.sql.should ==
227
- 'DROP TABLE a CASCADE;DROP TABLE bb CASCADE;DROP TABLE ccc CASCADE;'
228
+ 'DROP TABLE a;DROP TABLE bb;DROP TABLE ccc;'
228
229
  end
229
230
  end
230
231
 
data/spec/dataset_spec.rb CHANGED
@@ -1404,6 +1404,17 @@ context "A paginated dataset" do
1404
1404
  @paginated.prev_page.should be_nil
1405
1405
  @d.paginate(4, 50).prev_page.should == 3
1406
1406
  end
1407
+
1408
+ specify "should return the page range" do
1409
+ @paginated.page_range.should == (1..8)
1410
+ @d.paginate(4, 50).page_range.should == (1..4)
1411
+ end
1412
+
1413
+ specify "should return the record range for the current page" do
1414
+ @paginated.current_page_record_range.should == (1..20)
1415
+ @d.paginate(4, 50).current_page_record_range.should == (151..153)
1416
+ @d.paginate(5, 50).current_page_record_range.should == nil
1417
+ end
1407
1418
  end
1408
1419
 
1409
1420
  context "Dataset#columns" do
@@ -0,0 +1,185 @@
1
+ require File.join(File.dirname(__FILE__), '../lib/sequel')
2
+
3
+ class SchemaDummyDatabase < Sequel::Database
4
+ attr_reader :sqls
5
+
6
+ def execute(sql)
7
+ @sqls ||= []
8
+ @sqls << sql
9
+ end
10
+ end
11
+
12
+ context "DB#create_table" do
13
+ setup do
14
+ @db = SchemaDummyDatabase.new
15
+ end
16
+
17
+ specify "should accept the table name" do
18
+ @db.create_table(:cats) {}
19
+ @db.sqls.should == ['CREATE TABLE cats ();']
20
+ end
21
+
22
+ specify "should accept multiple columns" do
23
+ @db.create_table(:cats) do
24
+ column :id, :integer
25
+ column :name, :text
26
+ end
27
+ @db.sqls.should == ['CREATE TABLE cats (id integer, name text);']
28
+ end
29
+
30
+ specify "should accept method calls as data types" do
31
+ @db.create_table(:cats) do
32
+ integer :id
33
+ text :name
34
+ end
35
+ @db.sqls.should == ['CREATE TABLE cats (id integer, name text);']
36
+ end
37
+
38
+ specify "should accept primary key definition" do
39
+ @db.create_table(:cats) do
40
+ primary_key :id
41
+ end
42
+ @db.sqls.should == ['CREATE TABLE cats (id integer PRIMARY KEY AUTOINCREMENT);']
43
+ @db.sqls.clear
44
+ @db.create_table(:cats) do
45
+ primary_key :id, :serial, :auto_increment => false
46
+ end
47
+ @db.sqls.should == ['CREATE TABLE cats (id serial PRIMARY KEY);']
48
+ end
49
+
50
+ specify "should accept and literalize default values" do
51
+ @db.create_table(:cats) do
52
+ integer :id, :default => 123
53
+ text :name, :default => "abc'def"
54
+ end
55
+ @db.sqls.should == ["CREATE TABLE cats (id integer DEFAULT 123, name text DEFAULT 'abc''def');"]
56
+ end
57
+
58
+ specify "should accept not null definition" do
59
+ @db.create_table(:cats) do
60
+ integer :id
61
+ text :name, :null => false
62
+ end
63
+ @db.sqls.should == ["CREATE TABLE cats (id integer, name text NOT NULL);"]
64
+ end
65
+
66
+ specify "should accept unique definition" do
67
+ @db.create_table(:cats) do
68
+ integer :id
69
+ text :name, :unique => true
70
+ end
71
+ @db.sqls.should == ["CREATE TABLE cats (id integer, name text UNIQUE);"]
72
+ end
73
+
74
+ specify "should accept [SET|ENUM](...) types" do
75
+ @db.create_table(:cats) do
76
+ set :color, :elements => ['black', 'tricolor', 'grey']
77
+ end
78
+ @db.sqls.should == ["CREATE TABLE cats (color set('black', 'tricolor', 'grey'));"]
79
+ end
80
+
81
+ specify "should accept varchar size" do
82
+ @db.create_table(:cats) do
83
+ varchar :name
84
+ end
85
+ @db.sqls.should == ["CREATE TABLE cats (name varchar(255));"]
86
+ @db.sqls.clear
87
+ @db.create_table(:cats) do
88
+ varchar :name, :size => 51
89
+ end
90
+ @db.sqls.should == ["CREATE TABLE cats (name varchar(51));"]
91
+ end
92
+
93
+ specify "should accept foreign keys" do
94
+ @db.create_table(:cats) do
95
+ foreign_key :project_id, :table => :projects
96
+ end
97
+ @db.sqls.should == ["CREATE TABLE cats (project_id integer REFERENCES projects);"]
98
+ end
99
+
100
+ specify "should accept foreign keys with ON DELETE clause" do
101
+ @db.create_table(:cats) do
102
+ foreign_key :project_id, :table => :projects, :on_delete => :restrict
103
+ end
104
+ @db.sqls.should == ["CREATE TABLE cats (project_id integer REFERENCES projects ON DELETE RESTRICT);"]
105
+
106
+ @db.sqls.clear
107
+ @db.create_table(:cats) do
108
+ foreign_key :project_id, :table => :projects, :on_delete => :cascade
109
+ end
110
+ @db.sqls.should == ["CREATE TABLE cats (project_id integer REFERENCES projects ON DELETE CASCADE);"]
111
+
112
+ @db.sqls.clear
113
+ @db.create_table(:cats) do
114
+ foreign_key :project_id, :table => :projects, :on_delete => :no_action
115
+ end
116
+ @db.sqls.should == ["CREATE TABLE cats (project_id integer REFERENCES projects ON DELETE NO ACTION);"]
117
+ @db.sqls.clear
118
+
119
+ @db.sqls.clear
120
+ @db.create_table(:cats) do
121
+ foreign_key :project_id, :table => :projects, :on_delete => :set_null
122
+ end
123
+ @db.sqls.should == ["CREATE TABLE cats (project_id integer REFERENCES projects ON DELETE SET NULL);"]
124
+ @db.sqls.clear
125
+
126
+ @db.sqls.clear
127
+ @db.create_table(:cats) do
128
+ foreign_key :project_id, :table => :projects, :on_delete => :set_default
129
+ end
130
+ @db.sqls.should == ["CREATE TABLE cats (project_id integer REFERENCES projects ON DELETE SET DEFAULT);"]
131
+ @db.sqls.clear
132
+ end
133
+
134
+ specify "should accept index definitions" do
135
+ @db.create_table(:cats) do
136
+ integer :id
137
+ index :id
138
+ end
139
+ @db.sqls.should == ["CREATE TABLE cats (id integer);CREATE INDEX cats_id_index ON cats (id);"]
140
+ end
141
+
142
+ specify "should accept multiple index definitions" do
143
+ @db.create_table(:cats) do
144
+ integer :id
145
+ index :id
146
+ index :name
147
+ end
148
+ @db.sqls.should == ["CREATE TABLE cats (id integer);CREATE INDEX cats_id_index ON cats (id);CREATE INDEX cats_name_index ON cats (name);"]
149
+ end
150
+
151
+ specify "should accept custom index names" do
152
+ @db.create_table(:cats) do
153
+ integer :id
154
+ index :id, :name => 'abc'
155
+ end
156
+ @db.sqls.should == ["CREATE TABLE cats (id integer);CREATE INDEX abc ON cats (id);"]
157
+ end
158
+
159
+ specify "should accept unique index definitions" do
160
+ @db.create_table(:cats) do
161
+ integer :id
162
+ index :id, :unique => true
163
+ end
164
+ @db.sqls.should == ["CREATE TABLE cats (id integer);CREATE UNIQUE INDEX cats_id_index ON cats (id);"]
165
+ end
166
+
167
+ specify "should accept compound index definitions" do
168
+ @db.create_table(:cats) do
169
+ integer :id
170
+ index [:id, :name], :unique => true
171
+ end
172
+ @db.sqls.should == ["CREATE TABLE cats (id integer);CREATE UNIQUE INDEX cats_id_name_index ON cats (id, name);"]
173
+ end
174
+ end
175
+
176
+ context "DB#drop_table" do
177
+ setup do
178
+ @db = SchemaDummyDatabase.new
179
+ end
180
+
181
+ specify "should generate a DROP TABLE statement" do
182
+ @db.drop_table :cats
183
+ @db.sqls.should == ['DROP TABLE cats;']
184
+ end
185
+ 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.9.5
7
- date: 2007-08-11 00:00:00 +03:00
6
+ version: 0.1.9.6
7
+ date: 2007-08-13 00:00:00 +03:00
8
8
  summary: Concise ORM for Ruby.
9
9
  require_paths:
10
10
  - lib
@@ -41,6 +41,7 @@ files:
41
41
  - spec/dataset_spec.rb
42
42
  - spec/expressions_spec.rb
43
43
  - spec/migration_spec.rb
44
+ - spec/schema_spec.rb
44
45
  - spec/adapters/mysql_spec.rb
45
46
  - spec/adapters/sqlite_spec.rb
46
47
  - lib/sequel
@@ -59,10 +60,13 @@ files:
59
60
  - lib/sequel/odbc.rb
60
61
  - lib/sequel/postgres.rb
61
62
  - lib/sequel/pretty_table.rb
63
+ - lib/sequel/schema
62
64
  - lib/sequel/schema.rb
63
65
  - lib/sequel/sqlite.rb
64
66
  - lib/sequel/dataset/dataset_convenience.rb
65
67
  - lib/sequel/dataset/dataset_sql.rb
68
+ - lib/sequel/schema/schema_generator.rb
69
+ - lib/sequel/schema/schema_sql.rb
66
70
  - CHANGELOG
67
71
  test_files: []
68
72