fx 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.rspec +2 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +27 -0
  6. data/.yardopts +4 -0
  7. data/Appraisals +21 -0
  8. data/CONTRIBUTING.md +15 -0
  9. data/Gemfile +4 -0
  10. data/README.md +81 -0
  11. data/Rakefile +23 -0
  12. data/bin/appraisal +17 -0
  13. data/bin/console +14 -0
  14. data/bin/rake +17 -0
  15. data/bin/rspec +17 -0
  16. data/bin/setup +12 -0
  17. data/bin/yard +17 -0
  18. data/fx.gemspec +38 -0
  19. data/gemfiles/rails40.gemfile +8 -0
  20. data/gemfiles/rails40.gemfile.lock +111 -0
  21. data/gemfiles/rails41.gemfile +8 -0
  22. data/gemfiles/rails41.gemfile.lock +113 -0
  23. data/gemfiles/rails42.gemfile +8 -0
  24. data/gemfiles/rails42.gemfile.lock +130 -0
  25. data/gemfiles/rails50.gemfile +8 -0
  26. data/gemfiles/rails50.gemfile.lock +126 -0
  27. data/lib/fx.rb +21 -0
  28. data/lib/fx/adapters/postgres.rb +142 -0
  29. data/lib/fx/adapters/postgres/connection.rb +16 -0
  30. data/lib/fx/adapters/postgres/functions.rb +55 -0
  31. data/lib/fx/adapters/postgres/triggers.rb +56 -0
  32. data/lib/fx/command_recorder.rb +29 -0
  33. data/lib/fx/command_recorder/arguments.rb +43 -0
  34. data/lib/fx/command_recorder/function.rb +30 -0
  35. data/lib/fx/command_recorder/trigger.rb +30 -0
  36. data/lib/fx/configuration.rb +38 -0
  37. data/lib/fx/definition.rb +36 -0
  38. data/lib/fx/function.rb +24 -0
  39. data/lib/fx/schema_dumper.rb +15 -0
  40. data/lib/fx/schema_dumper/function.rb +29 -0
  41. data/lib/fx/schema_dumper/trigger.rb +29 -0
  42. data/lib/fx/statements.rb +16 -0
  43. data/lib/fx/statements/function.rb +105 -0
  44. data/lib/fx/statements/trigger.rb +133 -0
  45. data/lib/fx/trigger.rb +24 -0
  46. data/lib/fx/version.rb +4 -0
  47. data/lib/generators.rb +11 -0
  48. data/lib/generators/fx/function/USAGE +9 -0
  49. data/lib/generators/fx/function/function_generator.rb +98 -0
  50. data/lib/generators/fx/function/templates/db/migrate/create_function.erb +5 -0
  51. data/lib/generators/fx/function/templates/db/migrate/update_function.erb +5 -0
  52. data/lib/generators/fx/trigger/USAGE +18 -0
  53. data/lib/generators/fx/trigger/templates/db/migrate/create_trigger.erb +5 -0
  54. data/lib/generators/fx/trigger/templates/db/migrate/update_trigger.erb +5 -0
  55. data/lib/generators/fx/trigger/trigger_generator.rb +108 -0
  56. data/spec/acceptance/user_manages_functions_spec.rb +37 -0
  57. data/spec/acceptance/user_manages_triggers_spec.rb +51 -0
  58. data/spec/acceptance_helper.rb +61 -0
  59. data/spec/dummy/.gitignore +16 -0
  60. data/spec/dummy/Rakefile +6 -0
  61. data/spec/dummy/bin/bundle +3 -0
  62. data/spec/dummy/bin/rails +4 -0
  63. data/spec/dummy/bin/rake +4 -0
  64. data/spec/dummy/config.ru +4 -0
  65. data/spec/dummy/config/application.rb +15 -0
  66. data/spec/dummy/config/boot.rb +5 -0
  67. data/spec/dummy/config/database.yml +9 -0
  68. data/spec/dummy/config/environment.rb +5 -0
  69. data/spec/dummy/db/migrate/.keep +0 -0
  70. data/spec/features/functions/migrations_spec.rb +65 -0
  71. data/spec/features/functions/revert_spec.rb +75 -0
  72. data/spec/features/triggers/migrations_spec.rb +56 -0
  73. data/spec/features/triggers/revert_spec.rb +95 -0
  74. data/spec/fx/adapters/postgres_spec.rb +149 -0
  75. data/spec/fx/command_recorder/arguments_spec.rb +41 -0
  76. data/spec/fx/command_recorder_spec.rb +171 -0
  77. data/spec/fx/configuration_spec.rb +21 -0
  78. data/spec/fx/definition_spec.rb +111 -0
  79. data/spec/fx/schema_dumper/function_spec.rb +22 -0
  80. data/spec/fx/schema_dumper/trigger_spec.rb +40 -0
  81. data/spec/fx/statements/function_spec.rb +103 -0
  82. data/spec/fx/statements/trigger_spec.rb +132 -0
  83. data/spec/generators/fx/function/function_generator_spec.rb +34 -0
  84. data/spec/generators/fx/trigger/trigger_generator_spec.rb +47 -0
  85. data/spec/spec_helper.rb +21 -0
  86. data/spec/support/definition_helpers.rb +37 -0
  87. data/spec/support/generator_setup.rb +11 -0
  88. data/spec/support/migration_helpers.rb +17 -0
  89. metadata +334 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 07cc76f1310a1982698708c2022bbfae7853263a
4
+ data.tar.gz: a598bd9efd102a6d8b2789379c46f865a4319f86
5
+ SHA512:
6
+ metadata.gz: b9b0b8012f86bb96300811e6e7f3eaf0ae03f437da774bb8751759cd7c3546556d5bd3ed195410e97db0a808f55e118c88deca1887d570bd6752308aabd254b0
7
+ data.tar.gz: 022f693c2da994f7204e6320b4bf73b606df63d8d2c5a9f28bce6cb596d035ce949f2c39a3b6111aa6f926079a5b1b67ed73cd989b7ec1567aa5b3d2113a0e74
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
@@ -0,0 +1 @@
1
+ 2.3
@@ -0,0 +1,27 @@
1
+ addons:
2
+ postgresql: "9.4"
3
+ before_install:
4
+ - "echo '--colour' > ~/.rspec"
5
+ - "echo 'gem: --no-document' > ~/.gemrc"
6
+ - git config --global user.name "Travis CI"
7
+ - git config --global user.email "travis-ci@example.com"
8
+ branches:
9
+ only:
10
+ - master
11
+ install:
12
+ - travis_retry bin/setup
13
+ language:
14
+ - ruby
15
+ notifications:
16
+ email: false
17
+ rvm:
18
+ - 2.3.1
19
+ gemfile:
20
+ - gemfiles/rails40.gemfile
21
+ - gemfiles/rails41.gemfile
22
+ - gemfiles/rails42.gemfile
23
+ - gemfiles/rails50.gemfile
24
+ matrix:
25
+ exclude:
26
+ - rvm: 2.1.8
27
+ gemfile: gemfiles/rails50.gemfile
@@ -0,0 +1,4 @@
1
+ --hide-api private
2
+ --exclude templates
3
+ --markup markdown
4
+ --markup-provider redcarpet
@@ -0,0 +1,21 @@
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
+ appraise "rails42" do
12
+ gem "activerecord", "~> 4.2.0"
13
+ gem "railties", "~> 4.2.0"
14
+ end
15
+
16
+ if RUBY_VERSION > "2.2.0"
17
+ appraise "rails50" do
18
+ gem "activerecord", "~> 5.0"
19
+ gem "railties", "~> 5.0"
20
+ end
21
+ end
@@ -0,0 +1,15 @@
1
+ # Contributing
2
+
3
+ 1. Fork the repository.
4
+ 2. Run `bin/setup`, which will install dependencies and create the dummy
5
+ application database.
6
+ 3. Run `bin/appraisal rake` to verify that the tests pass against all
7
+ supported versions of Rails.
8
+ 4. Make your change with new passing tests, following the existing style.
9
+ 5. Write a [good commit message], push your fork, and submit a pull request.
10
+
11
+ [good commit message]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
12
+
13
+ Others will give constructive feedback. This is a time for discussion and
14
+ improvements, and making the necessary changes will be required before we can
15
+ merge the contribution.
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in fx.gemspec
4
+ gemspec
@@ -0,0 +1,81 @@
1
+ # F(x)
2
+
3
+ F(x) adds methods to `ActiveRecord::Migration` to create and manage database
4
+ functions and triggers in Rails.
5
+
6
+ Using F(x), you can bring the power of SQL functions and triggers to your Rails
7
+ application without having to switch your schema format to SQL. F(x) provides
8
+ a convention for versioning functions and triggers that keeps your migration
9
+ history consistent and reversible and avoids having to duplicate SQL strings
10
+ across migrations. As an added bonus, you define the structure of your function
11
+ in a SQL file, meaning you get full SQL syntax highlighting in the editor of
12
+ your choice and can easily test your SQL in the database console during
13
+ development.
14
+
15
+ F(x) ships with support for PostgreSQL. The adapter is configurable (see
16
+ `Fx::Configuration`) and has a minimal interface (see
17
+ `Fx::Adapters::Postgres`) that other gems can provide.
18
+
19
+ ## Great, how do I create a trigger and a function?
20
+
21
+ You've got this great idea for a trigger you'd like to call
22
+ `uppercase_users_name`. You can create the migration and the corresponding
23
+ definition file with the following command:
24
+
25
+ ```sh
26
+ % rails generate fx:trigger uppercase_users_name
27
+ create db/triggers/uppercase_users_name_v01.sql
28
+ create db/migrate/[TIMESTAMP]_create_trigger_uppercase_users_name.rb
29
+ ```
30
+
31
+ Edit the `db/triggers/uppercase_users_name_v01.sql` file with the SQL statement
32
+ that defines your trigger. In our example, this might look something like this:
33
+
34
+ ```sql
35
+ CREATE TRIGGER uppercase_users_name
36
+ BEFORE INSERT ON users
37
+ FOR EACH ROW
38
+ EXECUTE PROCEDURE uppercase_users_name();
39
+ ```
40
+
41
+ As you see, we execute a function called `uppercase_users_name` before each
42
+ `INSERT` on the `users` table, which is a function we don't have yet.
43
+
44
+ ```sh
45
+ % rails generate fx:function uppercase_users_name
46
+ create db/functions/uppercase_users_name_v01.sql
47
+ create db/migrate/[TIMESTAMP]_create_function_uppercase_users_name.rb
48
+ ```
49
+
50
+ The generated migrations contains `create_function` and `create_trigger`
51
+ statements. The migration is reversible and the schema will be dumped into your
52
+ `schema.rb` file.
53
+
54
+ ```sh
55
+ % rake db:migrate
56
+ ```
57
+
58
+ ## Cool, but what if I need to change a trigger or function?
59
+
60
+ Here's where F(x) really shines. Run that same function generator once more:
61
+
62
+ ```sh
63
+ % rails generate fx:function uppercase_users_name
64
+ create db/functions/uppercase_users_name_v02.sql
65
+ create db/migrate/[TIMESTAMP]_update_function_uppercase_users_name_to_version_2.rb
66
+ ```
67
+
68
+ F(x) detected that we already had an existing `uppercase_users_name` function at
69
+ version 1, created a copy of that definition as version 2, and created a
70
+ migration to update to the version 2 schema. All that's left for you to do is
71
+ tweak the schema in the new definition and run the `update_function` migration.
72
+
73
+ ## I don't need this trigger or function anymore. Make it go away.
74
+
75
+ F(x) gives you `drop_trigger` and `drop_function` too:
76
+
77
+ ```ruby
78
+ def change
79
+ drop_function :uppercase_users_name, revert_to_version: 2
80
+ end
81
+ ```
@@ -0,0 +1,23 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ namespace :dummy do
5
+ require_relative "spec/dummy/config/application"
6
+ Dummy::Application.load_tasks
7
+ end
8
+
9
+ task(:spec).clear
10
+ desc "Run specs other than spec/acceptance"
11
+ RSpec::Core::RakeTask.new("spec") do |task|
12
+ task.exclude_pattern = "spec/acceptance/**/*_spec.rb"
13
+ task.verbose = false
14
+ end
15
+
16
+ desc "Run acceptance specs in spec/acceptance"
17
+ RSpec::Core::RakeTask.new("spec:acceptance") do |task|
18
+ task.pattern = "spec/acceptance/**/*_spec.rb"
19
+ task.verbose = false
20
+ end
21
+
22
+ desc "Run the specs and acceptance tests"
23
+ task default: %w(spec spec:acceptance)
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+ #
4
+ # This file was generated by Bundler.
5
+ #
6
+ # The application 'appraisal' is installed as part of a gem, and
7
+ # this file is here to facilitate running it.
8
+ #
9
+
10
+ require "pathname"
11
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
12
+ Pathname.new(__FILE__).realpath)
13
+
14
+ require "rubygems"
15
+ require "bundler/setup"
16
+
17
+ load Gem.bin_path("appraisal", "appraisal")
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "fx"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+ #
4
+ # This file was generated by Bundler.
5
+ #
6
+ # The application 'rake' is installed as part of a gem, and
7
+ # this file is here to facilitate running it.
8
+ #
9
+
10
+ require "pathname"
11
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
12
+ Pathname.new(__FILE__).realpath)
13
+
14
+ require "rubygems"
15
+ require "bundler/setup"
16
+
17
+ load Gem.bin_path("rake", "rake")
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+ #
4
+ # This file was generated by Bundler.
5
+ #
6
+ # The application 'rspec' is installed as part of a gem, and
7
+ # this file is here to facilitate running it.
8
+ #
9
+
10
+ require "pathname"
11
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
12
+ Pathname.new(__FILE__).realpath)
13
+
14
+ require "rubygems"
15
+ require "bundler/setup"
16
+
17
+ load Gem.bin_path("rspec-core", "rspec")
@@ -0,0 +1,12 @@
1
+ #!/bin/sh
2
+
3
+ set -e
4
+
5
+ gem install bundler --conservative
6
+ bundle check || bundle install
7
+
8
+ if [ -z "$CI" ]; then
9
+ bundle exec appraisal install
10
+ fi
11
+
12
+ bundle exec rake dummy:db:create
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+ #
4
+ # This file was generated by Bundler.
5
+ #
6
+ # The application 'yard' is installed as part of a gem, and
7
+ # this file is here to facilitate running it.
8
+ #
9
+
10
+ require "pathname"
11
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
12
+ Pathname.new(__FILE__).realpath)
13
+
14
+ require "rubygems"
15
+ require "bundler/setup"
16
+
17
+ load Gem.bin_path("yard", "yard")
@@ -0,0 +1,38 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "fx/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "fx"
8
+ spec.version = Fx::VERSION
9
+ spec.authors = ["Teo Ljungberg"]
10
+ spec.email = ["teo@teoljungberg.com"]
11
+ spec.summary = %q{Support for database functions and triggers in Rails migrations}
12
+ spec.description = <<-DESCRIPTION
13
+ Adds methods to ActiveRecord::Migration to create and manage database functions
14
+ and triggers in Rails
15
+ DESCRIPTION
16
+ spec.homepage = "https://github.com/teoljungberg/fx"
17
+ spec.license = 'MIT'
18
+
19
+ spec.files = `git ls-files -z`.split("\x0")
20
+ spec.test_files = spec.files.grep(%r{^spec/})
21
+ spec.require_paths = ['lib']
22
+
23
+ spec.add_development_dependency "appraisal"
24
+ spec.add_development_dependency "bundler", '>= 1.5'
25
+ spec.add_development_dependency "database_cleaner"
26
+ spec.add_development_dependency "rake"
27
+ spec.add_development_dependency "rspec", '>= 3.3'
28
+ spec.add_development_dependency "pg"
29
+ spec.add_development_dependency "pry"
30
+ spec.add_development_dependency "ammeter", '>= 1.1.3'
31
+ spec.add_development_dependency "yard"
32
+ spec.add_development_dependency "redcarpet"
33
+
34
+ spec.add_dependency "activerecord", '>= 4.0.0'
35
+ spec.add_dependency "railties", '>= 4.0.0'
36
+
37
+ spec.required_ruby_version = "~> 2.1"
38
+ end
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 4.0.0"
6
+ gem "railties", "~> 4.0.0"
7
+
8
+ gemspec :path => "../"
@@ -0,0 +1,111 @@
1
+ PATH
2
+ remote: ../
3
+ specs:
4
+ fx (0.1.0)
5
+ activerecord (>= 4.0.0)
6
+ railties (>= 4.0.0)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ actionpack (4.0.13)
12
+ activesupport (= 4.0.13)
13
+ builder (~> 3.1.0)
14
+ erubis (~> 2.7.0)
15
+ rack (~> 1.5.2)
16
+ rack-test (~> 0.6.2)
17
+ activemodel (4.0.13)
18
+ activesupport (= 4.0.13)
19
+ builder (~> 3.1.0)
20
+ activerecord (4.0.13)
21
+ activemodel (= 4.0.13)
22
+ activerecord-deprecated_finders (~> 1.0.2)
23
+ activesupport (= 4.0.13)
24
+ arel (~> 4.0.0)
25
+ activerecord-deprecated_finders (1.0.4)
26
+ activesupport (4.0.13)
27
+ i18n (~> 0.6, >= 0.6.9)
28
+ minitest (~> 4.2)
29
+ multi_json (~> 1.3)
30
+ thread_safe (~> 0.1)
31
+ tzinfo (~> 0.3.37)
32
+ ammeter (1.1.3)
33
+ activesupport (>= 3.0)
34
+ railties (>= 3.0)
35
+ rspec-rails (>= 2.2)
36
+ appraisal (2.1.0)
37
+ bundler
38
+ rake
39
+ thor (>= 0.14.0)
40
+ arel (4.0.2)
41
+ builder (3.1.4)
42
+ coderay (1.1.1)
43
+ database_cleaner (1.5.3)
44
+ diff-lcs (1.2.5)
45
+ erubis (2.7.0)
46
+ i18n (0.7.0)
47
+ method_source (0.8.2)
48
+ minitest (4.7.5)
49
+ multi_json (1.12.1)
50
+ pg (0.18.4)
51
+ pry (0.10.3)
52
+ coderay (~> 1.1.0)
53
+ method_source (~> 0.8.1)
54
+ slop (~> 3.4)
55
+ rack (1.5.5)
56
+ rack-test (0.6.3)
57
+ rack (>= 1.0)
58
+ railties (4.0.13)
59
+ actionpack (= 4.0.13)
60
+ activesupport (= 4.0.13)
61
+ rake (>= 0.8.7)
62
+ thor (>= 0.18.1, < 2.0)
63
+ rake (11.1.2)
64
+ redcarpet (3.3.4)
65
+ rspec (3.4.0)
66
+ rspec-core (~> 3.4.0)
67
+ rspec-expectations (~> 3.4.0)
68
+ rspec-mocks (~> 3.4.0)
69
+ rspec-core (3.4.4)
70
+ rspec-support (~> 3.4.0)
71
+ rspec-expectations (3.4.0)
72
+ diff-lcs (>= 1.2.0, < 2.0)
73
+ rspec-support (~> 3.4.0)
74
+ rspec-mocks (3.4.1)
75
+ diff-lcs (>= 1.2.0, < 2.0)
76
+ rspec-support (~> 3.4.0)
77
+ rspec-rails (3.4.2)
78
+ actionpack (>= 3.0, < 4.3)
79
+ activesupport (>= 3.0, < 4.3)
80
+ railties (>= 3.0, < 4.3)
81
+ rspec-core (~> 3.4.0)
82
+ rspec-expectations (~> 3.4.0)
83
+ rspec-mocks (~> 3.4.0)
84
+ rspec-support (~> 3.4.0)
85
+ rspec-support (3.4.1)
86
+ slop (3.6.0)
87
+ thor (0.19.1)
88
+ thread_safe (0.3.5)
89
+ tzinfo (0.3.49)
90
+ yard (0.8.7.6)
91
+
92
+ PLATFORMS
93
+ ruby
94
+
95
+ DEPENDENCIES
96
+ activerecord (~> 4.0.0)
97
+ ammeter (>= 1.1.3)
98
+ appraisal
99
+ bundler (>= 1.5)
100
+ database_cleaner
101
+ fx!
102
+ pg
103
+ pry
104
+ railties (~> 4.0.0)
105
+ rake
106
+ redcarpet
107
+ rspec (>= 3.3)
108
+ yard
109
+
110
+ BUNDLED WITH
111
+ 1.12.4