fx-adapters-mysql 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 4ebc6f1cf1c463fa4aadb3614d33eb131d97342af331471f6969d8d1e7989de4
4
+ data.tar.gz: d92c5e1feda2fab057b9c4afd4714be97419d2565c9e72c86358afd9276c8c8e
5
+ SHA512:
6
+ metadata.gz: 9c390290b0fb7960229cec8885665dec1306a5d99d68feb0c746d1793c33e422ad5e86830f600f1f9e587d5f14af62d571eb43776ca1e0a0fa9ad6524199c175
7
+ data.tar.gz: df7f6e448852499022e1a4acb1ab9b803e66322e719358c8165ca0a77ebbebcc50f2c6042422e1488a26d466276e5b8b181978f0cefb44b93a9e72e2a557ec8f
data/CHANGELOG.md ADDED
@@ -0,0 +1,8 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0 (2022-02-03)
4
+
5
+
6
+ ### Features
7
+
8
+ * Initial implementation ([872d647](https://www.github.com/f-mer/fx-adapters-mysql/commit/872d64745dd3f6d1c9fba61485f4a27ce6d4c948))
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in fx-adapters-mysql.gemspec
6
+ gemspec
7
+
8
+ gem "rake", "~> 13.0"
9
+
10
+ gem "rspec", "~> 3.0"
data/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # Fx::Adapters::Mysql
2
+
3
+ MySQL adapter for [fx](https://github.com/teoljungberg/fx).
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'fx-adapters-mysql'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle install
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install fx-adapters-mysql
20
+
21
+ ## Usage
22
+
23
+ ```rb
24
+ # config/initializers/fx.rb
25
+
26
+ Fx.configure do |config|
27
+ config.adapter = Fx::Adapters::MySQL.new
28
+ end
29
+ ```
30
+
31
+ ## Development
32
+
33
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
34
+
35
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
36
+
37
+ ## Contributing
38
+
39
+ Bug reports and pull requests are welcome on GitHub at https://github.com/f-mer/fx-adapters-mysql.
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ APP_RAKEFILE = File.expand_path("spec/dummy/Rakefile", __dir__)
4
+ load("rails/tasks/engine.rake")
5
+
6
+ require "bundler/gem_tasks"
7
+ require "rspec/core/rake_task"
8
+ require "standard/rake"
9
+
10
+ RSpec::Core::RakeTask.new(:spec)
11
+
12
+ task default: ["db:create", "spec", "standard"]
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/mysql"
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(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,63 @@
1
+ module Fx
2
+ module Adapters
3
+ class MySQL
4
+ # Fetches defined functions from the mysql connection.
5
+ # @api private
6
+ class Functions
7
+ # Wraps #all as a static facade.
8
+ #
9
+ # @return [Array<Fx::Function>]
10
+ def self.all(*args)
11
+ new(*args).all
12
+ end
13
+
14
+ def initialize(connection)
15
+ @connection = connection
16
+ end
17
+
18
+ # All of the functions that this connection has defined.
19
+ #
20
+ # @return [Array<Fx::Function>]
21
+ def all
22
+ functions_from_mysql.map { |function| to_fx_function(function) }
23
+ end
24
+
25
+ private
26
+
27
+ attr_reader :connection
28
+
29
+ def functions_from_mysql
30
+ connection.exec_query(<<-SQL)
31
+ SELECT
32
+ ROUTINE_NAME AS name,
33
+ ROUTINE_DEFINITION AS definition
34
+ FROM INFORMATION_SCHEMA.ROUTINES
35
+ WHERE ROUTINE_SCHEMA NOT IN ('sys', 'information_schema', 'mysql', 'performance_schema')
36
+ AND ROUTINE_SCHEMA = '#{connection.current_database}'
37
+ AND ROUTINE_TYPE = 'FUNCTION'
38
+ SQL
39
+ end
40
+
41
+ def to_fx_function(result)
42
+ name = result.fetch("name")
43
+ definition = "DELIMITER $$\n#{delete_definer(find_definition(name))}$$\nDELIMITER ;"
44
+ Fx::Function.new(
45
+ "name" => name,
46
+ "definition" => definition
47
+ )
48
+ end
49
+
50
+ def delete_definer(string)
51
+ string.gsub(/ DEFINER=`[^`]+`@`[^`]+`/, "")
52
+ end
53
+
54
+ def find_definition(name)
55
+ connection
56
+ .exec_query("SHOW CREATE FUNCTION `#{name}`")
57
+ .first
58
+ .fetch("Create Function")
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,57 @@
1
+ module Fx
2
+ module Adapters
3
+ class MySQL
4
+ # Fetches defined triggers from the mysql connection.
5
+ # @api private
6
+ class Triggers
7
+ # Wraps #all as a static facade.
8
+ #
9
+ # @return [Array<Fx::Adapters::MySQL::Trigger>]
10
+ def self.all(*args)
11
+ new(*args).all
12
+ end
13
+
14
+ def initialize(connection)
15
+ @connection = connection
16
+ end
17
+
18
+ # All of the triggers that this connection has defined.
19
+ #
20
+ # @return [Array<Fx::Trigger>]
21
+ def all
22
+ triggers_from_mysql.map { |trigger| to_fx_trigger(trigger) }
23
+ end
24
+
25
+ private
26
+
27
+ attr_reader :connection
28
+
29
+ def triggers_from_mysql
30
+ connection.exec_query(<<-SQL)
31
+ SELECT
32
+ TRIGGER_NAME AS name,
33
+ ACTION_STATEMENT AS definition,
34
+ EVENT_MANIPULATION AS event,
35
+ EVENT_OBJECT_TABLE AS table_name,
36
+ ACTION_TIMING AS timing
37
+ FROM INFORMATION_SCHEMA.TRIGGERS
38
+ WHERE TRIGGER_SCHEMA = '#{connection.current_database}'
39
+ SQL
40
+ end
41
+
42
+ def to_fx_trigger(result)
43
+ name = result.fetch("name")
44
+ definition = <<~SQL
45
+ CREATE TRIGGER #{name} #{result.fetch("timing")} #{result.fetch("event")} ON #{result.fetch("table_name")}
46
+ FOR EACH ROW
47
+ #{result.fetch("definition")}
48
+ SQL
49
+ Fx::Trigger.new(
50
+ "name" => name,
51
+ "definition" => definition
52
+ )
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fx
4
+ module Adapters
5
+ module Mysql
6
+ VERSION = "0.1.0"
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,147 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fx"
4
+
5
+ require_relative "mysql/version"
6
+ require_relative "mysql/functions"
7
+ require_relative "mysql/triggers"
8
+
9
+ module Fx
10
+ module Adapters
11
+ # Creates an instance of the F(x) MySQL adapter.
12
+ #
13
+ # @param [#connection] connectable An object that returns the connection
14
+ # for F(x) to use. Defaults to `ActiveRecord::Base`.
15
+ #
16
+ # @example
17
+ # Fx.configure do |config|
18
+ # config.adapter = Fx::Adapters::MySQL.new
19
+ # end
20
+ class MySQL
21
+ # Creates an instance of the F(x) MySQL adapter.
22
+ #
23
+ # This is the default adapter for F(x). Configuring it via
24
+ # {Fx.configure} is not required, but the example below shows how one
25
+ # would explicitly set it.
26
+ #
27
+ # @param [#connection] connectable An object that returns the connection
28
+ # for F(x) to use. Defaults to `ActiveRecord::Base`.
29
+ #
30
+ # @example
31
+ # Fx.configure do |config|
32
+ # config.adapter = Fx::Adapters::MySQL.new
33
+ # end
34
+ def initialize(connectable = ActiveRecord::Base)
35
+ @connectable = connectable
36
+ end
37
+
38
+ # Returns an array of functions in the database.
39
+ #
40
+ # This collection of functions is used by the [Fx::SchemaDumper] to
41
+ # populate the `schema.rb` file.
42
+ #
43
+ # @return [Array<Fx::Function>]
44
+ def functions
45
+ Functions.all(connection)
46
+ end
47
+
48
+ # Returns an array of triggers in the database.
49
+ #
50
+ # This collection of triggers is used by the [Fx::SchemaDumper] to
51
+ # populate the `schema.rb` file.
52
+ #
53
+ # @return [Array<Fx::Trigger>]
54
+ def triggers
55
+ Triggers.all(connection)
56
+ end
57
+
58
+ # Creates a function in the database.
59
+ #
60
+ # This is typically called in a migration via
61
+ # {Fx::Statements::Function#create_function}.
62
+ #
63
+ # @param sql_definition The SQL schema for the function.
64
+ #
65
+ # @return [void]
66
+ def create_function(sql_definition)
67
+ execute sql_definition
68
+ end
69
+
70
+ # Creates a trigger in the database.
71
+ #
72
+ # This is typically called in a migration via
73
+ # {Fx::Statements::Trigger#create_trigger}.
74
+ #
75
+ # @param sql_definition The SQL schema for the trigger.
76
+ #
77
+ # @return [void]
78
+ def create_trigger(sql_definition)
79
+ execute sql_definition
80
+ end
81
+
82
+ # Updates a function in the database.
83
+ #
84
+ # This is typically called in a migration via
85
+ # {Fx::Statements::Function#update_function}.
86
+ #
87
+ # @param name The name of the function.
88
+ # @param sql_definition The SQL schema for the function.
89
+ #
90
+ # @return [void]
91
+ def update_function(name, sql_definition)
92
+ drop_function(name)
93
+ create_function(sql_definition)
94
+ end
95
+
96
+ # Updates a trigger in the database.
97
+ #
98
+ # The existing trigger is dropped and recreated using the supplied `on`
99
+ # and `version` parameter.
100
+ #
101
+ # This is typically called in a migration via
102
+ # {Fx::Statements::Function#update_trigger}.
103
+ #
104
+ # @param name The name of the trigger.
105
+ # @param on The associated table for the trigger to drop
106
+ # @param sql_definition The SQL schema for the function.
107
+ #
108
+ # @return [void]
109
+ def update_trigger(name, on:, sql_definition:)
110
+ drop_trigger(name, on: on)
111
+ create_trigger(sql_definition)
112
+ end
113
+
114
+ # Drops the function from the database
115
+ #
116
+ # This is typically called in a migration via
117
+ # {Fx::Statements::Function#drop_function}.
118
+ #
119
+ # @param name The name of the function to drop
120
+ #
121
+ # @return [void]
122
+ def drop_function(name)
123
+ execute "DROP FUNCTION #{name};"
124
+ end
125
+
126
+ # Drops the trigger from the database
127
+ #
128
+ # This is typically called in a migration via
129
+ # {Fx::Statements::Trigger#drop_trigger}.
130
+ #
131
+ # @param name The name of the trigger to drop
132
+ # @param on The associated table for the trigger to drop
133
+ #
134
+ # @return [void]
135
+ def drop_trigger(name, on:)
136
+ execute "DROP TRIGGER #{name} ON #{on};"
137
+ end
138
+
139
+ private
140
+
141
+ attr_reader :connectable
142
+
143
+ delegate :connection, to: :connectable
144
+ delegate :execute, to: :connection
145
+ end
146
+ end
147
+ end
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fx-adapters-mysql
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Fabian Mersch
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2022-02-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: mysql2
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: standard
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: fx
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.6.2
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.6.2
55
+ description:
56
+ email:
57
+ - fabianmersch@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - CHANGELOG.md
63
+ - Gemfile
64
+ - README.md
65
+ - Rakefile
66
+ - bin/console
67
+ - bin/setup
68
+ - lib/fx/adapters/mysql.rb
69
+ - lib/fx/adapters/mysql/functions.rb
70
+ - lib/fx/adapters/mysql/triggers.rb
71
+ - lib/fx/adapters/mysql/version.rb
72
+ homepage: https://github.com/f-mer/fx-adapters-mysql
73
+ licenses: []
74
+ metadata: {}
75
+ post_install_message:
76
+ rdoc_options: []
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ required_rubygems_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ requirements: []
90
+ rubygems_version: 3.2.15
91
+ signing_key:
92
+ specification_version: 4
93
+ summary: MySQL adapter for fx
94
+ test_files: []