schema_plus_functions 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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: '09790e6271a884bb4cf768a7f75a25ef2cce002b91b9c2bc066f6992ea340cb0'
4
+ data.tar.gz: f87cde834a3236137bbcc1aa0be6f417c186c8d505ef0c6ed421c68fe4224c70
5
+ SHA512:
6
+ metadata.gz: 61e40e645fb97bc23908992339eefe32fd99574f6846e4d7cc5d27ab064e9eca14faacb1445901d3e91757a61a27e1ee1a5d34d99ad3e85cf1bf2e3503fdcb60
7
+ data.tar.gz: e355ac3b4266adbff2f1d97690e725818d124a8a1f00c9976df23c35a862a51c7df7c72482c4d1be3c456d7fade5f7b742ed7a84c4b01a15d25a5bbab568c9b4
@@ -0,0 +1,7 @@
1
+ /coverage
2
+ /tmp
3
+ /pkg
4
+ /Gemfile.local
5
+
6
+ *.lock
7
+ *.log
@@ -0,0 +1,16 @@
1
+ # This file was auto-generated by the schema_dev tool, based on the data in
2
+ # ./schema_dev.yml
3
+ # Please do not edit this file; any changes will be overwritten next time
4
+ # schema_dev gets run.
5
+ ---
6
+ sudo: false
7
+ rvm:
8
+ - 2.3.1
9
+ gemfile:
10
+ - gemfiles/activerecord-5.2/Gemfile.postgresql
11
+ env: POSTGRESQL_DB_USER=postgres
12
+ addons:
13
+ postgresql: '9.4'
14
+ before_script: bundle exec rake create_databases
15
+ after_script: bundle exec rake drop_databases
16
+ script: bundle exec rake travis
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "http://rubygems.org"
4
+
5
+ gemspec
6
+
7
+ gemfile_local = File.expand_path '../Gemfile.local', __FILE__
8
+ eval File.read(gemfile_local), binding, gemfile_local if File.exist? gemfile_local
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2020 Edward Rudd
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,142 @@
1
+ [![Gem Version](https://badge.fury.io/rb/schema_plus_functions.svg)](http://badge.fury.io/rb/schema_plus_functions)
2
+ [![Build Status](https://secure.travis-ci.org/SchemaPlus/schema_plus_functions.svg)](http://travis-ci.org/SchemaPlus/schema_plus_functions)
3
+ [![Coverage Status](https://img.shields.io/coveralls/SchemaPlus/schema_plus_functions.svg)](https://coveralls.io/r/SchemaPlus/schema_plus_functions)
4
+ [![Dependency Status](https://gemnasium.com/SchemaPlus/schema_plus_functions.svg)](https://gemnasium.com/SchemaPlus/schema_plus_functions)
5
+
6
+ # SchemaPlus::Functions
7
+
8
+ SchemaPlus::Functions adds support for SQL functions in ActiveRecord.
9
+
10
+ SchemaPlus::Functions is part of the [SchemaPlus](https://github.com/SchemaPlus/) family of Ruby on Rails ActiveRecord extension gems.
11
+
12
+ ## Installation
13
+
14
+ <!-- SCHEMA_DEV: TEMPLATE INSTALLATION - begin -->
15
+ <!-- These lines are auto-inserted from a schema_dev template -->
16
+ As usual:
17
+
18
+ ```ruby
19
+ gem "schema_plus_functions" # in a Gemfile
20
+ gem.add_dependency "schema_plus_functions" # in a .gemspec
21
+ ```
22
+
23
+ <!-- SCHEMA_DEV: TEMPLATE INSTALLATION - end -->
24
+
25
+ ## Usage
26
+
27
+ ### Migrations
28
+
29
+ To declare a function use `create_function`:
30
+
31
+ create_function :test, "start date, stop date DEFAULT NULL::date", <<-END
32
+ RETURNS integer
33
+ LANGUAGE plpgsql
34
+ AS $$
35
+ DECLARE
36
+ processed INTEGER = 0;
37
+ BEGIN
38
+ processed = processed + 1;
39
+ RETURN processed;
40
+ END;
41
+ $$
42
+ END
43
+
44
+ To create an aggregate function specify the `function_type`:
45
+
46
+ create_function :array_cat_agg, "anyarray", <<-END, function_type: :aggregate
47
+ (SFUNC=array_cat,STYPE=anyarray)
48
+ END
49
+
50
+ To update a function in a new migration specify the `allow_replace` property
51
+
52
+ create_function :test, "start date, stop date DEFAULT NULL::date", <<-END, allow_replace: true
53
+ RETURNS integer
54
+ LANGUAGE plpgsql
55
+ AS $$
56
+ DECLARE
57
+ processed INTEGER = 0;
58
+ BEGIN
59
+ processed = processed + 5;
60
+ RETURN processed;
61
+ END;
62
+ $$
63
+ END
64
+
65
+ To remove a function use `drop_function` with the name and argument types:
66
+
67
+ drop_function :test, "start date, stop date"
68
+
69
+ To remove an aggregate use `drop_function` with the name and argument types with the `function_type`:
70
+
71
+ drop_function :array_cat_agg, "anyarray", function_type: :aggrgate
72
+
73
+ ### Introspection
74
+
75
+ You can query the list of user functions at the connection level (uncached):
76
+
77
+ connection.functions
78
+
79
+ This will return a array of arrays. The inner array containing the function_name, argument types
80
+ and possible function type.
81
+
82
+ ## Compatibility
83
+
84
+ SchemaPlus::Functions is tested on:
85
+
86
+ <!-- SCHEMA_DEV: MATRIX - begin -->
87
+ <!-- These lines are auto-generated by schema_dev based on schema_dev.yml -->
88
+ * ruby **2.3.1** with activerecord **5.2**, using **postgresql**
89
+
90
+ <!-- SCHEMA_DEV: MATRIX - end -->
91
+
92
+ ## History
93
+
94
+ * 0.1.0 - Initial release
95
+
96
+ ## Development & Testing
97
+
98
+ Are you interested in contributing to SchemaPlus::Functions? Thanks! Please follow
99
+ the standard protocol: fork, feature branch, develop, push, and issue pull
100
+ request.
101
+
102
+ Some things to know about to help you develop and test:
103
+
104
+ <!-- SCHEMA_DEV: TEMPLATE USES SCHEMA_DEV - begin -->
105
+ <!-- These lines are auto-inserted from a schema_dev template -->
106
+ * **schema_dev**: SchemaPlus::Functions uses [schema_dev](https://github.com/SchemaPlus/schema_dev) to
107
+ facilitate running rspec tests on the matrix of ruby, activerecord, and database
108
+ versions that the gem supports, both locally and on
109
+ [travis-ci](http://travis-ci.org/SchemaPlus/schema_plus_functions)
110
+
111
+ To to run rspec locally on the full matrix, do:
112
+
113
+ $ schema_dev bundle install
114
+ $ schema_dev rspec
115
+
116
+ You can also run on just one configuration at a time; For info, see `schema_dev --help` or the [schema_dev](https://github.com/SchemaPlus/schema_dev) README.
117
+
118
+ The matrix of configurations is specified in `schema_dev.yml` in
119
+ the project root.
120
+
121
+
122
+ <!-- SCHEMA_DEV: TEMPLATE USES SCHEMA_DEV - end -->
123
+
124
+ <!-- SCHEMA_DEV: TEMPLATE USES SCHEMA_PLUS_CORE - begin -->
125
+ <!-- These lines are auto-inserted from a schema_dev template -->
126
+ * **schema_plus_core**: SchemaPlus::Functions uses the SchemaPlus::Core API that
127
+ provides middleware callback stacks to make it easy to extend
128
+ ActiveRecord's behavior. If that API is missing something you need for
129
+ your contribution, please head over to
130
+ [schema_plus_core](https://github.com/SchemaPlus/schema_plus_core) and open
131
+ an issue or pull request.
132
+
133
+ <!-- SCHEMA_DEV: TEMPLATE USES SCHEMA_PLUS_CORE - end -->
134
+
135
+ <!-- SCHEMA_DEV: TEMPLATE USES SCHEMA_MONKEY - begin -->
136
+ <!-- These lines are auto-inserted from a schema_dev template -->
137
+ * **schema_monkey**: SchemaPlus::Functions is implemented as a
138
+ [schema_monkey](https://github.com/SchemaPlus/schema_monkey) client,
139
+ using [schema_monkey](https://github.com/SchemaPlus/schema_monkey)'s
140
+ convention-based protocols for extending ActiveRecord and using middleware stacks.
141
+
142
+ <!-- SCHEMA_DEV: TEMPLATE USES SCHEMA_MONKEY - end -->
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler'
4
+ Bundler::GemHelper.install_tasks
5
+
6
+ require 'schema_dev/tasks'
7
+
8
+ task :default => :spec
9
+
10
+ require 'rspec/core/rake_task'
11
+ RSpec::Core::RakeTask.new(:spec)
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+ gemspec :path => File.expand_path('..', __FILE__)
3
+
4
+ File.exist?(gemfile_local = File.expand_path('../Gemfile.local', __FILE__)) and eval File.read(gemfile_local), binding, gemfile_local
@@ -0,0 +1,3 @@
1
+ eval File.read File.expand_path('../../Gemfile.base', __FILE__)
2
+
3
+ gem "activerecord", ">= 5.2.0.beta0", "< 5.3"
@@ -0,0 +1,10 @@
1
+ require "pathname"
2
+ eval(Pathname.new(__FILE__).dirname.join("Gemfile.base").read, binding)
3
+
4
+ platform :ruby do
5
+ gem "pg"
6
+ end
7
+
8
+ platform :jruby do
9
+ gem 'activerecord-jdbcpostgresql-adapter'
10
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'schema_plus/core'
4
+
5
+ require_relative 'functions/version'
6
+ require_relative 'functions/active_record/connection_adapters/abstract_adapter'
7
+ require_relative 'functions/active_record/migration/command_recorder'
8
+ require_relative 'functions/middleware'
9
+
10
+ module SchemaPlus::Functions
11
+ module ActiveRecord
12
+ module ConnectionAdapters
13
+ autoload :PostgresqlAdapter, 'schema_plus/functions/active_record/connection_adapters/postgresql_adapter'
14
+ end
15
+ end
16
+ end
17
+
18
+ SchemaMonkey.register SchemaPlus::Functions
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SchemaPlus::Functions
4
+ module ActiveRecord
5
+ module ConnectionAdapters
6
+ module AbstractAdapter
7
+ # Create a function. Valid options are :force,
8
+ # :allow_replace, and :function_type
9
+ def create_function(function_name, params, definition, options = {})
10
+ SchemaMonkey::Middleware::Migration::CreateFunction.start(connection: self, function_name: function_name, params: params, definition: definition, options: options) do |env|
11
+ function_name = env.function_name
12
+ function_type = (options[:function_type] || :function).to_s.upcase
13
+ params = env.params
14
+ definition = env.definition
15
+ options = env.options
16
+
17
+ definition = definition.to_sql if definition.respond_to? :to_sql
18
+ if options[:force]
19
+ drop_function(function_name, params, function_type: options[:function_type], if_exists: true)
20
+ end
21
+
22
+ command = if options[:allow_replace]
23
+ "CREATE OR REPLACE"
24
+ else
25
+ "CREATE"
26
+ end
27
+ execute "#{command} #{function_type} #{function_name}(#{params}) #{definition}"
28
+ end
29
+ end
30
+
31
+ # Remove a function. Valid options are :function_type,
32
+ # :if_exists, and :cascade
33
+ #
34
+ # If your function type is an aggregate, you must specify the type
35
+ #
36
+ # drop_function 'my_func', 'int', if_exists: true, cascade: true
37
+ # drop_function 'my_agg', 'int', function_type: :aggregate
38
+ def drop_function(function_name, params, options = {})
39
+ SchemaMonkey::Middleware::Migration::CreateFunction.start(connection: self, function_name: function_name, params: params, options: options) do |env|
40
+ function_name = env.function_name
41
+ params = env.params
42
+ options = env.options
43
+ function_type = (options[:function_type] || :function).to_s.upcase
44
+
45
+ sql = "DROP #{function_type}"
46
+ sql += " IF EXISTS" if options[:if_exists]
47
+ sql += " #{function_name}(#{params})"
48
+ sql += " CASCADE" if options[:cascade]
49
+
50
+ execute sql
51
+ end
52
+ end
53
+
54
+ #####################################################################
55
+ #
56
+ # The functions below here are abstract; each subclass should
57
+ # define them all. Defining them here only for reference.
58
+ #
59
+
60
+ # (abstract) Return the Function objects for functions
61
+ def functions(name = nil)
62
+ raise "Internal Error: Connection adapter did not override abstract function"
63
+ end
64
+
65
+ # (abstract) Return the Function definition for the named function and parameter set
66
+ def function_definition(function_name, params, name = nil)
67
+ raise "Internal Error: Connection adapter did not override abstract function"
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SchemaPlus::Functions
4
+ module ActiveRecord
5
+ module ConnectionAdapters
6
+ module PostgresqlAdapter
7
+ def drop_function(function_name, params, options = {})
8
+ clean_params = params.gsub(/ DEFAULT[^,]+/i, '')
9
+ super(function_name, clean_params, options)
10
+ end
11
+
12
+ def functions(name = nil) #:nodoc:
13
+ SchemaMonkey::Middleware::Schema::Functions.start(connection: self, query_name: name, functions: []) do |env|
14
+ sql = <<-SQL
15
+ SELECT P.proname as function_name, pg_get_function_identity_arguments(P.oid), proisagg as is_agg
16
+ FROM pg_proc P
17
+ WHERE
18
+ pronamespace IN (SELECT oid FROM pg_namespace WHERE nspname = ANY (current_schemas(false)))
19
+ AND NOT EXISTS (SELECT 1 FROM pg_depend WHERE classid = 'pg_proc'::regclass
20
+ AND objid = p.oid AND deptype = 'i')
21
+ AND NOT EXISTS (SELECT 1 FROM pg_depend WHERE classid = 'pg_proc'::regclass
22
+ AND objid = p.oid AND refclassid = 'pg_extension'::regclass AND deptype = 'e')
23
+ ORDER BY 1,2
24
+ SQL
25
+
26
+ env.functions += env.connection.query(sql, env.query_name).map do |row|
27
+ options = {}
28
+ options[:function_type] = :aggregate if row[2]
29
+ [row[0], row[1], options]
30
+ end
31
+ end.functions
32
+ end
33
+
34
+ def function_definition(function_name, params, name = nil) #:nodoc:
35
+ data = SchemaMonkey::Middleware::Schema::FunctionDefinition.start(connection: self, function_name: function_name, params: params, query_name: name) do |env|
36
+ result = env.connection.query(<<-SQL, env.query_name)
37
+ SELECT prosrc,
38
+ pg_get_function_arguments(p.oid),
39
+ pg_catalog.pg_get_function_result(p.oid) AS funcresult,
40
+ (SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname,
41
+ a.aggtransfn as transfn,
42
+ format_type(a.aggtranstype, null) as transtype
43
+ FROM pg_proc p
44
+ LEFT JOIN pg_aggregate a ON a.aggfnoid = p.oid
45
+ WHERE
46
+ pronamespace IN (SELECT oid FROM pg_namespace WHERE nspname = ANY (current_schemas(false)))
47
+ AND proname = '#{quote_string(function_name)}'
48
+ AND pg_get_function_identity_arguments(P.oid) = '#{quote_string(params)}'
49
+ SQL
50
+
51
+ row = result.first
52
+
53
+ function_type = nil
54
+
55
+ unless row.nil?
56
+ sql = if row[4].present? || row[0] == 'aggregate_dummy'
57
+ # it's an aggregate function
58
+ function_type = :aggregate
59
+ "(SFUNC=#{row[4]},STYPE=#{row[5]})"
60
+ else
61
+ "RETURNS #{row[2]} LANGUAGE #{row[3]} AS $$#{row[0]}$$"
62
+ end
63
+ env.params = row[1]
64
+ env.definition = sql
65
+ env.function_type = function_type
66
+ end
67
+ end
68
+
69
+ return data.params, data.definition, data.function_type
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SchemaPlus::Functions
4
+ module ActiveRecord
5
+ module Migration
6
+ module CommandRecorder
7
+ def create_function(*args, &block)
8
+ record(:create_function, args, &block)
9
+ end
10
+
11
+ def drop_function(*args, &block)
12
+ record(:drop_function, args, &block)
13
+ end
14
+
15
+ def invert_create_function(args)
16
+ options = {}
17
+ options[:function_type] = args[3][:function_type] if args[3].has_key?(:function_type)
18
+ [:drop_function, [args.first, args.second, options]]
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SchemaPlus::Functions
4
+ module Middleware
5
+ module Dumper
6
+ module Tables
7
+ # Dump
8
+ def after(env)
9
+ env.connection.functions.each do |(function_name, params, _options)|
10
+ full_params, definition, function_type = env.connection.function_definition(function_name, params)
11
+ heredelim = "END_FUNCTION_#{function_name.upcase}"
12
+ extra_options = ", function_type: :#{function_type}" if function_type.present?
13
+ statement = <<~ENDFUNCTION
14
+ create_function "#{function_name}", "#{full_params}", <<-'#{heredelim}', :force => true#{extra_options}
15
+ #{definition}
16
+ #{heredelim}
17
+ ENDFUNCTION
18
+
19
+ env.dump.final << statement
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ module Schema
26
+ module Functions
27
+ ENV = [:connection, :query_name, :functions]
28
+ end
29
+
30
+ module FunctionDefinition
31
+ ENV = [:connection, :function_name, :params, :query_name, :definition, :function_type]
32
+ end
33
+ end
34
+
35
+ module Migration
36
+ module CreateFunction
37
+ ENV = [:connection, :function_name, :params, :definition, :options]
38
+ end
39
+
40
+ module DropFunction
41
+ ENV = [:connection, :function_name, :params, :options]
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SchemaPlus
4
+ module Functions
5
+ VERSION = "0.1.0"
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'schema_plus/functions'
@@ -0,0 +1,6 @@
1
+ ruby:
2
+ - 2.3.1
3
+ activerecord:
4
+ - 5.2
5
+ db:
6
+ - postgresql
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'schema_plus/functions/version'
6
+
7
+ Gem::Specification.new do |gem|
8
+ gem.name = "schema_plus_functions"
9
+ gem.version = SchemaPlus::Functions::VERSION
10
+ gem.authors = ["Edward Rudd"]
11
+ gem.email = ["urkle@outoforder.cc"]
12
+ gem.summary = %q{Adds support for functions in ActiveRecord}
13
+ gem.description = %q{Adds support for functions in ActiveRecord}
14
+ gem.homepage = "https://github.com/SchemaPlus/schema_plus_functions"
15
+ gem.license = "MIT"
16
+
17
+ gem.files = `git ls-files -z`.split("\x0")
18
+ gem.executables = gem.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
20
+ gem.require_paths = ["lib"]
21
+
22
+ gem.add_dependency "activerecord", ">= 5.2", "< 5.3"
23
+ gem.add_dependency "schema_plus_core"
24
+
25
+ gem.add_development_dependency "bundler"
26
+ gem.add_development_dependency "rake", "~> 10.0"
27
+ gem.add_development_dependency "rspec", "~> 3.0"
28
+ gem.add_development_dependency "schema_dev", "~> 3.11", ">= 3.11.1"
29
+ gem.add_development_dependency "simplecov"
30
+ gem.add_development_dependency "simplecov-gem-profile"
31
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe ActiveRecord::Migration do
6
+ it "creates the function definition for an aggregate function" do
7
+ apply_migration do
8
+ create_function :array_cat_agg, "anyarray", <<-END, function_type: :aggregate
9
+ (SFUNC=array_cat,STYPE=anyarray)
10
+ END
11
+ end
12
+
13
+ expect(functions).to include(['array_cat_agg', 'anyarray', {function_type: :aggregate}])
14
+ end
15
+
16
+ it "creates the function definition for a regular function" do
17
+ apply_migration do
18
+ create_function :test, "start date, stop date DEFAULT NULL::date", <<-END
19
+ RETURNS integer
20
+ LANGUAGE plpgsql
21
+ AS $$
22
+ DECLARE
23
+ processed INTEGER = 0;
24
+ BEGIN
25
+ processed = processed + 1;
26
+ RETURN processed;
27
+ END;
28
+ $$
29
+ END
30
+ end
31
+
32
+ expect(functions).to include(['test', 'start date, stop date', {}])
33
+ end
34
+
35
+ protected
36
+
37
+ def functions
38
+ ActiveRecord::Base.connection.functions
39
+ end
40
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'stringio'
5
+
6
+ describe "Schema dump" do
7
+ it "includes the function definition for an aggregate function" do
8
+ apply_migration do
9
+ create_function :array_cat_agg, "anyarray", <<-END, function_type: :aggregate
10
+ (SFUNC=array_cat,STYPE=anyarray)
11
+ END
12
+ end
13
+
14
+ expect(dump_schema).to match(%r{create_function.+array_cat_agg.+aggregate})
15
+ end
16
+
17
+ it "includes the function definition for a regular function" do
18
+ apply_migration do
19
+ create_function :test, "start date, stop date DEFAULT NULL::date", <<-END
20
+ RETURNS integer
21
+ LANGUAGE plpgsql
22
+ AS $$
23
+ DECLARE
24
+ processed INTEGER = 0;
25
+ BEGIN
26
+ processed = processed + 1;
27
+ RETURN processed;
28
+ END;
29
+ $$
30
+ END
31
+ end
32
+
33
+ expect(dump_schema).to match(%r{create_function.+test.+start date, stop date DEFAULT})
34
+ end
35
+
36
+ protected
37
+
38
+ def dump_schema(opts = {})
39
+ stream = StringIO.new
40
+
41
+ ActiveRecord::SchemaDumper.ignore_tables = Array.wrap(opts[:ignore]) || []
42
+ ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
43
+
44
+ stream.string
45
+ end
46
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'simplecov'
4
+ require 'simplecov-gem-profile'
5
+ SimpleCov.start "gem"
6
+
7
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
8
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
9
+
10
+ require 'rspec'
11
+ require 'active_record'
12
+ require 'schema_plus_functions'
13
+ require 'schema_dev/rspec'
14
+
15
+ SchemaDev::Rspec.setup
16
+
17
+ Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each { |f| require f }
18
+
19
+ RSpec.configure do |config|
20
+ config.warnings = true
21
+ config.around(:each) do |example|
22
+ ActiveRecord::Migration.suppress_messages do
23
+ begin
24
+ example.run
25
+ ensure
26
+ ActiveRecord::Base.connection.functions.each do |(func_name, params, options)|
27
+ ActiveRecord::Migration.drop_function func_name, params, options
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ def define_schema(config = {}, &block)
35
+ ActiveRecord::Migration.suppress_messages do
36
+ ActiveRecord::Schema.define do
37
+ ActiveRecord::Base.connection.functions.each do |(func_name, params, options)|
38
+ ActiveRecord::Migration.drop_function func_name, params, options
39
+ end
40
+ instance_eval &block
41
+ end
42
+ end
43
+ end
44
+
45
+ def apply_migration(config = {}, &block)
46
+ ActiveRecord::Schema.define do
47
+ instance_eval &block
48
+ end
49
+ end
50
+
51
+ SimpleCov.command_name "[ruby#{RUBY_VERSION}-activerecord#{::ActiveRecord.version}-#{ActiveRecord::Base.connection.adapter_name}]"
metadata ADDED
@@ -0,0 +1,191 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: schema_plus_functions
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Edward Rudd
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-08-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '5.2'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '5.3'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '5.2'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '5.3'
33
+ - !ruby/object:Gem::Dependency
34
+ name: schema_plus_core
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ - !ruby/object:Gem::Dependency
48
+ name: bundler
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ - !ruby/object:Gem::Dependency
62
+ name: rake
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '10.0'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '10.0'
75
+ - !ruby/object:Gem::Dependency
76
+ name: rspec
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '3.0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '3.0'
89
+ - !ruby/object:Gem::Dependency
90
+ name: schema_dev
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '3.11'
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: 3.11.1
99
+ type: :development
100
+ prerelease: false
101
+ version_requirements: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - "~>"
104
+ - !ruby/object:Gem::Version
105
+ version: '3.11'
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: 3.11.1
109
+ - !ruby/object:Gem::Dependency
110
+ name: simplecov
111
+ requirement: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ type: :development
117
+ prerelease: false
118
+ version_requirements: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: '0'
123
+ - !ruby/object:Gem::Dependency
124
+ name: simplecov-gem-profile
125
+ requirement: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ type: :development
131
+ prerelease: false
132
+ version_requirements: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ description: Adds support for functions in ActiveRecord
138
+ email:
139
+ - urkle@outoforder.cc
140
+ executables: []
141
+ extensions: []
142
+ extra_rdoc_files: []
143
+ files:
144
+ - ".gitignore"
145
+ - ".travis.yml"
146
+ - Gemfile
147
+ - LICENSE.txt
148
+ - README.md
149
+ - Rakefile
150
+ - gemfiles/Gemfile.base
151
+ - gemfiles/activerecord-5.2/Gemfile.base
152
+ - gemfiles/activerecord-5.2/Gemfile.postgresql
153
+ - lib/schema_plus/functions.rb
154
+ - lib/schema_plus/functions/active_record/connection_adapters/abstract_adapter.rb
155
+ - lib/schema_plus/functions/active_record/connection_adapters/postgresql_adapter.rb
156
+ - lib/schema_plus/functions/active_record/migration/command_recorder.rb
157
+ - lib/schema_plus/functions/middleware.rb
158
+ - lib/schema_plus/functions/version.rb
159
+ - lib/schema_plus_functions.rb
160
+ - schema_dev.yml
161
+ - schema_plus_functions.gemspec
162
+ - spec/migration_spec.rb
163
+ - spec/schema_dumper_spec.rb
164
+ - spec/spec_helper.rb
165
+ homepage: https://github.com/SchemaPlus/schema_plus_functions
166
+ licenses:
167
+ - MIT
168
+ metadata: {}
169
+ post_install_message:
170
+ rdoc_options: []
171
+ require_paths:
172
+ - lib
173
+ required_ruby_version: !ruby/object:Gem::Requirement
174
+ requirements:
175
+ - - ">="
176
+ - !ruby/object:Gem::Version
177
+ version: '0'
178
+ required_rubygems_version: !ruby/object:Gem::Requirement
179
+ requirements:
180
+ - - ">="
181
+ - !ruby/object:Gem::Version
182
+ version: '0'
183
+ requirements: []
184
+ rubygems_version: 3.0.6
185
+ signing_key:
186
+ specification_version: 4
187
+ summary: Adds support for functions in ActiveRecord
188
+ test_files:
189
+ - spec/migration_spec.rb
190
+ - spec/schema_dumper_spec.rb
191
+ - spec/spec_helper.rb