fx 0.7.0 → 0.9.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/.github/workflows/ci.yml +53 -0
- data/.gitignore +0 -1
- data/.rspec +1 -1
- data/.standard.yml +3 -0
- data/CHANGELOG.md +124 -0
- data/CONTRIBUTING.md +13 -4
- data/Gemfile +13 -2
- data/README.md +4 -2
- data/Rakefile +2 -1
- data/bin/setup +0 -4
- data/bin/standardrb +27 -0
- data/fx.gemspec +20 -27
- data/lib/fx/adapters/postgres/connection.rb +12 -0
- data/lib/fx/adapters/postgres/functions.rb +3 -3
- data/lib/fx/adapters/postgres/triggers.rb +3 -3
- data/lib/fx/adapters/postgres.rb +6 -14
- data/lib/fx/command_recorder.rb +87 -6
- data/lib/fx/configuration.rb +0 -25
- data/lib/fx/definition.rb +16 -6
- data/lib/fx/function.rb +7 -7
- data/lib/fx/schema_dumper.rb +45 -5
- data/lib/fx/statements.rb +228 -6
- data/lib/fx/trigger.rb +3 -3
- data/lib/fx/version.rb +1 -1
- data/lib/fx.rb +30 -12
- data/lib/generators/fx/function/function_generator.rb +8 -8
- data/lib/generators/fx/trigger/trigger_generator.rb +6 -10
- data/spec/acceptance/user_manages_functions_spec.rb +5 -5
- data/spec/acceptance/user_manages_triggers_spec.rb +8 -8
- data/spec/acceptance_helper.rb +6 -4
- data/spec/dummy/Rakefile +4 -4
- data/spec/dummy/bin/bundle +2 -2
- data/spec/dummy/bin/rails +3 -3
- data/spec/dummy/bin/rake +2 -2
- data/spec/dummy/config/application.rb +6 -0
- data/spec/dummy/config/database.yml +2 -0
- data/spec/dummy/config.ru +1 -1
- data/spec/features/functions/migrations_spec.rb +4 -4
- data/spec/features/functions/revert_spec.rb +7 -7
- data/spec/features/triggers/migrations_spec.rb +6 -6
- data/spec/features/triggers/revert_spec.rb +13 -13
- data/spec/fx/adapters/postgres/functions_spec.rb +26 -30
- data/spec/fx/adapters/postgres/triggers_spec.rb +34 -38
- data/spec/fx/adapters/postgres_spec.rb +107 -109
- data/spec/fx/command_recorder_spec.rb +41 -39
- data/spec/fx/configuration_spec.rb +20 -9
- data/spec/fx/definition_spec.rb +30 -38
- data/spec/fx/function_spec.rb +45 -48
- data/spec/fx/schema_dumper_spec.rb +123 -0
- data/spec/fx/statements_spec.rb +217 -0
- data/spec/fx/trigger_spec.rb +37 -40
- data/spec/fx_spec.rb +28 -0
- data/spec/generators/fx/function/function_generator_spec.rb +6 -6
- data/spec/generators/fx/trigger/trigger_generator_spec.rb +10 -10
- data/spec/spec_helper.rb +5 -0
- data/spec/support/definition_helpers.rb +5 -9
- data/spec/support/generator_setup.rb +1 -1
- data/spec/support/migration_helpers.rb +1 -1
- data/spec/support/warning_helper.rb +5 -0
- metadata +24 -213
- data/.hound.yml +0 -2
- data/.rubocop.yml +0 -648
- data/.travis.yml +0 -60
- data/Appraisals +0 -45
- data/bin/appraisal +0 -17
- data/gemfiles/rails42.gemfile +0 -10
- data/gemfiles/rails50.gemfile +0 -8
- data/gemfiles/rails51.gemfile +0 -8
- data/gemfiles/rails52.gemfile +0 -8
- data/gemfiles/rails60.gemfile +0 -8
- data/gemfiles/rails61.gemfile +0 -8
- data/gemfiles/rails_edge.gemfile +0 -8
- data/lib/fx/command_recorder/arguments.rb +0 -43
- data/lib/fx/command_recorder/function.rb +0 -30
- data/lib/fx/command_recorder/trigger.rb +0 -30
- data/lib/fx/schema_dumper/function.rb +0 -38
- data/lib/fx/schema_dumper/trigger.rb +0 -29
- data/lib/fx/statements/function.rb +0 -115
- data/lib/fx/statements/trigger.rb +0 -146
- data/spec/fx/command_recorder/arguments_spec.rb +0 -41
- data/spec/fx/schema_dumper/function_spec.rb +0 -80
- data/spec/fx/schema_dumper/trigger_spec.rb +0 -40
- data/spec/fx/statements/function_spec.rb +0 -103
- data/spec/fx/statements/trigger_spec.rb +0 -132
data/lib/fx/function.rb
CHANGED
@@ -6,9 +6,9 @@ module Fx
|
|
6
6
|
attr_reader :name, :definition
|
7
7
|
delegate :<=>, to: :name
|
8
8
|
|
9
|
-
def initialize(
|
10
|
-
@name =
|
11
|
-
@definition =
|
9
|
+
def initialize(row)
|
10
|
+
@name = row.fetch("name")
|
11
|
+
@definition = row.fetch("definition")
|
12
12
|
end
|
13
13
|
|
14
14
|
def ==(other)
|
@@ -16,10 +16,10 @@ module Fx
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def to_schema
|
19
|
-
|
20
|
-
create_function :#{name}, sql_definition: <<-'SQL'
|
21
|
-
#{definition.indent(4).rstrip}
|
22
|
-
SQL
|
19
|
+
<<~SCHEMA.indent(2)
|
20
|
+
create_function :#{name}, sql_definition: <<-'SQL'
|
21
|
+
#{definition.indent(4).rstrip}
|
22
|
+
SQL
|
23
23
|
SCHEMA
|
24
24
|
end
|
25
25
|
end
|
data/lib/fx/schema_dumper.rb
CHANGED
@@ -1,10 +1,50 @@
|
|
1
|
-
require "fx/schema_dumper/function"
|
2
|
-
require "fx/schema_dumper/trigger"
|
3
|
-
|
4
1
|
module Fx
|
5
2
|
# @api private
|
6
3
|
module SchemaDumper
|
7
|
-
|
8
|
-
|
4
|
+
def tables(stream)
|
5
|
+
if Fx.configuration.dump_functions_at_beginning_of_schema
|
6
|
+
functions(stream)
|
7
|
+
empty_line(stream)
|
8
|
+
end
|
9
|
+
|
10
|
+
super
|
11
|
+
|
12
|
+
unless Fx.configuration.dump_functions_at_beginning_of_schema
|
13
|
+
functions(stream)
|
14
|
+
empty_line(stream)
|
15
|
+
end
|
16
|
+
|
17
|
+
triggers(stream)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def empty_line(stream)
|
23
|
+
stream.puts if dumpable_functions_in_database.any?
|
24
|
+
end
|
25
|
+
|
26
|
+
def functions(stream)
|
27
|
+
dumpable_functions_in_database.each do |function|
|
28
|
+
stream.puts(function.to_schema)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def triggers(stream)
|
33
|
+
if dumpable_triggers_in_database.any?
|
34
|
+
stream.puts
|
35
|
+
end
|
36
|
+
|
37
|
+
dumpable_triggers_in_database.each do |trigger|
|
38
|
+
stream.puts(trigger.to_schema)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def dumpable_functions_in_database
|
43
|
+
@_dumpable_functions_in_database ||= Fx.database.functions
|
44
|
+
end
|
45
|
+
|
46
|
+
def dumpable_triggers_in_database
|
47
|
+
@_dumpable_triggers_in_database ||= Fx.database.triggers
|
48
|
+
end
|
9
49
|
end
|
10
50
|
end
|
data/lib/fx/statements.rb
CHANGED
@@ -1,11 +1,233 @@
|
|
1
|
-
require "rails"
|
2
|
-
require "fx/statements/function"
|
3
|
-
require "fx/statements/trigger"
|
4
|
-
|
5
1
|
module Fx
|
6
2
|
# @api private
|
7
3
|
module Statements
|
8
|
-
|
9
|
-
|
4
|
+
# Create a new database function.
|
5
|
+
#
|
6
|
+
# @param name [String, Symbol] The name of the database function.
|
7
|
+
# @param version [Fixnum] The version number of the function, used to
|
8
|
+
# find the definition file in `db/functions`. This defaults to `1` if
|
9
|
+
# not provided.
|
10
|
+
# @param sql_definition [String] The SQL query for the function schema.
|
11
|
+
# If both `sql_definition` and `version` are provided,
|
12
|
+
# `sql_definition` takes prescedence.
|
13
|
+
# @return The database response from executing the create statement.
|
14
|
+
#
|
15
|
+
# @example Create from `db/functions/uppercase_users_name_v02.sql`
|
16
|
+
# create_function(:uppercase_users_name, version: 2)
|
17
|
+
#
|
18
|
+
# @example Create from provided SQL string
|
19
|
+
# create_function(:uppercase_users_name, sql_definition: <<~SQL)
|
20
|
+
# CREATE OR REPLACE FUNCTION uppercase_users_name()
|
21
|
+
# RETURNS trigger AS $$
|
22
|
+
# BEGIN
|
23
|
+
# NEW.upper_name = UPPER(NEW.name);
|
24
|
+
# RETURN NEW;
|
25
|
+
# END;
|
26
|
+
# $$ LANGUAGE plpgsql;
|
27
|
+
# SQL
|
28
|
+
#
|
29
|
+
def create_function(name, options = {})
|
30
|
+
version = options.fetch(:version, 1)
|
31
|
+
sql_definition = options[:sql_definition]
|
32
|
+
|
33
|
+
if version.nil? && sql_definition.nil?
|
34
|
+
raise(
|
35
|
+
ArgumentError,
|
36
|
+
"version or sql_definition must be specified"
|
37
|
+
)
|
38
|
+
end
|
39
|
+
sql_definition = sql_definition.strip_heredoc if sql_definition
|
40
|
+
sql_definition ||= Fx::Definition.function(name: name, version: version).to_sql
|
41
|
+
|
42
|
+
Fx.database.create_function(sql_definition)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Drop a database function by name.
|
46
|
+
#
|
47
|
+
# @param name [String, Symbol] The name of the database function.
|
48
|
+
# @param revert_to_version [Fixnum] Used to reverse the `drop_function`
|
49
|
+
# command on `rake db:rollback`. The provided version will be passed as
|
50
|
+
# the `version` argument to {#create_function}.
|
51
|
+
# @return The database response from executing the drop statement.
|
52
|
+
#
|
53
|
+
# @example Drop a function, rolling back to version 2 on rollback
|
54
|
+
# drop_function(:uppercase_users_name, revert_to_version: 2)
|
55
|
+
#
|
56
|
+
def drop_function(name, options = {})
|
57
|
+
Fx.database.drop_function(name)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Update a database function.
|
61
|
+
#
|
62
|
+
# @param name [String, Symbol] The name of the database function.
|
63
|
+
# @param version [Fixnum] The version number of the function, used to
|
64
|
+
# find the definition file in `db/functions`. This defaults to `1` if
|
65
|
+
# not provided.
|
66
|
+
# @param sql_definition [String] The SQL query for the function schema.
|
67
|
+
# If both `sql_definition` and `version` are provided,
|
68
|
+
# `sql_definition` takes prescedence.
|
69
|
+
# @return The database response from executing the create statement.
|
70
|
+
#
|
71
|
+
# @example Update function to a given version
|
72
|
+
# update_function(
|
73
|
+
# :uppercase_users_name,
|
74
|
+
# version: 3,
|
75
|
+
# revert_to_version: 2,
|
76
|
+
# )
|
77
|
+
#
|
78
|
+
# @example Update function from provided SQL string
|
79
|
+
# update_function(:uppercase_users_name, sql_definition: <<~SQL)
|
80
|
+
# CREATE OR REPLACE FUNCTION uppercase_users_name()
|
81
|
+
# RETURNS trigger AS $$
|
82
|
+
# BEGIN
|
83
|
+
# NEW.upper_name = UPPER(NEW.name);
|
84
|
+
# RETURN NEW;
|
85
|
+
# END;
|
86
|
+
# $$ LANGUAGE plpgsql;
|
87
|
+
# SQL
|
88
|
+
#
|
89
|
+
def update_function(name, options = {})
|
90
|
+
version = options[:version]
|
91
|
+
sql_definition = options[:sql_definition]
|
92
|
+
|
93
|
+
if version.nil? && sql_definition.nil?
|
94
|
+
raise(
|
95
|
+
ArgumentError,
|
96
|
+
"version or sql_definition must be specified"
|
97
|
+
)
|
98
|
+
end
|
99
|
+
|
100
|
+
sql_definition = sql_definition.strip_heredoc if sql_definition
|
101
|
+
sql_definition ||= Fx::Definition.function(name: name, version: version).to_sql
|
102
|
+
|
103
|
+
Fx.database.update_function(name, sql_definition)
|
104
|
+
end
|
105
|
+
|
106
|
+
# Create a new database trigger.
|
107
|
+
#
|
108
|
+
# @param name [String, Symbol] The name of the database trigger.
|
109
|
+
# @param version [Fixnum] The version number of the trigger, used to
|
110
|
+
# find the definition file in `db/triggers`. This defaults to `1` if
|
111
|
+
# not provided.
|
112
|
+
# @param sql_definition [String] The SQL query for the function. An error
|
113
|
+
# will be raised if `sql_definition` and `version` are both set,
|
114
|
+
# as they are mutually exclusive.
|
115
|
+
# @return The database response from executing the create statement.
|
116
|
+
#
|
117
|
+
# @example Create trigger from `db/triggers/uppercase_users_name_v01.sql`
|
118
|
+
# create_trigger(:uppercase_users_name, version: 1)
|
119
|
+
#
|
120
|
+
# @example Create trigger from provided SQL string
|
121
|
+
# create_trigger(:uppercase_users_name, sql_definition: <<~SQL)
|
122
|
+
# CREATE TRIGGER uppercase_users_name
|
123
|
+
# BEFORE INSERT ON users
|
124
|
+
# FOR EACH ROW
|
125
|
+
# EXECUTE FUNCTION uppercase_users_name();
|
126
|
+
# SQL
|
127
|
+
#
|
128
|
+
def create_trigger(name, options = {})
|
129
|
+
version = options[:version]
|
130
|
+
_on = options[:on]
|
131
|
+
sql_definition = options[:sql_definition]
|
132
|
+
|
133
|
+
if version.present? && sql_definition.present?
|
134
|
+
raise(
|
135
|
+
ArgumentError,
|
136
|
+
"sql_definition and version cannot both be set"
|
137
|
+
)
|
138
|
+
end
|
139
|
+
|
140
|
+
if version.nil?
|
141
|
+
version = 1
|
142
|
+
end
|
143
|
+
|
144
|
+
sql_definition = sql_definition.strip_heredoc if sql_definition
|
145
|
+
sql_definition ||= Fx::Definition.trigger(name: name, version: version).to_sql
|
146
|
+
|
147
|
+
Fx.database.create_trigger(sql_definition)
|
148
|
+
end
|
149
|
+
|
150
|
+
# Drop a database trigger by name.
|
151
|
+
#
|
152
|
+
# @param name [String, Symbol] The name of the database trigger.
|
153
|
+
# @param on [String, Symbol] The name of the table the database trigger
|
154
|
+
# is associated with.
|
155
|
+
# @param revert_to_version [Fixnum] Used to reverse the `drop_trigger`
|
156
|
+
# command on `rake db:rollback`. The provided version will be passed as
|
157
|
+
# the `version` argument to {#create_trigger}.
|
158
|
+
# @return The database response from executing the drop statement.
|
159
|
+
#
|
160
|
+
# @example Drop a trigger, rolling back to version 3 on rollback
|
161
|
+
# drop_trigger(:log_inserts, on: :users, revert_to_version: 3)
|
162
|
+
#
|
163
|
+
def drop_trigger(name, options = {})
|
164
|
+
on = options.fetch(:on)
|
165
|
+
Fx.database.drop_trigger(name, on: on)
|
166
|
+
end
|
167
|
+
|
168
|
+
# Update a database trigger to a new version.
|
169
|
+
#
|
170
|
+
# The existing trigger is dropped and recreated using the supplied `on`
|
171
|
+
# and `version` parameter.
|
172
|
+
#
|
173
|
+
# @param name [String, Symbol] The name of the database trigger.
|
174
|
+
# @param version [Fixnum] The version number of the trigger.
|
175
|
+
# @param on [String, Symbol] The name of the table the database trigger
|
176
|
+
# is associated with.
|
177
|
+
# @param sql_definition [String] The SQL query for the function. An error
|
178
|
+
# will be raised if `sql_definition` and `version` are both set,
|
179
|
+
# as they are mutually exclusive.
|
180
|
+
# @param revert_to_version [Fixnum] The version number to rollback to on
|
181
|
+
# `rake db rollback`
|
182
|
+
# @return The database response from executing the create statement.
|
183
|
+
#
|
184
|
+
# @example Update trigger to a given version
|
185
|
+
# update_trigger(
|
186
|
+
# :log_inserts,
|
187
|
+
# on: :users,
|
188
|
+
# version: 3,
|
189
|
+
# revert_to_version: 2,
|
190
|
+
# )
|
191
|
+
#
|
192
|
+
# @example Update trigger from provided SQL string
|
193
|
+
# update_trigger(:uppercase_users_name, sql_definition: <<~SQL)
|
194
|
+
# CREATE TRIGGER uppercase_users_name
|
195
|
+
# BEFORE INSERT ON users
|
196
|
+
# FOR EACH ROW
|
197
|
+
# EXECUTE FUNCTION uppercase_users_name();
|
198
|
+
# SQL
|
199
|
+
#
|
200
|
+
def update_trigger(name, options = {})
|
201
|
+
version = options[:version]
|
202
|
+
on = options[:on]
|
203
|
+
sql_definition = options[:sql_definition]
|
204
|
+
|
205
|
+
if version.nil? && sql_definition.nil?
|
206
|
+
raise(
|
207
|
+
ArgumentError,
|
208
|
+
"version or sql_definition must be specified"
|
209
|
+
)
|
210
|
+
end
|
211
|
+
|
212
|
+
if version.present? && sql_definition.present?
|
213
|
+
raise(
|
214
|
+
ArgumentError,
|
215
|
+
"sql_definition and version cannot both be set"
|
216
|
+
)
|
217
|
+
end
|
218
|
+
|
219
|
+
if on.nil?
|
220
|
+
raise ArgumentError, "on is required"
|
221
|
+
end
|
222
|
+
|
223
|
+
sql_definition = sql_definition.strip_heredoc if sql_definition
|
224
|
+
sql_definition ||= Fx::Definition.trigger(name: name, version: version).to_sql
|
225
|
+
|
226
|
+
Fx.database.update_trigger(
|
227
|
+
name,
|
228
|
+
on: on,
|
229
|
+
sql_definition: sql_definition
|
230
|
+
)
|
231
|
+
end
|
10
232
|
end
|
11
233
|
end
|
data/lib/fx/trigger.rb
CHANGED
@@ -6,9 +6,9 @@ module Fx
|
|
6
6
|
attr_reader :name, :definition
|
7
7
|
delegate :<=>, to: :name
|
8
8
|
|
9
|
-
def initialize(
|
10
|
-
@name =
|
11
|
-
@definition =
|
9
|
+
def initialize(row)
|
10
|
+
@name = row.fetch("name")
|
11
|
+
@definition = row.fetch("definition")
|
12
12
|
end
|
13
13
|
|
14
14
|
def ==(other)
|
data/lib/fx/version.rb
CHANGED
data/lib/fx.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require "rails"
|
2
|
+
|
1
3
|
require "fx/version"
|
2
4
|
require "fx/adapters/postgres"
|
3
5
|
require "fx/command_recorder"
|
@@ -17,20 +19,36 @@ module Fx
|
|
17
19
|
# Enables fx migration methods, migration reversability, and `schema.rb`
|
18
20
|
# dumping.
|
19
21
|
def self.load
|
20
|
-
ActiveRecord::Migration::CommandRecorder.
|
21
|
-
|
22
|
-
|
23
|
-
|
22
|
+
ActiveRecord::Migration::CommandRecorder.include(Fx::CommandRecorder)
|
23
|
+
ActiveRecord::ConnectionAdapters::AbstractAdapter.include(Fx::Statements)
|
24
|
+
ActiveRecord::SchemaDumper.prepend(Fx::SchemaDumper)
|
25
|
+
|
26
|
+
true
|
27
|
+
end
|
28
|
+
|
29
|
+
# @return [Fx::Configuration] F(x)'s current configuration
|
30
|
+
def self.configuration
|
31
|
+
@_configuration ||= Configuration.new
|
32
|
+
end
|
24
33
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
34
|
+
# Set F(x)'s configuration
|
35
|
+
#
|
36
|
+
# @param config [Fx::Configuration]
|
37
|
+
def self.configuration=(config)
|
38
|
+
@_configuration = config
|
39
|
+
end
|
29
40
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
41
|
+
# Modify F(x)'s current configuration
|
42
|
+
#
|
43
|
+
# @yieldparam [Fx::Configuration] config current F(x) config
|
44
|
+
# ```
|
45
|
+
# Fx.configure do |config|
|
46
|
+
# config.database = Fx::Adapters::Postgres
|
47
|
+
# config.dump_functions_at_beginning_of_schema = true
|
48
|
+
# end
|
49
|
+
# ```
|
50
|
+
def self.configure
|
51
|
+
yield configuration
|
34
52
|
end
|
35
53
|
|
36
54
|
# The current database adapter used by F(x).
|
@@ -29,12 +29,12 @@ module Fx
|
|
29
29
|
if updating_existing_function?
|
30
30
|
migration_template(
|
31
31
|
"db/migrate/update_function.erb",
|
32
|
-
"db/migrate/update_function_#{file_name}_to_version_#{version}.rb"
|
32
|
+
"db/migrate/update_function_#{file_name}_to_version_#{version}.rb"
|
33
33
|
)
|
34
34
|
else
|
35
35
|
migration_template(
|
36
36
|
"db/migrate/create_function.erb",
|
37
|
-
"db/migrate/create_function_#{file_name}.rb"
|
37
|
+
"db/migrate/create_function_#{file_name}.rb"
|
38
38
|
)
|
39
39
|
end
|
40
40
|
end
|
@@ -45,9 +45,9 @@ module Fx
|
|
45
45
|
|
46
46
|
no_tasks do
|
47
47
|
def previous_version
|
48
|
-
@_previous_version ||= Dir.entries(function_definition_path)
|
49
|
-
map { |name| version_regex.match(name).try(:[], "version").to_i }
|
50
|
-
max
|
48
|
+
@_previous_version ||= Dir.entries(function_definition_path)
|
49
|
+
.map { |name| version_regex.match(name).try(:[], "version").to_i }
|
50
|
+
.max
|
51
51
|
end
|
52
52
|
|
53
53
|
def version
|
@@ -82,7 +82,7 @@ module Fx
|
|
82
82
|
private
|
83
83
|
|
84
84
|
def function_definition_path
|
85
|
-
@_function_definition_path ||= Rails.root.join(*%w
|
85
|
+
@_function_definition_path ||= Rails.root.join(*%w[db functions])
|
86
86
|
end
|
87
87
|
|
88
88
|
def version_regex
|
@@ -98,11 +98,11 @@ module Fx
|
|
98
98
|
end
|
99
99
|
|
100
100
|
def definition
|
101
|
-
Fx::Definition.
|
101
|
+
Fx::Definition.function(name: file_name, version: version)
|
102
102
|
end
|
103
103
|
|
104
104
|
def previous_definition
|
105
|
-
Fx::Definition.
|
105
|
+
Fx::Definition.function(name: file_name, version: previous_version)
|
106
106
|
end
|
107
107
|
|
108
108
|
# Skip creating migration file if:
|
@@ -42,9 +42,9 @@ module Fx
|
|
42
42
|
|
43
43
|
no_tasks do
|
44
44
|
def previous_version
|
45
|
-
@_previous_version ||= Dir.entries(trigger_definition_path)
|
46
|
-
map { |name| version_regex.match(name).try(:[], "version").to_i }
|
47
|
-
max
|
45
|
+
@_previous_version ||= Dir.entries(trigger_definition_path)
|
46
|
+
.map { |name| version_regex.match(name).try(:[], "version").to_i }
|
47
|
+
.max
|
48
48
|
end
|
49
49
|
|
50
50
|
def version
|
@@ -81,7 +81,7 @@ module Fx
|
|
81
81
|
if name.nil?
|
82
82
|
raise(
|
83
83
|
ArgumentError,
|
84
|
-
"Either `table_name:NAME` or `on:NAME` must be specified"
|
84
|
+
"Either `table_name:NAME` or `on:NAME` must be specified"
|
85
85
|
)
|
86
86
|
end
|
87
87
|
|
@@ -104,15 +104,11 @@ module Fx
|
|
104
104
|
end
|
105
105
|
|
106
106
|
def definition
|
107
|
-
Fx::Definition.
|
108
|
-
name: file_name,
|
109
|
-
version: version,
|
110
|
-
type: "trigger",
|
111
|
-
)
|
107
|
+
Fx::Definition.trigger(name: file_name, version: version)
|
112
108
|
end
|
113
109
|
|
114
110
|
def trigger_definition_path
|
115
|
-
@_trigger_definition_path ||= Rails.root.join(
|
111
|
+
@_trigger_definition_path ||= Rails.root.join("db", "triggers")
|
116
112
|
end
|
117
113
|
|
118
114
|
# Skip creating migration file if:
|
@@ -1,9 +1,9 @@
|
|
1
1
|
require "acceptance_helper"
|
2
2
|
|
3
|
-
describe "User manages functions" do
|
3
|
+
RSpec.describe "User manages functions" do
|
4
4
|
it "handles simple functions" do
|
5
5
|
successfully "rails generate fx:function test"
|
6
|
-
write_function_definition "test_v01",
|
6
|
+
write_function_definition "test_v01", <<~EOS
|
7
7
|
CREATE OR REPLACE FUNCTION test()
|
8
8
|
RETURNS text AS $$
|
9
9
|
BEGIN
|
@@ -19,9 +19,9 @@ describe "User manages functions" do
|
|
19
19
|
successfully "rails generate fx:function test"
|
20
20
|
verify_identical_definitions(
|
21
21
|
"db/functions/test_v01.sql",
|
22
|
-
"db/functions/test_v02.sql"
|
22
|
+
"db/functions/test_v02.sql"
|
23
23
|
)
|
24
|
-
write_function_definition "test_v02",
|
24
|
+
write_function_definition "test_v02", <<~EOS
|
25
25
|
CREATE OR REPLACE FUNCTION test()
|
26
26
|
RETURNS text AS $$
|
27
27
|
BEGIN
|
@@ -37,7 +37,7 @@ describe "User manages functions" do
|
|
37
37
|
|
38
38
|
it "handles functions with arguments" do
|
39
39
|
successfully "rails generate fx:function adder"
|
40
|
-
write_function_definition "adder_v01",
|
40
|
+
write_function_definition "adder_v01", <<~EOS
|
41
41
|
CREATE FUNCTION adder(x int, y int)
|
42
42
|
RETURNS int AS $$
|
43
43
|
BEGIN
|
@@ -1,10 +1,10 @@
|
|
1
1
|
require "acceptance_helper"
|
2
2
|
|
3
|
-
describe "User manages triggers" do
|
3
|
+
RSpec.describe "User manages triggers" do
|
4
4
|
it "handles simple triggers" do
|
5
5
|
successfully "rails generate model user name:string upper_name:string"
|
6
6
|
successfully "rails generate fx:function uppercase_users_name"
|
7
|
-
write_function_definition "uppercase_users_name_v01",
|
7
|
+
write_function_definition "uppercase_users_name_v01", <<~EOS
|
8
8
|
CREATE OR REPLACE FUNCTION uppercase_users_name()
|
9
9
|
RETURNS trigger AS $$
|
10
10
|
BEGIN
|
@@ -14,15 +14,15 @@ describe "User manages triggers" do
|
|
14
14
|
$$ LANGUAGE plpgsql;
|
15
15
|
EOS
|
16
16
|
successfully "rails generate fx:trigger uppercase_users_name table_name:users"
|
17
|
-
write_trigger_definition "uppercase_users_name_v01",
|
17
|
+
write_trigger_definition "uppercase_users_name_v01", <<~EOS
|
18
18
|
CREATE TRIGGER uppercase_users_name
|
19
19
|
BEFORE INSERT ON users
|
20
20
|
FOR EACH ROW
|
21
|
-
EXECUTE
|
21
|
+
EXECUTE FUNCTION uppercase_users_name();
|
22
22
|
EOS
|
23
23
|
successfully "rake db:migrate"
|
24
24
|
|
25
|
-
execute
|
25
|
+
execute <<~EOS
|
26
26
|
INSERT INTO users
|
27
27
|
(name, created_at, updated_at)
|
28
28
|
VALUES
|
@@ -32,14 +32,14 @@ describe "User manages triggers" do
|
|
32
32
|
expect(result).to eq("upper_name" => "BOB")
|
33
33
|
|
34
34
|
successfully "rails generate fx:trigger uppercase_users_name table_name:users"
|
35
|
-
write_trigger_definition "uppercase_users_name_v02",
|
35
|
+
write_trigger_definition "uppercase_users_name_v02", <<~EOS
|
36
36
|
CREATE TRIGGER uppercase_users_name
|
37
37
|
BEFORE UPDATE ON users
|
38
38
|
FOR EACH ROW
|
39
|
-
EXECUTE
|
39
|
+
EXECUTE FUNCTION uppercase_users_name();
|
40
40
|
EOS
|
41
41
|
successfully "rake db:migrate"
|
42
|
-
execute
|
42
|
+
execute <<~EOS
|
43
43
|
UPDATE users
|
44
44
|
SET name = 'Alice'
|
45
45
|
WHERE id = 1;
|
data/spec/acceptance_helper.rb
CHANGED
@@ -11,8 +11,10 @@ RSpec.configure do |config|
|
|
11
11
|
|
12
12
|
config.before(:suite) do
|
13
13
|
Dir.chdir("spec/dummy") do
|
14
|
-
system
|
15
|
-
git init 1>/dev/null &&
|
14
|
+
system <<~CMD
|
15
|
+
git init -b master 1>/dev/null &&
|
16
|
+
git config user.email "fx@example.com"
|
17
|
+
git config user.name "Fx"
|
16
18
|
git add -A &&
|
17
19
|
git commit --no-gpg-sign --message 'initial' 1>/dev/null
|
18
20
|
CMD
|
@@ -22,9 +24,9 @@ RSpec.configure do |config|
|
|
22
24
|
config.after(:suite) do
|
23
25
|
Dir.chdir("spec/dummy") do
|
24
26
|
ActiveRecord::Base.connection.disconnect!
|
25
|
-
system
|
27
|
+
system <<~CMD
|
26
28
|
echo &&
|
27
|
-
rake db:environment:set db:drop db:create &&
|
29
|
+
rake db:environment:set db:drop db:create 1>/dev/null &&
|
28
30
|
git add -A &&
|
29
31
|
git reset --hard HEAD 1>/dev/null &&
|
30
32
|
rm -rf .git/ 1>/dev/null
|
data/spec/dummy/Rakefile
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
# Add your own tasks in files placed in lib/tasks ending in .rake,
|
2
2
|
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
3
3
|
|
4
|
-
require File.expand_path(
|
4
|
+
require File.expand_path("../config/application", __FILE__)
|
5
5
|
|
6
6
|
Rails.application.load_tasks
|
7
7
|
|
8
|
-
unless Rake::Task.task_defined?(
|
9
|
-
desc
|
10
|
-
task
|
8
|
+
unless Rake::Task.task_defined?("db:environment:set")
|
9
|
+
desc "dummy task for rails versions where this task does not exist"
|
10
|
+
task "db:environment:set" do
|
11
11
|
# no-op
|
12
12
|
end
|
13
13
|
end
|
data/spec/dummy/bin/bundle
CHANGED
@@ -1,3 +1,3 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
ENV[
|
3
|
-
load Gem.bin_path(
|
2
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__)
|
3
|
+
load Gem.bin_path("bundler", "bundle")
|
data/spec/dummy/bin/rails
CHANGED
@@ -1,4 +1,4 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
APP_PATH = File.expand_path(
|
3
|
-
require_relative
|
4
|
-
require
|
2
|
+
APP_PATH = File.expand_path("../../config/application", __FILE__)
|
3
|
+
require_relative "../config/boot"
|
4
|
+
require "rails/commands"
|
data/spec/dummy/bin/rake
CHANGED
@@ -11,5 +11,11 @@ module Dummy
|
|
11
11
|
config.cache_classes = true
|
12
12
|
config.eager_load = false
|
13
13
|
config.active_support.deprecation = :stderr
|
14
|
+
|
15
|
+
config.load_defaults 7.0
|
16
|
+
|
17
|
+
if Rails.version >= "8.0"
|
18
|
+
config.active_support.to_time_preserves_timezone = :zone
|
19
|
+
end
|
14
20
|
end
|
15
21
|
end
|
data/spec/dummy/config.ru
CHANGED