sequel_core 1.5.1 → 2.0.0
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 +116 -0
- data/COPYING +19 -19
- data/README +83 -32
- data/Rakefile +9 -20
- data/bin/sequel +43 -112
- data/doc/cheat_sheet.rdoc +225 -0
- data/doc/dataset_filtering.rdoc +257 -0
- data/lib/sequel_core/adapters/adapter_skeleton.rb +4 -2
- data/lib/sequel_core/adapters/ado.rb +3 -1
- data/lib/sequel_core/adapters/db2.rb +4 -2
- data/lib/sequel_core/adapters/dbi.rb +127 -113
- data/lib/sequel_core/adapters/informix.rb +4 -2
- data/lib/sequel_core/adapters/jdbc.rb +5 -3
- data/lib/sequel_core/adapters/mysql.rb +112 -46
- data/lib/sequel_core/adapters/odbc.rb +5 -7
- data/lib/sequel_core/adapters/odbc_mssql.rb +12 -3
- data/lib/sequel_core/adapters/openbase.rb +3 -1
- data/lib/sequel_core/adapters/oracle.rb +11 -9
- data/lib/sequel_core/adapters/postgres.rb +261 -262
- data/lib/sequel_core/adapters/sqlite.rb +72 -22
- data/lib/sequel_core/connection_pool.rb +140 -73
- data/lib/sequel_core/core_ext.rb +201 -66
- data/lib/sequel_core/core_sql.rb +123 -153
- data/lib/sequel_core/database/schema.rb +156 -0
- data/lib/sequel_core/database.rb +321 -338
- data/lib/sequel_core/dataset/callback.rb +11 -12
- data/lib/sequel_core/dataset/convenience.rb +213 -240
- data/lib/sequel_core/dataset/pagination.rb +58 -43
- data/lib/sequel_core/dataset/parse_tree_sequelizer.rb +331 -0
- data/lib/sequel_core/dataset/query.rb +41 -0
- data/lib/sequel_core/dataset/schema.rb +15 -0
- data/lib/sequel_core/dataset/sequelizer.rb +41 -373
- data/lib/sequel_core/dataset/sql.rb +741 -632
- data/lib/sequel_core/dataset.rb +183 -168
- data/lib/sequel_core/deprecated.rb +1 -169
- data/lib/sequel_core/exceptions.rb +24 -19
- data/lib/sequel_core/migration.rb +44 -52
- data/lib/sequel_core/object_graph.rb +43 -42
- data/lib/sequel_core/pretty_table.rb +71 -76
- data/lib/sequel_core/schema/generator.rb +163 -105
- data/lib/sequel_core/schema/sql.rb +250 -93
- data/lib/sequel_core/schema.rb +2 -8
- data/lib/sequel_core/sql.rb +394 -0
- data/lib/sequel_core/worker.rb +37 -27
- data/lib/sequel_core.rb +99 -45
- data/spec/adapters/informix_spec.rb +0 -1
- data/spec/adapters/mysql_spec.rb +177 -124
- data/spec/adapters/oracle_spec.rb +0 -1
- data/spec/adapters/postgres_spec.rb +98 -58
- data/spec/adapters/sqlite_spec.rb +45 -4
- data/spec/blockless_filters_spec.rb +269 -0
- data/spec/connection_pool_spec.rb +21 -18
- data/spec/core_ext_spec.rb +169 -19
- data/spec/core_sql_spec.rb +56 -49
- data/spec/database_spec.rb +78 -17
- data/spec/dataset_spec.rb +300 -428
- data/spec/migration_spec.rb +1 -1
- data/spec/object_graph_spec.rb +5 -11
- data/spec/rcov.opts +1 -1
- data/spec/schema_generator_spec.rb +16 -4
- data/spec/schema_spec.rb +89 -10
- data/spec/sequelizer_spec.rb +56 -56
- data/spec/spec.opts +0 -5
- data/spec/spec_config.rb +7 -0
- data/spec/spec_config.rb.example +5 -5
- data/spec/spec_helper.rb +6 -0
- data/spec/worker_spec.rb +1 -1
- metadata +78 -63
@@ -1,37 +1,42 @@
|
|
1
1
|
module Sequel
|
2
2
|
# Represents an error raised in Sequel code.
|
3
|
-
class Error < StandardError
|
3
|
+
class Error < ::StandardError
|
4
4
|
|
5
|
-
#
|
6
|
-
class
|
7
|
-
|
8
|
-
# Rollback is a special error used to rollback a transactions.
|
9
|
-
# A transaction block will catch this error and wont pass further up the stack.
|
10
|
-
class Rollback < Error ; end
|
5
|
+
# Raised when Sequel is unable to load a specified adapter.
|
6
|
+
class AdapterNotFound < Error ; end
|
11
7
|
|
12
|
-
#
|
13
|
-
class
|
8
|
+
# Raise when an invalid expression is encountered inside a block filter.
|
9
|
+
class InvalidExpression < Error; end
|
14
10
|
|
15
|
-
# Represents an Invalid
|
16
|
-
class
|
11
|
+
# Represents an Invalid filter.
|
12
|
+
class InvalidFilter < Error ; end
|
17
13
|
|
14
|
+
# Represents an invalid join type.
|
15
|
+
class InvalidJoinType < Error ; end
|
16
|
+
|
18
17
|
# Raised on an invalid operation.
|
19
18
|
class InvalidOperation < Error; end
|
20
19
|
|
21
|
-
#
|
22
|
-
class
|
20
|
+
# Error raised when an invalid statement is executed.
|
21
|
+
class InvalidStatement < Error; end
|
22
|
+
|
23
|
+
# Represents an Invalid transform.
|
24
|
+
class InvalidTransform < Error ; end
|
23
25
|
|
24
|
-
|
26
|
+
# Represents an invalid value stored in the database.
|
27
|
+
class InvalidValue < Error ; end
|
25
28
|
|
26
29
|
# Represents an attempt to performing filter operations when no filter has been specified yet.
|
27
30
|
class NoExistingFilter < Error ; end
|
28
31
|
|
29
|
-
#
|
30
|
-
class
|
32
|
+
# There was an error while waiting on a connection from the connection pool
|
33
|
+
class PoolTimeoutError < Error ; end
|
31
34
|
|
32
|
-
|
35
|
+
# Rollback is a special error used to rollback a transactions.
|
36
|
+
# A transaction block will catch this error and won't pass further up the stack.
|
37
|
+
class Rollback < Error ; end
|
33
38
|
|
34
|
-
#
|
35
|
-
class
|
39
|
+
# Should be raised inside a worker loop to tell it to stop working.
|
40
|
+
class WorkerStop < RuntimeError ; end
|
36
41
|
end
|
37
42
|
end
|
@@ -1,6 +1,3 @@
|
|
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
1
|
module Sequel
|
5
2
|
# The Migration class describes a database migration that can be reversed.
|
6
3
|
# The migration looks very similar to ActiveRecord (Rails) migrations, e.g.:
|
@@ -23,28 +20,14 @@ module Sequel
|
|
23
20
|
# To apply a migration to a database, you can invoke the #apply with
|
24
21
|
# the target database instance and the direction :up or :down, e.g.:
|
25
22
|
#
|
26
|
-
# DB = Sequel.open ('sqlite
|
23
|
+
# DB = Sequel.open ('sqlite://mydb')
|
27
24
|
# CreateSessions.apply(DB, :up)
|
28
|
-
#
|
29
25
|
class Migration
|
30
26
|
# Creates a new instance of the migration and sets the @db attribute.
|
31
27
|
def initialize(db)
|
32
28
|
@db = db
|
33
29
|
end
|
34
30
|
|
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
31
|
# Applies the migration to the supplied database in the specified
|
49
32
|
# direction.
|
50
33
|
def self.apply(db, direction)
|
@@ -59,9 +42,27 @@ module Sequel
|
|
59
42
|
end
|
60
43
|
end
|
61
44
|
|
45
|
+
# Returns the list of Migration descendants.
|
46
|
+
def self.descendants
|
47
|
+
@descendants ||= []
|
48
|
+
end
|
49
|
+
|
50
|
+
# Adds the new migration class to the list of Migration descendants.
|
51
|
+
def self.inherited(base)
|
52
|
+
descendants << base
|
53
|
+
end
|
54
|
+
|
55
|
+
# The default down action does nothing
|
56
|
+
def down
|
57
|
+
end
|
58
|
+
|
62
59
|
# Intercepts method calls intended for the database and sends them along.
|
63
60
|
def method_missing(method_sym, *args, &block)
|
64
|
-
@db.send
|
61
|
+
@db.send(method_sym, *args, &block)
|
62
|
+
end
|
63
|
+
|
64
|
+
# The default up action does nothing
|
65
|
+
def up
|
65
66
|
end
|
66
67
|
end
|
67
68
|
|
@@ -96,8 +97,9 @@ module Sequel
|
|
96
97
|
# To migrate the database from version 1 to version 5:
|
97
98
|
#
|
98
99
|
# Sequel::Migrator.apply(DB, '.', 5, 1)
|
99
|
-
#
|
100
100
|
module Migrator
|
101
|
+
MIGRATION_FILE_PATTERN = /\A\d+_.+\.rb\z/.freeze
|
102
|
+
|
101
103
|
# Migrates the supplied database in the specified directory from the
|
102
104
|
# current version to the target version. If no current version is
|
103
105
|
# supplied, it is extracted from a schema_info table. The schema_info
|
@@ -121,6 +123,19 @@ module Sequel
|
|
121
123
|
target
|
122
124
|
end
|
123
125
|
|
126
|
+
# Gets the current migration version stored in the database. If no version
|
127
|
+
# number is stored, 0 is returned.
|
128
|
+
def self.get_current_migration_version(db)
|
129
|
+
r = schema_info_dataset(db).first
|
130
|
+
r ? r[:version] : 0
|
131
|
+
end
|
132
|
+
|
133
|
+
# Returns the latest version available in the specified directory.
|
134
|
+
def self.latest_migration_version(directory)
|
135
|
+
l = migration_files(directory).last
|
136
|
+
l ? File.basename(l).to_i : nil
|
137
|
+
end
|
138
|
+
|
124
139
|
# Returns a list of migration classes filtered for the migration range and
|
125
140
|
# ordered according to the migration direction.
|
126
141
|
def self.migration_classes(directory, target, current, direction)
|
@@ -142,50 +157,27 @@ module Sequel
|
|
142
157
|
classes
|
143
158
|
end
|
144
159
|
|
145
|
-
MIGRATION_FILE_PATTERN = '[0-9][0-9][0-9]_*.rb'.freeze
|
146
|
-
|
147
160
|
# Returns any found migration files in the supplied directory.
|
148
161
|
def self.migration_files(directory, range = nil)
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
m
|
162
|
+
files = []
|
163
|
+
Dir.new(directory).each do |file|
|
164
|
+
files[file.to_i] = File.join(directory, file) if MIGRATION_FILE_PATTERN.match(file)
|
153
165
|
end
|
154
166
|
filtered = range ? files[range] : files
|
155
167
|
filtered ? filtered.compact : []
|
156
168
|
end
|
157
169
|
|
158
|
-
# Returns the
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
# Gets the current migration version stored in the database. If no version
|
165
|
-
# number is stored, 0 is returned.
|
166
|
-
def self.get_current_migration_version(db)
|
167
|
-
r = schema_info_dataset(db).first
|
168
|
-
r ? r[:version] : 0
|
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
|
+
db.create_table(:schema_info) {integer :version} unless db.table_exists?(:schema_info)
|
174
|
+
db[:schema_info]
|
169
175
|
end
|
170
176
|
|
171
177
|
# Sets the current migration version stored in the database.
|
172
178
|
def self.set_current_migration_version(db, version)
|
173
179
|
dataset = schema_info_dataset(db)
|
174
|
-
|
175
|
-
dataset.update(:version => version)
|
176
|
-
else
|
177
|
-
dataset << {:version => version}
|
178
|
-
end
|
179
|
-
end
|
180
|
-
|
181
|
-
# Returns the dataset for the schema_info table. If no such table
|
182
|
-
# exists, it is automatically created.
|
183
|
-
def self.schema_info_dataset(db)
|
184
|
-
unless db.table_exists?(:schema_info)
|
185
|
-
db.create_table(:schema_info) {integer :version}
|
186
|
-
end
|
187
|
-
|
188
|
-
db[:schema_info]
|
180
|
+
dataset.send(dataset.first ? :update : :<<, :version => version)
|
189
181
|
end
|
190
182
|
end
|
191
183
|
end
|
@@ -68,7 +68,7 @@ module Sequel
|
|
68
68
|
raise_alias_error.call if @opts[:graph] && @opts[:graph][:table_aliases] && @opts[:graph][:table_aliases].include?(table_alias)
|
69
69
|
|
70
70
|
# Join the table early in order to avoid cloning the dataset twice
|
71
|
-
ds = join_table(options[:join_type] || :left_outer, table
|
71
|
+
ds = join_table(options[:join_type] || :left_outer, table, join_conditions, table_alias)
|
72
72
|
opts = ds.opts
|
73
73
|
|
74
74
|
# Whether to include the table in the result set
|
@@ -162,50 +162,51 @@ module Sequel
|
|
162
162
|
end
|
163
163
|
|
164
164
|
private
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
165
|
+
|
166
|
+
# Fetch the rows, split them into component table parts,
|
167
|
+
# tranform and run the row_proc on each part (if applicable),
|
168
|
+
# and yield a hash of the parts.
|
169
|
+
def graph_each(opts, &block)
|
170
|
+
# Reject tables with nil datasets, as they are excluded from
|
171
|
+
# the result set
|
172
|
+
datasets = @opts[:graph][:table_aliases].to_a.reject{|ta,ds| ds.nil?}
|
173
|
+
# Get just the list of table aliases into a local variable, for speed
|
174
|
+
table_aliases = datasets.collect{|ta,ds| ta}
|
175
|
+
# Get an array of arrays, one for each dataset, with
|
176
|
+
# the necessary information about each dataset, for speed
|
177
|
+
datasets = datasets.collect do |ta, ds|
|
178
|
+
[ta, ds, ds.instance_variable_get(:@transform), ds.row_proc]
|
179
|
+
end
|
180
|
+
# Use the manually set graph aliases, if any, otherwise
|
181
|
+
# use the ones automatically created by .graph
|
182
|
+
column_aliases = @opts[:graph_aliases] || @opts[:graph][:column_aliases]
|
183
|
+
fetch_rows(select_sql(opts)) do |r|
|
184
|
+
graph = {}
|
185
|
+
# Create the sub hashes, one per table
|
186
|
+
table_aliases.each{|ta| graph[ta]={}}
|
187
|
+
# Split the result set based on the column aliases
|
188
|
+
# If there are columns in the result set that are
|
189
|
+
# not in column_aliases, they are ignored
|
190
|
+
column_aliases.each do |col_alias, tc|
|
191
|
+
ta, column = tc
|
192
|
+
graph[ta][column] = r[col_alias]
|
178
193
|
end
|
179
|
-
#
|
180
|
-
#
|
181
|
-
|
182
|
-
|
183
|
-
graph =
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
column_aliases.each do |col_alias, tc|
|
190
|
-
ta, column = tc
|
191
|
-
graph[ta][column] = r[col_alias]
|
192
|
-
end
|
193
|
-
# For each dataset, transform and run the row
|
194
|
-
# row_proc if applicable
|
195
|
-
datasets.each do |ta,ds,tr,rp|
|
196
|
-
g = graph[ta]
|
197
|
-
graph[ta] = if g.values.any?
|
198
|
-
g = ds.transform_load(g) if tr
|
199
|
-
g = rp[g] if rp
|
200
|
-
g
|
201
|
-
else
|
202
|
-
nil
|
203
|
-
end
|
194
|
+
# For each dataset, transform and run the row
|
195
|
+
# row_proc if applicable
|
196
|
+
datasets.each do |ta,ds,tr,rp|
|
197
|
+
g = graph[ta]
|
198
|
+
graph[ta] = if g.values.any?
|
199
|
+
g = ds.transform_load(g) if tr
|
200
|
+
g = rp[g] if rp
|
201
|
+
g
|
202
|
+
else
|
203
|
+
nil
|
204
204
|
end
|
205
|
-
|
206
|
-
yield graph
|
207
205
|
end
|
208
|
-
|
206
|
+
|
207
|
+
yield graph
|
209
208
|
end
|
209
|
+
self
|
210
|
+
end
|
210
211
|
end
|
211
212
|
end
|
@@ -1,76 +1,71 @@
|
|
1
|
-
module Sequel
|
2
|
-
module PrettyTable
|
3
|
-
# Prints nice-looking plain-text tables
|
4
|
-
#
|
5
|
-
# +--+-------+
|
6
|
-
# |id|name |
|
7
|
-
# |--+-------|
|
8
|
-
# |1 |fasdfas|
|
9
|
-
# |2 |test |
|
10
|
-
# +--+-------+
|
11
|
-
def self.print(records, columns = nil) # records is an array of hashes
|
12
|
-
columns ||=
|
13
|
-
sizes = column_sizes(records, columns)
|
14
|
-
|
15
|
-
|
16
|
-
puts
|
17
|
-
puts
|
18
|
-
|
19
|
-
puts
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
'|' + columns.map {|c| "%-#{sizes[c]}s" % c.to_s}.join('|') + '|'
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
1
|
+
module Sequel
|
2
|
+
module PrettyTable
|
3
|
+
# Prints nice-looking plain-text tables via puts
|
4
|
+
#
|
5
|
+
# +--+-------+
|
6
|
+
# |id|name |
|
7
|
+
# |--+-------|
|
8
|
+
# |1 |fasdfas|
|
9
|
+
# |2 |test |
|
10
|
+
# +--+-------+
|
11
|
+
def self.print(records, columns = nil) # records is an array of hashes
|
12
|
+
columns ||= records.first.keys.sort_by{|x|x.to_s}
|
13
|
+
sizes = column_sizes(records, columns)
|
14
|
+
sep_line = separator_line(columns, sizes)
|
15
|
+
|
16
|
+
puts sep_line
|
17
|
+
puts header_line(columns, sizes)
|
18
|
+
puts sep_line
|
19
|
+
records.each {|r| puts data_line(columns, sizes, r)}
|
20
|
+
puts sep_line
|
21
|
+
end
|
22
|
+
|
23
|
+
### Private Module Methods ###
|
24
|
+
|
25
|
+
# Hash of the maximum size of the value for each column
|
26
|
+
def self.column_sizes(records, columns) # :nodoc:
|
27
|
+
sizes = Hash.new {0}
|
28
|
+
columns.each do |c|
|
29
|
+
s = c.to_s.size
|
30
|
+
sizes[c.to_sym] = s if s > sizes[c.to_sym]
|
31
|
+
end
|
32
|
+
records.each do |r|
|
33
|
+
columns.each do |c|
|
34
|
+
s = r[c].to_s.size
|
35
|
+
sizes[c.to_sym] = s if s > sizes[c.to_sym]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
sizes
|
39
|
+
end
|
40
|
+
|
41
|
+
# String for each data line
|
42
|
+
def self.data_line(columns, sizes, record) # :nodoc:
|
43
|
+
'|' << columns.map {|c| format_cell(sizes[c], record[c])}.join('|') << '|'
|
44
|
+
end
|
45
|
+
|
46
|
+
# Format the value so it takes up exactly size characters
|
47
|
+
def self.format_cell(size, v) # :nodoc:
|
48
|
+
case v
|
49
|
+
when Bignum, Fixnum
|
50
|
+
"%#{size}d" % v
|
51
|
+
when Float
|
52
|
+
"%#{size}g" % v
|
53
|
+
else
|
54
|
+
"%-#{size}s" % v.to_s
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# String for header line
|
59
|
+
def self.header_line(columns, sizes) # :nodoc:
|
60
|
+
'|' << columns.map {|c| "%-#{sizes[c]}s" % c.to_s}.join('|') << '|'
|
61
|
+
end
|
62
|
+
|
63
|
+
# String for separtor line
|
64
|
+
def self.separator_line(columns, sizes) # :nodoc:
|
65
|
+
'+' << columns.map {|c| '-' * sizes[c]}.join('+') << '+'
|
66
|
+
end
|
67
|
+
|
68
|
+
metaprivate :column_sizes, :data_line, :format_cell, :header_line, :separator_line
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|