fx-sqlserver-adapter 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b8ad3b063af5510ece9b0e43abac26c1dcf9e704614722ad700f7ee677af7da5
4
+ data.tar.gz: c42e672daa3bc810c8318ad4386597cf769b51364fe50838672669326a9ae9e0
5
+ SHA512:
6
+ metadata.gz: 703f7997526b87f34e9cbcff8808abca22f192cea53fb0b53b4ed63de417e02feaa32716649aec5bf13ff162b5bc8de55630466266dda66fdd170a0b2b0e5c14
7
+ data.tar.gz: ef61aa2b87bc31da67fe41d34df6907387c5411e1b829172543652e6320f9690fdd72b4ef4f2b8cabe2501267b8bd3aa00c5976d637f62a0564f61df68fa7aad
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /gemfiles/*.gemfile.lock
3
+ /.yardoc
4
+ /Gemfile.lock
5
+ /_yardoc/
6
+ /coverage/
7
+ /doc/
8
+ /pkg/
9
+ /spec/reports/
10
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,73 @@
1
+ require:
2
+ - rubocop-performance
3
+ - rubocop-rspec
4
+
5
+ AllCops:
6
+ NewCops: enable
7
+ TargetRubyVersion: 2.7
8
+ Exclude:
9
+ - '.bundle/*'
10
+ - '**.gem'
11
+ - '**.gemspec'
12
+ - 'Gemfile'
13
+ - 'Guardfile'
14
+ - 'Rakefile'
15
+ - '.**'
16
+ - 'bin/**/*'
17
+ - 'cache/ruby/**/*'
18
+ - 'coverage/**/*'
19
+ - 'docs/**/*'
20
+ - 'pkg/**/*'
21
+ - 'tmp/**'
22
+ - 'vendor/**/*'
23
+ - '**/*.tt'
24
+ - '**.yml'
25
+ - '**/**.bak'
26
+ UseCache: false
27
+
28
+ Layout/EmptyLinesAroundAttributeAccessor:
29
+ Enabled: false
30
+ Layout/LineLength:
31
+ AllowURI: true
32
+ Enabled: false
33
+ Lint/DuplicateMethods:
34
+ Enabled: false
35
+ Lint/NonDeterministicRequireOrder:
36
+ Enabled: false
37
+ Metrics/AbcSize:
38
+ Max: 42
39
+ Enabled: false
40
+ Metrics/ClassLength:
41
+ Enabled: false
42
+ Metrics/CyclomaticComplexity:
43
+ Max: 12
44
+ Enabled: false
45
+ Metrics/MethodLength:
46
+ CountComments: false
47
+ Max: 43
48
+ Metrics/ModuleLength:
49
+ Max: 164
50
+ Metrics/PerceivedComplexity:
51
+ Max: 18
52
+ # Naming/AccessorMethodName is disabled because of overriding some default rails methods
53
+ Naming/AccessorMethodName:
54
+ Enabled: false
55
+ Naming/FileName:
56
+ Enabled: false
57
+ Naming/MemoizedInstanceVariableName:
58
+ Enabled: false
59
+ Style/Documentation:
60
+ Enabled: false
61
+ Style/EmptyMethod:
62
+ EnforcedStyle: expanded
63
+ Style/FrozenStringLiteralComment:
64
+ Description: ">- Apply frozen_string_literal to the top of ruby files\nThis is for transitioniting from Ruby 2.3 to Ruby 3.0"
65
+ Enabled: false
66
+ Style/Lambda:
67
+ EnforcedStyle: line_count_dependent
68
+ Style/RedundantBegin:
69
+ Enabled: false
70
+ Style/RedundantSelf:
71
+ Enabled: false
72
+ Style/RescueStandardError:
73
+ EnforcedStyle: implicit
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,14 @@
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 `rspec` to verify that the tests pass.
7
+ 4. Make your change with new passing tests, following the existing style.
8
+ 5. Write a [good commit message], push your fork, and submit a pull request.
9
+
10
+ [good commit message]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
11
+
12
+ Others will give constructive feedback. This is a time for discussion and
13
+ improvements, and making the necessary changes will be required before we can
14
+ merge the contribution.
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in healthicons.gemspec
6
+ gemspec
7
+
8
+ gem 'rake', '~> 13.0'
9
+
10
+ group :development do
11
+ gem 'fasterer'
12
+ gem 'rubocop', '>= 0.89', require: false
13
+ gem 'rubocop-performance'
14
+ gem 'rubocop-rspec'
15
+ end
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2021 Brandon Hicks
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,48 @@
1
+ # F(x) Sqlserver Adapter
2
+
3
+ A Sqlserver adapter for [fx](https://github.com/teoljungberg/fx) gem
4
+
5
+ ## Features
6
+
7
+ This adapter makes possible to use sqlserver database functions/procedures _(under functions)_ and triggers with active record migrations and schema dump for them.
8
+
9
+ ## Installation
10
+
11
+ Add this line to gemfile
12
+
13
+ ```ruby
14
+ gem 'fx'
15
+ gem 'fx-sqlserver-adapter'
16
+ ```
17
+
18
+ And then execute:
19
+
20
+ $ bundle install
21
+
22
+ Or install it yourself as:
23
+
24
+ $ gem install fx-sqlserver-adapter
25
+
26
+ ## Usage
27
+
28
+ After that, you will need to tell F(x) to use this adapter in an initializer `config/initializer/fx.rb`:
29
+
30
+ ```ruby
31
+ # frozen_string_litearl: true
32
+
33
+ require 'fx/adapters/sqlserver'
34
+ if defined?(Fx)
35
+ Fx.configuration.database = Fx::Adapters::Sqlserver.new
36
+ end
37
+ ```
38
+
39
+ The generators for this gem still uses generators from the original [fx](https://github.com/teoljungberg/fx#great-how-do-i-create-a-trigger-and-a-function) gem.
40
+
41
+ ## Contributing
42
+
43
+ Bug reports and pull requests are welcome on GitHub at https://github.com/tarellel/fx-sqlserver-adapter.
44
+ This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org/) code of conduct.
45
+
46
+ ## License
47
+
48
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rake/testtask'
5
+
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << 'test'
8
+ t.libs << 'lib'
9
+ t.test_files = FileList["test/**/*_test.rb"]
10
+ end
11
+
12
+ require 'rubocop/rake_task'
13
+
14
+ RuboCop::RakeTask.new
15
+
16
+ task default: %i[test rubocop]
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'fx/adapters/sqlserver'
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require 'irb'
15
+ IRB.start
data/bin/rake ADDED
@@ -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")
data/bin/rspec ADDED
@@ -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")
data/bin/setup ADDED
@@ -0,0 +1,9 @@
1
+ #!/bin/sh
2
+
3
+ set -e
4
+
5
+ gem install bundler --conservative
6
+ bundle check || bundle install
7
+
8
+ bundle exec rake dummy:db:drop
9
+ bundle exec rake dummy:db:create
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+ # coding: utf-8
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'fx/sqlserver_adapter/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'fx-sqlserver-adapter'
9
+ spec.version = Fx::SqlserverAdapter::VERSION
10
+ spec.authors = ['Brandon Hicks']
11
+ spec.email = ['tarellel@gmail.com']
12
+ spec.summary = %q{SqlServer/MsSQL adapter for Fx gem}
13
+ spec.description = <<-DESCRIPTION
14
+ Adds sqlserver adapter to Fx gem to enable database migrations and schema
15
+ to work with functions and triggers on applications using
16
+ sqlserver as database
17
+ DESCRIPTION
18
+ spec.homepage = 'https://github.com/tarellel/fx-sqlserver-adapter'
19
+ spec.license = 'MIT'
20
+
21
+ spec.files = `git ls-files -z`.split("\x0")
22
+ spec.test_files = spec.files.grep(%r{^spec/})
23
+ spec.require_paths = ['lib']
24
+
25
+ spec.add_development_dependency 'bundler', '>= 1.5'
26
+ spec.add_development_dependency 'database_cleaner'
27
+ spec.add_development_dependency 'rake'
28
+ spec.add_development_dependency 'rspec', '>= 3.3'
29
+ spec.add_development_dependency 'tiny_tds', '>= 2.0'
30
+ spec.add_development_dependency 'pry'
31
+
32
+ spec.add_dependency 'activerecord', '>= 6.0.0'
33
+ spec.add_dependency 'railties', '>= 6.0.0'
34
+ spec.add_dependency 'fx', '~> 0.6.2'
35
+
36
+ spec.required_ruby_version = '>= 2.7'
37
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fx
4
+ module Adapters
5
+ class Sqlserver
6
+ # Decorates an ActiveRecord connection with methods that help determine
7
+ # the connections capabilities.
8
+ #
9
+ # Every attempt is made to use the versions of these methods defined by
10
+ # Rails where they are available and public before falling back to our own
11
+ # implementations for older Rails versions.
12
+ #
13
+ # @api private
14
+ class Connection < SimpleDelegator
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fx/function'
4
+
5
+ module Fx
6
+ module Adapters
7
+ class Sqlserver
8
+ # Fetches defined functions from the sqlserver connection.
9
+ # @api private
10
+ class Functions
11
+ # The SQL query used by F(x) to retrieve the functions considered
12
+ # dumpable into `db/schema.rb`.
13
+ FUNCTIONS_WITH_DEFINITIONS_QUERY = <<-STR
14
+ SELECT
15
+ routine_name AS name,
16
+ routine_definition AS definition
17
+ FROM INFORMATION_SCHEMA.ROUTINES
18
+ WHERE routine_type = 'FUNCTION'
19
+ STR
20
+
21
+ # Wraps #all as a static facade.
22
+ #
23
+ # @return [Array<Fx::Function>]
24
+ def self.all(*args)
25
+ new(*args).all
26
+ end
27
+
28
+ def initialize(connection)
29
+ @connection = connection
30
+ end
31
+
32
+ # All of the functions that this connection has defined.
33
+ #
34
+ # @return [Array<Fx::Function>]
35
+ def all
36
+ functions_from_sqlserver.map { |function| to_fx_function(function) }
37
+ end
38
+
39
+ private
40
+
41
+ attr_reader :connection
42
+
43
+ def functions_from_sqlserver
44
+ connection.exec_query(FUNCTIONS_WITH_DEFINITIONS_QUERY)
45
+ end
46
+
47
+ def to_fx_function(result)
48
+ Fx::Function.new(result)
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fx/trigger'
4
+
5
+ module Fx
6
+ module Adapters
7
+ class Sqlserver
8
+ # Fetches defined triggers from the sqlserver connection.
9
+ # @api private
10
+ class Triggers
11
+ # The query must return two attributes, name and definition
12
+ TRIGGERS_WITH_DEFINITIONS_QUERY = <<-STR
13
+ SELECT
14
+ t.name AS name,
15
+ m.definition AS definition
16
+ FROM sys.triggers t,
17
+ sys.sql_modules m
18
+ WHERE
19
+ t.type = 'TR'
20
+ AND t.object_id = m.object_id
21
+ STR
22
+
23
+ # Wraps #all as a static facade.
24
+ #
25
+ # @return [Array<Fx::Trigger>]
26
+ def self.all(*args)
27
+ new(*args).all
28
+ end
29
+
30
+ def initialize(connection)
31
+ @connection = connection
32
+ end
33
+
34
+ # All of the triggers that this connection has defined.
35
+ #
36
+ # @return [Array<Fx::Trigger>]
37
+ def all
38
+ triggers_from_sqlserver.map { |trigger| to_fx_trigger(trigger) }
39
+ end
40
+
41
+ private
42
+
43
+ attr_reader :connection
44
+
45
+ def triggers_from_sqlserver
46
+ connection.exec_query(TRIGGERS_WITH_DEFINITIONS_QUERY)
47
+ end
48
+
49
+ def to_fx_trigger(result)
50
+ Fx::Trigger.new(result)
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,148 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'sqlserver/connection'
4
+ require_relative 'sqlserver/functions'
5
+ require_relative 'sqlserver/triggers'
6
+
7
+ module Fx
8
+ # F(x) database adapters.
9
+ #
10
+ module Adapters
11
+ # Sqlserver adapter class to be used with F(x)
12
+ #
13
+ class Sqlserver
14
+ # Creates an instance of the F(x) Sqlserver adapter.
15
+ #
16
+ # To use this adapter is required to configure via {Fx.configure},
17
+ # explicitly setting it accordingly with the example below.
18
+ #
19
+ # @param [#connection] connectable An object that returns the connection
20
+ # for F(x) to use. Defaults to `ActiveRecord::Base`.
21
+ #
22
+ # @example
23
+ # Fx.configure do |config|
24
+ # config.adapter = Fx::Adapters::Sqlserver.new
25
+ # end
26
+ def initialize(connectable = ActiveRecord::Base)
27
+ @connectable = connectable
28
+ end
29
+
30
+ # Returns an array of functions in the database.
31
+ #
32
+ # This collection of functions is used by the [Fx::SchemaDumper] to
33
+ # populate the `schema.rb` file.
34
+ #
35
+ # @return [Array<Fx::Function>]
36
+ def functions
37
+ Functions.all(connection)
38
+ end
39
+
40
+ # Returns an array of triggers in the database.
41
+ #
42
+ # This collection of triggers is used by the [Fx::SchemaDumper] to
43
+ # populate the `schema.rb` file.
44
+ #
45
+ # @return [Array<Fx::Trigger>]
46
+ def triggers
47
+ Triggers.all(connection)
48
+ end
49
+
50
+ # Creates a function in the database.
51
+ #
52
+ # This is typically called in a migration via
53
+ # {Fx::Statements::Function#create_function}.
54
+ #
55
+ # @param sql_definition The SQL schema for the function.
56
+ #
57
+ # @return [void]
58
+ def create_function(sql_definition)
59
+ execute sql_definition
60
+ end
61
+
62
+ # Creates a trigger in the database.
63
+ #
64
+ # This is typically called in a migration via
65
+ # {Fx::Statements::Trigger#create_trigger}.
66
+ #
67
+ # @param sql_definition The SQL schema for the trigger.
68
+ #
69
+ # @return [void]
70
+ def create_trigger(sql_definition)
71
+ execute sql_definition
72
+ end
73
+
74
+ # Updates a function in the database.
75
+ #
76
+ # This is typically called in a migration via
77
+ # {Fx::Statements::Function#update_function}.
78
+ #
79
+ # @param name The name of the function.
80
+ # @param sql_definition The SQL schema for the function.
81
+ #
82
+ # @return [void]
83
+ def update_function(name, sql_definition)
84
+ drop_function(name)
85
+ create_function(sql_definition)
86
+ end
87
+
88
+ # Updates a trigger in the database.
89
+ #
90
+ # The existing trigger is dropped and recreated using the supplied `on`
91
+ # and `version` parameter.
92
+ #
93
+ # This is typically called in a migration via
94
+ # {Fx::Statements::Function#update_trigger}.
95
+ #
96
+ # @param name The name of the trigger.
97
+ # @param on The associated table for the trigger to drop
98
+ # @param sql_definition The SQL schema for the function.
99
+ #
100
+ # @return [void]
101
+ def update_trigger(name, on:, sql_definition:)
102
+ drop_trigger(name, on: on)
103
+ create_trigger(sql_definition)
104
+ end
105
+
106
+ # Drops the function from the database
107
+ #
108
+ # This is typically called in a migration via
109
+ # {Fx::Statements::Function#drop_function}.
110
+ #
111
+ # @param name The name of the function to drop
112
+ #
113
+ # @return [void]
114
+ def drop_function(name, *_opts, on: '', **_options)
115
+ execute <<~SQL
116
+ DROP FUNCTION IF EXISTS #{name};
117
+ DROP PROCEDURE IF EXISTS #{name};
118
+ SQL
119
+ end
120
+
121
+ # Drops the trigger from the database
122
+ #
123
+ # This is typically called in a migration via
124
+ # {Fx::Statements::Trigger#drop_trigger}.
125
+ #
126
+ # @param name The name of the trigger to drop
127
+ # @param on The associated table for the trigger to drop
128
+ #
129
+ # @return [void]
130
+ def drop_trigger(name, *_opts, on: '', **_options)
131
+ execute <<~SQL
132
+ DROP TRIGGER IF EXISTS #{name};
133
+ GO
134
+ SQL
135
+ end
136
+
137
+ private
138
+
139
+ attr_reader :connectable
140
+
141
+ delegate :execute, to: :connection
142
+
143
+ def connection
144
+ Connection.new(connectable.connection)
145
+ end
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fx
4
+ module SqlserverAdapter
5
+ VERSION = '0.0.1'
6
+ end
7
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fx'
4
+ require 'fx/adapters/sqlserver'
5
+
6
+ module Fx
7
+ module SqlserverAdapter
8
+ end
9
+ end
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails'
4
+
5
+ module Fx
6
+ module Statements
7
+ # Methods that are made available in migrations for managing Fx functions.
8
+ module Function
9
+ # Create a new database function.
10
+ #
11
+ # @param name [String, Symbol] The name of the database function.
12
+ # @param version [Fixnum] The version number of the function, used to
13
+ # find the definition file in `db/functions`. This defaults to `1` if
14
+ # not provided.
15
+ # @param sql_definition [String] The SQL query for the function schema.
16
+ # If both `sql_defintion` and `version` are provided,
17
+ # `sql_definition` takes prescedence.
18
+ # @return The database response from executing the create statement.
19
+ #
20
+ # @example Create from `db/functions/uppercase_users_name_v02.sql`
21
+ # create_function(:uppercase_users_name, version: 2)
22
+ #
23
+ # @example Create from provided SQL string
24
+ # create_function(:uppercase_users_name, sql_definition: <<-SQL)
25
+ # CREATE OR REPLACE FUNCTION uppercase_users_name()
26
+ # RETURNS trigger AS $$
27
+ # BEGIN
28
+ # NEW.upper_name = UPPER(NEW.name);
29
+ # RETURN NEW;
30
+ # END;
31
+ # $$ LANGUAGE plpgsql;
32
+ # SQL
33
+ #
34
+ def create_function(name, on: '', version: 1, sql_definition: nil)
35
+ if version.nil? && sql_definition.nil?
36
+ raise(
37
+ ArgumentError,
38
+ 'version or sql_definition must be specified'
39
+ )
40
+ end
41
+ sql_definition = sql_definition.strip_heredoc if sql_definition
42
+ sql_definition ||= Fx::Definition.new(name: name, version: version).to_sql
43
+
44
+ Fx.database.create_function(sql_definition)
45
+ end
46
+
47
+ # Drop a database function by name.
48
+ #
49
+ # @param name [String, Symbol] The name of the database function.
50
+ # @param revert_to_version [Fixnum] Used to reverse the `drop_function`
51
+ # command on `rake db:rollback`. The provided version will be passed as
52
+ # the `version` argument to {#create_function}.
53
+ # @return The database response from executing the drop statement.
54
+ #
55
+ # @example Drop a function, rolling back to version 2 on rollback
56
+ # drop_function(:uppercase_users_name, revert_to_version: 2)
57
+ #
58
+ def drop_function(name, *_opts, revert_to_version: nil, **_options)
59
+ Fx.database.drop_function(name)
60
+ end
61
+
62
+ # Update a database function.
63
+ #
64
+ # @param name [String, Symbol] The name of the database function.
65
+ # @param version [Fixnum] The version number of the function, used to
66
+ # find the definition file in `db/functions`. This defaults to `1` if
67
+ # not provided.
68
+ # @param sql_definition [String] The SQL query for the function schema.
69
+ # If both `sql_defintion` and `version` are provided,
70
+ # `sql_definition` takes prescedence.
71
+ # @return The database response from executing the create statement.
72
+ #
73
+ # @example Update function to a given version
74
+ # update_function(
75
+ # :uppercase_users_name,
76
+ # version: 3,
77
+ # revert_to_version: 2,
78
+ # )
79
+ #
80
+ # @example Update function from provided SQL string
81
+ # update_function(:uppercase_users_name, sql_definition: <<-SQL)
82
+ # CREATE OR REPLACE FUNCTION uppercase_users_name()
83
+ # RETURNS trigger AS $$
84
+ # BEGIN
85
+ # NEW.upper_name = UPPER(NEW.name);
86
+ # RETURN NEW;
87
+ # END;
88
+ # $$ LANGUAGE plpgsql;
89
+ # SQL
90
+ #
91
+ def update_function(name, version: nil, sql_definition: nil, revert_to_version: nil)
92
+ if version.nil? && sql_definition.nil?
93
+ raise(
94
+ ArgumentError,
95
+ 'version or sql_definition must be specified'
96
+ )
97
+ end
98
+
99
+ sql_definition = sql_definition.strip_heredoc if sql_definition
100
+ sql_definition ||= Fx::Definition.new(
101
+ name: name,
102
+ version: version,
103
+ ).to_sql
104
+
105
+ Fx.database.update_function(name, sql_definition)
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,135 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fx
4
+ module Statements
5
+ # Methods that are made available in migrations for managing Fx triggers.
6
+ module Trigger
7
+ # @api private
8
+ DEFINTION_TYPE = 'trigger'
9
+
10
+ # Create a new database trigger.
11
+ #
12
+ # @param name [String, Symbol] The name of the database trigger.
13
+ # @param version [Fixnum] The version number of the trigger, used to
14
+ # find the definition file in `db/triggers`. This defaults to `1` if
15
+ # not provided.
16
+ # @param sql_definition [String] The SQL query for the function. An error
17
+ # will be raised if `sql_definition` and `version` are both set,
18
+ # as they are mutually exclusive.
19
+ # @return The database response from executing the create statement.
20
+ #
21
+ # @example Create trigger from `db/triggers/uppercase_users_name_v01.sql`
22
+ # create_trigger(:uppercase_users_name, version: 1)
23
+ #
24
+ # @example Create trigger from provided SQL string
25
+ # create_trigger(:uppercase_users_name, sql_definition: <<-SQL)
26
+ # CREATE TRIGGER uppercase_users_name
27
+ # BEFORE INSERT ON users
28
+ # FOR EACH ROW
29
+ # EXECUTE PROCEDURE uppercase_users_name();
30
+ # SQL
31
+ #
32
+ def create_trigger(name, version: nil, on: nil, sql_definition: nil)
33
+ if version.present? && sql_definition.present?
34
+ raise(
35
+ ArgumentError,
36
+ 'sql_definition and version cannot both be set'
37
+ )
38
+ end
39
+
40
+ if version.nil?
41
+ version = 1
42
+ end
43
+
44
+ sql_definition = sql_definition.strip_heredoc if sql_definition
45
+ sql_definition ||= Fx::Definition.new(
46
+ name: name,
47
+ version: version,
48
+ type: DEFINTION_TYPE,
49
+ ).to_sql
50
+
51
+ Fx.database.create_trigger(sql_definition)
52
+ end
53
+
54
+ # Drop a database trigger by name.
55
+ #
56
+ # @param name [String, Symbol] The name of the database trigger.
57
+ # @param on [String, Symbol] The name of the table the database trigger
58
+ # is associated with.
59
+ # @param revert_to_version [Fixnum] Used to reverse the `drop_trigger`
60
+ # command on `rake db:rollback`. The provided version will be passed as
61
+ # the `version` argument to {#create_trigger}.
62
+ # @return The database response from executing the drop statement.
63
+ #
64
+ # @example Drop a trigger, rolling back to version 3 on rollback
65
+ # drop_trigger(:log_inserts, on: :users, revert_to_version: 3)
66
+ #
67
+ def drop_trigger(name, *_opts, on:, revert_to_version: nil)
68
+ Fx.database.drop_trigger(name, on: on)
69
+ end
70
+
71
+ # Update a database trigger to a new version.
72
+ #
73
+ # The existing trigger is dropped and recreated using the supplied `on`
74
+ # and `version` parameter.
75
+ #
76
+ # @param name [String, Symbol] The name of the database trigger.
77
+ # @param version [Fixnum] The version number of the trigger.
78
+ # @param on [String, Symbol] The name of the table the database trigger
79
+ # is associated with.
80
+ # @param sql_definition [String] The SQL query for the function. An error
81
+ # will be raised if `sql_definition` and `version` are both set,
82
+ # as they are mutually exclusive.
83
+ # @param revert_to_version [Fixnum] The version number to rollback to on
84
+ # `rake db rollback`
85
+ # @return The database response from executing the create statement.
86
+ #
87
+ # @example Update trigger to a given version
88
+ # update_trigger(
89
+ # :log_inserts,
90
+ # on: :users,
91
+ # version: 3,
92
+ # revert_to_version: 2,
93
+ # )
94
+ #
95
+ # @example Update trigger from provided SQL string
96
+ # update_trigger(:uppercase_users_name, sql_definition: <<-SQL)
97
+ # CREATE TRIGGER uppercase_users_name
98
+ # BEFORE INSERT ON users
99
+ # FOR EACH ROW
100
+ # EXECUTE PROCEDURE uppercase_users_name();
101
+ # SQL
102
+ #
103
+ def update_trigger(name, version: nil, on: nil, sql_definition: nil, revert_to_version: nil)
104
+ if version.nil? && sql_definition.nil?
105
+ raise(
106
+ ArgumentError,
107
+ 'version or sql_definition must be specified'
108
+ )
109
+ end
110
+
111
+ if version.present? && sql_definition.present?
112
+ raise(
113
+ ArgumentError,
114
+ 'sql_definition and version cannot both be set'
115
+ )
116
+ end
117
+
118
+ raise ArgumentError, 'on is required' if on.nil?
119
+
120
+ sql_definition = sql_definition.strip_heredoc if sql_definition
121
+ sql_definition ||= Fx::Definition.new(
122
+ name: name,
123
+ version: version,
124
+ type: DEFINTION_TYPE
125
+ ).to_sql
126
+
127
+ Fx.database.update_trigger(
128
+ name,
129
+ on: on,
130
+ sql_definition: sql_definition
131
+ )
132
+ end
133
+ end
134
+ end
135
+ end
metadata ADDED
@@ -0,0 +1,193 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fx-sqlserver-adapter
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Brandon Hicks
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-12-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '1.5'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '1.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: database_cleaner
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '3.3'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '3.3'
69
+ - !ruby/object:Gem::Dependency
70
+ name: tiny_tds
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '2.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '2.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: activerecord
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 6.0.0
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: 6.0.0
111
+ - !ruby/object:Gem::Dependency
112
+ name: railties
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: 6.0.0
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: 6.0.0
125
+ - !ruby/object:Gem::Dependency
126
+ name: fx
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: 0.6.2
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: 0.6.2
139
+ description: |2
140
+ Adds sqlserver adapter to Fx gem to enable database migrations and schema
141
+ to work with functions and triggers on applications using
142
+ sqlserver as database
143
+ email:
144
+ - tarellel@gmail.com
145
+ executables: []
146
+ extensions: []
147
+ extra_rdoc_files: []
148
+ files:
149
+ - ".gitignore"
150
+ - ".rspec"
151
+ - ".rubocop.yml"
152
+ - CONTRIBUTING.md
153
+ - Gemfile
154
+ - LICENSE
155
+ - README.md
156
+ - Rakefile
157
+ - bin/console
158
+ - bin/rake
159
+ - bin/rspec
160
+ - bin/setup
161
+ - fx-sqlserver-adapter.gemspec
162
+ - lib/fx/adapters/sqlserver.rb
163
+ - lib/fx/adapters/sqlserver/connection.rb
164
+ - lib/fx/adapters/sqlserver/functions.rb
165
+ - lib/fx/adapters/sqlserver/triggers.rb
166
+ - lib/fx/sqlserver_adapter.rb
167
+ - lib/fx/sqlserver_adapter/version.rb
168
+ - lib/fx/statements/function.rb
169
+ - lib/fx/statements/trigger.rb
170
+ homepage: https://github.com/tarellel/fx-sqlserver-adapter
171
+ licenses:
172
+ - MIT
173
+ metadata: {}
174
+ post_install_message:
175
+ rdoc_options: []
176
+ require_paths:
177
+ - lib
178
+ required_ruby_version: !ruby/object:Gem::Requirement
179
+ requirements:
180
+ - - ">="
181
+ - !ruby/object:Gem::Version
182
+ version: '2.7'
183
+ required_rubygems_version: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - ">="
186
+ - !ruby/object:Gem::Version
187
+ version: '0'
188
+ requirements: []
189
+ rubygems_version: 3.2.32
190
+ signing_key:
191
+ specification_version: 4
192
+ summary: SqlServer/MsSQL adapter for Fx gem
193
+ test_files: []