sequel 4.38.0 → 4.39.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.
- checksums.yaml +4 -4
- data/CHANGELOG +28 -0
- data/doc/association_basics.rdoc +1 -1
- data/doc/core_extensions.rdoc +8 -8
- data/doc/object_model.rdoc +7 -8
- data/doc/querying.rdoc +2 -2
- data/doc/release_notes/4.39.0.txt +127 -0
- data/doc/sql.rdoc +31 -31
- data/doc/transactions.rdoc +1 -1
- data/doc/virtual_rows.rdoc +1 -1
- data/lib/sequel/adapters/mock.rb +22 -66
- data/lib/sequel/adapters/shared/access.rb +2 -0
- data/lib/sequel/adapters/shared/cubrid.rb +2 -0
- data/lib/sequel/adapters/shared/db2.rb +2 -0
- data/lib/sequel/adapters/shared/firebird.rb +2 -0
- data/lib/sequel/adapters/shared/informix.rb +2 -0
- data/lib/sequel/adapters/shared/mssql.rb +10 -2
- data/lib/sequel/adapters/shared/mysql.rb +17 -4
- data/lib/sequel/adapters/shared/oracle.rb +9 -0
- data/lib/sequel/adapters/shared/postgres.rb +34 -1
- data/lib/sequel/adapters/shared/sqlanywhere.rb +1 -0
- data/lib/sequel/adapters/shared/sqlite.rb +8 -0
- data/lib/sequel/core.rb +10 -0
- data/lib/sequel/database.rb +5 -0
- data/lib/sequel/database/connecting.rb +28 -0
- data/lib/sequel/database/misc.rb +0 -51
- data/lib/sequel/database/query.rb +1 -1
- data/lib/sequel/database/schema_generator.rb +9 -0
- data/lib/sequel/database/transactions.rb +65 -0
- data/lib/sequel/dataset/actions.rb +1 -1
- data/lib/sequel/extensions/constraint_validations.rb +1 -1
- data/lib/sequel/extensions/core_extensions.rb +1 -1
- data/lib/sequel/extensions/core_refinements.rb +1 -1
- data/lib/sequel/extensions/migration.rb +17 -1
- data/lib/sequel/extensions/no_auto_literal_strings.rb +1 -1
- data/lib/sequel/extensions/pg_array_ops.rb +1 -1
- data/lib/sequel/extensions/pg_hstore_ops.rb +1 -1
- data/lib/sequel/extensions/pg_inet_ops.rb +1 -1
- data/lib/sequel/extensions/pg_interval.rb +1 -1
- data/lib/sequel/extensions/pg_json_ops.rb +28 -15
- data/lib/sequel/extensions/pg_range_ops.rb +1 -1
- data/lib/sequel/extensions/pg_row_ops.rb +1 -1
- data/lib/sequel/extensions/select_remove.rb +1 -1
- data/lib/sequel/extensions/sql_expr.rb +1 -1
- data/lib/sequel/model/associations.rb +1 -1
- data/lib/sequel/plugins/active_model.rb +19 -8
- data/lib/sequel/plugins/dataset_associations.rb +1 -1
- data/lib/sequel/plugins/hook_class_methods.rb +38 -2
- data/lib/sequel/plugins/list.rb +1 -1
- data/lib/sequel/plugins/pg_array_associations.rb +3 -3
- data/lib/sequel/plugins/timestamps.rb +15 -2
- data/lib/sequel/plugins/touch.rb +6 -0
- data/lib/sequel/sql.rb +15 -11
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mysql_spec.rb +18 -0
- data/spec/adapters/postgres_spec.rb +30 -1
- data/spec/core/database_spec.rb +29 -0
- data/spec/core/mock_adapter_spec.rb +32 -1
- data/spec/extensions/migration_spec.rb +46 -0
- data/spec/extensions/pg_interval_spec.rb +1 -0
- data/spec/extensions/pg_json_ops_spec.rb +13 -0
- data/spec/extensions/timestamps_spec.rb +11 -0
- data/spec/extensions/touch_spec.rb +8 -0
- metadata +4 -2
|
@@ -88,7 +88,7 @@ module Sequel
|
|
|
88
88
|
# :schema :: An explicit schema to use. It may also be implicitly provided
|
|
89
89
|
# via the table name.
|
|
90
90
|
#
|
|
91
|
-
# If schema parsing is supported by the database, the column information should
|
|
91
|
+
# If schema parsing is supported by the database, the column information hash should contain at least the
|
|
92
92
|
# following entries:
|
|
93
93
|
#
|
|
94
94
|
# :allow_null :: Whether NULL is an allowed value for the column.
|
|
@@ -336,6 +336,15 @@ module Sequel
|
|
|
336
336
|
# See CreateTableGenerator#column for the available options.
|
|
337
337
|
#
|
|
338
338
|
# add_column(:name, String) # ADD COLUMN name varchar(255)
|
|
339
|
+
#
|
|
340
|
+
# PostgreSQL specific options:
|
|
341
|
+
#
|
|
342
|
+
# :if_not_exists :: Set to true to not add the column if it already exists (PostgreSQL 9.6+)
|
|
343
|
+
#
|
|
344
|
+
# MySQL specific options:
|
|
345
|
+
#
|
|
346
|
+
# :after :: The name of an existing column that the new column should be positioned after
|
|
347
|
+
# :first :: Create this new column before all other existing columns
|
|
339
348
|
def add_column(name, type, opts = OPTS)
|
|
340
349
|
@operations << {:op => :add_column, :name => name, :type => type}.merge!(opts)
|
|
341
350
|
end
|
|
@@ -32,6 +32,58 @@ module Sequel
|
|
|
32
32
|
# on the same connection.
|
|
33
33
|
attr_accessor :transaction_isolation_level
|
|
34
34
|
|
|
35
|
+
# If a transaction is not currently in process, yield to the block immediately.
|
|
36
|
+
# Otherwise, add the block to the list of blocks to call after the currently
|
|
37
|
+
# in progress transaction commits (and only if it commits).
|
|
38
|
+
# Options:
|
|
39
|
+
# :server :: The server/shard to use.
|
|
40
|
+
def after_commit(opts=OPTS, &block)
|
|
41
|
+
raise Error, "must provide block to after_commit" unless block
|
|
42
|
+
synchronize(opts[:server]) do |conn|
|
|
43
|
+
if h = _trans(conn)
|
|
44
|
+
raise Error, "cannot call after_commit in a prepared transaction" if h[:prepare]
|
|
45
|
+
add_transaction_hook(conn, :after_commit, block)
|
|
46
|
+
else
|
|
47
|
+
yield
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# If a transaction is not currently in progress, ignore the block.
|
|
53
|
+
# Otherwise, add the block to the list of the blocks to call after the currently
|
|
54
|
+
# in progress transaction rolls back (and only if it rolls back).
|
|
55
|
+
# Options:
|
|
56
|
+
# :server :: The server/shard to use.
|
|
57
|
+
def after_rollback(opts=OPTS, &block)
|
|
58
|
+
raise Error, "must provide block to after_rollback" unless block
|
|
59
|
+
synchronize(opts[:server]) do |conn|
|
|
60
|
+
if h = _trans(conn)
|
|
61
|
+
raise Error, "cannot call after_rollback in a prepared transaction" if h[:prepare]
|
|
62
|
+
add_transaction_hook(conn, :after_rollback, block)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Return true if already in a transaction given the options,
|
|
68
|
+
# false otherwise. Respects the :server option for selecting
|
|
69
|
+
# a shard.
|
|
70
|
+
def in_transaction?(opts=OPTS)
|
|
71
|
+
synchronize(opts[:server]){|conn| !!_trans(conn)}
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Returns a proc that you can call to check if the transaction
|
|
75
|
+
# has been rolled back. The proc will return nil if the
|
|
76
|
+
# transaction is still in progress, true if the transaction was
|
|
77
|
+
# rolled back, and false if it was committed. Raises an
|
|
78
|
+
# Error if called outside a transaction. Respects the :server
|
|
79
|
+
# option for selecting a shard.
|
|
80
|
+
def rollback_checker(opts=OPTS)
|
|
81
|
+
synchronize(opts[:server]) do |conn|
|
|
82
|
+
raise Error, "not in a transaction" unless t = _trans(conn)
|
|
83
|
+
t[:rollback_checker] ||= proc{t[:rolled_back]}
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
35
87
|
# Starts a database transaction. When a database transaction is used,
|
|
36
88
|
# either all statements are successful or none of the statements are
|
|
37
89
|
# successful. Note that MySQL MyISAM tables do not support transactions.
|
|
@@ -215,6 +267,13 @@ module Sequel
|
|
|
215
267
|
Sequel.synchronize{@transactions[conn] = hash}
|
|
216
268
|
end
|
|
217
269
|
|
|
270
|
+
# Set the given callable as a hook to be called. Type should be either
|
|
271
|
+
# :after_commit or :after_rollback.
|
|
272
|
+
def add_transaction_hook(conn, type, block)
|
|
273
|
+
hooks = _trans(conn)[type] ||= []
|
|
274
|
+
hooks << block
|
|
275
|
+
end
|
|
276
|
+
|
|
218
277
|
# Whether the current thread/connection is already inside a transaction
|
|
219
278
|
def already_in_transaction?(conn, opts)
|
|
220
279
|
_trans(conn) && (!supports_savepoints? || !opts[:savepoint])
|
|
@@ -305,6 +364,11 @@ module Sequel
|
|
|
305
364
|
:execute
|
|
306
365
|
end
|
|
307
366
|
|
|
367
|
+
# Which transaction errors to translate, blank by default.
|
|
368
|
+
def database_error_classes
|
|
369
|
+
[]
|
|
370
|
+
end
|
|
371
|
+
|
|
308
372
|
# Retrieve the transaction hooks that should be run for the given
|
|
309
373
|
# connection and commit status.
|
|
310
374
|
def transaction_hooks(conn, committed)
|
|
@@ -318,6 +382,7 @@ module Sequel
|
|
|
318
382
|
callbacks = transaction_hooks(conn, committed)
|
|
319
383
|
|
|
320
384
|
if transaction_finished?(conn)
|
|
385
|
+
@transactions[conn][:rolled_back] = !committed
|
|
321
386
|
Sequel.synchronize{@transactions.delete(conn)}
|
|
322
387
|
end
|
|
323
388
|
|
|
@@ -817,7 +817,7 @@ module Sequel
|
|
|
817
817
|
# DB[:table].update(:x=>nil) # UPDATE table SET x = NULL
|
|
818
818
|
# # => 10
|
|
819
819
|
#
|
|
820
|
-
# DB[:table].update(:x=>Sequel
|
|
820
|
+
# DB[:table].update(:x=>Sequel[:x]+1, :y=>0) # UPDATE table SET x = (x + 1), y = 0
|
|
821
821
|
# # => 10
|
|
822
822
|
def update(values=OPTS, &block)
|
|
823
823
|
sql = update_sql(values)
|
|
@@ -444,7 +444,7 @@ module Sequel
|
|
|
444
444
|
# for all columns unless the :allow_nil option is given.
|
|
445
445
|
def generator_add_constraint_from_validation(generator, val, cons)
|
|
446
446
|
if val[:allow_nil]
|
|
447
|
-
nil_cons = Sequel
|
|
447
|
+
nil_cons = Sequel[val[:columns].map{|c| [c, nil]}]
|
|
448
448
|
cons = Sequel.|(nil_cons, cons) if cons
|
|
449
449
|
else
|
|
450
450
|
nil_cons = Sequel.negate(val[:columns].map{|c| [c, nil]})
|
|
@@ -58,7 +58,7 @@ class Array
|
|
|
58
58
|
# [[:a, true]].sql_expr # SQL: a IS TRUE
|
|
59
59
|
# [[:a, 1], [:b, [2, 3]]].sql_expr # SQL: a = 1 AND b IN (2, 3)
|
|
60
60
|
def sql_expr
|
|
61
|
-
Sequel
|
|
61
|
+
Sequel[self]
|
|
62
62
|
end
|
|
63
63
|
|
|
64
64
|
# Return a <tt>Sequel::SQL::BooleanExpression</tt> created from this array, matching none
|
|
@@ -55,7 +55,7 @@ module Sequel::CoreRefinements
|
|
|
55
55
|
# [[:a, true]].sql_expr # SQL: a IS TRUE
|
|
56
56
|
# [[:a, 1], [:b, [2, 3]]].sql_expr # SQL: a = 1 AND b IN (2, 3)
|
|
57
57
|
def sql_expr
|
|
58
|
-
Sequel
|
|
58
|
+
Sequel[self]
|
|
59
59
|
end
|
|
60
60
|
|
|
61
61
|
# Return a <tt>Sequel::SQL::BooleanExpression</tt> created from this array, matching none
|
|
@@ -387,6 +387,8 @@ module Sequel
|
|
|
387
387
|
# :column :: The column in the :table argument storing the migration version (default: :version).
|
|
388
388
|
# :current :: The current version of the database. If not given, it is retrieved from the database
|
|
389
389
|
# using the :table and :column options.
|
|
390
|
+
# :relative :: Run the given number of migrations, with a positive number being migrations to migrate
|
|
391
|
+
# up, and a negative number being migrations to migrate down (IntegerMigrator only).
|
|
390
392
|
# :table :: The table containing the schema version (default: :schema_info).
|
|
391
393
|
# :target :: The target version to which to migrate. If not given, migrates to the maximum version.
|
|
392
394
|
#
|
|
@@ -520,8 +522,22 @@ module Sequel
|
|
|
520
522
|
# Set up all state for the migrator instance
|
|
521
523
|
def initialize(db, directory, opts=OPTS)
|
|
522
524
|
super
|
|
523
|
-
@target = opts[:target] || latest_migration_version
|
|
524
525
|
@current = opts[:current] || current_migration_version
|
|
526
|
+
latest_version = latest_migration_version
|
|
527
|
+
|
|
528
|
+
@target = if opts[:target]
|
|
529
|
+
opts[:target]
|
|
530
|
+
elsif opts[:relative]
|
|
531
|
+
@current + opts[:relative]
|
|
532
|
+
else
|
|
533
|
+
latest_version
|
|
534
|
+
end
|
|
535
|
+
|
|
536
|
+
if @target > latest_version
|
|
537
|
+
@target = latest_version
|
|
538
|
+
elsif @target < 0
|
|
539
|
+
@target = 0
|
|
540
|
+
end
|
|
525
541
|
|
|
526
542
|
raise(Error, "No current version available") unless current
|
|
527
543
|
raise(Error, "No target version available, probably because no migration files found or filenames don't follow the migration filename convention") unless target
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
# Also, on most Sequel expression objects, you can call the pg_array
|
|
20
20
|
# method:
|
|
21
21
|
#
|
|
22
|
-
# ia = Sequel
|
|
22
|
+
# ia = Sequel[:int_array_column].pg_array
|
|
23
23
|
#
|
|
24
24
|
# If you have loaded the {core_extensions extension}[rdoc-ref:doc/core_extensions.rdoc],
|
|
25
25
|
# or you have loaded the core_refinements extension
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
# Also, on most Sequel expression objects, you can call the hstore
|
|
21
21
|
# method:
|
|
22
22
|
#
|
|
23
|
-
# h = Sequel
|
|
23
|
+
# h = Sequel[:hstore_column].hstore
|
|
24
24
|
#
|
|
25
25
|
# If you have loaded the {core_extensions extension}[rdoc-ref:doc/core_extensions.rdoc],
|
|
26
26
|
# or you have loaded the core_refinements extension
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
# Also, on most Sequel expression objects, you can call the pg_inet
|
|
15
15
|
# method:
|
|
16
16
|
#
|
|
17
|
-
# r = Sequel
|
|
17
|
+
# r = Sequel[:ip].pg_inet
|
|
18
18
|
#
|
|
19
19
|
# If you have loaded the {core_extensions extension}[rdoc-ref:doc/core_extensions.rdoc],
|
|
20
20
|
# or you have loaded the core_refinements extension
|
|
@@ -42,7 +42,7 @@ module Sequel
|
|
|
42
42
|
module Postgres
|
|
43
43
|
module IntervalDatabaseMethods
|
|
44
44
|
EMPTY_INTERVAL = '0'.freeze
|
|
45
|
-
DURATION_UNITS = [:years, :months, :days, :minutes, :seconds].freeze
|
|
45
|
+
DURATION_UNITS = [:years, :months, :weeks, :days, :hours, :minutes, :seconds].freeze
|
|
46
46
|
|
|
47
47
|
# Return an unquoted string version of the duration object suitable for
|
|
48
48
|
# use as a bound variable.
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
# Also, on most Sequel expression objects, you can call the pg_json
|
|
25
25
|
# or pg_jsonb # method:
|
|
26
26
|
#
|
|
27
|
-
# j = Sequel
|
|
28
|
-
# jb = Sequel
|
|
27
|
+
# j = Sequel[:json_column].pg_json
|
|
28
|
+
# jb = Sequel[:jsonb_column].pg_jsonb
|
|
29
29
|
#
|
|
30
30
|
# If you have loaded the {core_extensions extension}[rdoc-ref:doc/core_extensions.rdoc],
|
|
31
31
|
# or you have loaded the core_refinements extension
|
|
@@ -61,16 +61,17 @@
|
|
|
61
61
|
#
|
|
62
62
|
# There are additional methods are are only supported on JSONBOp instances:
|
|
63
63
|
#
|
|
64
|
-
# j - 1
|
|
65
|
-
# j.concat(:h)
|
|
66
|
-
# j.contain_all(:a)
|
|
67
|
-
# j.contain_any(:a)
|
|
68
|
-
# j.contains(:h)
|
|
69
|
-
# j.contained_by(:h)
|
|
70
|
-
# j.delete_path(%w'0 a')
|
|
71
|
-
# j.has_key?('a')
|
|
72
|
-
# j.
|
|
73
|
-
# j.
|
|
64
|
+
# j - 1 # (jsonb_column - 1)
|
|
65
|
+
# j.concat(:h) # (jsonb_column || h)
|
|
66
|
+
# j.contain_all(:a) # (jsonb_column ?& a)
|
|
67
|
+
# j.contain_any(:a) # (jsonb_column ?| a)
|
|
68
|
+
# j.contains(:h) # (jsonb_column @> h)
|
|
69
|
+
# j.contained_by(:h) # (jsonb_column <@ h)
|
|
70
|
+
# j.delete_path(%w'0 a') # (jsonb_column #- ARRAY['0','a'])
|
|
71
|
+
# j.has_key?('a') # (jsonb_column ? 'a')
|
|
72
|
+
# j.insert(%w'0 a', 'a'=>1) # jsonb_insert(jsonb_column, ARRAY[0, 'a'], '{"a":1}'::jsonb, false)
|
|
73
|
+
# j.pretty # jsonb_pretty(jsonb_column)
|
|
74
|
+
# j.set(%w'0 a', :h) # jsonb_set(jsonb_column, ARRAY['0','a'], h, true)
|
|
74
75
|
#
|
|
75
76
|
# If you are also using the pg_json extension, you should load it before
|
|
76
77
|
# loading this extension. Doing so will allow you to use the #op method on
|
|
@@ -336,7 +337,7 @@ module Sequel
|
|
|
336
337
|
bool_op(CONTAINED_BY, wrap_input_jsonb(other))
|
|
337
338
|
end
|
|
338
339
|
|
|
339
|
-
#
|
|
340
|
+
# Removes the given path from the receiver.
|
|
340
341
|
#
|
|
341
342
|
# jsonb_op.delete_path(:h) # (jsonb #- h)
|
|
342
343
|
def delete_path(other)
|
|
@@ -351,19 +352,31 @@ module Sequel
|
|
|
351
352
|
end
|
|
352
353
|
alias include? has_key?
|
|
353
354
|
|
|
355
|
+
# Inserts the given jsonb value at the given path in the receiver.
|
|
356
|
+
# The default is to insert the value before the given path, but
|
|
357
|
+
# insert_after can be set to true to insert it after the given path.
|
|
358
|
+
#
|
|
359
|
+
# jsonb_op.insert(['a', 'b'], h) # jsonb_insert(jsonb, ARRAY['a', 'b'], h, false)
|
|
360
|
+
# jsonb_op.insert(['a', 'b'], h, true) # jsonb_insert(jsonb, ARRAY['a', 'b'], h, true)
|
|
361
|
+
def insert(path, other, insert_after=false)
|
|
362
|
+
self.class.new(function(:insert, wrap_input_array(path), wrap_input_jsonb(other), insert_after))
|
|
363
|
+
end
|
|
364
|
+
|
|
354
365
|
# Return the receiver, since it is already a JSONBOp.
|
|
355
366
|
def pg_jsonb
|
|
356
367
|
self
|
|
357
368
|
end
|
|
358
369
|
|
|
359
|
-
#
|
|
370
|
+
# Return a pretty printed version of the receiver as a string expression.
|
|
360
371
|
#
|
|
361
372
|
# jsonb_op.pretty # jsonb_pretty(jsonb)
|
|
362
373
|
def pretty
|
|
363
374
|
Sequel::SQL::StringExpression.new(:NOOP, function(:pretty))
|
|
364
375
|
end
|
|
365
376
|
|
|
366
|
-
#
|
|
377
|
+
# Set the given jsonb value at the given path in the receiver.
|
|
378
|
+
# By default, this will create the value if it does not exist, but
|
|
379
|
+
# create_missing can be set to false to not create a new value.
|
|
367
380
|
#
|
|
368
381
|
# jsonb_op.set(['a', 'b'], h) # jsonb_set(jsonb, ARRAY['a', 'b'], h, true)
|
|
369
382
|
# jsonb_op.set(['a', 'b'], h, false) # jsonb_set(jsonb, ARRAY['a', 'b'], h, false)
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
# Also, on most Sequel expression objects, you can call the pg_range
|
|
20
20
|
# method:
|
|
21
21
|
#
|
|
22
|
-
# r = Sequel
|
|
22
|
+
# r = Sequel[:range].pg_range
|
|
23
23
|
#
|
|
24
24
|
# If you have loaded the {core_extensions extension}[rdoc-ref:doc/core_extensions.rdoc],
|
|
25
25
|
# or you have loaded the core_refinements extension
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
# Also, on most Sequel expression objects, you can call the pg_row
|
|
20
20
|
# method:
|
|
21
21
|
#
|
|
22
|
-
# r = Sequel
|
|
22
|
+
# r = Sequel[:row_column].pg_row
|
|
23
23
|
#
|
|
24
24
|
# If you have loaded the {core_extensions extension}[rdoc-ref:doc/core_extensions.rdoc],
|
|
25
25
|
# or you have loaded the core_refinements extension
|
|
@@ -35,7 +35,7 @@ module Sequel
|
|
|
35
35
|
# In this case, the code will currently use unqualified column names for all columns
|
|
36
36
|
# the dataset returns, except for the columns given.
|
|
37
37
|
# * This dataset has an existing explicit selection containing an item that returns
|
|
38
|
-
# multiple database columns (e.g. Sequel
|
|
38
|
+
# multiple database columns (e.g. Sequel[:table].*, Sequel.lit('column1, column2')). In this case,
|
|
39
39
|
# the behavior is undefined and this method should not be used.
|
|
40
40
|
#
|
|
41
41
|
# There may be other cases where this method does not work correctly, use it with caution.
|
|
@@ -2792,7 +2792,7 @@ END
|
|
|
2792
2792
|
# included by the association's conditions.
|
|
2793
2793
|
def add_association_filter_conditions(ref, obj, expr)
|
|
2794
2794
|
if expr != SQL::Constants::FALSE && ref.filter_by_associations_add_conditions?
|
|
2795
|
-
Sequel
|
|
2795
|
+
Sequel[ref.filter_by_associations_conditions_expression(obj)]
|
|
2796
2796
|
else
|
|
2797
2797
|
expr
|
|
2798
2798
|
end
|
|
@@ -46,13 +46,6 @@ module Sequel
|
|
|
46
46
|
@destroyed = true
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
-
# Mark current instance as destroyed if the transaction in which this
|
|
50
|
-
# instance is created is rolled back.
|
|
51
|
-
def before_create
|
|
52
|
-
db.after_rollback{@destroyed = true}
|
|
53
|
-
super
|
|
54
|
-
end
|
|
55
|
-
|
|
56
49
|
# Return ::ActiveModel::Name instance for the class.
|
|
57
50
|
def model_name
|
|
58
51
|
model.model_name
|
|
@@ -60,7 +53,16 @@ module Sequel
|
|
|
60
53
|
|
|
61
54
|
# False if the object is new? or has been destroyed, true otherwise.
|
|
62
55
|
def persisted?
|
|
63
|
-
|
|
56
|
+
return false if new?
|
|
57
|
+
return false if defined?(@destroyed)
|
|
58
|
+
|
|
59
|
+
if defined?(@rollback_checker)
|
|
60
|
+
if @rollback_checker.call
|
|
61
|
+
return false
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
true
|
|
64
66
|
end
|
|
65
67
|
|
|
66
68
|
# An array of primary key values, or nil if the object is not persisted.
|
|
@@ -93,6 +95,15 @@ module Sequel
|
|
|
93
95
|
|
|
94
96
|
private
|
|
95
97
|
|
|
98
|
+
# For new objects, add a rollback checker to check if the transaction
|
|
99
|
+
# in which this instance is created is rolled back.
|
|
100
|
+
def _save(opts)
|
|
101
|
+
if new? && db.in_transaction?(opts)
|
|
102
|
+
@rollback_checker = db.rollback_checker(opts)
|
|
103
|
+
end
|
|
104
|
+
super
|
|
105
|
+
end
|
|
106
|
+
|
|
96
107
|
# Use ActiveModel compliant errors class.
|
|
97
108
|
def errors_class
|
|
98
109
|
Errors
|
|
@@ -103,7 +103,7 @@ module Sequel
|
|
|
103
103
|
edges.each{|e| mds = mds.join(e[:table], Array(e[:right]).zip(Array(e[:left])))}
|
|
104
104
|
ds.filter(r.qualified_right_primary_key=>r.send(:apply_filter_by_associations_limit_strategy, mds))
|
|
105
105
|
when :pg_array_to_many
|
|
106
|
-
ds.filter(Sequel
|
|
106
|
+
ds.filter(Sequel[r.primary_key=>sds.select{Sequel.pg_array_op(r.qualify(r[:model].table_name, r[:key])).unnest}])
|
|
107
107
|
when :many_to_pg_array
|
|
108
108
|
ds.filter(Sequel.function(:coalesce, Sequel.pg_array_op(r[:key]).overlaps(sds.select{array_agg(r.qualify(r[:model].table_name, r.primary_key))}), false))
|
|
109
109
|
else
|
|
@@ -119,8 +119,44 @@ module Sequel
|
|
|
119
119
|
end
|
|
120
120
|
|
|
121
121
|
module InstanceMethods
|
|
122
|
-
Model::BEFORE_HOOKS.each{|h| class_eval("def #{h}; model.hook_blocks(:#{h}){|b| return false if instance_eval(&b) == false}; super; end", __FILE__, __LINE__)}
|
|
123
|
-
Model::AFTER_HOOKS.each{|h| class_eval("def #{h}; super; model.hook_blocks(:#{h}){|b| instance_eval(&b)}; end", __FILE__, __LINE__)}
|
|
122
|
+
(Model::BEFORE_HOOKS - [:before_save, :before_destroy]).each{|h| class_eval("def #{h}; model.hook_blocks(:#{h}){|b| return false if instance_eval(&b) == false}; super; end", __FILE__, __LINE__)}
|
|
123
|
+
(Model::AFTER_HOOKS - [:after_save, :after_destroy, :after_commit, :after_rollback, :after_destroy_commit, :after_destroy_rollback]).each{|h| class_eval("def #{h}; super; model.hook_blocks(:#{h}){|b| instance_eval(&b)}; end", __FILE__, __LINE__)}
|
|
124
|
+
|
|
125
|
+
def after_destroy
|
|
126
|
+
super
|
|
127
|
+
model.hook_blocks(:after_destroy){|b| instance_eval(&b)}
|
|
128
|
+
if model.has_hooks?(:after_destroy_commit)
|
|
129
|
+
db.after_rollback{model.hook_blocks(:after_destroy_commit){|b| instance_eval(&b)}}
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def after_save
|
|
134
|
+
super
|
|
135
|
+
model.hook_blocks(:after_save){|b| instance_eval(&b)}
|
|
136
|
+
if model.has_hooks?(:after_commit)
|
|
137
|
+
db.after_rollback{model.hook_blocks(:after_commit){|b| instance_eval(&b)}}
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def before_destroy
|
|
142
|
+
model.hook_blocks(:before_destroy) do |b|
|
|
143
|
+
return false if instance_eval(&b) == false
|
|
144
|
+
end
|
|
145
|
+
super
|
|
146
|
+
if model.has_hooks?(:after_destroy_rollback)
|
|
147
|
+
db.after_rollback{model.hook_blocks(:after_destroy_rollback){|b| instance_eval(&b)}}
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def before_save
|
|
152
|
+
model.hook_blocks(:before_save) do |b|
|
|
153
|
+
return false if instance_eval(&b) == false
|
|
154
|
+
end
|
|
155
|
+
super
|
|
156
|
+
if model.has_hooks?(:after_rollback)
|
|
157
|
+
db.after_rollback{model.hook_blocks(:after_rollback){|b| instance_eval(&b)}}
|
|
158
|
+
end
|
|
159
|
+
end
|
|
124
160
|
end
|
|
125
161
|
end
|
|
126
162
|
end
|