sequel 0.1.9.2 → 0.1.9.3

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
+ === SVN
2
+
3
+ * Added Sequel.dbi convenience method for using DBI connection strings to open DBI databases.
4
+
5
+ === 0.1.9.3 (2007-08-10)
6
+
7
+ * Added support for specifying field size in schema definitions (thanks Florian Aßmann.)
8
+
9
+ * Added migration code based on work by Florian Aßmann.
10
+
11
+ * Reintroduced metaid dependency. No need to keep a local copy of it.
12
+
1
13
  === 0.1.9.2 (2007-07-24)
2
14
 
3
15
  * Removed metaid dependency. Refactored requires in lib/sequel.rb.
data/Rakefile CHANGED
@@ -6,7 +6,7 @@ require 'fileutils'
6
6
  include FileUtils
7
7
 
8
8
  NAME = "sequel"
9
- VERS = "0.1.9.2"
9
+ VERS = "0.1.9.3"
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",
@@ -43,7 +43,9 @@ spec = Gem::Specification.new do |s|
43
43
  s.homepage = 'http://sequel.rubyforge.org'
44
44
  s.executables = ['sequel']
45
45
 
46
- s.required_ruby_version = '>= 1.8.2'
46
+ s.add_dependency('metaid')
47
+
48
+ s.required_ruby_version = '>= 1.8.4'
47
49
 
48
50
  s.files = %w(COPYING README Rakefile) + Dir.glob("{bin,doc,spec,lib}/**/*")
49
51
 
data/lib/sequel.rb CHANGED
@@ -1,6 +1,8 @@
1
+ require 'metaid'
2
+
1
3
  files = %w[
2
- metaid core_ext error database connection_pool
3
- schema pretty_table expressions dataset model
4
+ core_ext error database connection_pool
5
+ schema pretty_table expressions dataset migration model
4
6
  ]
5
7
  dir = File.join(File.dirname(__FILE__), 'sequel')
6
8
  files.each {|f| require(File.join(dir, f))}
data/lib/sequel/dbi.rb CHANGED
@@ -5,14 +5,19 @@ end
5
5
  require 'dbi'
6
6
 
7
7
  module Sequel
8
+ def self.dbi(conn_string, opts = nil)
9
+ opts ||= {}
10
+ opts.merge!(:database => conn_string)
11
+ Sequel::DBI::Database.new(opts)
12
+ end
13
+
8
14
  module DBI
9
-
10
15
  class Database < Sequel::Database
11
16
  set_adapter_scheme :dbi
12
17
 
13
18
  def connect
14
- dbname = @opts[:database] =~ /^DBI:/ ? \
15
- @opts[:database] : @opts[:database] = 'DBI:' + @opts[:database]
19
+ dbname = @opts[:database]
20
+ dbname = 'DBI:' + dbname unless dbname =~ /^DBI:/
16
21
  ::DBI.connect(dbname, @opts[:user], @opts[:password])
17
22
  end
18
23
 
@@ -0,0 +1,180 @@
1
+ # The migration code is based on work by Florian Aßmann:
2
+ # http://code.google.com/p/ruby-sequel/issues/detail?id=23
3
+
4
+ module Sequel
5
+ # The Migration class describes a database migration that can be reversed.
6
+ # The migration looks very similar to ActiveRecord (Rails) migrations, e.g.:
7
+ #
8
+ # class CreateSessions < Sequel::Migration
9
+ # def up
10
+ # create_table :sessions do
11
+ # primary_key :id
12
+ # varchar :session_id, :length => 32, :unique => true
13
+ # timestamp :created_at
14
+ # text :data
15
+ # end
16
+ # end
17
+ #
18
+ # def down
19
+ # execute 'DROP TABLE sessions'
20
+ # end
21
+ # end
22
+ #
23
+ # To apply a migration to a database, you can invoke the #apply with
24
+ # the target database instance and the direction :up or :down, e.g.:
25
+ #
26
+ # DB = Sequel.open ('sqlite:///mydb')
27
+ # CreateSessions.apply(DB, :up)
28
+ #
29
+ class Migration
30
+ # Creates a new instance of the migration and sets the @db attribute.
31
+ def initialize(db)
32
+ @db = db
33
+ end
34
+
35
+ # Adds the new migration class to the list of Migration descendants.
36
+ def self.inherited(base)
37
+ descendants << base
38
+ end
39
+
40
+ # Returns the list of Migration descendants.
41
+ def self.descendants
42
+ @descendants ||= []
43
+ end
44
+
45
+ def up; end #:nodoc:
46
+ def down; end #:nodoc:
47
+
48
+ # Applies the migration to the supplied database in the specified
49
+ # direction.
50
+ def self.apply(db, direction)
51
+ obj = new(db)
52
+ case direction
53
+ when :up: obj.up
54
+ when :down: obj.down
55
+ else
56
+ raise SequelError, "Invalid migration direction (#{direction})"
57
+ end
58
+ end
59
+
60
+ # Intercepts method calls intended for the database and sends them along.
61
+ def method_missing(method_sym, *args, &block)
62
+ @db.send method_sym, *args, &block
63
+ end
64
+ end
65
+
66
+ # The Migrator module performs migrations based on migration files in a
67
+ # specified directory. The migration files should be named using the
68
+ # following pattern (in similar fashion to ActiveRecord migrations):
69
+ #
70
+ # <version>_<title>.rb
71
+ #
72
+ # For example, the following files are considered migration files:
73
+ #
74
+ # 001_create_sessions.rb
75
+ # 002_add_data_column.rb
76
+ # ...
77
+ #
78
+ # The migration files should contain one or more migration classes based
79
+ # on Sequel::Migration.
80
+ #
81
+ # To apply a migration, the #apply method must be invoked with the database
82
+ # instance, the directory of migration files and the target version. If
83
+ # no current version is supplied, it is read from the database. The migrator
84
+ # automatically creates a schema_info table in the database to keep track
85
+ # of the current migration version. If no migration version is stored in the
86
+ # database, the version is considered to be 0. If no target version is
87
+ # specified, the database is migrated to the latest version available in the
88
+ # migration directory.
89
+ #
90
+ # For example, to migrate the database to the latest version:
91
+ #
92
+ # Sequel::Migrator.apply(DB, '.')
93
+ #
94
+ # To migrate the database from version 1 to version 5:
95
+ #
96
+ # Sequel::Migrator.apply(DB, '.', 5, 1)
97
+ #
98
+ module Migrator
99
+ # Migrates the supplied database in the specified directory from the
100
+ # current version to the target version. If no current version is
101
+ # supplied, it is extracted from a schema_info table. The schema_info
102
+ # table is automatically created and maintained by the apply function.
103
+ def self.apply(db, directory, target = nil, current = nil)
104
+ # determine current and target version and direction
105
+ current ||= get_current_migration_version(db)
106
+ target ||= latest_migration_version(directory)
107
+ raise SequelError, "No current version available" if current.nil?
108
+ raise SequelError, "No target version available" if target.nil?
109
+ direction = current < target ? :up : :down
110
+
111
+ classes = migration_classes(directory, target, current, direction)
112
+
113
+ db.transaction do
114
+ classes.each {|c| c.apply(db, direction)}
115
+ set_current_migration_version(db, target)
116
+ end
117
+ end
118
+
119
+ # Returns a list of migration classes filter for the migration range and
120
+ # ordered according to the migration direction.
121
+ def self.migration_classes(directory, target, current, direction)
122
+ range = direction == :up ?
123
+ (current + 1)..target : (target + 1)..current
124
+
125
+ # load migration files
126
+ Migration.descendants.clear # remove any defined migration classes
127
+ migration_files(directory, range).each {|fn| load(fn)}
128
+
129
+ # get migration classes
130
+ classes = Migration.descendants
131
+ classes.reverse! if direction == :down
132
+ classes
133
+ end
134
+
135
+ MIGRATION_FILE_PATTERN = '[0-9][0-9][0-9]_*.rb'.freeze
136
+
137
+ # Returns any found migration files in the supplied directory.
138
+ def self.migration_files(directory, range = nil)
139
+ pattern = File.join(directory, MIGRATION_FILE_PATTERN)
140
+ files = Dir[pattern].inject([]) do |m, path|
141
+ m[File.basename(path).to_i] = path
142
+ m
143
+ end
144
+ filtered = range ? files[range] : files
145
+ filtered ? filtered.compact : []
146
+ end
147
+
148
+ def self.latest_migration_version(directory)
149
+ l = migration_files(directory).last
150
+ l ? File.basename(l).to_i : nil
151
+ end
152
+
153
+ # Gets the current migration version stored in the database. If no version
154
+ # number is stored, 0 is returned.
155
+ def self.get_current_migration_version(db)
156
+ r = schema_info_dataset(db).first
157
+ r ? r[:version] : 0
158
+ end
159
+
160
+ # Sets the current migration version stored in the database.
161
+ def self.set_current_migration_version(db, version)
162
+ dataset = schema_info_dataset(db)
163
+ if dataset.first
164
+ dataset.update(:version => version)
165
+ else
166
+ dataset << {:version => version}
167
+ end
168
+ end
169
+
170
+ # Returns the dataset for the schema_info table. If no such table
171
+ # exists, it is automatically created.
172
+ def self.schema_info_dataset(db)
173
+ unless db.table_exists?(:schema_info)
174
+ db.create_table(:schema_info) {integer :version}
175
+ end
176
+
177
+ db[:schema_info]
178
+ end
179
+ end
180
+ end
data/lib/sequel/schema.rb CHANGED
@@ -2,6 +2,7 @@ module Sequel
2
2
  class Schema
3
3
  COMMA_SEPARATOR = ', '.freeze
4
4
  COLUMN_DEF = '%s %s'.freeze
5
+ SIZE_DEF = '(%d)'.freeze
5
6
  UNIQUE = ' UNIQUE'.freeze
6
7
  NOT_NULL = ' NOT NULL'.freeze
7
8
  DEFAULT = ' DEFAULT %s'.freeze
@@ -31,6 +32,8 @@ module Sequel
31
32
 
32
33
  def self.column_definition(column)
33
34
  c = COLUMN_DEF % [column[:name], TYPES[column[:type]]]
35
+ column[:size] ||= 255 if column[:type] == :varchar
36
+ c << SIZE_DEF % column[:size] if column[:size]
34
37
  c << UNIQUE if column[:unique]
35
38
  c << NOT_NULL if column[:null] == false
36
39
  c << DEFAULT % PGconn.quote(column[:default]) if column.include?(:default)
@@ -0,0 +1,241 @@
1
+ require File.join(File.dirname(__FILE__), '../lib/sequel')
2
+
3
+ context "Migration classes" do
4
+ setup do
5
+ Sequel::Migration.descendants.clear
6
+ end
7
+
8
+ specify "should be registred in Migration.descendants" do
9
+ @class = Class.new(Sequel::Migration)
10
+
11
+ Sequel::Migration.descendants.should == [@class]
12
+ end
13
+
14
+ specify "should be registered in the right order" do
15
+ @c1 = Class.new(Sequel::Migration)
16
+ @c2 = Class.new(Sequel::Migration)
17
+ @c3 = Class.new(Sequel::Migration)
18
+
19
+ Sequel::Migration.descendants.should == [@c1, @c2, @c3]
20
+ end
21
+ end
22
+
23
+ context "Migration#apply" do
24
+ setup do
25
+ @c = Class.new do
26
+ define_method(:one) {|x| [1111, x]}
27
+ define_method(:two) {|x| [2222, x]}
28
+ end
29
+ @db = @c.new
30
+
31
+ @migration = Class.new(Sequel::Migration) do
32
+ define_method(:up) {one(3333)}
33
+ define_method(:down) {two(4444)}
34
+ end
35
+ end
36
+
37
+ specify "should raise for an invalid direction" do
38
+ proc {@migration.apply(@db, :hahaha)}.should raise_error(SequelError)
39
+ end
40
+
41
+ specify "should apply the up direction correctly" do
42
+ @migration.apply(@db, :up).should == [1111, 3333]
43
+ end
44
+
45
+ specify "should apply the down direction correctly" do
46
+ @migration.apply(@db, :down).should == [2222, 4444]
47
+ end
48
+ end
49
+
50
+ class DummyMigrationDataset
51
+ attr_reader :from
52
+
53
+ def initialize(x); @from = x; end
54
+
55
+ @@version = nil
56
+
57
+ def version; @@version; end
58
+ def version=(x); @@version = x; end
59
+ def first; @@version ? {:version => @@version} : nil; end
60
+ def update(h); @@version = h[:version]; end
61
+ def <<(h); @@version = h[:version]; end
62
+ end
63
+
64
+ class DummyMigrationDB
65
+ attr_reader :creates, :drops, :table_created
66
+
67
+ def initialize
68
+ @creates = []
69
+ @drops = []
70
+ end
71
+
72
+ def create(x); @creates << x; end
73
+ def drop(x); @drops << x; end
74
+
75
+ def [](x); DummyMigrationDataset.new(x); end
76
+
77
+ def create_table(x); raise if @table_created == x; @table_created = x; end
78
+ def table_exists?(x); @table_created == x; end
79
+
80
+ def transaction; yield; end
81
+ end
82
+
83
+ MIGRATION_001 = %[
84
+ class CreateSessions < Sequel::Migration
85
+ def up
86
+ create(1111)
87
+ end
88
+
89
+ def drop
90
+ drop(1111)
91
+ end
92
+ end
93
+ ]
94
+
95
+ MIGRATION_002 = %[
96
+ class CreateNodes < Sequel::Migration
97
+ def up
98
+ create(2222)
99
+ end
100
+
101
+ def down
102
+ drop(2222)
103
+ end
104
+ end
105
+ ]
106
+
107
+ MIGRATION_003 = %[
108
+ class CreateUsers < Sequel::Migration
109
+ def up
110
+ create(3333)
111
+ end
112
+
113
+ def down
114
+ drop(3333)
115
+ end
116
+ end
117
+ ]
118
+
119
+ MIGRATION_005 = %[
120
+ class CreateAttributes < Sequel::Migration
121
+ def up
122
+ create(5555)
123
+ end
124
+
125
+ def down
126
+ drop(5555)
127
+ end
128
+ end
129
+ ]
130
+
131
+ context "Sequel::Migrator" do
132
+ setup do
133
+ @db = DummyMigrationDB.new
134
+
135
+ File.open('001_create_sessions.rb', 'w') {|f| f << MIGRATION_001}
136
+ File.open('002_create_nodes.rb', 'w') {|f| f << MIGRATION_002}
137
+ File.open('003_create_users.rb', 'w') {|f| f << MIGRATION_003}
138
+ File.open('005_create_attributes.rb', 'w') {|f| f << MIGRATION_005}
139
+
140
+ @db[:schema_info].version = nil
141
+ end
142
+
143
+ teardown do
144
+ Object.send(:remove_const, "CreateSessions") if Object.const_defined?("CreateSessions")
145
+ Object.send(:remove_const, "CreateNodes") if Object.const_defined?("CreateNodes")
146
+ Object.send(:remove_const, "CreateUsers") if Object.const_defined?("CreateUsers")
147
+ Object.send(:remove_const, "CreateAttributes") if Object.const_defined?("CreateAttributes")
148
+
149
+ FileUtils.rm('001_create_sessions.rb')
150
+ FileUtils.rm('002_create_nodes.rb')
151
+ FileUtils.rm('003_create_users.rb')
152
+ FileUtils.rm('005_create_attributes.rb')
153
+ end
154
+
155
+ specify "should return the list of files for a specified version range" do
156
+ Sequel::Migrator.migration_files('.', 1..1).should == \
157
+ ['./001_create_sessions.rb']
158
+
159
+ Sequel::Migrator.migration_files('.', 1..3).should == \
160
+ ['./001_create_sessions.rb', './002_create_nodes.rb', './003_create_users.rb']
161
+
162
+ Sequel::Migrator.migration_files('.', 3..5).should == \
163
+ ['./003_create_users.rb', './005_create_attributes.rb']
164
+
165
+ Sequel::Migrator.migration_files('.', 7..8).should == []
166
+ end
167
+
168
+ specify "should return the latest version available" do
169
+ Sequel::Migrator.latest_migration_version('.').should == 5
170
+ end
171
+
172
+ specify "should load the migration classes for the specified range" do
173
+ Sequel::Migrator.migration_classes('.', 3, 0, :up).should == \
174
+ [CreateSessions, CreateNodes, CreateUsers]
175
+ end
176
+
177
+ specify "should start from current + 1 for the up direction" do
178
+ Sequel::Migrator.migration_classes('.', 3, 1, :up).should == \
179
+ [CreateNodes, CreateUsers]
180
+ end
181
+
182
+ specify "should end on current + 1 for the down direction" do
183
+ Sequel::Migrator.migration_classes('.', 2, 5, :down).should == \
184
+ [CreateAttributes, CreateUsers]
185
+ end
186
+
187
+ specify "should automatically create the schema_info table" do
188
+ @db.table_exists?(:schema_info).should be_false
189
+ Sequel::Migrator.schema_info_dataset(@db)
190
+ @db.table_exists?(:schema_info).should be_true
191
+
192
+ # should not raise if table already exists
193
+ proc {Sequel::Migrator.schema_info_dataset(@db)}.should_not raise_error
194
+ end
195
+
196
+ specify "should return a dataset for the schema_info table" do
197
+ d = Sequel::Migrator.schema_info_dataset(@db)
198
+ d.from.should == :schema_info
199
+ end
200
+
201
+ specify "should get the migration version stored in the database" do
202
+ # default is 0
203
+ Sequel::Migrator.get_current_migration_version(@db).should == 0
204
+
205
+ Sequel::Migrator.schema_info_dataset(@db) << {:version => 4321}
206
+
207
+ Sequel::Migrator.get_current_migration_version(@db).should == 4321
208
+ end
209
+
210
+ specify "should set the migration versison stored in the datbase" do
211
+ Sequel::Migrator.get_current_migration_version(@db).should == 0
212
+ Sequel::Migrator.set_current_migration_version(@db, 6666)
213
+ Sequel::Migrator.get_current_migration_version(@db).should == 6666
214
+ end
215
+
216
+ specify "should apply migrations correctly in the up direction" do
217
+ Sequel::Migrator.apply(@db, '.', 3, 2)
218
+ @db.creates.should == [3333]
219
+
220
+ Sequel::Migrator.get_current_migration_version(@db).should == 3
221
+
222
+ Sequel::Migrator.apply(@db, '.', 5)
223
+ @db.creates.should == [3333, 5555]
224
+
225
+ Sequel::Migrator.get_current_migration_version(@db).should == 5
226
+ end
227
+
228
+ specify "should apply migrations correctly in the down direction" do
229
+ Sequel::Migrator.apply(@db, '.', 1, 5)
230
+ @db.drops.should == [5555, 3333, 2222]
231
+
232
+ Sequel::Migrator.get_current_migration_version(@db).should == 1
233
+ end
234
+
235
+ specify "should apply migrations up to the latest version if no target is given" do
236
+ Sequel::Migrator.apply(@db, '.')
237
+ @db.creates.should == [1111, 2222, 3333, 5555]
238
+
239
+ Sequel::Migrator.get_current_migration_version(@db).should == 5
240
+ end
241
+ 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.2
7
- date: 2007-07-24 00:00:00 +03:00
6
+ version: 0.1.9.3
7
+ date: 2007-08-10 00:00:00 +03:00
8
8
  summary: Concise ORM for Ruby.
9
9
  require_paths:
10
10
  - lib
@@ -20,7 +20,7 @@ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
20
  requirements:
21
21
  - - ">="
22
22
  - !ruby/object:Gem::Version
23
- version: 1.8.2
23
+ version: 1.8.4
24
24
  version:
25
25
  platform: ruby
26
26
  signing_key:
@@ -40,6 +40,7 @@ files:
40
40
  - spec/database_spec.rb
41
41
  - spec/dataset_spec.rb
42
42
  - spec/expressions_spec.rb
43
+ - spec/migration_spec.rb
43
44
  - spec/adapters/mysql_spec.rb
44
45
  - spec/adapters/sqlite_spec.rb
45
46
  - lib/sequel
@@ -52,7 +53,7 @@ files:
52
53
  - lib/sequel/dbi.rb
53
54
  - lib/sequel/error.rb
54
55
  - lib/sequel/expressions.rb
55
- - lib/sequel/metaid.rb
56
+ - lib/sequel/migration.rb
56
57
  - lib/sequel/model.rb
57
58
  - lib/sequel/mysql.rb
58
59
  - lib/sequel/odbc.rb
@@ -89,5 +90,13 @@ extensions: []
89
90
 
90
91
  requirements: []
91
92
 
92
- dependencies: []
93
-
93
+ dependencies:
94
+ - !ruby/object:Gem::Dependency
95
+ name: metaid
96
+ version_requirement:
97
+ version_requirements: !ruby/object:Gem::Version::Requirement
98
+ requirements:
99
+ - - ">"
100
+ - !ruby/object:Gem::Version
101
+ version: 0.0.0
102
+ version:
data/lib/sequel/metaid.rb DELETED
@@ -1,24 +0,0 @@
1
- # Metaid == a few simple metaclass helper
2
- # (See http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html.)
3
- class Object
4
- # The hidden singleton lurks behind everyone
5
- def metaclass; class << self; self; end; end
6
- def meta_eval &blk; metaclass.instance_eval &blk; end
7
-
8
- # Adds methods to a metaclass
9
- def meta_def name, &blk
10
- meta_eval { define_method name, &blk }
11
- end
12
- end
13
-
14
- class Module
15
- # Defines an instance method within a module
16
- def module_def name, &blk
17
- module_eval { define_method name, &blk }
18
- end
19
- end
20
-
21
- class Class
22
- alias class_def module_def
23
- end
24
-