pg_trunk 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +4 -15
- data/CHANGELOG.md +21 -0
- data/README.md +3 -1
- data/lib/pg_trunk/core/operation/attributes.rb +1 -1
- data/lib/pg_trunk/core/railtie/custom_types.rb +5 -6
- data/lib/pg_trunk/operations/check_constraints/add_check_constraint.rb +42 -33
- data/lib/pg_trunk/operations/check_constraints/drop_check_constraint.rb +51 -40
- data/lib/pg_trunk/operations/check_constraints/rename_check_constraint.rb +39 -30
- data/lib/pg_trunk/operations/check_constraints/validate_check_constraint.rb +28 -21
- data/lib/pg_trunk/operations/composite_types/change_composite_type.rb +59 -50
- data/lib/pg_trunk/operations/composite_types/create_composite_type.rb +23 -19
- data/lib/pg_trunk/operations/composite_types/drop_composite_type.rb +48 -43
- data/lib/pg_trunk/operations/composite_types/rename_composite_type.rb +15 -12
- data/lib/pg_trunk/operations/domains/change_domain.rb +53 -47
- data/lib/pg_trunk/operations/domains/create_domain.rb +28 -25
- data/lib/pg_trunk/operations/domains/drop_domain.rb +50 -41
- data/lib/pg_trunk/operations/domains/rename_domain.rb +17 -12
- data/lib/pg_trunk/operations/enums/change_enum.rb +37 -32
- data/lib/pg_trunk/operations/enums/create_enum.rb +23 -20
- data/lib/pg_trunk/operations/enums/drop_enum.rb +50 -39
- data/lib/pg_trunk/operations/enums/rename_enum.rb +17 -12
- data/lib/pg_trunk/operations/foreign_keys/add_foreign_key.rb +58 -49
- data/lib/pg_trunk/operations/foreign_keys/drop_foreign_key.rb +57 -48
- data/lib/pg_trunk/operations/foreign_keys/rename_foreign_key.rb +38 -29
- data/lib/pg_trunk/operations/functions/change_function.rb +53 -47
- data/lib/pg_trunk/operations/functions/create_function.rb +75 -64
- data/lib/pg_trunk/operations/functions/drop_function.rb +78 -65
- data/lib/pg_trunk/operations/functions/rename_function.rb +29 -22
- data/lib/pg_trunk/operations/materialized_views/change_materialized_view.rb +65 -55
- data/lib/pg_trunk/operations/materialized_views/create_materialized_view.rb +82 -71
- data/lib/pg_trunk/operations/materialized_views/drop_materialized_view.rb +59 -46
- data/lib/pg_trunk/operations/materialized_views/refresh_materialized_view.rb +29 -24
- data/lib/pg_trunk/operations/materialized_views/rename_materialized_view.rb +29 -22
- data/lib/pg_trunk/operations/procedures/change_procedure.rb +53 -46
- data/lib/pg_trunk/operations/procedures/create_procedure.rb +63 -52
- data/lib/pg_trunk/operations/procedures/drop_procedure.rb +56 -45
- data/lib/pg_trunk/operations/procedures/rename_procedure.rb +29 -22
- data/lib/pg_trunk/operations/rules/base.rb +77 -0
- data/lib/pg_trunk/operations/rules/create_rule.rb +155 -0
- data/lib/pg_trunk/operations/rules/drop_rule.rb +94 -0
- data/lib/pg_trunk/operations/rules/rename_rule.rb +62 -0
- data/lib/pg_trunk/operations/rules.rb +13 -0
- data/lib/pg_trunk/operations/sequences/base.rb +79 -0
- data/lib/pg_trunk/operations/sequences/change_sequence.rb +142 -0
- data/lib/pg_trunk/operations/sequences/create_sequence.rb +180 -0
- data/lib/pg_trunk/operations/sequences/drop_sequence.rb +82 -0
- data/lib/pg_trunk/operations/sequences/rename_sequence.rb +64 -0
- data/lib/pg_trunk/operations/sequences.rb +14 -0
- data/lib/pg_trunk/operations/statistics/create_statistics.rb +67 -56
- data/lib/pg_trunk/operations/statistics/drop_statistics.rb +64 -53
- data/lib/pg_trunk/operations/statistics/rename_statistics.rb +18 -13
- data/lib/pg_trunk/operations/triggers/change_trigger.rb +23 -18
- data/lib/pg_trunk/operations/triggers/create_trigger.rb +63 -54
- data/lib/pg_trunk/operations/triggers/drop_trigger.rb +55 -46
- data/lib/pg_trunk/operations/triggers/rename_trigger.rb +51 -48
- data/lib/pg_trunk/operations/views/change_view.rb +47 -38
- data/lib/pg_trunk/operations/views/create_view.rb +56 -45
- data/lib/pg_trunk/operations/views/drop_view.rb +59 -46
- data/lib/pg_trunk/operations/views/rename_view.rb +27 -20
- data/lib/pg_trunk/operations.rb +2 -0
- data/lib/pg_trunk/version.rb +1 -1
- data/pg_trunk.gemspec +0 -1
- data/spec/operations/rules/create_rule_spec.rb +119 -0
- data/spec/operations/rules/drop_rule_spec.rb +117 -0
- data/spec/operations/rules/rename_rule_spec.rb +148 -0
- data/spec/operations/sequences/change_sequence_spec.rb +134 -0
- data/spec/operations/sequences/create_sequence_spec.rb +156 -0
- data/spec/operations/sequences/drop_sequence_spec.rb +102 -0
- data/spec/operations/sequences/rename_sequence_spec.rb +100 -0
- metadata +22 -68
@@ -1,44 +1,53 @@
|
|
1
1
|
# frozen_string_literal: false
|
2
2
|
|
3
|
-
# @!
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
# @
|
8
|
-
# @
|
9
|
-
# @
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
3
|
+
# @!parse
|
4
|
+
# class ActiveRecord::Migration
|
5
|
+
# # Modify a view
|
6
|
+
# #
|
7
|
+
# # @param [#to_s] name (nil) The qualified name of the view
|
8
|
+
# # @option options [Boolean] :if_exists (false) Suppress the error when the view is absent
|
9
|
+
# # @yield [v] the block with the view's definition
|
10
|
+
# # @yieldparam Object receiver of methods specifying the view
|
11
|
+
# # @return [void]
|
12
|
+
# #
|
13
|
+
# # The operation replaces the view with a new definition(s):
|
14
|
+
# #
|
15
|
+
# # ```ruby
|
16
|
+
# # change_view "admin_users" do |v|
|
17
|
+
# # v.sql_definition: <<~SQL, from: <<~SQL
|
18
|
+
# # SELECT id, name FROM users WHERE admin;
|
19
|
+
# # SQL
|
20
|
+
# # SELECT * FROM users WHERE admin;
|
21
|
+
# # SQL
|
22
|
+
# # end
|
23
|
+
# # ```
|
24
|
+
# #
|
25
|
+
# # For some compatibility to the `scenic` gem, we also support
|
26
|
+
# # adding a definition via its version:
|
27
|
+
# #
|
28
|
+
# # ```ruby
|
29
|
+
# # change_view "admin_users" do |v|
|
30
|
+
# # v.version 2, from: 1
|
31
|
+
# # end
|
32
|
+
# # ```
|
33
|
+
# #
|
34
|
+
# # It is expected, that both `db/views/admin_users_v01.sql`
|
35
|
+
# # and `db/views/admin_users_v02.sql` to contain SQL snippets.
|
36
|
+
# #
|
37
|
+
# # Please, notice that neither deletion of columns,
|
38
|
+
# # nor changing their types is supported by the PostgreSQL.
|
39
|
+
# #
|
40
|
+
# # You can also (re)set a comment describing the view,
|
41
|
+
# # and the check option (either `:local` or `:cascaded`):
|
42
|
+
# #
|
43
|
+
# # ```ruby
|
44
|
+
# # change_view "admin_users" do |v|
|
45
|
+
# # v.check :local, from: :cascaded
|
46
|
+
# # v.comment "Admin users only", from: ""
|
47
|
+
# # end
|
48
|
+
# # ```
|
49
|
+
# def change_view(name, **options, &block); end
|
19
50
|
# end
|
20
|
-
#
|
21
|
-
# For some compatibility to the `scenic` gem, we also support
|
22
|
-
# adding a definition via its version:
|
23
|
-
#
|
24
|
-
# change_view "admin_users" do |v|
|
25
|
-
# v.version 2, from: 1
|
26
|
-
# end
|
27
|
-
#
|
28
|
-
# It is expected, that both `db/views/admin_users_v01.sql`
|
29
|
-
# and `db/views/admin_users_v02.sql` to contain SQL snippets.
|
30
|
-
#
|
31
|
-
# Please, notice that neither deletion of columns,
|
32
|
-
# nor changing their types is supported by the PostgreSQL.
|
33
|
-
#
|
34
|
-
# You can also (re)set a comment describing the view,
|
35
|
-
# and the check option (either `:local` or `:cascaded`):
|
36
|
-
#
|
37
|
-
# change_view "admin_users" do |v|
|
38
|
-
# v.check :local, from: :cascaded
|
39
|
-
# v.comment "Admin users only", from: ""
|
40
|
-
# end
|
41
|
-
|
42
51
|
module PGTrunk::Operations::Views
|
43
52
|
# @private
|
44
53
|
class ChangeView < Base
|
@@ -1,51 +1,62 @@
|
|
1
1
|
# frozen_string_literal: false
|
2
2
|
|
3
|
-
# @!
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
# @
|
8
|
-
# @option [
|
9
|
-
# @option [#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
# @
|
15
|
-
# @
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
3
|
+
# @!parse
|
4
|
+
# class ActiveRecord::Migration
|
5
|
+
# # Create a view
|
6
|
+
# #
|
7
|
+
# # @param [#to_s] name (nil) The qualified name of the view
|
8
|
+
# # @option options [Boolean] :replace_existing (false) If the view should overwrite an existing one
|
9
|
+
# # @option options [#to_s] :sql_definition (nil) The snippet containing the query
|
10
|
+
# # @option options [#to_i] :version (nil)
|
11
|
+
# # The alternative way to set sql_definition by referencing to a file containing the snippet
|
12
|
+
# # @option options [#to_s] :check (nil) Controls the behavior of automatically updatable views
|
13
|
+
# # Supported values: :local, :cascaded
|
14
|
+
# # @option options [#to_s] :comment (nil) The comment describing the view
|
15
|
+
# # @yield [v] the block with the view's definition
|
16
|
+
# # @yieldparam Object receiver of methods specifying the view
|
17
|
+
# # @return [void]
|
18
|
+
# #
|
19
|
+
# # The operation creates the view using its `sql_definition`:
|
20
|
+
# #
|
21
|
+
# # ```ruby
|
22
|
+
# # create_view("views.admin_users", sql_definition: <<~SQL)
|
23
|
+
# # SELECT id, name FROM users WHERE admin;
|
24
|
+
# # SQL
|
25
|
+
# # ```
|
26
|
+
# #
|
27
|
+
# # For compatibility to the `scenic` gem, we also support
|
28
|
+
# # adding a definition via its version:
|
29
|
+
# #
|
30
|
+
# # ```ruby
|
31
|
+
# # create_view "admin_users", version: 1
|
32
|
+
# # ```
|
33
|
+
# #
|
34
|
+
# # It is expected, that a `db/views/admin_users_v01.sql`
|
35
|
+
# # to contain the SQL snippet.
|
36
|
+
# #
|
37
|
+
# # You can also set a comment describing the view, and the check option
|
38
|
+
# # (either `:local` or `:cascaded`):
|
39
|
+
# #
|
40
|
+
# # ```ruby
|
41
|
+
# # create_view "admin_users" do |v|
|
42
|
+
# # v.sql_definition "SELECT id, name FROM users WHERE admin;"
|
43
|
+
# # v.check :local
|
44
|
+
# # v.comment "Admin users only"
|
45
|
+
# # end
|
46
|
+
# # ```
|
47
|
+
# #
|
48
|
+
# # With the `replace_existing: true` option the operation
|
49
|
+
# # would use `CREATE OR REPLACE VIEW` command, so it
|
50
|
+
# # can be used to "update" (or reload) the existing view.
|
51
|
+
# #
|
52
|
+
# # ```ruby
|
53
|
+
# # create_view "admin_users", version: 1, replace_existing: true
|
54
|
+
# # ```
|
55
|
+
# #
|
56
|
+
# # This option makes an operation irreversible due to uncertainty
|
57
|
+
# # of the previous state of the database.
|
58
|
+
# def create_view(name, **options, &block); end
|
38
59
|
# end
|
39
|
-
#
|
40
|
-
# With the `replace_existing: true` option the operation
|
41
|
-
# would use `CREATE OR REPLACE VIEW` command, so it
|
42
|
-
# can be used to "update" (or reload) the existing view.
|
43
|
-
#
|
44
|
-
# create_view "admin_users", version: 1, replace_existing: true
|
45
|
-
#
|
46
|
-
# This option makes an operation irreversible due to uncertainty
|
47
|
-
# of the previous state of the database.
|
48
|
-
|
49
60
|
module PGTrunk::Operations::Views
|
50
61
|
# @private
|
51
62
|
class CreateView < Base
|
@@ -1,52 +1,65 @@
|
|
1
1
|
# frozen_string_literal: false
|
2
2
|
|
3
|
-
# @!
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
# @
|
8
|
-
# @option [Boolean] :
|
9
|
-
# @option [
|
10
|
-
# @option [
|
11
|
-
# @option [#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
# @
|
17
|
-
# @
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
3
|
+
# @!parse
|
4
|
+
# class ActiveRecord::Migration
|
5
|
+
# # Drop a view
|
6
|
+
# #
|
7
|
+
# # @param [#to_s] name (nil) The qualified name of the view
|
8
|
+
# # @option options [Boolean] :replace_existing (false) If the view should overwrite an existing one
|
9
|
+
# # @option options [Boolean] :if_exists (false) Suppress the error when the view is absent
|
10
|
+
# # @option options [Symbol] :force (:restrict) How to process dependent objects (`:cascade` or `:restrict`)
|
11
|
+
# # @option options [#to_s] :sql_definition (nil) The snippet containing the query
|
12
|
+
# # @option options [#to_i] :revert_to_version (nil)
|
13
|
+
# # The alternative way to set sql_definition by referencing to a file containing the snippet
|
14
|
+
# # @option options [#to_s] :check (nil) Controls the behavior of automatically updatable views
|
15
|
+
# # Supported values: :local, :cascaded
|
16
|
+
# # @option options [#to_s] :comment (nil) The comment describing the view
|
17
|
+
# # @yield [v] the block with the view's definition
|
18
|
+
# # @yieldparam Object receiver of methods specifying the view
|
19
|
+
# # @return [void]
|
20
|
+
# #
|
21
|
+
# # The operation drops the existing view identified by its
|
22
|
+
# # qualified name (it can include a schema).
|
23
|
+
# #
|
24
|
+
# # ```ruby
|
25
|
+
# # drop_view "views.admin_users"
|
26
|
+
# # ```
|
27
|
+
# #
|
28
|
+
# # To make the operation invertible, use the same options
|
29
|
+
# # as in the `create_view` operation.
|
30
|
+
# #
|
31
|
+
# # ```ruby
|
32
|
+
# # drop_view "views.admin_users" do |v|
|
33
|
+
# # v.sql_definition "SELECT name, email FROM users WHERE admin;"
|
34
|
+
# # v.check :local
|
35
|
+
# # v.comment "Admin users only"
|
36
|
+
# # end
|
37
|
+
# # ```
|
38
|
+
# #
|
39
|
+
# # You can also use a version-base SQL definition like:
|
40
|
+
# #
|
41
|
+
# # ```ruby
|
42
|
+
# # drop_view "views.admin_users", revert_to_version: 1
|
43
|
+
# # ```
|
44
|
+
# #
|
45
|
+
# # With the `force: :cascade` option the operation would remove
|
46
|
+
# # all the objects which depend on the view.
|
47
|
+
# #
|
48
|
+
# # ```ruby
|
49
|
+
# # drop_view "views.admin_users", force: :cascade
|
50
|
+
# # ```
|
51
|
+
# #
|
52
|
+
# # With the `if_exists: true` option the operation won't fail
|
53
|
+
# # even when the view was absent in the database.
|
54
|
+
# #
|
55
|
+
# # ```ruby
|
56
|
+
# # drop_view "views.admin_users", if_exists: true
|
57
|
+
# # ```
|
58
|
+
# #
|
59
|
+
# # Both options make an operation irreversible due to uncertainty
|
60
|
+
# # of the previous state of the database.
|
61
|
+
# def drop_view(name, **options, &block); end
|
31
62
|
# end
|
32
|
-
#
|
33
|
-
# You can also use a version-base SQL definition like:
|
34
|
-
#
|
35
|
-
# drop_view "views.admin_users", revert_to_version: 1
|
36
|
-
#
|
37
|
-
# With the `force: :cascade` option the operation would remove
|
38
|
-
# all the objects which depend on the view.
|
39
|
-
#
|
40
|
-
# drop_view "views.admin_users", force: :cascade
|
41
|
-
#
|
42
|
-
# With the `if_exists: true` option the operation won't fail
|
43
|
-
# even when the view was absent in the database.
|
44
|
-
#
|
45
|
-
# drop_view "views.admin_users", if_exists: true
|
46
|
-
#
|
47
|
-
# Both options make an operation irreversible due to uncertainty
|
48
|
-
# of the previous state of the database.
|
49
|
-
|
50
63
|
module PGTrunk::Operations::Views
|
51
64
|
# @private
|
52
65
|
class DropView < Base
|
@@ -1,25 +1,32 @@
|
|
1
1
|
# frozen_string_literal: false
|
2
2
|
|
3
|
-
# @!
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
# @
|
8
|
-
# @option [
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
|
3
|
+
# @!parse
|
4
|
+
# class ActiveRecord::Migration
|
5
|
+
# # Change the name and/or schema of a view
|
6
|
+
# #
|
7
|
+
# # @param [#to_s] :name (nil) The qualified name of the view
|
8
|
+
# # @option options [#to_s] :to (nil) The new qualified name for the view
|
9
|
+
# # @option options [Boolean] :if_exists (false) Suppress the error when the view is absent
|
10
|
+
# # @return [void]
|
11
|
+
# #
|
12
|
+
# # A view can be renamed by changing both the name
|
13
|
+
# # and the schema (namespace) it belongs to.
|
14
|
+
# #
|
15
|
+
# # ```ruby
|
16
|
+
# # rename_view "views.admin_users", to: "admins"
|
17
|
+
# # ```
|
18
|
+
# #
|
19
|
+
# # With the `if_exists: true` option, the operation won't fail
|
20
|
+
# # even when the view wasn't existed.
|
21
|
+
# #
|
22
|
+
# # ```ruby
|
23
|
+
# # rename_view "views.admin_users", to: "admins", if_exists: true
|
24
|
+
# # ```
|
25
|
+
# #
|
26
|
+
# # At the same time, the option makes a view irreversible
|
27
|
+
# # due to uncertainty of the previous state of the database.
|
28
|
+
# def rename_view(name, **options); end
|
29
|
+
# end
|
23
30
|
module PGTrunk::Operations::Views
|
24
31
|
# @private
|
25
32
|
class RenameView < Base
|
data/lib/pg_trunk/operations.rb
CHANGED
@@ -9,6 +9,7 @@ module PGTrunk
|
|
9
9
|
require_relative "operations/enums"
|
10
10
|
require_relative "operations/composite_types"
|
11
11
|
require_relative "operations/domains"
|
12
|
+
require_relative "operations/sequences"
|
12
13
|
require_relative "operations/tables"
|
13
14
|
require_relative "operations/views"
|
14
15
|
require_relative "operations/materialized_views"
|
@@ -18,6 +19,7 @@ module PGTrunk
|
|
18
19
|
require_relative "operations/foreign_keys"
|
19
20
|
require_relative "operations/procedures"
|
20
21
|
require_relative "operations/triggers"
|
22
|
+
require_relative "operations/rules"
|
21
23
|
require_relative "operations/statistics"
|
22
24
|
end
|
23
25
|
end
|
data/lib/pg_trunk/version.rb
CHANGED
data/pg_trunk.gemspec
CHANGED
@@ -23,7 +23,6 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.metadata["rubygems_mfa_required"] = "true"
|
24
24
|
|
25
25
|
spec.files = `git ls-files -z`.split("\x0")
|
26
|
-
spec.test_files = spec.files.grep(%r{^spec/})
|
27
26
|
spec.require_paths = ["lib"]
|
28
27
|
|
29
28
|
spec.add_dependency "activerecord", ">= 4.0.0"
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
describe ActiveRecord::Migration, "#create_rule" do
|
4
|
+
before_all do
|
5
|
+
run_migration <<~RUBY
|
6
|
+
create_table :users do |t|
|
7
|
+
t.string :name
|
8
|
+
end
|
9
|
+
|
10
|
+
create_table :user_updates do |t|
|
11
|
+
t.timestamps
|
12
|
+
end
|
13
|
+
RUBY
|
14
|
+
end
|
15
|
+
|
16
|
+
context "with a minimal definition" do
|
17
|
+
let(:migration) do
|
18
|
+
<<~RUBY
|
19
|
+
create_rule "users", "prevent_insertion" do |r|
|
20
|
+
r.event :insert
|
21
|
+
r.kind :instead
|
22
|
+
r.comment "Prevent insertion to users"
|
23
|
+
end
|
24
|
+
RUBY
|
25
|
+
end
|
26
|
+
|
27
|
+
its(:execution) { is_expected.to insert(migration).into_schema }
|
28
|
+
its(:inversion) { is_expected.not_to change_schema }
|
29
|
+
end
|
30
|
+
|
31
|
+
context "with a commands definition" do
|
32
|
+
let(:migration) do
|
33
|
+
<<~RUBY
|
34
|
+
create_rule "users", "count_updates" do |r|
|
35
|
+
r.event :update
|
36
|
+
r.command <<~Q.chomp
|
37
|
+
INSERT INTO user_updates (created_at) VALUES (now())
|
38
|
+
Q
|
39
|
+
r.comment "Count updates of users"
|
40
|
+
end
|
41
|
+
RUBY
|
42
|
+
end
|
43
|
+
|
44
|
+
its(:execution) { is_expected.to insert(migration).into_schema }
|
45
|
+
its(:inversion) { is_expected.not_to change_schema }
|
46
|
+
end
|
47
|
+
|
48
|
+
context "without an explicit name of the rule" do
|
49
|
+
let(:migration) do
|
50
|
+
<<~RUBY
|
51
|
+
create_rule "users" do |r|
|
52
|
+
r.event :update
|
53
|
+
r.command <<~Q.chomp
|
54
|
+
INSERT INTO user_updates (created_at) VALUES (now())
|
55
|
+
Q
|
56
|
+
r.comment "Count updates of users"
|
57
|
+
end
|
58
|
+
RUBY
|
59
|
+
end
|
60
|
+
|
61
|
+
its(:execution) { is_expected.to insert(migration).into_schema }
|
62
|
+
its(:inversion) { is_expected.not_to change_schema }
|
63
|
+
end
|
64
|
+
|
65
|
+
context "with the `replace_existing: true` option" do
|
66
|
+
let(:migration) do
|
67
|
+
<<~RUBY
|
68
|
+
create_rule "users", replace_existing: true do |r|
|
69
|
+
r.event :update
|
70
|
+
r.command <<~Q.chomp
|
71
|
+
INSERT INTO user_updates (created_at) VALUES (now());
|
72
|
+
Q
|
73
|
+
r.comment "Count updates of users"
|
74
|
+
end
|
75
|
+
RUBY
|
76
|
+
end
|
77
|
+
let(:snippet) do
|
78
|
+
<<~RUBY
|
79
|
+
create_rule "users" do |r|
|
80
|
+
r.event :update
|
81
|
+
r.command <<~Q.chomp
|
82
|
+
INSERT INTO user_updates (created_at) VALUES (now())
|
83
|
+
Q
|
84
|
+
r.comment "Count updates of users"
|
85
|
+
end
|
86
|
+
RUBY
|
87
|
+
end
|
88
|
+
|
89
|
+
its(:execution) { is_expected.to insert(snippet).into_schema }
|
90
|
+
it { is_expected.to be_irreversible.because_of(/replace_existing: true/i) }
|
91
|
+
end
|
92
|
+
|
93
|
+
context "without an event" do
|
94
|
+
let(:migration) do
|
95
|
+
<<~RUBY
|
96
|
+
create_rule "users" do |r|
|
97
|
+
r.kind :instead
|
98
|
+
r.comment "Prevent insertion to users"
|
99
|
+
end
|
100
|
+
RUBY
|
101
|
+
end
|
102
|
+
|
103
|
+
it { is_expected.to fail_validation.because(/event can't be blank/i) }
|
104
|
+
end
|
105
|
+
|
106
|
+
context "without a table" do
|
107
|
+
let(:migration) do
|
108
|
+
<<~RUBY
|
109
|
+
create_rule do |r|
|
110
|
+
r.event :insert
|
111
|
+
r.kind :instead
|
112
|
+
r.comment "Prevent insertion to users"
|
113
|
+
end
|
114
|
+
RUBY
|
115
|
+
end
|
116
|
+
|
117
|
+
it { is_expected.to fail_validation.because(/table can't be blank/i) }
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
describe ActiveRecord::Migration, "#drop_rule" do
|
4
|
+
before_all do
|
5
|
+
run_migration <<~RUBY
|
6
|
+
create_table :users do |t|
|
7
|
+
t.string :name
|
8
|
+
end
|
9
|
+
RUBY
|
10
|
+
end
|
11
|
+
before { run_migration(snippet) }
|
12
|
+
|
13
|
+
context "when a rule was named" do
|
14
|
+
let(:snippet) do
|
15
|
+
<<~RUBY
|
16
|
+
create_rule "users", "prevent_insertion" do |r|
|
17
|
+
r.event :insert
|
18
|
+
r.kind :instead
|
19
|
+
r.comment "Prevent insertion to users"
|
20
|
+
end
|
21
|
+
RUBY
|
22
|
+
end
|
23
|
+
|
24
|
+
context "with a full definition" do
|
25
|
+
let(:migration) do
|
26
|
+
<<~RUBY
|
27
|
+
drop_rule "users", "prevent_insertion" do |r|
|
28
|
+
r.event :insert
|
29
|
+
r.kind :instead
|
30
|
+
r.comment "Prevent insertion to users"
|
31
|
+
end
|
32
|
+
RUBY
|
33
|
+
end
|
34
|
+
|
35
|
+
its(:execution) { is_expected.to remove(snippet).from_schema }
|
36
|
+
its(:inversion) { is_expected.not_to change_schema }
|
37
|
+
end
|
38
|
+
|
39
|
+
context "with a name only" do
|
40
|
+
let(:migration) do
|
41
|
+
<<~RUBY
|
42
|
+
drop_rule "users", "prevent_insertion"
|
43
|
+
RUBY
|
44
|
+
end
|
45
|
+
|
46
|
+
its(:execution) { is_expected.to remove(snippet).from_schema }
|
47
|
+
it { is_expected.to be_irreversible.because(/event can't be blank/i) }
|
48
|
+
end
|
49
|
+
|
50
|
+
context "with if_exists: true option" do
|
51
|
+
let(:migration) do
|
52
|
+
<<~RUBY
|
53
|
+
drop_rule "users", "prevent_insertion", if_exists: true do |r|
|
54
|
+
r.event :insert
|
55
|
+
r.kind :instead
|
56
|
+
r.comment "Prevent insertion to users"
|
57
|
+
end
|
58
|
+
RUBY
|
59
|
+
end
|
60
|
+
|
61
|
+
its(:execution) { is_expected.to remove(snippet).from_schema }
|
62
|
+
it { is_expected.to be_irreversible.because_of(/if_exists: true/i) }
|
63
|
+
end
|
64
|
+
|
65
|
+
context "with force: :cascade option" do
|
66
|
+
let(:migration) do
|
67
|
+
<<~RUBY
|
68
|
+
drop_rule "users", "prevent_insertion", force: :cascade do |r|
|
69
|
+
r.event :insert
|
70
|
+
r.kind :instead
|
71
|
+
r.comment "Prevent insertion to users"
|
72
|
+
end
|
73
|
+
RUBY
|
74
|
+
end
|
75
|
+
|
76
|
+
its(:execution) { is_expected.to remove(snippet).from_schema }
|
77
|
+
it { is_expected.to be_irreversible.because_of(/force: :cascade/i) }
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context "when a rule was anonymous" do
|
82
|
+
let(:snippet) do
|
83
|
+
<<~RUBY
|
84
|
+
create_rule "users" do |r|
|
85
|
+
r.event :insert
|
86
|
+
r.kind :instead
|
87
|
+
r.comment "Prevent insertion to users"
|
88
|
+
end
|
89
|
+
RUBY
|
90
|
+
end
|
91
|
+
|
92
|
+
context "with a full definition" do
|
93
|
+
let(:migration) do
|
94
|
+
<<~RUBY
|
95
|
+
drop_rule "users" do |r|
|
96
|
+
r.event :insert
|
97
|
+
r.kind :instead
|
98
|
+
r.comment "Prevent insertion to users"
|
99
|
+
end
|
100
|
+
RUBY
|
101
|
+
end
|
102
|
+
|
103
|
+
its(:execution) { is_expected.to remove(snippet).from_schema }
|
104
|
+
its(:inversion) { is_expected.not_to change_schema }
|
105
|
+
end
|
106
|
+
|
107
|
+
context "with a table only" do
|
108
|
+
let(:migration) do
|
109
|
+
<<~RUBY
|
110
|
+
drop_rule "users"
|
111
|
+
RUBY
|
112
|
+
end
|
113
|
+
|
114
|
+
it { is_expected.to fail_validation.because(/name can't be blank/i) }
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|