sequel 3.0.0 → 3.1.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 +100 -0
- data/README.rdoc +3 -3
- data/bin/sequel +102 -19
- data/doc/reflection.rdoc +83 -0
- data/doc/release_notes/3.1.0.txt +406 -0
- data/lib/sequel/adapters/ado.rb +11 -0
- data/lib/sequel/adapters/amalgalite.rb +5 -20
- data/lib/sequel/adapters/do.rb +44 -36
- data/lib/sequel/adapters/firebird.rb +29 -43
- data/lib/sequel/adapters/jdbc.rb +17 -27
- data/lib/sequel/adapters/mysql.rb +35 -40
- data/lib/sequel/adapters/odbc.rb +4 -23
- data/lib/sequel/adapters/oracle.rb +22 -19
- data/lib/sequel/adapters/postgres.rb +6 -15
- data/lib/sequel/adapters/shared/mssql.rb +1 -1
- data/lib/sequel/adapters/shared/mysql.rb +29 -10
- data/lib/sequel/adapters/shared/oracle.rb +6 -8
- data/lib/sequel/adapters/shared/postgres.rb +28 -72
- data/lib/sequel/adapters/shared/sqlite.rb +5 -3
- data/lib/sequel/adapters/sqlite.rb +5 -20
- data/lib/sequel/adapters/utils/savepoint_transactions.rb +80 -0
- data/lib/sequel/adapters/utils/unsupported.rb +0 -12
- data/lib/sequel/core.rb +12 -3
- data/lib/sequel/core_sql.rb +1 -8
- data/lib/sequel/database.rb +107 -43
- data/lib/sequel/database/schema_generator.rb +1 -0
- data/lib/sequel/database/schema_methods.rb +38 -4
- data/lib/sequel/dataset.rb +6 -0
- data/lib/sequel/dataset/convenience.rb +2 -2
- data/lib/sequel/dataset/graph.rb +2 -2
- data/lib/sequel/dataset/prepared_statements.rb +3 -8
- data/lib/sequel/dataset/sql.rb +93 -19
- data/lib/sequel/extensions/blank.rb +2 -1
- data/lib/sequel/extensions/inflector.rb +4 -3
- data/lib/sequel/extensions/migration.rb +13 -2
- data/lib/sequel/extensions/pagination.rb +4 -0
- data/lib/sequel/extensions/pretty_table.rb +4 -0
- data/lib/sequel/extensions/query.rb +4 -0
- data/lib/sequel/extensions/schema_dumper.rb +100 -24
- data/lib/sequel/extensions/string_date_time.rb +3 -4
- data/lib/sequel/model.rb +2 -1
- data/lib/sequel/model/associations.rb +96 -38
- data/lib/sequel/model/base.rb +14 -14
- data/lib/sequel/model/plugins.rb +32 -21
- data/lib/sequel/plugins/caching.rb +13 -15
- data/lib/sequel/plugins/identity_map.rb +107 -0
- data/lib/sequel/plugins/lazy_attributes.rb +65 -0
- data/lib/sequel/plugins/many_through_many.rb +188 -0
- data/lib/sequel/plugins/schema.rb +13 -0
- data/lib/sequel/plugins/serialization.rb +53 -37
- data/lib/sequel/plugins/single_table_inheritance.rb +1 -1
- data/lib/sequel/plugins/tactical_eager_loading.rb +61 -0
- data/lib/sequel/plugins/validation_class_methods.rb +28 -7
- data/lib/sequel/plugins/validation_helpers.rb +31 -24
- data/lib/sequel/sql.rb +16 -0
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/ado_spec.rb +47 -1
- data/spec/adapters/firebird_spec.rb +39 -36
- data/spec/adapters/mysql_spec.rb +25 -9
- data/spec/adapters/postgres_spec.rb +11 -24
- data/spec/core/database_spec.rb +54 -13
- data/spec/core/dataset_spec.rb +147 -29
- data/spec/core/object_graph_spec.rb +6 -1
- data/spec/core/schema_spec.rb +34 -0
- data/spec/core/spec_helper.rb +0 -2
- data/spec/extensions/caching_spec.rb +7 -0
- data/spec/extensions/identity_map_spec.rb +158 -0
- data/spec/extensions/lazy_attributes_spec.rb +113 -0
- data/spec/extensions/many_through_many_spec.rb +813 -0
- data/spec/extensions/migration_spec.rb +4 -4
- data/spec/extensions/schema_dumper_spec.rb +114 -13
- data/spec/extensions/schema_spec.rb +19 -3
- data/spec/extensions/serialization_spec.rb +28 -0
- data/spec/extensions/single_table_inheritance_spec.rb +25 -1
- data/spec/extensions/spec_helper.rb +2 -7
- data/spec/extensions/tactical_eager_loading_spec.rb +65 -0
- data/spec/extensions/validation_class_methods_spec.rb +10 -5
- data/spec/integration/dataset_test.rb +39 -6
- data/spec/integration/eager_loader_test.rb +7 -7
- data/spec/integration/spec_helper.rb +0 -1
- data/spec/integration/transaction_test.rb +28 -1
- data/spec/model/association_reflection_spec.rb +29 -3
- data/spec/model/associations_spec.rb +1 -0
- data/spec/model/eager_loading_spec.rb +70 -1
- data/spec/model/plugins_spec.rb +236 -50
- data/spec/model/spec_helper.rb +0 -2
- metadata +18 -5
@@ -223,6 +223,7 @@ module Sequel
|
|
223
223
|
@operations << {:op => :add_constraint, :name => name, :type => :check, :check => block || args}
|
224
224
|
end
|
225
225
|
|
226
|
+
# Add a unique constraint to the given column(s)
|
226
227
|
def add_unique_constraint(columns, opts = {})
|
227
228
|
@operations << {:op => :add_constraint, :type => :unique, :columns => Array(columns)}.merge(opts)
|
228
229
|
end
|
@@ -16,9 +16,18 @@ module Sequel
|
|
16
16
|
# DB.add_index :posts, :title
|
17
17
|
# DB.add_index :posts, [:author, :title], :unique => true
|
18
18
|
#
|
19
|
+
#
|
20
|
+
# Options:
|
21
|
+
# * :ignore_errors - Ignore any DatabaseErrors that are raised
|
22
|
+
#
|
19
23
|
# See alter_table.
|
20
|
-
def add_index(table,
|
21
|
-
|
24
|
+
def add_index(table, columns, options={})
|
25
|
+
e = options[:ignore_errors]
|
26
|
+
begin
|
27
|
+
alter_table(table){add_index(columns, options)}
|
28
|
+
rescue DatabaseError
|
29
|
+
raise unless e
|
30
|
+
end
|
22
31
|
end
|
23
32
|
|
24
33
|
# Alters the given table with the specified block. Example:
|
@@ -55,13 +64,14 @@ module Sequel
|
|
55
64
|
#
|
56
65
|
# Options:
|
57
66
|
# * :temp - Create the table as a temporary table.
|
67
|
+
# * :ignore_index_errors - Ignore any errors when creating indexes.
|
58
68
|
#
|
59
69
|
# See Schema::Generator.
|
60
70
|
def create_table(name, options={}, &block)
|
61
71
|
options = {:generator=>options} if options.is_a?(Schema::Generator)
|
62
72
|
generator = options[:generator] || Schema::Generator.new(self, &block)
|
63
|
-
|
64
|
-
|
73
|
+
create_table_from_generator(name, generator, options)
|
74
|
+
create_table_indexes_from_generator(name, generator, options)
|
65
75
|
end
|
66
76
|
|
67
77
|
# Forcibly creates a table, attempting to drop it unconditionally (and catching any errors), then creating it.
|
@@ -70,6 +80,11 @@ module Sequel
|
|
70
80
|
create_table(name, options, &block)
|
71
81
|
end
|
72
82
|
|
83
|
+
# Creates the table unless the table already exists
|
84
|
+
def create_table?(name, options={}, &block)
|
85
|
+
create_table(name, options, &block) unless table_exists?(name)
|
86
|
+
end
|
87
|
+
|
73
88
|
# Creates a view, replacing it if it already exists:
|
74
89
|
#
|
75
90
|
# DB.create_or_replace_view(:cheap_items, "SELECT * FROM items WHERE price < 100")
|
@@ -165,5 +180,24 @@ module Sequel
|
|
165
180
|
def set_column_type(table, *args)
|
166
181
|
alter_table(table) {set_column_type(*args)}
|
167
182
|
end
|
183
|
+
|
184
|
+
private
|
185
|
+
|
186
|
+
# Execute the create table statements using the generator.
|
187
|
+
def create_table_from_generator(name, generator, options)
|
188
|
+
execute_ddl(create_table_sql(name, generator, options))
|
189
|
+
end
|
190
|
+
|
191
|
+
# Execute the create index statements using the generator.
|
192
|
+
def create_table_indexes_from_generator(name, generator, options)
|
193
|
+
e = options[:ignore_index_errors]
|
194
|
+
index_sql_list(name, generator.indexes).each do |sql|
|
195
|
+
begin
|
196
|
+
execute_ddl(sql)
|
197
|
+
rescue DatabaseError
|
198
|
+
raise unless e
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
168
202
|
end
|
169
203
|
end
|
data/lib/sequel/dataset.rb
CHANGED
@@ -259,6 +259,12 @@ module Sequel
|
|
259
259
|
!(@opts.collect{|k,v| k unless v.nil?}.compact & opts).empty?
|
260
260
|
end
|
261
261
|
|
262
|
+
# Whether this dataset is a simple SELECT * FROM table.
|
263
|
+
def simple_select_all?
|
264
|
+
o = @opts.reject{|k,v| v.nil?}
|
265
|
+
o.length == 1 && o[:from] && o[:from].length == 1
|
266
|
+
end
|
267
|
+
|
262
268
|
private
|
263
269
|
|
264
270
|
# Set the server to use to :default unless it is already set in the passed opts
|
@@ -11,7 +11,7 @@ module Sequel
|
|
11
11
|
#
|
12
12
|
# ds[:id=>1] => {:id=1}
|
13
13
|
def [](*conditions)
|
14
|
-
raise(Error, ARRAY_ACCESS_ERROR_MSG) if (conditions.length == 1 and conditions.is_a?(Integer)) or conditions.length == 0
|
14
|
+
raise(Error, ARRAY_ACCESS_ERROR_MSG) if (conditions.length == 1 and conditions.first.is_a?(Integer)) or conditions.length == 0
|
15
15
|
first(*conditions)
|
16
16
|
end
|
17
17
|
|
@@ -109,7 +109,7 @@ module Sequel
|
|
109
109
|
# # this will commit every 50 records
|
110
110
|
# dataset.import([:x, :y], [[1, 2], [3, 4], ...], :slice => 50)
|
111
111
|
def import(columns, values, opts={})
|
112
|
-
return @db.transaction{execute_dui("
|
112
|
+
return @db.transaction{execute_dui("#{insert_sql_base}#{quote_schema_table(@opts[:from].first)} (#{identifier_list(columns)}) VALUES #{literal(values)}")} if values.is_a?(Dataset)
|
113
113
|
|
114
114
|
return if values.empty?
|
115
115
|
raise(Error, IMPORT_ERROR_MSG) if columns.empty?
|
data/lib/sequel/dataset/graph.rb
CHANGED
@@ -69,7 +69,7 @@ module Sequel
|
|
69
69
|
raise_alias_error.call if @opts[:graph] && @opts[:graph][:table_aliases] && @opts[:graph][:table_aliases].include?(table_alias)
|
70
70
|
|
71
71
|
# Join the table early in order to avoid cloning the dataset twice
|
72
|
-
ds = join_table(options[:join_type] || :left_outer, table, join_conditions, :table_alias=>table_alias, :implicit_qualifier=>options[:implicit_qualifier], &block)
|
72
|
+
ds = join_table(options[:join_type] || :left_outer, dataset.simple_select_all? ? table : dataset, join_conditions, :table_alias=>table_alias, :implicit_qualifier=>options[:implicit_qualifier], &block)
|
73
73
|
opts = ds.opts
|
74
74
|
|
75
75
|
# Whether to include the table in the result set
|
@@ -167,7 +167,7 @@ module Sequel
|
|
167
167
|
# #set_graph_aliases.
|
168
168
|
def add_graph_aliases(graph_aliases)
|
169
169
|
ds = select_more(*graph_alias_columns(graph_aliases))
|
170
|
-
ds.opts[:graph_aliases] = (ds.opts[:graph_aliases] || {}).merge(graph_aliases)
|
170
|
+
ds.opts[:graph_aliases] = (ds.opts[:graph_aliases] || ds.opts[:graph][:column_aliases] || {}).merge(graph_aliases)
|
171
171
|
ds
|
172
172
|
end
|
173
173
|
|
@@ -90,14 +90,9 @@ module Sequel
|
|
90
90
|
# Changes the values of symbols if they start with $ and
|
91
91
|
# prepared_args is present. If so, they are considered placeholders,
|
92
92
|
# and they are substituted using prepared_arg.
|
93
|
-
def
|
94
|
-
|
95
|
-
|
96
|
-
if match = PLACEHOLDER_RE.match(v.to_s) and @prepared_args
|
97
|
-
super(prepared_arg(match[1].to_sym))
|
98
|
-
else
|
99
|
-
super
|
100
|
-
end
|
93
|
+
def literal_symbol(v)
|
94
|
+
if match = PLACEHOLDER_RE.match(v.to_s) and @prepared_args
|
95
|
+
literal(prepared_arg(match[1].to_sym))
|
101
96
|
else
|
102
97
|
super
|
103
98
|
end
|
data/lib/sequel/dataset/sql.rb
CHANGED
@@ -7,10 +7,12 @@ module Sequel
|
|
7
7
|
COLUMN_REF_RE2 = /\A([\w ]+)___([\w ]+)\z/.freeze
|
8
8
|
COLUMN_REF_RE3 = /\A([\w ]+)__([\w ]+)\z/.freeze
|
9
9
|
COUNT_FROM_SELF_OPTS = [:distinct, :group, :sql, :limit, :compounds]
|
10
|
+
INSERT_SQL_BASE="INSERT INTO ".freeze
|
10
11
|
IS_LITERALS = {nil=>'NULL'.freeze, true=>'TRUE'.freeze, false=>'FALSE'.freeze}.freeze
|
11
12
|
IS_OPERATORS = ::Sequel::SQL::ComplexExpression::IS_OPERATORS
|
12
13
|
N_ARITY_OPERATORS = ::Sequel::SQL::ComplexExpression::N_ARITY_OPERATORS
|
13
14
|
NULL = "NULL".freeze
|
15
|
+
QUALIFY_KEYS = [:select, :where, :having, :order, :group]
|
14
16
|
QUESTION_MARK = '?'.freeze
|
15
17
|
STOCK_COUNT_OPTS = {:select => [SQL::AliasedExpression.new(LiteralString.new("COUNT(*)").freeze, :count)], :order => nil}.freeze
|
16
18
|
SELECT_CLAUSE_ORDER = %w'distinct columns from join where group having compounds order limit'.freeze
|
@@ -317,7 +319,7 @@ module Sequel
|
|
317
319
|
if values.empty?
|
318
320
|
insert_default_values_sql
|
319
321
|
else
|
320
|
-
"
|
322
|
+
"#{insert_sql_base}#{from} VALUES #{literal(values)}"
|
321
323
|
end
|
322
324
|
when Hash
|
323
325
|
values = @opts[:defaults].merge(values) if @opts[:defaults]
|
@@ -330,10 +332,10 @@ module Sequel
|
|
330
332
|
fl << literal(String === k ? k.to_sym : k)
|
331
333
|
vl << literal(v)
|
332
334
|
end
|
333
|
-
"
|
335
|
+
"#{insert_sql_base}#{from} (#{fl.join(COMMA_SEPARATOR)}) VALUES (#{vl.join(COMMA_SEPARATOR)})"
|
334
336
|
end
|
335
337
|
when Dataset
|
336
|
-
"
|
338
|
+
"#{insert_sql_base}#{from} #{literal(values)}"
|
337
339
|
end
|
338
340
|
end
|
339
341
|
|
@@ -532,7 +534,7 @@ module Sequel
|
|
532
534
|
# This method should be overridden by descendants if the support
|
533
535
|
# inserting multiple records in a single SQL statement.
|
534
536
|
def multi_insert_sql(columns, values)
|
535
|
-
s = "
|
537
|
+
s = "#{insert_sql_base}#{source_list(@opts[:from])} (#{identifier_list(columns)}) VALUES "
|
536
538
|
values.map{|r| s + literal(r)}
|
537
539
|
end
|
538
540
|
|
@@ -595,6 +597,30 @@ module Sequel
|
|
595
597
|
[qcr.table, qcr.column].map{|x| [SQL::QualifiedIdentifier, SQL::Identifier, Symbol].any?{|c| x.is_a?(c)} ? literal(x) : quote_identifier(x)}.join('.')
|
596
598
|
end
|
597
599
|
|
600
|
+
# Return a copy of the dataset with unqualified identifiers in the
|
601
|
+
# SELECT, WHERE, GROUP, HAVING, and ORDER clauses qualified by the
|
602
|
+
# given table. If no columns are currently selected, select all
|
603
|
+
# columns of the given table.
|
604
|
+
def qualify_to(table)
|
605
|
+
o = @opts
|
606
|
+
return clone if o[:sql]
|
607
|
+
h = {}
|
608
|
+
(o.keys & QUALIFY_KEYS).each do |k|
|
609
|
+
h[k] = qualified_expression(o[k], table)
|
610
|
+
end
|
611
|
+
h[:select] = [SQL::ColumnAll.new(table)] if !o[:select] || o[:select].empty?
|
612
|
+
clone(h)
|
613
|
+
end
|
614
|
+
|
615
|
+
# Qualify the dataset to its current first source. This is useful
|
616
|
+
# if you have unqualified identifiers in the query that all refer to
|
617
|
+
# the first source, and you want to join to another table which
|
618
|
+
# has columns with the same name as columns in the current dataset.
|
619
|
+
# See qualify_to.
|
620
|
+
def qualify_to_first_source
|
621
|
+
qualify_to(first_source)
|
622
|
+
end
|
623
|
+
|
598
624
|
# Adds quoting to identifiers (columns and tables). If identifiers are not
|
599
625
|
# being quoted, returns name as a string. If identifiers are being quoted
|
600
626
|
# quote the name with quoted_identifier.
|
@@ -654,7 +680,11 @@ module Sequel
|
|
654
680
|
# dataset.select{|o| o.a, o.sum(:b)} # SELECT a, sum(b) FROM items
|
655
681
|
def select(*columns, &block)
|
656
682
|
columns += Array(virtual_row_block_call(block)) if block
|
657
|
-
|
683
|
+
m = []
|
684
|
+
columns.map do |i|
|
685
|
+
i.is_a?(Hash) ? m.concat(i.map{|k, v| SQL::AliasedExpression.new(k,v)}) : m << i
|
686
|
+
end
|
687
|
+
clone(:select => m)
|
658
688
|
end
|
659
689
|
|
660
690
|
# Returns a copy of the dataset selecting the wildcard.
|
@@ -690,7 +720,7 @@ module Sequel
|
|
690
720
|
|
691
721
|
# SQL fragment for specifying subscripts (SQL arrays)
|
692
722
|
def subscript_sql(s)
|
693
|
-
"#{literal(s.f)}[#{s.sub
|
723
|
+
"#{literal(s.f)}[#{expression_list(s.sub)}]"
|
694
724
|
end
|
695
725
|
|
696
726
|
# Returns a copy of the dataset with no filters (HAVING or WHERE clause) applied.
|
@@ -778,6 +808,12 @@ module Sequel
|
|
778
808
|
|
779
809
|
protected
|
780
810
|
|
811
|
+
# Return a from_self dataset if an order or limit is specified, so it works as expected
|
812
|
+
# with UNION, EXCEPT, and INTERSECT clauses.
|
813
|
+
def compound_from_self
|
814
|
+
(@opts[:limit] || @opts[:order]) ? from_self : self
|
815
|
+
end
|
816
|
+
|
781
817
|
# Returns a table reference for use in the FROM clause. Returns an SQL subquery
|
782
818
|
# frgament with an optional table alias.
|
783
819
|
def to_table_reference(table_alias=nil)
|
@@ -803,21 +839,14 @@ module Sequel
|
|
803
839
|
# Converts an array of column names into a comma seperated string of
|
804
840
|
# column names. If the array is empty, a wildcard (*) is returned.
|
805
841
|
def column_list(columns)
|
806
|
-
|
807
|
-
WILDCARD
|
808
|
-
else
|
809
|
-
m = columns.map do |i|
|
810
|
-
i.is_a?(Hash) ? i.map{|k, v| as_sql(literal(k), v)} : literal(i)
|
811
|
-
end
|
812
|
-
m.join(COMMA_SEPARATOR)
|
813
|
-
end
|
842
|
+
(columns.nil? || columns.empty?) ? WILDCARD : expression_list(columns)
|
814
843
|
end
|
815
844
|
|
816
845
|
# Add the dataset to the list of compounds
|
817
846
|
def compound_clone(type, dataset, all)
|
818
|
-
clone(:compounds=>Array(@opts[:compounds]).map{|x| x.dup} + [[type, dataset, all]])
|
847
|
+
compound_from_self.clone(:compounds=>Array(@opts[:compounds]).map{|x| x.dup} + [[type, dataset.compound_from_self, all]]).from_self
|
819
848
|
end
|
820
|
-
|
849
|
+
|
821
850
|
# Converts an array of expressions into a comma separated string of
|
822
851
|
# expressions.
|
823
852
|
def expression_list(columns)
|
@@ -863,9 +892,14 @@ module Sequel
|
|
863
892
|
columns.map{|i| quote_identifier(i)}.join(COMMA_SEPARATOR)
|
864
893
|
end
|
865
894
|
|
895
|
+
# SQL statement for the beginning of an INSERT statement
|
896
|
+
def insert_sql_base
|
897
|
+
INSERT_SQL_BASE
|
898
|
+
end
|
899
|
+
|
866
900
|
# SQL statement for formatting an insert statement with default values
|
867
901
|
def insert_default_values_sql
|
868
|
-
"
|
902
|
+
"#{insert_sql_base}#{source_list(@opts[:from])} DEFAULT VALUES"
|
869
903
|
end
|
870
904
|
|
871
905
|
# Inverts the given order by breaking it into a list of column references
|
@@ -1003,6 +1037,47 @@ module Sequel
|
|
1003
1037
|
column
|
1004
1038
|
end
|
1005
1039
|
end
|
1040
|
+
|
1041
|
+
# Qualify the given expression e to the given table.
|
1042
|
+
def qualified_expression(e, table)
|
1043
|
+
case e
|
1044
|
+
when Symbol
|
1045
|
+
t, column, aliaz = split_symbol(e)
|
1046
|
+
if t
|
1047
|
+
e
|
1048
|
+
elsif aliaz
|
1049
|
+
SQL::AliasedExpression.new(SQL::QualifiedIdentifier.new(table, SQL::Identifier.new(column)), aliaz)
|
1050
|
+
else
|
1051
|
+
SQL::QualifiedIdentifier.new(table, e)
|
1052
|
+
end
|
1053
|
+
when Array
|
1054
|
+
e.map{|a| qualified_expression(a, table)}
|
1055
|
+
when Hash
|
1056
|
+
h = {}
|
1057
|
+
e.each{|k,v| h[qualified_expression(k, table)] = qualified_expression(v, table)}
|
1058
|
+
h
|
1059
|
+
when SQL::Identifier
|
1060
|
+
SQL::QualifiedIdentifier.new(table, e)
|
1061
|
+
when SQL::OrderedExpression
|
1062
|
+
SQL::OrderedExpression.new(qualified_expression(e.expression, table), e.descending)
|
1063
|
+
when SQL::AliasedExpression
|
1064
|
+
SQL::AliasedExpression.new(qualified_expression(e.expression, table), e.aliaz)
|
1065
|
+
when SQL::CaseExpression
|
1066
|
+
SQL::CaseExpression.new(qualified_expression(e.conditions, table), qualified_expression(e.default, table), qualified_expression(e.expression, table))
|
1067
|
+
when SQL::Cast
|
1068
|
+
SQL::Cast.new(qualified_expression(e.expr, table), e.type)
|
1069
|
+
when SQL::Function
|
1070
|
+
SQL::Function.new(e.f, *qualified_expression(e.args, table))
|
1071
|
+
when SQL::ComplexExpression
|
1072
|
+
SQL::ComplexExpression.new(e.op, *qualified_expression(e.args, table))
|
1073
|
+
when SQL::SQLArray
|
1074
|
+
SQL::SQLArray.new(qualified_expression(e.array, table))
|
1075
|
+
when SQL::Subscript
|
1076
|
+
SQL::Subscript.new(qualified_expression(e.f, table), qualified_expression(e.sub, table))
|
1077
|
+
else
|
1078
|
+
e
|
1079
|
+
end
|
1080
|
+
end
|
1006
1081
|
|
1007
1082
|
# The order of methods to call to build the SELECT SQL statement
|
1008
1083
|
def select_clause_order
|
@@ -1028,8 +1103,7 @@ module Sequel
|
|
1028
1103
|
return unless @opts[:compounds]
|
1029
1104
|
@opts[:compounds].each do |type, dataset, all|
|
1030
1105
|
compound_sql = subselect_sql(dataset)
|
1031
|
-
|
1032
|
-
sql.replace("#{sql} #{type.to_s.upcase}#{' ALL' if all} #{compound_sql}")
|
1106
|
+
sql << " #{type.to_s.upcase}#{' ALL' if all} #{compound_sql}"
|
1033
1107
|
end
|
1034
1108
|
end
|
1035
1109
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# The blank extension adds the blank? method to all objects (e.g. Object#blank?).
|
2
|
+
|
1
3
|
class FalseClass
|
2
4
|
# false is always blank
|
3
5
|
def blank?
|
@@ -5,7 +7,6 @@ class FalseClass
|
|
5
7
|
end
|
6
8
|
end
|
7
9
|
|
8
|
-
# Helpers from Metaid and a bit more
|
9
10
|
class Object
|
10
11
|
# Objects are blank if they respond true to empty?
|
11
12
|
def blank?
|
@@ -1,6 +1,7 @@
|
|
1
|
-
#
|
2
|
-
# words from singular to plural,class names to table names, modularized class
|
3
|
-
# names to ones without, and class names to foreign keys.
|
1
|
+
# The inflector extension adds inflection instance methods to String, which allows the easy transformation of
|
2
|
+
# words from singular to plural, class names to table names, modularized class
|
3
|
+
# names to ones without, and class names to foreign keys. It exists for
|
4
|
+
# backwards compatibility to legacy Sequel code.
|
4
5
|
|
5
6
|
class String
|
6
7
|
# This module acts as a singleton returned/yielded by String.inflections,
|
@@ -1,3 +1,7 @@
|
|
1
|
+
# Adds the Sequel::Migration and Sequel::Migrator classes, which allow
|
2
|
+
# the user to easily group schema changes and migrate the database
|
3
|
+
# to a newer version or revert to a previous version.
|
4
|
+
|
1
5
|
module Sequel
|
2
6
|
# The Migration class describes a database migration that can be reversed.
|
3
7
|
# The migration looks very similar to ActiveRecord (Rails) migrations, e.g.:
|
@@ -128,6 +132,7 @@ module Sequel
|
|
128
132
|
# Sequel::Migrator.apply(DB, '.', 5, 1)
|
129
133
|
module Migrator
|
130
134
|
MIGRATION_FILE_PATTERN = /\A\d+_.+\.rb\z/.freeze
|
135
|
+
MIGRATION_SPLITTER = '_'.freeze
|
131
136
|
|
132
137
|
# Migrates the supplied database in the specified directory from the
|
133
138
|
# current version to the target version. If no current version is
|
@@ -162,7 +167,7 @@ module Sequel
|
|
162
167
|
# Returns the latest version available in the specified directory.
|
163
168
|
def self.latest_migration_version(directory)
|
164
169
|
l = migration_files(directory).last
|
165
|
-
l ? File.basename(l)
|
170
|
+
l ? migration_version_from_file(File.basename(l)) : nil
|
166
171
|
end
|
167
172
|
|
168
173
|
# Returns a list of migration classes filtered for the migration range and
|
@@ -190,7 +195,7 @@ module Sequel
|
|
190
195
|
def self.migration_files(directory, range = nil)
|
191
196
|
files = []
|
192
197
|
Dir.new(directory).each do |file|
|
193
|
-
files[file
|
198
|
+
files[migration_version_from_file(file)] = File.join(directory, file) if MIGRATION_FILE_PATTERN.match(file)
|
194
199
|
end
|
195
200
|
filtered = range ? files[range] : files
|
196
201
|
filtered ? filtered.compact : []
|
@@ -208,5 +213,11 @@ module Sequel
|
|
208
213
|
dataset = schema_info_dataset(db)
|
209
214
|
dataset.send(dataset.first ? :update : :<<, :version => version)
|
210
215
|
end
|
216
|
+
|
217
|
+
# Return the integer migration version based on the filename.
|
218
|
+
def self.migration_version_from_file(filename)
|
219
|
+
filename.split(MIGRATION_SPLITTER, 2).first.to_i
|
220
|
+
end
|
221
|
+
private_class_method :migration_version_from_file
|
211
222
|
end
|
212
223
|
end
|
@@ -1,3 +1,7 @@
|
|
1
|
+
# The pagination extension adds the Sequel::Dataset#paginate and #each_page methods,
|
2
|
+
# which return paginated (limited and offset) datasets with some helpful methods
|
3
|
+
# that make creating a paginated display easier.
|
4
|
+
|
1
5
|
module Sequel
|
2
6
|
class Dataset
|
3
7
|
# Returns a paginated dataset. The returned dataset is limited to
|