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.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +4 -15
  3. data/CHANGELOG.md +21 -0
  4. data/README.md +3 -1
  5. data/lib/pg_trunk/core/operation/attributes.rb +1 -1
  6. data/lib/pg_trunk/core/railtie/custom_types.rb +5 -6
  7. data/lib/pg_trunk/operations/check_constraints/add_check_constraint.rb +42 -33
  8. data/lib/pg_trunk/operations/check_constraints/drop_check_constraint.rb +51 -40
  9. data/lib/pg_trunk/operations/check_constraints/rename_check_constraint.rb +39 -30
  10. data/lib/pg_trunk/operations/check_constraints/validate_check_constraint.rb +28 -21
  11. data/lib/pg_trunk/operations/composite_types/change_composite_type.rb +59 -50
  12. data/lib/pg_trunk/operations/composite_types/create_composite_type.rb +23 -19
  13. data/lib/pg_trunk/operations/composite_types/drop_composite_type.rb +48 -43
  14. data/lib/pg_trunk/operations/composite_types/rename_composite_type.rb +15 -12
  15. data/lib/pg_trunk/operations/domains/change_domain.rb +53 -47
  16. data/lib/pg_trunk/operations/domains/create_domain.rb +28 -25
  17. data/lib/pg_trunk/operations/domains/drop_domain.rb +50 -41
  18. data/lib/pg_trunk/operations/domains/rename_domain.rb +17 -12
  19. data/lib/pg_trunk/operations/enums/change_enum.rb +37 -32
  20. data/lib/pg_trunk/operations/enums/create_enum.rb +23 -20
  21. data/lib/pg_trunk/operations/enums/drop_enum.rb +50 -39
  22. data/lib/pg_trunk/operations/enums/rename_enum.rb +17 -12
  23. data/lib/pg_trunk/operations/foreign_keys/add_foreign_key.rb +58 -49
  24. data/lib/pg_trunk/operations/foreign_keys/drop_foreign_key.rb +57 -48
  25. data/lib/pg_trunk/operations/foreign_keys/rename_foreign_key.rb +38 -29
  26. data/lib/pg_trunk/operations/functions/change_function.rb +53 -47
  27. data/lib/pg_trunk/operations/functions/create_function.rb +75 -64
  28. data/lib/pg_trunk/operations/functions/drop_function.rb +78 -65
  29. data/lib/pg_trunk/operations/functions/rename_function.rb +29 -22
  30. data/lib/pg_trunk/operations/materialized_views/change_materialized_view.rb +65 -55
  31. data/lib/pg_trunk/operations/materialized_views/create_materialized_view.rb +82 -71
  32. data/lib/pg_trunk/operations/materialized_views/drop_materialized_view.rb +59 -46
  33. data/lib/pg_trunk/operations/materialized_views/refresh_materialized_view.rb +29 -24
  34. data/lib/pg_trunk/operations/materialized_views/rename_materialized_view.rb +29 -22
  35. data/lib/pg_trunk/operations/procedures/change_procedure.rb +53 -46
  36. data/lib/pg_trunk/operations/procedures/create_procedure.rb +63 -52
  37. data/lib/pg_trunk/operations/procedures/drop_procedure.rb +56 -45
  38. data/lib/pg_trunk/operations/procedures/rename_procedure.rb +29 -22
  39. data/lib/pg_trunk/operations/rules/base.rb +77 -0
  40. data/lib/pg_trunk/operations/rules/create_rule.rb +155 -0
  41. data/lib/pg_trunk/operations/rules/drop_rule.rb +94 -0
  42. data/lib/pg_trunk/operations/rules/rename_rule.rb +62 -0
  43. data/lib/pg_trunk/operations/rules.rb +13 -0
  44. data/lib/pg_trunk/operations/sequences/base.rb +79 -0
  45. data/lib/pg_trunk/operations/sequences/change_sequence.rb +142 -0
  46. data/lib/pg_trunk/operations/sequences/create_sequence.rb +180 -0
  47. data/lib/pg_trunk/operations/sequences/drop_sequence.rb +82 -0
  48. data/lib/pg_trunk/operations/sequences/rename_sequence.rb +64 -0
  49. data/lib/pg_trunk/operations/sequences.rb +14 -0
  50. data/lib/pg_trunk/operations/statistics/create_statistics.rb +67 -56
  51. data/lib/pg_trunk/operations/statistics/drop_statistics.rb +64 -53
  52. data/lib/pg_trunk/operations/statistics/rename_statistics.rb +18 -13
  53. data/lib/pg_trunk/operations/triggers/change_trigger.rb +23 -18
  54. data/lib/pg_trunk/operations/triggers/create_trigger.rb +63 -54
  55. data/lib/pg_trunk/operations/triggers/drop_trigger.rb +55 -46
  56. data/lib/pg_trunk/operations/triggers/rename_trigger.rb +51 -48
  57. data/lib/pg_trunk/operations/views/change_view.rb +47 -38
  58. data/lib/pg_trunk/operations/views/create_view.rb +56 -45
  59. data/lib/pg_trunk/operations/views/drop_view.rb +59 -46
  60. data/lib/pg_trunk/operations/views/rename_view.rb +27 -20
  61. data/lib/pg_trunk/operations.rb +2 -0
  62. data/lib/pg_trunk/version.rb +1 -1
  63. data/pg_trunk.gemspec +0 -1
  64. data/spec/operations/rules/create_rule_spec.rb +119 -0
  65. data/spec/operations/rules/drop_rule_spec.rb +117 -0
  66. data/spec/operations/rules/rename_rule_spec.rb +148 -0
  67. data/spec/operations/sequences/change_sequence_spec.rb +134 -0
  68. data/spec/operations/sequences/create_sequence_spec.rb +156 -0
  69. data/spec/operations/sequences/drop_sequence_spec.rb +102 -0
  70. data/spec/operations/sequences/rename_sequence_spec.rb +100 -0
  71. metadata +22 -68
@@ -1,44 +1,53 @@
1
1
  # frozen_string_literal: false
2
2
 
3
- # @!method ActiveRecord::Migration#change_view(name, **options, &block)
4
- # Modify a view
5
- #
6
- # @param [#to_s] name (nil) The qualified name of the view
7
- # @option [Boolean] :if_exists (false) Suppress the error when the view is absent
8
- # @yield [Proc] the block with the view's definition
9
- # @yieldparam The receiver of methods specifying the view
10
- #
11
- # The operation replaces the view with a new definition(s):
12
- #
13
- # change_view "admin_users" do |v|
14
- # v.sql_definition: <<~SQL, from: <<~SQL
15
- # SELECT id, name FROM users WHERE admin;
16
- # SQL
17
- # SELECT * FROM users WHERE admin;
18
- # SQL
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
- # @!method ActiveRecord::Migration#create_view(name, **options, &block)
4
- # Create a view
5
- #
6
- # @param [#to_s] name (nil) The qualified name of the view
7
- # @option [Boolean] :replace_existing (false) If the view should overwrite an existing one
8
- # @option [#to_s] :sql_definition (nil) The snippet containing the query
9
- # @option [#to_i] :version (nil)
10
- # The alternative way to set sql_definition by referencing to a file containing the snippet
11
- # @option [#to_s] :check (nil) Controls the behavior of automatically updatable views
12
- # Supported values: :local, :cascaded
13
- # @option [#to_s] :comment (nil) The comment describing the view
14
- # @yield [Proc] the block with the view's definition
15
- # @yieldparam The receiver of methods specifying the view
16
- #
17
- # The operation creates the view using its `sql_definition`:
18
- #
19
- # create_view("views.admin_users", sql_definition: <<~SQL)
20
- # SELECT id, name FROM users WHERE admin;
21
- # SQL
22
- #
23
- # For compatibility to the `scenic` gem, we also support
24
- # adding a definition via its version:
25
- #
26
- # create_view "admin_users", version: 1
27
- #
28
- # It is expected, that a `db/views/admin_users_v01.sql`
29
- # to contain the SQL snippet.
30
- #
31
- # You can also set a comment describing the view, and the check option
32
- # (either `:local` or `:cascaded`):
33
- #
34
- # create_view "admin_users" do |v|
35
- # v.sql_definition "SELECT id, name FROM users WHERE admin;"
36
- # v.check :local
37
- # v.comment "Admin users only"
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
- # @!method ActiveRecord::Migration#drop_view(name, **options, &block)
4
- # Drop a view
5
- #
6
- # @param [#to_s] name (nil) The qualified name of the view
7
- # @option [Boolean] :replace_existing (false) If the view should overwrite an existing one
8
- # @option [Boolean] :if_exists (false) Suppress the error when the view is absent
9
- # @option [Symbol] :force (:restrict) How to process dependent objects (`:cascade` or `:restrict`)
10
- # @option [#to_s] :sql_definition (nil) The snippet containing the query
11
- # @option [#to_i] :revert_to_version (nil)
12
- # The alternative way to set sql_definition by referencing to a file containing the snippet
13
- # @option [#to_s] :check (nil) Controls the behavior of automatically updatable views
14
- # Supported values: :local, :cascaded
15
- # @option [#to_s] :comment (nil) The comment describing the view
16
- # @yield [Proc] the block with the view's definition
17
- # @yieldparam The receiver of methods specifying the view
18
- #
19
- # The operation drops the existing view identified by its
20
- # qualified name (it can include a schema).
21
- #
22
- # drop_view "views.admin_users"
23
- #
24
- # To make the operation invertible, use the same options
25
- # as in the `create_view` operation.
26
- #
27
- # drop_view "views.admin_users" do |v|
28
- # v.sql_definition "SELECT name, email FROM users WHERE admin;"
29
- # v.check :local
30
- # v.comment "Admin users only"
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
- # @!method ActiveRecord::Migration#rename_view(name, **options)
4
- # Change the name and/or schema of a view
5
- #
6
- # @param [#to_s] :name (nil) The qualified name of the view
7
- # @option [#to_s] :to (nil) The new qualified name for the view
8
- # @option [Boolean] :if_exists (false) Suppress the error when the view is absent
9
- #
10
- # A view can be renamed by changing both the name
11
- # and the schema (namespace) it belongs to.
12
- #
13
- # rename_view "views.admin_users", to: "admins"
14
- #
15
- # With the `if_exists: true` option, the operation won't fail
16
- # even when the view wasn't existed.
17
- #
18
- # rename_view "views.admin_users", to: "admins", if_exists: true
19
- #
20
- # At the same time, the option makes a view irreversible
21
- # due to uncertainty of the previous state of the database.
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
@@ -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
@@ -2,5 +2,5 @@
2
2
 
3
3
  module PGTrunk
4
4
  # @private
5
- VERSION = "0.1.0"
5
+ VERSION = "0.2.0"
6
6
  end
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