sequel 2.12.0 → 3.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 +62 -0
- data/README.rdoc +3 -3
- data/Rakefile +7 -0
- data/doc/advanced_associations.rdoc +44 -0
- data/doc/release_notes/3.0.0.txt +221 -0
- data/lib/sequel/adapters/amalgalite.rb +208 -0
- data/lib/sequel/adapters/db2.rb +3 -0
- data/lib/sequel/adapters/dbi.rb +9 -0
- data/lib/sequel/adapters/do.rb +0 -4
- data/lib/sequel/adapters/firebird.rb +16 -18
- data/lib/sequel/adapters/informix.rb +5 -3
- data/lib/sequel/adapters/jdbc.rb +24 -20
- data/lib/sequel/adapters/jdbc/h2.rb +15 -4
- data/lib/sequel/adapters/mysql.rb +4 -8
- data/lib/sequel/adapters/odbc.rb +0 -4
- data/lib/sequel/adapters/oracle.rb +0 -4
- data/lib/sequel/adapters/shared/mssql.rb +16 -5
- data/lib/sequel/adapters/shared/mysql.rb +87 -86
- data/lib/sequel/adapters/shared/oracle.rb +92 -3
- data/lib/sequel/adapters/shared/postgres.rb +85 -29
- data/lib/sequel/adapters/shared/progress.rb +8 -3
- data/lib/sequel/adapters/shared/sqlite.rb +53 -23
- data/lib/sequel/adapters/sqlite.rb +4 -7
- data/lib/sequel/adapters/utils/unsupported.rb +3 -3
- data/lib/sequel/connection_pool.rb +18 -25
- data/lib/sequel/core.rb +2 -21
- data/lib/sequel/database.rb +60 -44
- data/lib/sequel/database/schema_generator.rb +26 -31
- data/lib/sequel/database/schema_methods.rb +8 -3
- data/lib/sequel/database/schema_sql.rb +114 -28
- data/lib/sequel/dataset.rb +14 -41
- data/lib/sequel/dataset/convenience.rb +31 -54
- data/lib/sequel/dataset/graph.rb +7 -13
- data/lib/sequel/dataset/sql.rb +43 -54
- data/lib/sequel/extensions/inflector.rb +0 -5
- data/lib/sequel/extensions/schema_dumper.rb +238 -0
- data/lib/sequel/metaprogramming.rb +0 -20
- data/lib/sequel/model.rb +1 -2
- data/lib/sequel/model/base.rb +18 -16
- data/lib/sequel/model/inflections.rb +6 -9
- data/lib/sequel/plugins/caching.rb +0 -6
- data/lib/sequel/plugins/hook_class_methods.rb +1 -1
- data/lib/sequel/sql.rb +2 -0
- data/lib/sequel/version.rb +2 -2
- data/spec/adapters/firebird_spec.rb +35 -8
- data/spec/adapters/mysql_spec.rb +173 -266
- data/spec/adapters/oracle_spec.rb +13 -0
- data/spec/adapters/postgres_spec.rb +127 -227
- data/spec/adapters/sqlite_spec.rb +13 -171
- data/spec/core/connection_pool_spec.rb +15 -4
- data/spec/core/core_sql_spec.rb +14 -170
- data/spec/core/database_spec.rb +50 -132
- data/spec/core/dataset_spec.rb +47 -930
- data/spec/core/expression_filters_spec.rb +12 -0
- data/spec/core/schema_generator_spec.rb +37 -45
- data/spec/core/schema_spec.rb +26 -16
- data/spec/core/spec_helper.rb +0 -25
- data/spec/extensions/inflector_spec.rb +0 -3
- data/spec/extensions/schema_dumper_spec.rb +292 -0
- data/spec/extensions/serialization_spec.rb +9 -0
- data/spec/extensions/single_table_inheritance_spec.rb +6 -1
- data/spec/extensions/spec_helper.rb +1 -3
- data/spec/extensions/validation_helpers_spec.rb +4 -4
- data/spec/integration/database_test.rb +18 -0
- data/spec/integration/dataset_test.rb +112 -1
- data/spec/integration/eager_loader_test.rb +70 -9
- data/spec/integration/prepared_statement_test.rb +2 -2
- data/spec/integration/schema_test.rb +76 -27
- data/spec/integration/spec_helper.rb +0 -14
- data/spec/integration/transaction_test.rb +27 -0
- data/spec/model/associations_spec.rb +0 -36
- data/spec/model/base_spec.rb +18 -123
- data/spec/model/hooks_spec.rb +2 -235
- data/spec/model/inflector_spec.rb +15 -115
- data/spec/model/model_spec.rb +0 -120
- data/spec/model/plugins_spec.rb +0 -70
- data/spec/model/record_spec.rb +35 -93
- data/spec/model/spec_helper.rb +0 -27
- data/spec/model/validations_spec.rb +0 -931
- metadata +9 -14
- data/lib/sequel/deprecated.rb +0 -593
- data/lib/sequel/deprecated_migration.rb +0 -91
- data/lib/sequel/model/deprecated.rb +0 -204
- data/lib/sequel/model/deprecated_hooks.rb +0 -103
- data/lib/sequel/model/deprecated_inflector.rb +0 -335
- data/lib/sequel/model/deprecated_validations.rb +0 -388
- data/spec/core/core_ext_spec.rb +0 -156
- data/spec/core/migration_spec.rb +0 -263
- data/spec/core/pretty_table_spec.rb +0 -58
- data/spec/model/caching_spec.rb +0 -217
- data/spec/model/schema_spec.rb +0 -92
@@ -53,10 +53,15 @@ module Sequel
|
|
53
53
|
# index :title
|
54
54
|
# end
|
55
55
|
#
|
56
|
+
# Options:
|
57
|
+
# * :temp - Create the table as a temporary table.
|
58
|
+
#
|
56
59
|
# See Schema::Generator.
|
57
60
|
def create_table(name, options={}, &block)
|
58
61
|
options = {:generator=>options} if options.is_a?(Schema::Generator)
|
59
|
-
|
62
|
+
generator = options[:generator] || Schema::Generator.new(self, &block)
|
63
|
+
execute_ddl(create_table_sql(name, generator, options))
|
64
|
+
index_sql_list(name, generator.indexes).each{|sql| execute_ddl(sql)}
|
60
65
|
end
|
61
66
|
|
62
67
|
# Forcibly creates a table, attempting to drop it unconditionally (and catching any errors), then creating it.
|
@@ -99,8 +104,8 @@ module Sequel
|
|
99
104
|
# DB.drop_index :posts, [:author, :title]
|
100
105
|
#
|
101
106
|
# See alter_table.
|
102
|
-
def drop_index(table, columns)
|
103
|
-
alter_table(table)
|
107
|
+
def drop_index(table, columns, options={})
|
108
|
+
alter_table(table){drop_index(columns, options)}
|
104
109
|
end
|
105
110
|
|
106
111
|
# Drops one or more tables corresponding to the given names:
|
@@ -10,12 +10,7 @@ module Sequel
|
|
10
10
|
RESTRICT = 'RESTRICT'.freeze
|
11
11
|
SET_DEFAULT = 'SET DEFAULT'.freeze
|
12
12
|
SET_NULL = 'SET NULL'.freeze
|
13
|
-
|
14
|
-
TYPES.merge!(:double=>'double precision', String=>'varchar(255)',
|
15
|
-
Integer=>'integer', Fixnum=>'integer', Bignum=>'bigint',
|
16
|
-
Float=>'double precision', BigDecimal=>'numeric', Numeric=>'numeric',
|
17
|
-
Date=>'date', DateTime=>'timestamp', Time=>'timestamp', File=>'blob',
|
18
|
-
TrueClass=>'boolean', FalseClass=>'boolean')
|
13
|
+
TEMPORARY = 'TEMPORARY '.freeze
|
19
14
|
UNDERSCORE = '_'.freeze
|
20
15
|
UNIQUE = ' UNIQUE'.freeze
|
21
16
|
UNSIGNED = ' UNSIGNED'.freeze
|
@@ -72,7 +67,6 @@ module Sequel
|
|
72
67
|
|
73
68
|
# SQL DDL fragment containing the column creation SQL for the given column.
|
74
69
|
def column_definition_sql(column)
|
75
|
-
return constraint_definition_sql(column) if column[:type] == :check
|
76
70
|
sql = "#{quote_identifier(column[:name])} #{type_literal(column)}"
|
77
71
|
sql << UNIQUE if column[:unique]
|
78
72
|
sql << NOT_NULL if column[:null] == false
|
@@ -86,8 +80,8 @@ module Sequel
|
|
86
80
|
|
87
81
|
# SQL DDL fragment containing the column creation
|
88
82
|
# SQL for all given columns, used inside a CREATE TABLE block.
|
89
|
-
def column_list_sql(
|
90
|
-
columns.map{|c| column_definition_sql(c)}.join(COMMA_SEPARATOR)
|
83
|
+
def column_list_sql(generator)
|
84
|
+
(generator.columns.map{|c| column_definition_sql(c)} + generator.constraints.map{|c| constraint_definition_sql(c)}).join(COMMA_SEPARATOR)
|
91
85
|
end
|
92
86
|
|
93
87
|
# SQL DDL fragment for column foreign key references
|
@@ -102,7 +96,10 @@ module Sequel
|
|
102
96
|
# SQL DDL fragment specifying a constraint on a table.
|
103
97
|
def constraint_definition_sql(constraint)
|
104
98
|
sql = constraint[:name] ? "CONSTRAINT #{quote_identifier(constraint[:name])} " : ""
|
105
|
-
case constraint[:
|
99
|
+
case constraint[:type]
|
100
|
+
when :check
|
101
|
+
check = constraint[:check]
|
102
|
+
sql << "CHECK #{filter_expr((check.is_a?(Array) && check.length == 1) ? check.first : check)}"
|
106
103
|
when :primary_key
|
107
104
|
sql << "PRIMARY KEY #{literal(constraint[:columns])}"
|
108
105
|
when :foreign_key
|
@@ -111,21 +108,16 @@ module Sequel
|
|
111
108
|
when :unique
|
112
109
|
sql << "UNIQUE #{literal(constraint[:columns])}"
|
113
110
|
else
|
114
|
-
|
115
|
-
sql << "CHECK #{filter_expr((check.is_a?(Array) && check.length == 1) ? check.first : check)}"
|
111
|
+
raise Error, "Invalid constriant type #{constraint[:type]}, should be :check, :primary_key, :foreign_key, or :unique"
|
116
112
|
end
|
117
113
|
sql
|
118
114
|
end
|
119
115
|
|
120
|
-
#
|
121
|
-
|
122
|
-
|
123
|
-
def create_table_sql_list(name, columns, indexes = nil, options = {})
|
124
|
-
sql = ["CREATE TABLE #{quote_schema_table(name)} (#{column_list_sql(columns)})"]
|
125
|
-
sql.concat(index_list_sql_list(name, indexes)) if indexes && !indexes.empty?
|
126
|
-
sql
|
116
|
+
# DDL statement for creating a table with the given name, columns, and options
|
117
|
+
def create_table_sql(name, generator, options)
|
118
|
+
"CREATE #{temporary_table_sql if options[:temp]}TABLE #{quote_schema_table(name)} (#{column_list_sql(generator)})"
|
127
119
|
end
|
128
|
-
|
120
|
+
|
129
121
|
# Default index name for the table and columns, may be too long
|
130
122
|
# for certain databases.
|
131
123
|
def default_index_name(table_name, columns)
|
@@ -163,7 +155,7 @@ module Sequel
|
|
163
155
|
|
164
156
|
# Array of SQL DDL statements, one for each index specification,
|
165
157
|
# for the given table.
|
166
|
-
def
|
158
|
+
def index_sql_list(table_name, indexes)
|
167
159
|
indexes.map{|i| index_definition_sql(table_name, i)}
|
168
160
|
end
|
169
161
|
|
@@ -207,18 +199,112 @@ module Sequel
|
|
207
199
|
"ALTER TABLE #{quote_schema_table(name)} RENAME TO #{quote_schema_table(new_name)}"
|
208
200
|
end
|
209
201
|
|
202
|
+
# SQL DDL fragment for temporary table
|
203
|
+
def temporary_table_sql
|
204
|
+
self.class.const_get(:TEMPORARY)
|
205
|
+
end
|
206
|
+
|
210
207
|
# SQL fragment specifying the type of a given column.
|
211
208
|
def type_literal(column)
|
212
|
-
type
|
209
|
+
column[:type].is_a?(Class) ? type_literal_generic(column) : type_literal_specific(column)
|
210
|
+
end
|
211
|
+
|
212
|
+
# SQL fragment specifying the full type of a column,
|
213
|
+
# consider the type with possible modifiers.
|
214
|
+
def type_literal_generic(column)
|
215
|
+
meth = "type_literal_generic_#{column[:type].name.to_s.downcase}"
|
216
|
+
if respond_to?(meth, true)
|
217
|
+
send(meth, column)
|
218
|
+
else
|
219
|
+
raise Error, "Unsupported ruby class used as database type: #{column[:type]}"
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
# Alias for type_literal_generic_numeric, to make overriding in a subclass easier.
|
224
|
+
def type_literal_generic_bigdecimal(column)
|
225
|
+
type_literal_generic_numeric(column)
|
226
|
+
end
|
227
|
+
|
228
|
+
# Sequel uses the bigint type by default for Bignums.
|
229
|
+
def type_literal_generic_bignum(column)
|
230
|
+
:bigint
|
231
|
+
end
|
232
|
+
|
233
|
+
# Sequel uses the date type by default for Dates.
|
234
|
+
def type_literal_generic_date(column)
|
235
|
+
:date
|
236
|
+
end
|
237
|
+
|
238
|
+
# Sequel uses the timestamp type by default for DateTimes.
|
239
|
+
def type_literal_generic_datetime(column)
|
240
|
+
:timestamp
|
241
|
+
end
|
242
|
+
|
243
|
+
# Alias for type_literal_generic_trueclass, to make overriding in a subclass easier.
|
244
|
+
def type_literal_generic_falseclass(column)
|
245
|
+
type_literal_generic_trueclass(column)
|
246
|
+
end
|
247
|
+
|
248
|
+
# Sequel uses the blob type by default for Files.
|
249
|
+
def type_literal_generic_file(column)
|
250
|
+
:blob
|
251
|
+
end
|
252
|
+
|
253
|
+
# Alias for type_literal_generic_integer, to make overriding in a subclass easier.
|
254
|
+
def type_literal_generic_fixnum(column)
|
255
|
+
type_literal_generic_integer(column)
|
256
|
+
end
|
257
|
+
|
258
|
+
# Sequel uses the double precision type by default for Floats.
|
259
|
+
def type_literal_generic_float(column)
|
260
|
+
:"double precision"
|
261
|
+
end
|
262
|
+
|
263
|
+
# Sequel uses the integer type by default for integers
|
264
|
+
def type_literal_generic_integer(column)
|
265
|
+
:integer
|
266
|
+
end
|
267
|
+
|
268
|
+
# Sequel uses the numeric type by default for Numerics and BigDecimals.
|
269
|
+
# If a size is given, it is used, otherwise, it will default to whatever
|
270
|
+
# the database default is for an unsized value.
|
271
|
+
def type_literal_generic_numeric(column)
|
272
|
+
column[:size] ? "numeric(#{Array(column[:size]).join(', ')})" : :numeric
|
273
|
+
end
|
274
|
+
|
275
|
+
# Sequel uses the varchar type by default for Strings. If a
|
276
|
+
# size isn't present, Sequel assumes a size of 255. If the
|
277
|
+
# :fixed option is used, Sequel uses the char type. If the
|
278
|
+
# :text option is used, Sequel uses the :text type.
|
279
|
+
def type_literal_generic_string(column)
|
280
|
+
if column[:text]
|
281
|
+
:text
|
282
|
+
elsif column[:fixed]
|
283
|
+
"char(#{column[:size]||255})"
|
284
|
+
else
|
285
|
+
"varchar(#{column[:size]||255})"
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
# Sequel uses the timestamp type by default for Time values.
|
290
|
+
# If the :only_time option is used, the time type is used.
|
291
|
+
def type_literal_generic_time(column)
|
292
|
+
column[:only_time] ? :time : :timestamp
|
293
|
+
end
|
294
|
+
|
295
|
+
# Sequel uses the boolean type by default for TrueClass and FalseClass.
|
296
|
+
def type_literal_generic_trueclass(column)
|
297
|
+
:boolean
|
298
|
+
end
|
299
|
+
|
300
|
+
# SQL fragment for the given type of a column if the column is not one of the
|
301
|
+
# generic types specified with a ruby class.
|
302
|
+
def type_literal_specific(column)
|
303
|
+
type = column[:type]
|
304
|
+
type = "double precision" if type.to_s == 'double'
|
213
305
|
column[:size] ||= 255 if type.to_s == 'varchar'
|
214
306
|
elements = column[:size] || column[:elements]
|
215
307
|
"#{type}#{literal(Array(elements)) if elements}#{UNSIGNED if column[:unsigned]}"
|
216
308
|
end
|
217
|
-
|
218
|
-
# SQL fragment specifying the base type of a given column,
|
219
|
-
# without the size or elements.
|
220
|
-
def type_literal_base(column)
|
221
|
-
TYPES[column[:type]]
|
222
|
-
end
|
223
309
|
end
|
224
310
|
end
|
data/lib/sequel/dataset.rb
CHANGED
@@ -87,7 +87,6 @@ module Sequel
|
|
87
87
|
@identifier_output_method = db.identifier_output_method if db.respond_to?(:identifier_output_method)
|
88
88
|
@opts = opts || {}
|
89
89
|
@row_proc = nil
|
90
|
-
@transform = nil
|
91
90
|
end
|
92
91
|
|
93
92
|
### Class Methods ###
|
@@ -118,10 +117,9 @@ module Sequel
|
|
118
117
|
|
119
118
|
# Returns an array with all records in the dataset. If a block is given,
|
120
119
|
# the array is iterated over after all items have been loaded.
|
121
|
-
def all(
|
122
|
-
Deprecation.deprecate("Calling Dataset#all with an argument is deprecated and will raise an error in Sequel 3.0. Use dataset.clone(opts).all.") unless defarg
|
120
|
+
def all(&block)
|
123
121
|
a = []
|
124
|
-
|
122
|
+
each{|r| a << r}
|
125
123
|
post_load(a)
|
126
124
|
a.each(&block) if block
|
127
125
|
a
|
@@ -170,24 +168,21 @@ module Sequel
|
|
170
168
|
|
171
169
|
# Deletes the records in the dataset. The returned value is generally the
|
172
170
|
# number of records deleted, but that is adapter dependent.
|
173
|
-
def delete
|
174
|
-
|
175
|
-
execute_dui(defarg ? delete_sql : delete_sql(opts))
|
171
|
+
def delete
|
172
|
+
execute_dui(delete_sql)
|
176
173
|
end
|
177
174
|
|
178
175
|
# Iterates over the records in the dataset as they are yielded from the
|
179
176
|
# database adapter, and returns self.
|
180
|
-
def each(
|
181
|
-
|
182
|
-
|
183
|
-
prev_columns = @columns
|
184
|
-
begin
|
185
|
-
defarg ? _each(&block) : _each(opts, &block)
|
186
|
-
ensure
|
187
|
-
@columns = prev_columns
|
188
|
-
end
|
177
|
+
def each(&block)
|
178
|
+
if @opts[:graph]
|
179
|
+
graph_each(&block)
|
189
180
|
else
|
190
|
-
|
181
|
+
if row_proc = @row_proc
|
182
|
+
fetch_rows(select_sql){|r| yield row_proc.call(r)}
|
183
|
+
else
|
184
|
+
fetch_rows(select_sql, &block)
|
185
|
+
end
|
191
186
|
end
|
192
187
|
self
|
193
188
|
end
|
@@ -250,9 +245,8 @@ module Sequel
|
|
250
245
|
|
251
246
|
# Updates values for the dataset. The returned value is generally the
|
252
247
|
# number of rows updated, but that is adapter dependent.
|
253
|
-
def update(values={}
|
254
|
-
|
255
|
-
execute_dui(defarg ? update_sql(values) : update_sql(value, opts))
|
248
|
+
def update(values={})
|
249
|
+
execute_dui(update_sql(values))
|
256
250
|
end
|
257
251
|
|
258
252
|
# Add the mutation methods via metaprogramming
|
@@ -267,23 +261,6 @@ module Sequel
|
|
267
261
|
|
268
262
|
private
|
269
263
|
|
270
|
-
# Runs #graph_each if graphing. Otherwise, iterates through the records
|
271
|
-
# yielded by #fetch_rows, applying any row_proc or transform if necessary,
|
272
|
-
# and yielding the result.
|
273
|
-
def _each(opts=(defarg=true;nil), &block)
|
274
|
-
if @opts[:graph] and !(opts && opts[:graph] == false)
|
275
|
-
defarg ? graph_each(&block) : graph_each(opts, &block)
|
276
|
-
else
|
277
|
-
row_proc = @row_proc unless opts && opts[:naked]
|
278
|
-
transform = @transform
|
279
|
-
fetch_rows(defarg ? select_sql : select_sql(opts)) do |r|
|
280
|
-
r = transform_load(r) if transform
|
281
|
-
r = row_proc[r] if row_proc
|
282
|
-
yield r
|
283
|
-
end
|
284
|
-
end
|
285
|
-
end
|
286
|
-
|
287
264
|
# Set the server to use to :default unless it is already set in the passed opts
|
288
265
|
def default_server_opts(opts)
|
289
266
|
{:server=>@opts[:server] || :default}.merge(opts)
|
@@ -338,10 +315,6 @@ module Sequel
|
|
338
315
|
# VirtualRow instance.
|
339
316
|
def virtual_row_block_call(block)
|
340
317
|
return unless block
|
341
|
-
unless Sequel.virtual_row_instance_eval
|
342
|
-
Deprecation.deprecate('Using a VirtualRow block without an argument is deprecated, and its meaning will change in Sequel 3.0. Add a block argument to keep the old semantics, or set Sequel.virtual_row_instance_eval = true to use instance_eval for VirtualRow blocks without arguments.') unless block.arity == 1
|
343
|
-
return block.call(SQL::VirtualRow.new)
|
344
|
-
end
|
345
318
|
case block.arity
|
346
319
|
when -1, 0
|
347
320
|
SQL::VirtualRow.new.instance_eval(&block)
|
@@ -2,13 +2,16 @@ module Sequel
|
|
2
2
|
class Dataset
|
3
3
|
COMMA_SEPARATOR = ', '.freeze
|
4
4
|
COUNT_OF_ALL_AS_COUNT = SQL::Function.new(:count, LiteralString.new('*'.freeze)).as(:count)
|
5
|
+
ARRAY_ACCESS_ERROR_MSG = 'You cannot call Dataset#[] with an integer or with no arguments.'.freeze
|
6
|
+
MAP_ERROR_MSG = 'Using Dataset#map with an argument and a block is not allowed'.freeze
|
7
|
+
GET_ERROR_MSG = 'must provide argument or block to Dataset#get, not both'.freeze
|
8
|
+
IMPORT_ERROR_MSG = 'Using Sequel::Dataset#import an empty column array is not allowed'.freeze
|
5
9
|
|
6
10
|
# Returns the first record matching the conditions. Examples:
|
7
11
|
#
|
8
12
|
# ds[:id=>1] => {:id=1}
|
9
13
|
def [](*conditions)
|
10
|
-
|
11
|
-
Deprecation.deprecate('Using Dataset#[] without an argument is deprecated and will raise an error in Sequel 3.0. Use Dataset#first.') if conditions.length == 0
|
14
|
+
raise(Error, ARRAY_ACCESS_ERROR_MSG) if (conditions.length == 1 and conditions.is_a?(Integer)) or conditions.length == 0
|
12
15
|
first(*conditions)
|
13
16
|
end
|
14
17
|
|
@@ -70,8 +73,12 @@ module Sequel
|
|
70
73
|
# ds.get(:id)
|
71
74
|
# ds.get{|o| o.sum(:id)}
|
72
75
|
def get(column=nil, &block)
|
73
|
-
|
74
|
-
|
76
|
+
if column
|
77
|
+
raise(Error, GET_ERROR_MSG) if block
|
78
|
+
select(column).single_value
|
79
|
+
else
|
80
|
+
select(&block).single_value
|
81
|
+
end
|
75
82
|
end
|
76
83
|
|
77
84
|
# Returns a dataset grouped by the given column with count by group,
|
@@ -101,31 +108,18 @@ module Sequel
|
|
101
108
|
#
|
102
109
|
# # this will commit every 50 records
|
103
110
|
# dataset.import([:x, :y], [[1, 2], [3, 4], ...], :slice => 50)
|
104
|
-
def import(
|
105
|
-
if
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
columns, values, opts = *args
|
110
|
-
elsif args[0].is_a?(Array) && args[1].is_a?(Dataset)
|
111
|
-
table = @opts[:from].first
|
112
|
-
columns, dataset = *args
|
113
|
-
sql = "INSERT INTO #{quote_identifier(table)} (#{identifier_list(columns)}) VALUES #{literal(dataset)}"
|
114
|
-
return @db.transaction{execute_dui(sql)}
|
115
|
-
else
|
116
|
-
Sequel::Deprecation.deprecate('Calling Sequel::Dataset#import with hashes', 'Use Sequel::Dataset#multi_insert')
|
117
|
-
return multi_insert(*args)
|
118
|
-
end
|
119
|
-
# make sure there's work to do
|
120
|
-
Sequel::Deprecation.deprecate('Calling Sequel::Dataset#import an empty column array is deprecated and will raise an error in Sequel 3.0.') if columns.empty?
|
121
|
-
return if columns.empty? || values.empty?
|
122
|
-
|
123
|
-
slice_size = opts && (opts[:commit_every] || opts[:slice])
|
111
|
+
def import(columns, values, opts={})
|
112
|
+
return @db.transaction{execute_dui("INSERT INTO #{quote_schema_table(@opts[:from].first)} (#{identifier_list(columns)}) VALUES #{literal(values)}")} if values.is_a?(Dataset)
|
113
|
+
|
114
|
+
return if values.empty?
|
115
|
+
raise(Error, IMPORT_ERROR_MSG) if columns.empty?
|
124
116
|
|
125
|
-
if slice_size
|
126
|
-
|
127
|
-
|
128
|
-
@db.transaction(opts){
|
117
|
+
if slice_size = opts[:commit_every] || opts[:slice]
|
118
|
+
offset = 0
|
119
|
+
loop do
|
120
|
+
@db.transaction(opts){multi_insert_sql(columns, values[offset, slice_size]).each{|st| execute_dui(st)}}
|
121
|
+
offset += slice_size
|
122
|
+
break if offset >= values.length
|
129
123
|
end
|
130
124
|
else
|
131
125
|
statements = multi_insert_sql(columns, values)
|
@@ -155,8 +149,8 @@ module Sequel
|
|
155
149
|
# ds.map(:id) => [1, 2, 3, ...]
|
156
150
|
# ds.map{|r| r[:id] * 2} => [2, 4, 6, ...]
|
157
151
|
def map(column=nil, &block)
|
158
|
-
Deprecation.deprecate('Using Dataset#map with an argument and a block is deprecated and will raise an error in Sequel 3.0. Use an argument or a block, not both.') if column && block
|
159
152
|
if column
|
153
|
+
raise(Error, MAP_ERROR_MSG) if block
|
160
154
|
super(){|r| r[column]}
|
161
155
|
else
|
162
156
|
super(&block)
|
@@ -183,22 +177,10 @@ module Sequel
|
|
183
177
|
# values.
|
184
178
|
#
|
185
179
|
# You can also use the :slice or :commit_every option that import accepts.
|
186
|
-
def multi_insert(
|
187
|
-
if
|
188
|
-
|
189
|
-
|
190
|
-
elsif args[0].is_a?(Array) && (args[1].is_a?(Array) || args[1].is_a?(Dataset))
|
191
|
-
Sequel::Deprecation.deprecate('Calling Sequel::Dataset#multi_insert with an array of columns and an array of arrays of values', 'Use Sequel::Dataset#import')
|
192
|
-
return import(*args)
|
193
|
-
else
|
194
|
-
# we assume that an array of hashes is given
|
195
|
-
hashes, opts = *args
|
196
|
-
return if hashes.empty?
|
197
|
-
columns = hashes.first.keys
|
198
|
-
# convert the hashes into arrays
|
199
|
-
values = hashes.map {|h| columns.map {|c| h[c]}}
|
200
|
-
end
|
201
|
-
import(columns, values, opts)
|
180
|
+
def multi_insert(hashes, opts={})
|
181
|
+
return if hashes.empty?
|
182
|
+
columns = hashes.first.keys
|
183
|
+
import(columns, hashes.map{|h| columns.map{|c| h[c]}}, opts)
|
202
184
|
end
|
203
185
|
|
204
186
|
# Returns a Range object made from the minimum and maximum values for the
|
@@ -210,20 +192,15 @@ module Sequel
|
|
210
192
|
end
|
211
193
|
|
212
194
|
# Returns the first record in the dataset.
|
213
|
-
def single_record
|
214
|
-
|
215
|
-
ds = clone(:limit=>1)
|
216
|
-
opts = opts.merge(:limit=>1) if opts and opts[:limit]
|
217
|
-
defarg ? ds.each{|r| return r} : ds.each(opts){|r| return r}
|
195
|
+
def single_record
|
196
|
+
clone(:limit=>1).each{|r| return r}
|
218
197
|
nil
|
219
198
|
end
|
220
199
|
|
221
200
|
# Returns the first value of the first record in the dataset.
|
222
201
|
# Returns nil if dataset is empty.
|
223
|
-
def single_value
|
224
|
-
|
225
|
-
ds = naked.clone(:graph=>false)
|
226
|
-
if r = (defarg ? ds.single_record : ds.single_record(opts))
|
202
|
+
def single_value
|
203
|
+
if r = naked.clone(:graph=>false).single_record
|
227
204
|
r.values.first
|
228
205
|
end
|
229
206
|
end
|