fx 0.3.1 → 0.6.2
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 +5 -5
- data/.gitignore +1 -0
- data/.travis.yml +15 -8
- data/Appraisals +16 -10
- data/LICENSE +18 -0
- data/README.md +42 -13
- data/fx.gemspec +1 -1
- data/gemfiles/rails42.gemfile +2 -1
- data/gemfiles/rails50.gemfile +1 -1
- data/gemfiles/rails51.gemfile +8 -0
- data/gemfiles/rails52.gemfile +8 -0
- data/gemfiles/rails60.gemfile +8 -0
- data/gemfiles/rails_edge.gemfile +3 -3
- data/lib/fx.rb +22 -0
- data/lib/fx/adapters/postgres.rb +13 -1
- data/lib/fx/adapters/postgres/functions.rb +3 -0
- data/lib/fx/command_recorder.rb +0 -5
- data/lib/fx/configuration.rb +10 -0
- data/lib/fx/definition.rb +13 -3
- data/lib/fx/railtie.rb +15 -0
- data/lib/fx/schema_dumper.rb +0 -5
- data/lib/fx/schema_dumper/function.rb +14 -5
- data/lib/fx/statements.rb +0 -5
- data/lib/fx/version.rb +1 -1
- data/lib/generators/fx/function/USAGE +2 -0
- data/lib/generators/fx/function/function_generator.rb +15 -1
- data/lib/generators/fx/trigger/USAGE +2 -0
- data/lib/generators/fx/trigger/trigger_generator.rb +15 -1
- data/spec/acceptance/user_manages_functions_spec.rb +20 -0
- data/spec/fx/adapters/postgres/triggers_spec.rb +4 -3
- data/spec/fx/adapters/postgres_spec.rb +36 -14
- data/spec/fx/definition_spec.rb +23 -0
- data/spec/fx/schema_dumper/function_spec.rb +57 -1
- data/spec/generators/fx/function/function_generator_spec.rb +12 -0
- data/spec/generators/fx/trigger/trigger_generator_spec.rb +12 -0
- metadata +12 -16
- data/.ruby-version +0 -1
- data/gemfiles/rails40.gemfile +0 -8
- data/gemfiles/rails40.gemfile.lock +0 -111
- data/gemfiles/rails41.gemfile +0 -8
- data/gemfiles/rails41.gemfile.lock +0 -113
- data/gemfiles/rails42.gemfile.lock +0 -130
- data/gemfiles/rails50.gemfile.lock +0 -126
- data/gemfiles/rails_edge.gemfile.lock +0 -179
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 1e391283922484cf5a5b06c7de944c3162a85b7b49546f1fd1a017a6fc762898
|
4
|
+
data.tar.gz: 73b179c85ebc70977bf4d2afbe45088284a9730138c2a424d940d72fb2ab0a30
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 144fcbf71aad79383ee1ae98047b6fc018212ecd3ea2d747f883d7def2c649590b1d04fc77b0a84113fa832a6a0377857cf8482d2290c0c40f6496be0e6db470
|
7
|
+
data.tar.gz: 057f585e7e83a89aebfda256605813a7db9e7d01b5841f436be0a9f7323540fd5a49999e4bf3bbc6db33ab0342e4ad0727b1b9b16690ed3a1aea00ea3011ea2d
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
addons:
|
2
|
-
postgresql: "
|
2
|
+
postgresql: "10"
|
3
|
+
apt:
|
4
|
+
packages:
|
5
|
+
- postgresql-10
|
6
|
+
- postgresql-client-10
|
3
7
|
before_install:
|
4
8
|
- "echo '--colour' > ~/.rspec"
|
5
9
|
- "echo 'gem: --no-document' > ~/.gemrc"
|
@@ -15,18 +19,21 @@ language:
|
|
15
19
|
notifications:
|
16
20
|
email: false
|
17
21
|
rvm:
|
18
|
-
- 2.
|
19
|
-
- 2.
|
20
|
-
- 2.
|
22
|
+
- 2.6
|
23
|
+
- 2.5
|
24
|
+
- 2.4
|
21
25
|
gemfile:
|
22
|
-
- gemfiles/rails40.gemfile
|
23
|
-
- gemfiles/rails41.gemfile
|
24
26
|
- gemfiles/rails42.gemfile
|
25
27
|
- gemfiles/rails50.gemfile
|
28
|
+
- gemfiles/rails51.gemfile
|
29
|
+
- gemfiles/rails52.gemfile
|
30
|
+
- gemfiles/rails60.gemfile
|
26
31
|
- gemfiles/rails_edge.gemfile
|
27
32
|
matrix:
|
28
33
|
allow_failures:
|
29
34
|
- gemfile: gemfiles/rails_edge.gemfile
|
30
35
|
exclude:
|
31
|
-
- rvm: 2.
|
32
|
-
gemfile: gemfiles/
|
36
|
+
- rvm: 2.4
|
37
|
+
gemfile: gemfiles/rails_edge.gemfile
|
38
|
+
- rvm: 2.4
|
39
|
+
gemfile: gemfiles/rails60.gemfile
|
data/Appraisals
CHANGED
@@ -1,16 +1,7 @@
|
|
1
|
-
appraise "rails40" do
|
2
|
-
gem "activerecord", "~> 4.0.0"
|
3
|
-
gem "railties", "~> 4.0.0"
|
4
|
-
end
|
5
|
-
|
6
|
-
appraise "rails41" do
|
7
|
-
gem "activerecord", "~> 4.1.0"
|
8
|
-
gem "railties", "~> 4.1.0"
|
9
|
-
end
|
10
|
-
|
11
1
|
appraise "rails42" do
|
12
2
|
gem "activerecord", "~> 4.2.0"
|
13
3
|
gem "railties", "~> 4.2.0"
|
4
|
+
gem "pg", "~> 0.15"
|
14
5
|
end
|
15
6
|
|
16
7
|
if RUBY_VERSION > "2.2.0"
|
@@ -19,6 +10,21 @@ if RUBY_VERSION > "2.2.0"
|
|
19
10
|
gem "railties", "~> 5.0"
|
20
11
|
end
|
21
12
|
|
13
|
+
appraise "rails51" do
|
14
|
+
gem "activerecord", "~> 5.1"
|
15
|
+
gem "railties", "~> 5.1"
|
16
|
+
end
|
17
|
+
|
18
|
+
appraise "rails52" do
|
19
|
+
gem "activerecord", "~> 5.2"
|
20
|
+
gem "railties", "~> 5.2"
|
21
|
+
end
|
22
|
+
|
23
|
+
appraise "rails60" do
|
24
|
+
gem "activerecord", "~> 6.0"
|
25
|
+
gem "railties", "~> 6.0"
|
26
|
+
end
|
27
|
+
|
22
28
|
appraise "rails-edge" do
|
23
29
|
gem "rails", github: "rails/rails"
|
24
30
|
gem "arel", :github => "rails/arel"
|
data/LICENSE
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
Copyright 2016 Teo Ljungberg
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
4
|
+
this software and associated documentation files (the "Software"), to deal in
|
5
|
+
the Software without restriction, including without limitation the rights to
|
6
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
7
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
8
|
+
subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
11
|
+
copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
15
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
16
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
17
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
18
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
CHANGED
@@ -21,18 +21,29 @@ F(x) ships with support for PostgreSQL. The adapter is configurable (see
|
|
21
21
|
|
22
22
|
## Great, how do I create a trigger and a function?
|
23
23
|
|
24
|
-
You've got this great idea for a
|
24
|
+
You've got this great idea for a function you'd like to call
|
25
25
|
`uppercase_users_name`. You can create the migration and the corresponding
|
26
26
|
definition file with the following command:
|
27
27
|
|
28
28
|
```sh
|
29
|
-
% rails generate fx:
|
29
|
+
% rails generate fx:function uppercase_users_name
|
30
|
+
create db/functions/uppercase_users_name_v01.sql
|
31
|
+
create db/migrate/[TIMESTAMP]_create_function_uppercase_users_name.rb
|
32
|
+
```
|
33
|
+
|
34
|
+
Edit the `db/functions/uppercase_users_name_v01.sql` file with the SQL statement
|
35
|
+
that defines your function.
|
36
|
+
|
37
|
+
Next, let's add a trigger called `uppercase_users_name` to call our new
|
38
|
+
function each time we `INSERT` on the `users` table.
|
39
|
+
|
40
|
+
```sh
|
41
|
+
% rails generate fx:trigger uppercase_users_name table_name:users
|
30
42
|
create db/triggers/uppercase_users_name_v01.sql
|
31
43
|
create db/migrate/[TIMESTAMP]_create_trigger_uppercase_users_name.rb
|
32
44
|
```
|
33
45
|
|
34
|
-
|
35
|
-
that defines your trigger. In our example, this might look something like this:
|
46
|
+
In our example, this might look something like this:
|
36
47
|
|
37
48
|
```sql
|
38
49
|
CREATE TRIGGER uppercase_users_name
|
@@ -41,15 +52,6 @@ CREATE TRIGGER uppercase_users_name
|
|
41
52
|
EXECUTE PROCEDURE uppercase_users_name();
|
42
53
|
```
|
43
54
|
|
44
|
-
As you see, we execute a function called `uppercase_users_name` before each
|
45
|
-
`INSERT` on the `users` table, which is a function we don't have yet.
|
46
|
-
|
47
|
-
```sh
|
48
|
-
% rails generate fx:function uppercase_users_name
|
49
|
-
create db/functions/uppercase_users_name_v01.sql
|
50
|
-
create db/migrate/[TIMESTAMP]_create_function_uppercase_users_name.rb
|
51
|
-
```
|
52
|
-
|
53
55
|
The generated migrations contains `create_function` and `create_trigger`
|
54
56
|
statements. The migration is reversible and the schema will be dumped into your
|
55
57
|
`schema.rb` file.
|
@@ -82,3 +84,30 @@ def change
|
|
82
84
|
drop_function :uppercase_users_name, revert_to_version: 2
|
83
85
|
end
|
84
86
|
```
|
87
|
+
|
88
|
+
## What if I need to use a function as the default value of a column?
|
89
|
+
|
90
|
+
You need to set F(x) to dump the functions in the beginning of db/schema.rb in a
|
91
|
+
initializer:
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
# config/initializers/fx.rb
|
95
|
+
Fx.configure do |config|
|
96
|
+
config.dump_functions_at_beginning_of_schema = true
|
97
|
+
end
|
98
|
+
```
|
99
|
+
|
100
|
+
And then you can use a lambda in your migration file:
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
create_table :my_table do |t|
|
104
|
+
t.string :my_column, default: -> { "my_function()" }
|
105
|
+
end
|
106
|
+
```
|
107
|
+
|
108
|
+
That's how you tell Rails to use the default as a literal SQL for the default
|
109
|
+
column value instead of a plain string.
|
110
|
+
|
111
|
+
## Contributing
|
112
|
+
|
113
|
+
See [contributing](CONTRIBUTING.md) for more details.
|
data/fx.gemspec
CHANGED
data/gemfiles/rails42.gemfile
CHANGED
data/gemfiles/rails50.gemfile
CHANGED
data/gemfiles/rails_edge.gemfile
CHANGED
data/lib/fx.rb
CHANGED
@@ -7,10 +7,32 @@ require "fx/function"
|
|
7
7
|
require "fx/statements"
|
8
8
|
require "fx/schema_dumper"
|
9
9
|
require "fx/trigger"
|
10
|
+
require "fx/railtie"
|
10
11
|
|
11
12
|
# F(x) adds methods `ActiveRecord::Migration` to create and manage database
|
12
13
|
# triggers and functions in Rails applications.
|
13
14
|
module Fx
|
15
|
+
# Hooks Fx into Rails.
|
16
|
+
#
|
17
|
+
# Enables fx migration methods, migration reversability, and `schema.rb`
|
18
|
+
# dumping.
|
19
|
+
def self.load
|
20
|
+
ActiveRecord::Migration::CommandRecorder.send(
|
21
|
+
:include,
|
22
|
+
Fx::CommandRecorder,
|
23
|
+
)
|
24
|
+
|
25
|
+
ActiveRecord::SchemaDumper.send(
|
26
|
+
:prepend,
|
27
|
+
Fx::SchemaDumper,
|
28
|
+
)
|
29
|
+
|
30
|
+
ActiveRecord::ConnectionAdapters::AbstractAdapter.send(
|
31
|
+
:include,
|
32
|
+
Fx::Statements,
|
33
|
+
)
|
34
|
+
end
|
35
|
+
|
14
36
|
# The current database adapter used by F(x).
|
15
37
|
#
|
16
38
|
# This defaults to {Fx::Adapters::Postgres} but can be overridden
|
data/lib/fx/adapters/postgres.rb
CHANGED
@@ -125,7 +125,11 @@ module Fx
|
|
125
125
|
#
|
126
126
|
# @return [void]
|
127
127
|
def drop_function(name)
|
128
|
-
|
128
|
+
if support_drop_function_without_args
|
129
|
+
execute "DROP FUNCTION #{name};"
|
130
|
+
else
|
131
|
+
execute "DROP FUNCTION #{name}();"
|
132
|
+
end
|
129
133
|
end
|
130
134
|
|
131
135
|
# Drops the trigger from the database
|
@@ -150,6 +154,14 @@ module Fx
|
|
150
154
|
def connection
|
151
155
|
Connection.new(connectable.connection)
|
152
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
|
153
165
|
end
|
154
166
|
end
|
155
167
|
end
|
@@ -17,7 +17,10 @@ module Fx
|
|
17
17
|
ON pn.oid = pp.pronamespace
|
18
18
|
LEFT JOIN pg_depend pd
|
19
19
|
ON pd.objid = pp.oid AND pd.deptype = 'e'
|
20
|
+
LEFT JOIN pg_aggregate pa
|
21
|
+
ON pa.aggfnoid = pp.oid
|
20
22
|
WHERE pn.nspname = 'public' AND pd.objid IS NULL
|
23
|
+
AND pa.aggfnoid IS NULL
|
21
24
|
ORDER BY pp.oid;
|
22
25
|
EOS
|
23
26
|
|
data/lib/fx/command_recorder.rb
CHANGED
data/lib/fx/configuration.rb
CHANGED
@@ -17,6 +17,7 @@ module Fx
|
|
17
17
|
# ```
|
18
18
|
# Fx.configure do |config|
|
19
19
|
# config.database = Fx::Adapters::Postgres
|
20
|
+
# config.dump_functions_at_beginning_of_schema = true
|
20
21
|
# end
|
21
22
|
# ```
|
22
23
|
def self.configure
|
@@ -31,8 +32,17 @@ module Fx
|
|
31
32
|
# @return Fx adapter
|
32
33
|
attr_accessor :database
|
33
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
|
+
|
34
43
|
def initialize
|
35
44
|
@database = Fx::Adapters::Postgres.new
|
45
|
+
@dump_functions_at_beginning_of_schema = false
|
36
46
|
end
|
37
47
|
end
|
38
48
|
end
|
data/lib/fx/definition.rb
CHANGED
@@ -8,7 +8,7 @@ module Fx
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def to_sql
|
11
|
-
File.read(full_path).tap do |content|
|
11
|
+
File.read(find_file || full_path).tap do |content|
|
12
12
|
if content.empty?
|
13
13
|
raise "Define #{@type} in #{path} before migrating."
|
14
14
|
end
|
@@ -20,7 +20,7 @@ module Fx
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def path
|
23
|
-
File.join("db", @type.pluralize, filename)
|
23
|
+
@_path ||= File.join("db", @type.pluralize, filename)
|
24
24
|
end
|
25
25
|
|
26
26
|
def version
|
@@ -30,7 +30,17 @@ module Fx
|
|
30
30
|
private
|
31
31
|
|
32
32
|
def filename
|
33
|
-
"#{@name}_v#{version}.sql"
|
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
|
+
Rails.application.config.paths["db/migrate"].expanded
|
34
44
|
end
|
35
45
|
end
|
36
46
|
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
|
data/lib/fx/schema_dumper.rb
CHANGED
@@ -5,15 +5,24 @@ module Fx
|
|
5
5
|
# @api private
|
6
6
|
module Function
|
7
7
|
def tables(stream)
|
8
|
+
if Fx.configuration.dump_functions_at_beginning_of_schema
|
9
|
+
functions(stream)
|
10
|
+
empty_line(stream)
|
11
|
+
end
|
12
|
+
|
8
13
|
super
|
9
|
-
functions(stream)
|
10
|
-
end
|
11
14
|
|
12
|
-
|
13
|
-
|
14
|
-
stream
|
15
|
+
unless Fx.configuration.dump_functions_at_beginning_of_schema
|
16
|
+
functions(stream)
|
17
|
+
empty_line(stream)
|
15
18
|
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def empty_line(stream)
|
22
|
+
stream.puts if dumpable_functions_in_database.any?
|
23
|
+
end
|
16
24
|
|
25
|
+
def functions(stream)
|
17
26
|
dumpable_functions_in_database.each do |function|
|
18
27
|
stream.puts(function.to_schema)
|
19
28
|
end
|