fx-jets 0.6.3s
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 +7 -0
- data/.gitignore +10 -0
- data/.hound.yml +2 -0
- data/.rspec +2 -0
- data/.rubocop.yml +648 -0
- data/.travis.yml +60 -0
- data/.yardopts +4 -0
- data/Appraisals +45 -0
- data/CONTRIBUTING.md +15 -0
- data/Gemfile +4 -0
- data/LICENSE +18 -0
- data/README.md +1 -0
- data/Rakefile +23 -0
- data/bin/appraisal +17 -0
- data/bin/console +14 -0
- data/bin/rake +17 -0
- data/bin/rspec +17 -0
- data/bin/setup +13 -0
- data/bin/yard +17 -0
- data/fx.gemspec +39 -0
- data/gemfiles/rails42.gemfile +10 -0
- data/gemfiles/rails50.gemfile +8 -0
- data/gemfiles/rails51.gemfile +8 -0
- data/gemfiles/rails52.gemfile +8 -0
- data/gemfiles/rails60.gemfile +8 -0
- data/gemfiles/rails61.gemfile +8 -0
- data/gemfiles/rails_edge.gemfile +8 -0
- data/lib/fx/adapters/postgres/connection.rb +16 -0
- data/lib/fx/adapters/postgres/functions.rb +59 -0
- data/lib/fx/adapters/postgres/triggers.rb +57 -0
- data/lib/fx/adapters/postgres.rb +167 -0
- data/lib/fx/command_recorder/arguments.rb +43 -0
- data/lib/fx/command_recorder/function.rb +30 -0
- data/lib/fx/command_recorder/trigger.rb +30 -0
- data/lib/fx/command_recorder.rb +24 -0
- data/lib/fx/configuration.rb +48 -0
- data/lib/fx/definition.rb +46 -0
- data/lib/fx/function.rb +26 -0
- data/lib/fx/railtie.rb +15 -0
- data/lib/fx/schema_dumper/function.rb +38 -0
- data/lib/fx/schema_dumper/trigger.rb +29 -0
- data/lib/fx/schema_dumper.rb +10 -0
- data/lib/fx/statements/function.rb +115 -0
- data/lib/fx/statements/trigger.rb +146 -0
- data/lib/fx/statements.rb +11 -0
- data/lib/fx/trigger.rb +26 -0
- data/lib/fx/version.rb +4 -0
- data/lib/fx.rb +43 -0
- data/lib/generators/fx/function/USAGE +11 -0
- data/lib/generators/fx/function/function_generator.rb +120 -0
- data/lib/generators/fx/function/templates/db/migrate/create_function.erb +5 -0
- data/lib/generators/fx/function/templates/db/migrate/update_function.erb +5 -0
- data/lib/generators/fx/trigger/USAGE +20 -0
- data/lib/generators/fx/trigger/templates/db/migrate/create_trigger.erb +5 -0
- data/lib/generators/fx/trigger/templates/db/migrate/update_trigger.erb +5 -0
- data/lib/generators/fx/trigger/trigger_generator.rb +130 -0
- data/lib/generators.rb +11 -0
- data/spec/acceptance/user_manages_functions_spec.rb +57 -0
- data/spec/acceptance/user_manages_triggers_spec.rb +51 -0
- data/spec/acceptance_helper.rb +62 -0
- data/spec/dummy/.gitignore +16 -0
- data/spec/dummy/Rakefile +13 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config/application.rb +15 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +9 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/db/migrate/.keep +0 -0
- data/spec/features/functions/migrations_spec.rb +65 -0
- data/spec/features/functions/revert_spec.rb +75 -0
- data/spec/features/triggers/migrations_spec.rb +56 -0
- data/spec/features/triggers/revert_spec.rb +95 -0
- data/spec/fx/adapters/postgres/functions_spec.rb +37 -0
- data/spec/fx/adapters/postgres/triggers_spec.rb +45 -0
- data/spec/fx/adapters/postgres_spec.rb +146 -0
- data/spec/fx/command_recorder/arguments_spec.rb +41 -0
- data/spec/fx/command_recorder_spec.rb +171 -0
- data/spec/fx/configuration_spec.rb +21 -0
- data/spec/fx/definition_spec.rb +134 -0
- data/spec/fx/function_spec.rb +68 -0
- data/spec/fx/schema_dumper/function_spec.rb +80 -0
- data/spec/fx/schema_dumper/trigger_spec.rb +40 -0
- data/spec/fx/statements/function_spec.rb +103 -0
- data/spec/fx/statements/trigger_spec.rb +132 -0
- data/spec/fx/trigger_spec.rb +55 -0
- data/spec/generators/fx/function/function_generator_spec.rb +46 -0
- data/spec/generators/fx/trigger/trigger_generator_spec.rb +59 -0
- data/spec/spec_helper.rb +21 -0
- data/spec/support/definition_helpers.rb +37 -0
- data/spec/support/generator_setup.rb +11 -0
- data/spec/support/migration_helpers.rb +25 -0
- metadata +357 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
require "fx/adapters/postgres/connection"
|
|
2
|
+
require "fx/adapters/postgres/functions"
|
|
3
|
+
require "fx/adapters/postgres/triggers"
|
|
4
|
+
|
|
5
|
+
module Fx
|
|
6
|
+
# F(x) database adapters.
|
|
7
|
+
#
|
|
8
|
+
# F(x) ships with a Postgres adapter only but can be extended with
|
|
9
|
+
# additional adapters. The {Fx::Adapters::Postgres} adapter provides the
|
|
10
|
+
# interface.
|
|
11
|
+
module Adapters
|
|
12
|
+
# Creates an instance of the F(x) Postgres adapter.
|
|
13
|
+
#
|
|
14
|
+
# This is the default adapter for F(x). Configuring it via
|
|
15
|
+
# {Fx.configure} is not required, but the example below shows how one
|
|
16
|
+
# would explicitly set it.
|
|
17
|
+
#
|
|
18
|
+
# @param [#connection] connectable An object that returns the connection
|
|
19
|
+
# for F(x) to use. Defaults to `ActiveRecord::Base`.
|
|
20
|
+
#
|
|
21
|
+
# @example
|
|
22
|
+
# Fx.configure do |config|
|
|
23
|
+
# config.adapter = Fx::Adapters::Postgres.new
|
|
24
|
+
# end
|
|
25
|
+
class Postgres
|
|
26
|
+
# Creates an instance of the F(x) Postgres adapter.
|
|
27
|
+
#
|
|
28
|
+
# This is the default adapter for F(x). Configuring it via
|
|
29
|
+
# {Fx.configure} is not required, but the example below shows how one
|
|
30
|
+
# would explicitly set it.
|
|
31
|
+
#
|
|
32
|
+
# @param [#connection] connectable An object that returns the connection
|
|
33
|
+
# for F(x) to use. Defaults to `ActiveRecord::Base`.
|
|
34
|
+
#
|
|
35
|
+
# @example
|
|
36
|
+
# Fx.configure do |config|
|
|
37
|
+
# config.adapter = Fx::Adapters::Postgres.new
|
|
38
|
+
# end
|
|
39
|
+
def initialize(connectable = ActiveRecord::Base)
|
|
40
|
+
@connectable = connectable
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Returns an array of functions in the database.
|
|
44
|
+
#
|
|
45
|
+
# This collection of functions is used by the [Fx::SchemaDumper] to
|
|
46
|
+
# populate the `schema.rb` file.
|
|
47
|
+
#
|
|
48
|
+
# @return [Array<Fx::Function>]
|
|
49
|
+
def functions
|
|
50
|
+
Functions.all(connection)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Returns an array of triggers in the database.
|
|
54
|
+
#
|
|
55
|
+
# This collection of triggers is used by the [Fx::SchemaDumper] to
|
|
56
|
+
# populate the `schema.rb` file.
|
|
57
|
+
#
|
|
58
|
+
# @return [Array<Fx::Trigger>]
|
|
59
|
+
def triggers
|
|
60
|
+
Triggers.all(connection)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Creates a function in the database.
|
|
64
|
+
#
|
|
65
|
+
# This is typically called in a migration via
|
|
66
|
+
# {Fx::Statements::Function#create_function}.
|
|
67
|
+
#
|
|
68
|
+
# @param sql_definition The SQL schema for the function.
|
|
69
|
+
#
|
|
70
|
+
# @return [void]
|
|
71
|
+
def create_function(sql_definition)
|
|
72
|
+
execute sql_definition
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Creates a trigger in the database.
|
|
76
|
+
#
|
|
77
|
+
# This is typically called in a migration via
|
|
78
|
+
# {Fx::Statements::Trigger#create_trigger}.
|
|
79
|
+
#
|
|
80
|
+
# @param sql_definition The SQL schema for the trigger.
|
|
81
|
+
#
|
|
82
|
+
# @return [void]
|
|
83
|
+
def create_trigger(sql_definition)
|
|
84
|
+
execute sql_definition
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Updates a function in the database.
|
|
88
|
+
#
|
|
89
|
+
# This is typically called in a migration via
|
|
90
|
+
# {Fx::Statements::Function#update_function}.
|
|
91
|
+
#
|
|
92
|
+
# @param name The name of the function.
|
|
93
|
+
# @param sql_definition The SQL schema for the function.
|
|
94
|
+
#
|
|
95
|
+
# @return [void]
|
|
96
|
+
def update_function(name, sql_definition)
|
|
97
|
+
drop_function(name)
|
|
98
|
+
create_function(sql_definition)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Updates a trigger in the database.
|
|
102
|
+
#
|
|
103
|
+
# The existing trigger is dropped and recreated using the supplied `on`
|
|
104
|
+
# and `version` parameter.
|
|
105
|
+
#
|
|
106
|
+
# This is typically called in a migration via
|
|
107
|
+
# {Fx::Statements::Function#update_trigger}.
|
|
108
|
+
#
|
|
109
|
+
# @param name The name of the trigger.
|
|
110
|
+
# @param on The associated table for the trigger to drop
|
|
111
|
+
# @param sql_definition The SQL schema for the function.
|
|
112
|
+
#
|
|
113
|
+
# @return [void]
|
|
114
|
+
def update_trigger(name, on:, sql_definition:)
|
|
115
|
+
drop_trigger(name, on: on)
|
|
116
|
+
create_trigger(sql_definition)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Drops the function from the database
|
|
120
|
+
#
|
|
121
|
+
# This is typically called in a migration via
|
|
122
|
+
# {Fx::Statements::Function#drop_function}.
|
|
123
|
+
#
|
|
124
|
+
# @param name The name of the function to drop
|
|
125
|
+
#
|
|
126
|
+
# @return [void]
|
|
127
|
+
def drop_function(name)
|
|
128
|
+
if support_drop_function_without_args
|
|
129
|
+
execute "DROP FUNCTION #{name};"
|
|
130
|
+
else
|
|
131
|
+
execute "DROP FUNCTION #{name}();"
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Drops the trigger from the database
|
|
136
|
+
#
|
|
137
|
+
# This is typically called in a migration via
|
|
138
|
+
# {Fx::Statements::Trigger#drop_trigger}.
|
|
139
|
+
#
|
|
140
|
+
# @param name The name of the trigger to drop
|
|
141
|
+
# @param on The associated table for the trigger to drop
|
|
142
|
+
#
|
|
143
|
+
# @return [void]
|
|
144
|
+
def drop_trigger(name, on:)
|
|
145
|
+
execute "DROP TRIGGER #{name} ON #{on};"
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
private
|
|
149
|
+
|
|
150
|
+
attr_reader :connectable
|
|
151
|
+
|
|
152
|
+
delegate :execute, to: :connection
|
|
153
|
+
|
|
154
|
+
def connection
|
|
155
|
+
Connection.new(connectable.connection)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def support_drop_function_without_args
|
|
159
|
+
# https://www.postgresql.org/docs/9.6/sql-dropfunction.html
|
|
160
|
+
# https://www.postgresql.org/docs/10/sql-dropfunction.html
|
|
161
|
+
|
|
162
|
+
pg_connection = connectable.connection.raw_connection
|
|
163
|
+
pg_connection.server_version >= 10_00_00
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module Fx
|
|
2
|
+
module CommandRecorder
|
|
3
|
+
# @api private
|
|
4
|
+
class Arguments
|
|
5
|
+
def initialize(args)
|
|
6
|
+
@args = args.freeze
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def function
|
|
10
|
+
@args[0]
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def version
|
|
14
|
+
options[:version]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def revert_to_version
|
|
18
|
+
options[:revert_to_version]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def invert_version
|
|
22
|
+
Arguments.new([function, options_for_revert])
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def to_a
|
|
26
|
+
@args.to_a
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def options
|
|
32
|
+
@options ||= @args[1] || {}
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def options_for_revert
|
|
36
|
+
options.clone.tap do |revert_options|
|
|
37
|
+
revert_options[:version] = revert_to_version
|
|
38
|
+
revert_options.delete(:revert_to_version)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Fx
|
|
2
|
+
module CommandRecorder
|
|
3
|
+
# @api private
|
|
4
|
+
module Function
|
|
5
|
+
def create_function(*args)
|
|
6
|
+
record(:create_function, args)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def drop_function(*args)
|
|
10
|
+
record(:drop_function, args)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def update_function(*args)
|
|
14
|
+
record(:update_function, args)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def invert_create_function(args)
|
|
18
|
+
[:drop_function, args]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def invert_drop_function(args)
|
|
22
|
+
perform_inversion(:create_function, args)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def invert_update_function(args)
|
|
26
|
+
perform_inversion(:update_function, args)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Fx
|
|
2
|
+
module CommandRecorder
|
|
3
|
+
# @api private
|
|
4
|
+
module Trigger
|
|
5
|
+
def create_trigger(*args)
|
|
6
|
+
record(:create_trigger, args)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def drop_trigger(*args)
|
|
10
|
+
record(:drop_trigger, args)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def update_trigger(*args)
|
|
14
|
+
record(:update_trigger, args)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def invert_create_trigger(args)
|
|
18
|
+
[:drop_trigger, args]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def invert_drop_trigger(args)
|
|
22
|
+
perform_inversion(:create_trigger, args)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def invert_update_trigger(args)
|
|
26
|
+
perform_inversion(:update_trigger, args)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require "fx/command_recorder/arguments"
|
|
2
|
+
require "fx/command_recorder/function"
|
|
3
|
+
require "fx/command_recorder/trigger"
|
|
4
|
+
|
|
5
|
+
module Fx
|
|
6
|
+
# @api private
|
|
7
|
+
module CommandRecorder
|
|
8
|
+
include Function
|
|
9
|
+
include Trigger
|
|
10
|
+
|
|
11
|
+
private
|
|
12
|
+
|
|
13
|
+
def perform_inversion(method, args)
|
|
14
|
+
arguments = Arguments.new(args)
|
|
15
|
+
|
|
16
|
+
if arguments.revert_to_version.nil?
|
|
17
|
+
message = "`#{method}` is reversible only if given a `revert_to_version`"
|
|
18
|
+
raise ActiveRecord::IrreversibleMigration, message
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
[method, arguments.invert_version.to_a]
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
module Fx
|
|
2
|
+
# @return [Fx::Configuration] F(x)'s current configuration
|
|
3
|
+
def self.configuration
|
|
4
|
+
@_configuration ||= Configuration.new
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
# Set F(x)'s configuration
|
|
8
|
+
#
|
|
9
|
+
# @param config [Fx::Configuration]
|
|
10
|
+
def self.configuration=(config)
|
|
11
|
+
@_configuration = config
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Modify F(x)'s current configuration
|
|
15
|
+
#
|
|
16
|
+
# @yieldparam [Fx::Configuration] config current F(x) config
|
|
17
|
+
# ```
|
|
18
|
+
# Fx.configure do |config|
|
|
19
|
+
# config.database = Fx::Adapters::Postgres
|
|
20
|
+
# config.dump_functions_at_beginning_of_schema = true
|
|
21
|
+
# end
|
|
22
|
+
# ```
|
|
23
|
+
def self.configure
|
|
24
|
+
yield configuration
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# F(x)'s configuration object.
|
|
28
|
+
class Configuration
|
|
29
|
+
# The F(x) database adapter instance to use when executing SQL.
|
|
30
|
+
#
|
|
31
|
+
# Defaults to an instance of {Fx::Adapters::Postgres}
|
|
32
|
+
# @return Fx adapter
|
|
33
|
+
attr_accessor :database
|
|
34
|
+
|
|
35
|
+
# Prioritizes the order in the schema.rb of functions before other
|
|
36
|
+
# statements in order to make directly schema load work when using functions
|
|
37
|
+
# in statements below, i.e.: default column values.
|
|
38
|
+
#
|
|
39
|
+
# Defaults to false
|
|
40
|
+
# @return Boolean
|
|
41
|
+
attr_accessor :dump_functions_at_beginning_of_schema
|
|
42
|
+
|
|
43
|
+
def initialize
|
|
44
|
+
@database = Fx::Adapters::Postgres.new
|
|
45
|
+
@dump_functions_at_beginning_of_schema = false
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
module Fx
|
|
2
|
+
# @api private
|
|
3
|
+
class Definition
|
|
4
|
+
def initialize(name:, version:, type: "function")
|
|
5
|
+
@name = name
|
|
6
|
+
@version = version.to_i
|
|
7
|
+
@type = type
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def to_sql
|
|
11
|
+
File.read(find_file || full_path).tap do |content|
|
|
12
|
+
if content.empty?
|
|
13
|
+
raise "Define #{@type} in #{path} before migrating."
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def full_path
|
|
19
|
+
Jets.root.join(path)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def path
|
|
23
|
+
@_path ||= File.join("db", @type.pluralize, filename)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def version
|
|
27
|
+
@version.to_s.rjust(2, "0")
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def filename
|
|
33
|
+
@_filename ||= "#{@name}_v#{version}.sql"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def find_file
|
|
37
|
+
migration_paths.lazy
|
|
38
|
+
.map { |migration_path| File.expand_path(File.join("..", "..", path), migration_path) }
|
|
39
|
+
.find { |definition_path| File.exist?(definition_path) }
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def migration_paths
|
|
43
|
+
[Jets.root.join('db', 'migrate').to_s]
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
data/lib/fx/function.rb
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Fx
|
|
2
|
+
# @api private
|
|
3
|
+
class Function
|
|
4
|
+
include Comparable
|
|
5
|
+
|
|
6
|
+
attr_reader :name, :definition
|
|
7
|
+
delegate :<=>, to: :name
|
|
8
|
+
|
|
9
|
+
def initialize(function_row)
|
|
10
|
+
@name = function_row.fetch("name")
|
|
11
|
+
@definition = function_row.fetch("definition")
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def ==(other)
|
|
15
|
+
name == other.name && definition == other.definition
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def to_schema
|
|
19
|
+
<<-SCHEMA.indent(2)
|
|
20
|
+
create_function :#{name}, sql_definition: <<-'SQL'
|
|
21
|
+
#{definition.indent(4).rstrip}
|
|
22
|
+
SQL
|
|
23
|
+
SCHEMA
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
data/lib/fx/railtie.rb
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require "rails/railtie"
|
|
2
|
+
|
|
3
|
+
module Fx
|
|
4
|
+
# Automatically initializes Fx in the context of a Rails application when
|
|
5
|
+
# ActiveRecord is loaded.
|
|
6
|
+
#
|
|
7
|
+
# @see Fx.load
|
|
8
|
+
class Railtie < Rails::Railtie
|
|
9
|
+
initializer "fx.load" do
|
|
10
|
+
ActiveSupport.on_load :active_record do
|
|
11
|
+
Fx.load
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
require "rails"
|
|
2
|
+
|
|
3
|
+
module Fx
|
|
4
|
+
module SchemaDumper
|
|
5
|
+
# @api private
|
|
6
|
+
module Function
|
|
7
|
+
def tables(stream)
|
|
8
|
+
if Fx.configuration.dump_functions_at_beginning_of_schema
|
|
9
|
+
functions(stream)
|
|
10
|
+
empty_line(stream)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
super
|
|
14
|
+
|
|
15
|
+
unless Fx.configuration.dump_functions_at_beginning_of_schema
|
|
16
|
+
functions(stream)
|
|
17
|
+
empty_line(stream)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def empty_line(stream)
|
|
22
|
+
stream.puts if dumpable_functions_in_database.any?
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def functions(stream)
|
|
26
|
+
dumpable_functions_in_database.each do |function|
|
|
27
|
+
stream.puts(function.to_schema)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def dumpable_functions_in_database
|
|
34
|
+
@_dumpable_functions_in_database ||= Fx.database.functions
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require "rails"
|
|
2
|
+
|
|
3
|
+
module Fx
|
|
4
|
+
module SchemaDumper
|
|
5
|
+
# @api private
|
|
6
|
+
module Trigger
|
|
7
|
+
def tables(stream)
|
|
8
|
+
super
|
|
9
|
+
triggers(stream)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def triggers(stream)
|
|
13
|
+
if dumpable_triggers_in_database.any?
|
|
14
|
+
stream.puts
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
dumpable_triggers_in_database.each do |trigger|
|
|
18
|
+
stream.puts(trigger.to_schema)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def dumpable_triggers_in_database
|
|
25
|
+
@_dumpable_triggers_in_database ||= Fx.database.triggers
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
require "rails"
|
|
2
|
+
|
|
3
|
+
module Fx
|
|
4
|
+
module Statements
|
|
5
|
+
# Methods that are made available in migrations for managing Fx functions.
|
|
6
|
+
module Function
|
|
7
|
+
# Create a new database function.
|
|
8
|
+
#
|
|
9
|
+
# @param name [String, Symbol] The name of the database function.
|
|
10
|
+
# @param version [Fixnum] The version number of the function, used to
|
|
11
|
+
# find the definition file in `db/functions`. This defaults to `1` if
|
|
12
|
+
# not provided.
|
|
13
|
+
# @param sql_definition [String] The SQL query for the function schema.
|
|
14
|
+
# If both `sql_defintion` and `version` are provided,
|
|
15
|
+
# `sql_definition` takes prescedence.
|
|
16
|
+
# @return The database response from executing the create statement.
|
|
17
|
+
#
|
|
18
|
+
# @example Create from `db/functions/uppercase_users_name_v02.sql`
|
|
19
|
+
# create_function(:uppercase_users_name, version: 2)
|
|
20
|
+
#
|
|
21
|
+
# @example Create from provided SQL string
|
|
22
|
+
# create_function(:uppercase_users_name, sql_definition: <<-SQL)
|
|
23
|
+
# CREATE OR REPLACE FUNCTION uppercase_users_name()
|
|
24
|
+
# RETURNS trigger AS $$
|
|
25
|
+
# BEGIN
|
|
26
|
+
# NEW.upper_name = UPPER(NEW.name);
|
|
27
|
+
# RETURN NEW;
|
|
28
|
+
# END;
|
|
29
|
+
# $$ LANGUAGE plpgsql;
|
|
30
|
+
# SQL
|
|
31
|
+
#
|
|
32
|
+
def create_function(name, options = {})
|
|
33
|
+
version = options.fetch(:version, 1)
|
|
34
|
+
sql_definition = options[:sql_definition]
|
|
35
|
+
|
|
36
|
+
if version.nil? && sql_definition.nil?
|
|
37
|
+
raise(
|
|
38
|
+
ArgumentError,
|
|
39
|
+
"version or sql_definition must be specified",
|
|
40
|
+
)
|
|
41
|
+
end
|
|
42
|
+
sql_definition = sql_definition.strip_heredoc if sql_definition
|
|
43
|
+
sql_definition ||= Fx::Definition.new(name: name, version: version).to_sql
|
|
44
|
+
|
|
45
|
+
Fx.database.create_function(sql_definition)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Drop a database function by name.
|
|
49
|
+
#
|
|
50
|
+
# @param name [String, Symbol] The name of the database function.
|
|
51
|
+
# @param revert_to_version [Fixnum] Used to reverse the `drop_function`
|
|
52
|
+
# command on `rake db:rollback`. The provided version will be passed as
|
|
53
|
+
# the `version` argument to {#create_function}.
|
|
54
|
+
# @return The database response from executing the drop statement.
|
|
55
|
+
#
|
|
56
|
+
# @example Drop a function, rolling back to version 2 on rollback
|
|
57
|
+
# drop_function(:uppercase_users_name, revert_to_version: 2)
|
|
58
|
+
#
|
|
59
|
+
def drop_function(name, options = {})
|
|
60
|
+
revert_to_version = options[:revert_to_version]
|
|
61
|
+
Fx.database.drop_function(name)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Update a database function.
|
|
65
|
+
#
|
|
66
|
+
# @param name [String, Symbol] The name of the database function.
|
|
67
|
+
# @param version [Fixnum] The version number of the function, used to
|
|
68
|
+
# find the definition file in `db/functions`. This defaults to `1` if
|
|
69
|
+
# not provided.
|
|
70
|
+
# @param sql_definition [String] The SQL query for the function schema.
|
|
71
|
+
# If both `sql_defintion` and `version` are provided,
|
|
72
|
+
# `sql_definition` takes prescedence.
|
|
73
|
+
# @return The database response from executing the create statement.
|
|
74
|
+
#
|
|
75
|
+
# @example Update function to a given version
|
|
76
|
+
# update_function(
|
|
77
|
+
# :uppercase_users_name,
|
|
78
|
+
# version: 3,
|
|
79
|
+
# revert_to_version: 2,
|
|
80
|
+
# )
|
|
81
|
+
#
|
|
82
|
+
# @example Update function from provided SQL string
|
|
83
|
+
# update_function(:uppercase_users_name, sql_definition: <<-SQL)
|
|
84
|
+
# CREATE OR REPLACE FUNCTION uppercase_users_name()
|
|
85
|
+
# RETURNS trigger AS $$
|
|
86
|
+
# BEGIN
|
|
87
|
+
# NEW.upper_name = UPPER(NEW.name);
|
|
88
|
+
# RETURN NEW;
|
|
89
|
+
# END;
|
|
90
|
+
# $$ LANGUAGE plpgsql;
|
|
91
|
+
# SQL
|
|
92
|
+
#
|
|
93
|
+
def update_function(name, options = {})
|
|
94
|
+
version = options[:version]
|
|
95
|
+
sql_definition = options[:sql_definition]
|
|
96
|
+
revert_to_version = options[:revert_to_version]
|
|
97
|
+
|
|
98
|
+
if version.nil? && sql_definition.nil?
|
|
99
|
+
raise(
|
|
100
|
+
ArgumentError,
|
|
101
|
+
"version or sql_definition must be specified",
|
|
102
|
+
)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
sql_definition = sql_definition.strip_heredoc if sql_definition
|
|
106
|
+
sql_definition ||= Fx::Definition.new(
|
|
107
|
+
name: name,
|
|
108
|
+
version: version,
|
|
109
|
+
).to_sql
|
|
110
|
+
|
|
111
|
+
Fx.database.update_function(name, sql_definition)
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|