sequel_core 2.2.0 → 3.8.0
Sign up to get free protection for your applications and to get access to all the features.
- metadata +30 -101
- data/CHANGELOG +0 -1519
- data/COPYING +0 -19
- data/README +0 -313
- data/Rakefile +0 -158
- data/bin/sequel +0 -117
- data/doc/cheat_sheet.rdoc +0 -225
- data/doc/dataset_filtering.rdoc +0 -182
- data/lib/sequel_core.rb +0 -136
- data/lib/sequel_core/adapters/adapter_skeleton.rb +0 -68
- data/lib/sequel_core/adapters/ado.rb +0 -90
- data/lib/sequel_core/adapters/db2.rb +0 -160
- data/lib/sequel_core/adapters/dbi.rb +0 -127
- data/lib/sequel_core/adapters/informix.rb +0 -89
- data/lib/sequel_core/adapters/jdbc.rb +0 -110
- data/lib/sequel_core/adapters/mysql.rb +0 -486
- data/lib/sequel_core/adapters/odbc.rb +0 -167
- data/lib/sequel_core/adapters/odbc_mssql.rb +0 -106
- data/lib/sequel_core/adapters/openbase.rb +0 -76
- data/lib/sequel_core/adapters/oracle.rb +0 -182
- data/lib/sequel_core/adapters/postgres.rb +0 -560
- data/lib/sequel_core/adapters/sqlite.rb +0 -270
- data/lib/sequel_core/connection_pool.rb +0 -194
- data/lib/sequel_core/core_ext.rb +0 -197
- data/lib/sequel_core/core_sql.rb +0 -184
- data/lib/sequel_core/database.rb +0 -462
- data/lib/sequel_core/database/schema.rb +0 -156
- data/lib/sequel_core/dataset.rb +0 -457
- data/lib/sequel_core/dataset/callback.rb +0 -13
- data/lib/sequel_core/dataset/convenience.rb +0 -245
- data/lib/sequel_core/dataset/pagination.rb +0 -96
- data/lib/sequel_core/dataset/query.rb +0 -41
- data/lib/sequel_core/dataset/schema.rb +0 -15
- data/lib/sequel_core/dataset/sql.rb +0 -889
- data/lib/sequel_core/deprecated.rb +0 -26
- data/lib/sequel_core/exceptions.rb +0 -42
- data/lib/sequel_core/migration.rb +0 -187
- data/lib/sequel_core/object_graph.rb +0 -216
- data/lib/sequel_core/pretty_table.rb +0 -71
- data/lib/sequel_core/schema.rb +0 -2
- data/lib/sequel_core/schema/generator.rb +0 -239
- data/lib/sequel_core/schema/sql.rb +0 -326
- data/lib/sequel_core/sql.rb +0 -812
- data/lib/sequel_core/worker.rb +0 -68
- data/spec/adapters/informix_spec.rb +0 -96
- data/spec/adapters/mysql_spec.rb +0 -765
- data/spec/adapters/oracle_spec.rb +0 -222
- data/spec/adapters/postgres_spec.rb +0 -441
- data/spec/adapters/sqlite_spec.rb +0 -413
- data/spec/connection_pool_spec.rb +0 -363
- data/spec/core_ext_spec.rb +0 -156
- data/spec/core_sql_spec.rb +0 -427
- data/spec/database_spec.rb +0 -963
- data/spec/dataset_spec.rb +0 -2933
- data/spec/expression_filters_spec.rb +0 -316
- data/spec/migration_spec.rb +0 -261
- data/spec/object_graph_spec.rb +0 -230
- data/spec/pretty_table_spec.rb +0 -58
- data/spec/rcov.opts +0 -6
- data/spec/schema_generator_spec.rb +0 -122
- data/spec/schema_spec.rb +0 -422
- data/spec/spec.opts +0 -0
- data/spec/spec_config.rb +0 -7
- data/spec/spec_config.rb.example +0 -8
- data/spec/spec_helper.rb +0 -55
- data/spec/worker_spec.rb +0 -96
@@ -1,71 +0,0 @@
|
|
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
|
-
private_class_method :column_sizes, :data_line, :format_cell, :header_line, :separator_line
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
data/lib/sequel_core/schema.rb
DELETED
@@ -1,239 +0,0 @@
|
|
1
|
-
module Sequel
|
2
|
-
# The Schema module holds the schema generators and the SQL code relating
|
3
|
-
# to SQL DDL (Data Definition Language).
|
4
|
-
module Schema
|
5
|
-
# Schema::Generator is used to create tables. It takes a Database
|
6
|
-
# object and a block of column/index/constraint specifications, and
|
7
|
-
# creates a table in the database based on the specifications.
|
8
|
-
#
|
9
|
-
# Schema::Generator has some methods but also includes method_missing,
|
10
|
-
# allowing users to specify column type as a method instead of using
|
11
|
-
# the column method, which makes for a nicer DSL.
|
12
|
-
#
|
13
|
-
# See Database#create_table.
|
14
|
-
class Generator
|
15
|
-
# Set the database in which to create the table, and evaluate the block
|
16
|
-
# in the context of this object.
|
17
|
-
def initialize(db, &block)
|
18
|
-
@db = db
|
19
|
-
@columns = []
|
20
|
-
@indexes = []
|
21
|
-
@primary_key = nil
|
22
|
-
instance_eval(&block) if block
|
23
|
-
end
|
24
|
-
|
25
|
-
# Add a unnamed constraint to the DDL, specified by the given block
|
26
|
-
# or args.
|
27
|
-
def check(*args, &block)
|
28
|
-
constraint(nil, *args, &block)
|
29
|
-
end
|
30
|
-
|
31
|
-
# Add a column with the given name, type, and opts to the DDL.
|
32
|
-
#
|
33
|
-
# You can also create columns via method missing, so the following are
|
34
|
-
# equivalent:
|
35
|
-
#
|
36
|
-
# column :number, :integer
|
37
|
-
# integer :number
|
38
|
-
#
|
39
|
-
# The following options are supported:
|
40
|
-
#
|
41
|
-
# * :default - The default value for the column.
|
42
|
-
# * :index - Create an index on this column.
|
43
|
-
# * :key - For foreign key columns, the column in the associated table
|
44
|
-
# that this column references. Unnecessary if this column
|
45
|
-
# references the primary key of the associated table.
|
46
|
-
# * :null - Mark the column as allowing NULL values (if true),
|
47
|
-
# or not allowing NULL values (if false). If unspecified, will default
|
48
|
-
# to whatever the database default is.
|
49
|
-
# * :on_delete - Specify the behavior of this column when being deleted.
|
50
|
-
# See Schema::SQL#on_delete_clause for options.
|
51
|
-
# * :size - The size of the column, generally used with string
|
52
|
-
# columns to specify the maximum number of characters the column will hold.
|
53
|
-
# * :unique - Mark the column is unique, generally has the same effect as
|
54
|
-
# creating a unique index on the column.
|
55
|
-
# * :unsigned - Make the column type unsigned, only useful for integer
|
56
|
-
# columns.
|
57
|
-
def column(name, type, opts = {})
|
58
|
-
@columns << {:name => name, :type => type}.merge(opts)
|
59
|
-
index(name) if opts[:index]
|
60
|
-
end
|
61
|
-
|
62
|
-
# Adds a named constraint (or unnamed if name is nil) to the DDL,
|
63
|
-
# with the given block or args.
|
64
|
-
def constraint(name, *args, &block)
|
65
|
-
@columns << {:name => name, :type => :check, :check => block || args}
|
66
|
-
end
|
67
|
-
|
68
|
-
# Return the DDL created by the generator as a array of two elements,
|
69
|
-
# the first being the columns and the second being the indexes.
|
70
|
-
def create_info
|
71
|
-
@columns.unshift(@primary_key) if @primary_key && !has_column?(primary_key_name)
|
72
|
-
[@columns, @indexes]
|
73
|
-
end
|
74
|
-
|
75
|
-
# Add a foreign key in the table that references another table to the DDL. See column
|
76
|
-
# for available options.
|
77
|
-
def foreign_key(name, table=nil, opts = {})
|
78
|
-
opts = case table
|
79
|
-
when Hash
|
80
|
-
table.merge(opts)
|
81
|
-
when Symbol
|
82
|
-
opts.merge(:table=>table)
|
83
|
-
when NilClass
|
84
|
-
opts
|
85
|
-
else
|
86
|
-
raise(Error, "The seconds argument to foreign_key should be a Hash, Symbol, or nil")
|
87
|
-
end
|
88
|
-
column(name, :integer, opts)
|
89
|
-
end
|
90
|
-
|
91
|
-
# Add a full text index on the given columns to the DDL.
|
92
|
-
def full_text_index(columns, opts = {})
|
93
|
-
index(columns, opts.merge(:type => :full_text))
|
94
|
-
end
|
95
|
-
|
96
|
-
# True if the DDL includes the creation of a column with the given name.
|
97
|
-
def has_column?(name)
|
98
|
-
@columns.any?{|c| c[:name] == name}
|
99
|
-
end
|
100
|
-
|
101
|
-
# Add an index on the given column(s) with the given options to the DDL.
|
102
|
-
# The available options are:
|
103
|
-
#
|
104
|
-
# * :type - The type of index to use (only supported by some databases)
|
105
|
-
# * :unique - Make the index unique, so duplicate values are not allowed.
|
106
|
-
# * :where - Create a partial index (only supported by some databases)
|
107
|
-
def index(columns, opts = {})
|
108
|
-
@indexes << {:columns => Array(columns)}.merge(opts)
|
109
|
-
end
|
110
|
-
|
111
|
-
# Add a column with the given type, name, and opts to the DDL. See column for available
|
112
|
-
# options.
|
113
|
-
def method_missing(type, name = nil, opts = {})
|
114
|
-
name ? column(name, type, opts) : super
|
115
|
-
end
|
116
|
-
|
117
|
-
# Add a column with the given name and primary key options to the DDL. You
|
118
|
-
# can optionally provide a type argument and/or an options hash argument
|
119
|
-
# to change the primary key options. See column for available options.
|
120
|
-
def primary_key(name, *args)
|
121
|
-
@primary_key = @db.serial_primary_key_options.merge({:name => name})
|
122
|
-
|
123
|
-
if opts = args.pop
|
124
|
-
opts = {:type => opts} unless opts.is_a?(Hash)
|
125
|
-
if type = args.pop
|
126
|
-
opts.merge!(:type => type)
|
127
|
-
end
|
128
|
-
@primary_key.merge!(opts)
|
129
|
-
end
|
130
|
-
@primary_key
|
131
|
-
end
|
132
|
-
|
133
|
-
# The name of the primary key for this table, if it has a primary key.
|
134
|
-
def primary_key_name
|
135
|
-
@primary_key[:name] if @primary_key
|
136
|
-
end
|
137
|
-
|
138
|
-
# Add a spatial index on the given columns to the DDL.
|
139
|
-
def spatial_index(columns, opts = {})
|
140
|
-
index(columns, opts.merge(:type => :spatial))
|
141
|
-
end
|
142
|
-
|
143
|
-
# Add a unique index on the given columns to the DDL.
|
144
|
-
def unique(columns, opts = {})
|
145
|
-
index(columns, opts.merge(:unique => true))
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
# The Schema::AlterTableGenerator creates DDL operations on existing tables,
|
150
|
-
# such as adding/removing/modifying columns/indexes/constraints.
|
151
|
-
class AlterTableGenerator
|
152
|
-
# An array of DDL operations to perform
|
153
|
-
attr_reader :operations
|
154
|
-
|
155
|
-
# Set the Database object to which to apply the DDL, and evaluate the
|
156
|
-
# block in the context of this object.
|
157
|
-
def initialize(db, &block)
|
158
|
-
@db = db
|
159
|
-
@operations = []
|
160
|
-
instance_eval(&block) if block
|
161
|
-
end
|
162
|
-
|
163
|
-
# Add a column with the given name, type, and opts to the DDL for the table.
|
164
|
-
# See Generator#column for the available options.
|
165
|
-
def add_column(name, type, opts = {})
|
166
|
-
@operations << {:op => :add_column, :name => name, :type => type}.merge(opts)
|
167
|
-
end
|
168
|
-
|
169
|
-
# Add a constraint with the given name and args to the DDL for the table.
|
170
|
-
# See Generator#constraint.
|
171
|
-
def add_constraint(name, *args, &block)
|
172
|
-
@operations << {:op => :add_constraint, :name => name, :type => :check, \
|
173
|
-
:check => block || args}
|
174
|
-
end
|
175
|
-
|
176
|
-
# Add a foreign key with the given name and referencing the given table
|
177
|
-
# to the DDL for the table. See Generator#column for the available options.
|
178
|
-
def add_foreign_key(name, table, opts = {})
|
179
|
-
add_column(name, :integer, {:table=>table}.merge(opts))
|
180
|
-
end
|
181
|
-
|
182
|
-
# Add a full text index on the given columns to the DDL for the table.
|
183
|
-
# See Generator#index for available options.
|
184
|
-
def add_full_text_index(columns, opts = {})
|
185
|
-
add_index(columns, {:type=>:full_text}.merge(opts))
|
186
|
-
end
|
187
|
-
|
188
|
-
# Add an index on the given columns to the DDL for the table. See
|
189
|
-
# Generator#index for available options.
|
190
|
-
def add_index(columns, opts = {})
|
191
|
-
@operations << {:op => :add_index, :columns => Array(columns)}.merge(opts)
|
192
|
-
end
|
193
|
-
|
194
|
-
# Add a primary key to the DDL for the table. See Generator#column
|
195
|
-
# for the available options.
|
196
|
-
def add_primary_key(name, opts = {})
|
197
|
-
opts = @db.serial_primary_key_options.merge(opts)
|
198
|
-
add_column(name, opts.delete(:type), opts)
|
199
|
-
end
|
200
|
-
|
201
|
-
# Add a spatial index on the given columns to the DDL for the table.
|
202
|
-
# See Generator#index for available options.
|
203
|
-
def add_spatial_index(columns, opts = {})
|
204
|
-
add_index(columns, {:type=>:spatial}.merge(opts))
|
205
|
-
end
|
206
|
-
|
207
|
-
# Remove a column from the DDL for the table.
|
208
|
-
def drop_column(name)
|
209
|
-
@operations << {:op => :drop_column, :name => name}
|
210
|
-
end
|
211
|
-
|
212
|
-
# Remove a constraint from the DDL for the table.
|
213
|
-
def drop_constraint(name)
|
214
|
-
@operations << {:op => :drop_constraint, :name => name}
|
215
|
-
end
|
216
|
-
|
217
|
-
# Remove an index from the DDL for the table.
|
218
|
-
def drop_index(columns)
|
219
|
-
@operations << {:op => :drop_index, :columns => Array(columns)}
|
220
|
-
end
|
221
|
-
|
222
|
-
# Modify a column's name in the DDL for the table.
|
223
|
-
def rename_column(name, new_name, opts = {})
|
224
|
-
@operations << {:op => :rename_column, :name => name, :new_name => new_name}.merge(opts)
|
225
|
-
end
|
226
|
-
|
227
|
-
# Modify a column's default value in the DDL for the table.
|
228
|
-
def set_column_default(name, default)
|
229
|
-
@operations << {:op => :set_column_default, :name => name, :default => default}
|
230
|
-
end
|
231
|
-
|
232
|
-
# Modify a column's type in the DDL for the table.
|
233
|
-
def set_column_type(name, type)
|
234
|
-
@operations << {:op => :set_column_type, :name => name, :type => type}
|
235
|
-
end
|
236
|
-
end
|
237
|
-
end
|
238
|
-
end
|
239
|
-
|
@@ -1,326 +0,0 @@
|
|
1
|
-
module Sequel
|
2
|
-
module Schema
|
3
|
-
module SQL
|
4
|
-
AUTOINCREMENT = 'AUTOINCREMENT'.freeze
|
5
|
-
CASCADE = 'CASCADE'.freeze
|
6
|
-
COMMA_SEPARATOR = ', '.freeze
|
7
|
-
NO_ACTION = 'NO ACTION'.freeze
|
8
|
-
NOT_NULL = ' NOT NULL'.freeze
|
9
|
-
NULL = ' NULL'.freeze
|
10
|
-
PRIMARY_KEY = ' PRIMARY KEY'.freeze
|
11
|
-
RESTRICT = 'RESTRICT'.freeze
|
12
|
-
SET_DEFAULT = 'SET DEFAULT'.freeze
|
13
|
-
SET_NULL = 'SET NULL'.freeze
|
14
|
-
TYPES = Hash.new {|h, k| k}
|
15
|
-
TYPES[:double] = 'double precision'
|
16
|
-
UNDERSCORE = '_'.freeze
|
17
|
-
UNIQUE = ' UNIQUE'.freeze
|
18
|
-
UNSIGNED = ' UNSIGNED'.freeze
|
19
|
-
|
20
|
-
# The SQL to execute to modify the DDL for the given table name. op
|
21
|
-
# should be one of the operations returned by the AlterTableGenerator.
|
22
|
-
def alter_table_sql(table, op)
|
23
|
-
quoted_table = quote_identifier(table)
|
24
|
-
quoted_name = quote_identifier(op[:name]) if op[:name]
|
25
|
-
case op[:op]
|
26
|
-
when :add_column
|
27
|
-
"ALTER TABLE #{quoted_table} ADD COLUMN #{column_definition_sql(op)}"
|
28
|
-
when :drop_column
|
29
|
-
"ALTER TABLE #{quoted_table} DROP COLUMN #{quoted_name}"
|
30
|
-
when :rename_column
|
31
|
-
"ALTER TABLE #{quoted_table} RENAME COLUMN #{quoted_name} TO #{quote_identifier(op[:new_name])}"
|
32
|
-
when :set_column_type
|
33
|
-
"ALTER TABLE #{quoted_table} ALTER COLUMN #{quoted_name} TYPE #{op[:type]}"
|
34
|
-
when :set_column_default
|
35
|
-
"ALTER TABLE #{quoted_table} ALTER COLUMN #{quoted_name} SET DEFAULT #{literal(op[:default])}"
|
36
|
-
when :add_index
|
37
|
-
index_definition_sql(table, op)
|
38
|
-
when :drop_index
|
39
|
-
"DROP INDEX #{default_index_name(table, op[:columns])}"
|
40
|
-
when :add_constraint
|
41
|
-
"ALTER TABLE #{quoted_table} ADD #{constraint_definition_sql(op)}"
|
42
|
-
when :drop_constraint
|
43
|
-
"ALTER TABLE #{quoted_table} DROP CONSTRAINT #{quoted_name}"
|
44
|
-
else
|
45
|
-
raise Error, "Unsupported ALTER TABLE operation"
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
# Array of SQL DDL modification statements for the given table,
|
50
|
-
# corresponding to the DDL changes specified by the operations.
|
51
|
-
def alter_table_sql_list(table, operations)
|
52
|
-
operations.map{|op| alter_table_sql(table, op)}
|
53
|
-
end
|
54
|
-
|
55
|
-
# The SQL string specify the autoincrement property, generally used by
|
56
|
-
# primary keys.
|
57
|
-
def auto_increment_sql
|
58
|
-
AUTOINCREMENT
|
59
|
-
end
|
60
|
-
|
61
|
-
# SQL DDL fragment containing the column creation SQL for the given column.
|
62
|
-
def column_definition_sql(column)
|
63
|
-
return constraint_definition_sql(column) if column[:type] == :check
|
64
|
-
sql = "#{quote_identifier(column[:name])} #{type_literal(TYPES[column[:type]])}"
|
65
|
-
column[:size] ||= 255 if column[:type] == :varchar
|
66
|
-
elements = column[:size] || column[:elements]
|
67
|
-
sql << literal(Array(elements)) if elements
|
68
|
-
sql << UNSIGNED if column[:unsigned]
|
69
|
-
sql << UNIQUE if column[:unique]
|
70
|
-
sql << NOT_NULL if column[:null] == false
|
71
|
-
sql << NULL if column[:null] == true
|
72
|
-
sql << " DEFAULT #{literal(column[:default])}" if column.include?(:default)
|
73
|
-
sql << PRIMARY_KEY if column[:primary_key]
|
74
|
-
sql << " #{auto_increment_sql}" if column[:auto_increment]
|
75
|
-
if column[:table]
|
76
|
-
sql << " REFERENCES #{quote_identifier(column[:table])}"
|
77
|
-
sql << "(#{quote_identifier(column[:key])})" if column[:key]
|
78
|
-
sql << " ON DELETE #{on_delete_clause(column[:on_delete])}" if column[:on_delete]
|
79
|
-
end
|
80
|
-
sql
|
81
|
-
end
|
82
|
-
|
83
|
-
# SQL DDL fragment containing the column creation
|
84
|
-
# SQL for all given columns, used instead a CREATE TABLE block.
|
85
|
-
def column_list_sql(columns)
|
86
|
-
columns.map{|c| column_definition_sql(c)}.join(COMMA_SEPARATOR)
|
87
|
-
end
|
88
|
-
|
89
|
-
# SQL DDL fragment specifying a constraint on a table.
|
90
|
-
def constraint_definition_sql(constraint)
|
91
|
-
sql = constraint[:name] ? "CONSTRAINT #{quote_identifier(constraint[:name])} " : ""
|
92
|
-
sql << "CHECK #{filter_expr(constraint[:check])}"
|
93
|
-
sql
|
94
|
-
end
|
95
|
-
|
96
|
-
# Array of SQL DDL statements, the first for creating a table with the given
|
97
|
-
# name and column specifications, and the others for specifying indexes on
|
98
|
-
# the table.
|
99
|
-
def create_table_sql_list(name, columns, indexes = nil)
|
100
|
-
sql = ["CREATE TABLE #{quote_identifier(name)} (#{column_list_sql(columns)})"]
|
101
|
-
sql.concat(index_list_sql_list(name, indexes)) if indexes && !indexes.empty?
|
102
|
-
sql
|
103
|
-
end
|
104
|
-
|
105
|
-
# Default index name for the table and columns, may be too long
|
106
|
-
# for certain databases.
|
107
|
-
def default_index_name(table_name, columns)
|
108
|
-
"#{table_name}_#{columns.join(UNDERSCORE)}_index"
|
109
|
-
end
|
110
|
-
|
111
|
-
# SQL DDL statement to drop the table with the given name.
|
112
|
-
def drop_table_sql(name)
|
113
|
-
"DROP TABLE #{quote_identifier(name)}"
|
114
|
-
end
|
115
|
-
|
116
|
-
# Proxy the filter_expr call to the dataset, used for creating constraints.
|
117
|
-
def filter_expr(*args, &block)
|
118
|
-
schema_utility_dataset.literal(schema_utility_dataset.send(:filter_expr, *args, &block))
|
119
|
-
end
|
120
|
-
|
121
|
-
# SQL DDL statement for creating an index for the table with the given name
|
122
|
-
# and index specifications.
|
123
|
-
def index_definition_sql(table_name, index)
|
124
|
-
index_name = index[:name] || default_index_name(table_name, index[:columns])
|
125
|
-
if index[:type]
|
126
|
-
raise Error, "Index types are not supported for this database"
|
127
|
-
elsif index[:where]
|
128
|
-
raise Error, "Partial indexes are not supported for this database"
|
129
|
-
else
|
130
|
-
"CREATE #{'UNIQUE ' if index[:unique]}INDEX #{index_name} ON #{quote_identifier(table_name)} #{literal(index[:columns])}"
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
# Array of SQL DDL statements, one for each index specification,
|
135
|
-
# for the given table.
|
136
|
-
def index_list_sql_list(table_name, indexes)
|
137
|
-
indexes.map{|i| index_definition_sql(table_name, i)}
|
138
|
-
end
|
139
|
-
|
140
|
-
# Proxy the literal call to the dataset, used for default values.
|
141
|
-
def literal(v)
|
142
|
-
schema_utility_dataset.literal(v)
|
143
|
-
end
|
144
|
-
|
145
|
-
# SQL DDL ON DELETE fragment to use, based on the given action.
|
146
|
-
# The following actions are recognized:
|
147
|
-
#
|
148
|
-
# * :cascade - Delete rows referencing this row.
|
149
|
-
# * :no_action (default) - Raise an error if other rows reference this
|
150
|
-
# row, allow deferring of the integrity check.
|
151
|
-
# * :restrict - Raise an error if other rows reference this row,
|
152
|
-
# but do not allow deferring the integrity check.
|
153
|
-
# * :set_default - Set columns referencing this row to their default value.
|
154
|
-
# * :set_null - Set columns referencing this row to NULL.
|
155
|
-
def on_delete_clause(action)
|
156
|
-
case action
|
157
|
-
when :restrict
|
158
|
-
RESTRICT
|
159
|
-
when :cascade
|
160
|
-
CASCADE
|
161
|
-
when :set_null
|
162
|
-
SET_NULL
|
163
|
-
when :set_default
|
164
|
-
SET_DEFAULT
|
165
|
-
else
|
166
|
-
NO_ACTION
|
167
|
-
end
|
168
|
-
end
|
169
|
-
|
170
|
-
# Proxy the quote_identifier method to the dataset, used for quoting tables and columns.
|
171
|
-
def quote_identifier(v)
|
172
|
-
schema_utility_dataset.quote_identifier(v)
|
173
|
-
end
|
174
|
-
|
175
|
-
# SQL DDL statement for renaming a table.
|
176
|
-
def rename_table_sql(name, new_name)
|
177
|
-
"ALTER TABLE #{quote_identifier(name)} RENAME TO #{quote_identifier(new_name)}"
|
178
|
-
end
|
179
|
-
|
180
|
-
# Parse the schema from the database using the SQL standard INFORMATION_SCHEMA.
|
181
|
-
# If the table_name is not given, returns the schema for all tables as a hash.
|
182
|
-
# If the table_name is given, returns the schema for a single table as an
|
183
|
-
# array with all members being arrays of length 2. Available options are:
|
184
|
-
#
|
185
|
-
# * :reload - Get fresh information from the database, instead of using
|
186
|
-
# cached information. If table_name is blank, :reload should be used
|
187
|
-
# unless you are sure that schema has not been called before with a
|
188
|
-
# table_name, otherwise you may only getting the schemas for tables
|
189
|
-
# that have been requested explicitly.
|
190
|
-
def schema(table_name = nil, opts={})
|
191
|
-
if opts[:reload] && @schemas
|
192
|
-
if table_name
|
193
|
-
@schemas.delete(table_name)
|
194
|
-
else
|
195
|
-
@schemas = nil
|
196
|
-
end
|
197
|
-
end
|
198
|
-
|
199
|
-
if table_name
|
200
|
-
return @schemas[table_name] if @schemas && @schemas[table_name]
|
201
|
-
else
|
202
|
-
return @schemas if @schemas
|
203
|
-
end
|
204
|
-
|
205
|
-
if table_name
|
206
|
-
@schemas ||= {}
|
207
|
-
@schemas[table_name] ||= schema_parse_table(table_name, opts)
|
208
|
-
else
|
209
|
-
@schemas = schema_parse_tables(opts)
|
210
|
-
end
|
211
|
-
end
|
212
|
-
|
213
|
-
# The dataset to use for proxying certain schema methods.
|
214
|
-
def schema_utility_dataset
|
215
|
-
@schema_utility_dataset ||= dataset
|
216
|
-
end
|
217
|
-
|
218
|
-
# SQL fragment specifying the type of a given column.
|
219
|
-
def type_literal(t)
|
220
|
-
t.is_a?(Symbol) ? t.to_s : literal(t)
|
221
|
-
end
|
222
|
-
|
223
|
-
private
|
224
|
-
|
225
|
-
# Match the database's column type to a ruby type via a
|
226
|
-
# regular expression. The following ruby types are supported:
|
227
|
-
# integer, string, date, datetime, boolean, and float.
|
228
|
-
def schema_column_type(db_type)
|
229
|
-
case db_type
|
230
|
-
when 'tinyint'
|
231
|
-
Sequel.convert_tinyint_to_bool ? :boolean : :integer
|
232
|
-
when /\A(int(eger)?|bigint|smallint)\z/
|
233
|
-
:integer
|
234
|
-
when /\A(character( varying)?|varchar|text)\z/
|
235
|
-
:string
|
236
|
-
when /\Adate\z/
|
237
|
-
:date
|
238
|
-
when /\A(datetime|timestamp( with(out)? time zone)?)\z/
|
239
|
-
:datetime
|
240
|
-
when /\Atime( with(out)? time zone)?\z/
|
241
|
-
:time
|
242
|
-
when "boolean"
|
243
|
-
:boolean
|
244
|
-
when /\A(real|float|double( precision)?)\z/
|
245
|
-
:float
|
246
|
-
when /\A(numeric|decimal|money)\z/
|
247
|
-
:decimal
|
248
|
-
when "bytea"
|
249
|
-
:blob
|
250
|
-
end
|
251
|
-
end
|
252
|
-
|
253
|
-
# The final dataset used by the schema parser, after all
|
254
|
-
# options have been applied.
|
255
|
-
def schema_ds(table_name, opts)
|
256
|
-
schema_ds_dataset.from(*schema_ds_from(table_name, opts)) \
|
257
|
-
.select(*schema_ds_select(table_name, opts)) \
|
258
|
-
.join(*schema_ds_join(table_name, opts)) \
|
259
|
-
.filter(*schema_ds_filter(table_name, opts))
|
260
|
-
end
|
261
|
-
|
262
|
-
# The blank dataset used by the schema parser.
|
263
|
-
def schema_ds_dataset
|
264
|
-
schema_utility_dataset
|
265
|
-
end
|
266
|
-
|
267
|
-
# Argument array for the schema dataset's filter method.
|
268
|
-
def schema_ds_filter(table_name, opts)
|
269
|
-
if table_name
|
270
|
-
[{:c__table_name=>table_name.to_s}]
|
271
|
-
else
|
272
|
-
[{:t__table_type=>'BASE TABLE'}]
|
273
|
-
end
|
274
|
-
end
|
275
|
-
|
276
|
-
# Argument array for the schema dataset's from method.
|
277
|
-
def schema_ds_from(table_name, opts)
|
278
|
-
[:information_schema__tables___t]
|
279
|
-
end
|
280
|
-
|
281
|
-
# Argument array for the schema dataset's join method.
|
282
|
-
def schema_ds_join(table_name, opts)
|
283
|
-
[:information_schema__columns, {:table_catalog=>:table_catalog,
|
284
|
-
:table_schema => :table_schema, :table_name => :table_name} , :c]
|
285
|
-
end
|
286
|
-
|
287
|
-
# Argument array for the schema dataset's select method.
|
288
|
-
def schema_ds_select(table_name, opts)
|
289
|
-
cols = [:column_name___column, :data_type___db_type, :character_maximum_length___max_chars, \
|
290
|
-
:numeric_precision, :column_default___default, :is_nullable___allow_null]
|
291
|
-
cols << :c__table_name unless table_name
|
292
|
-
cols
|
293
|
-
end
|
294
|
-
|
295
|
-
# Parse the schema for a given table.
|
296
|
-
def schema_parse_table(table_name, opts)
|
297
|
-
schema_parse_rows(schema_ds(table_name, opts))
|
298
|
-
end
|
299
|
-
|
300
|
-
# Parse the schema all tables in the database.
|
301
|
-
def schema_parse_tables(opts)
|
302
|
-
schemas = {}
|
303
|
-
schema_ds(nil, opts).each do |row|
|
304
|
-
(schemas[row.delete(:table_name).to_sym] ||= []) << row
|
305
|
-
end
|
306
|
-
schemas.each do |table, rows|
|
307
|
-
schemas[table] = schema_parse_rows(rows)
|
308
|
-
end
|
309
|
-
schemas
|
310
|
-
end
|
311
|
-
|
312
|
-
# Parse the output of the information schema columns into
|
313
|
-
# the hash used by Sequel.
|
314
|
-
def schema_parse_rows(rows)
|
315
|
-
schema = []
|
316
|
-
rows.each do |row|
|
317
|
-
row[:allow_null] = row[:allow_null] == 'YES' ? true : false
|
318
|
-
row[:default] = nil if row[:default].blank?
|
319
|
-
row[:type] = schema_column_type(row[:db_type])
|
320
|
-
schema << [row.delete(:column).to_sym, row]
|
321
|
-
end
|
322
|
-
schema
|
323
|
-
end
|
324
|
-
end
|
325
|
-
end
|
326
|
-
end
|