sequel 0.1.9.5 → 0.1.9.6

Sign up to get free protection for your applications and to get access to all the features.
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