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.
- checksums.yaml +7 -0
- data/.gitignore +7 -0
- data/.travis.yml +16 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +22 -0
- data/README.md +142 -0
- data/Rakefile +11 -0
- data/gemfiles/Gemfile.base +4 -0
- data/gemfiles/activerecord-5.2/Gemfile.base +3 -0
- data/gemfiles/activerecord-5.2/Gemfile.postgresql +10 -0
- data/lib/schema_plus/functions.rb +18 -0
- data/lib/schema_plus/functions/active_record/connection_adapters/abstract_adapter.rb +72 -0
- data/lib/schema_plus/functions/active_record/connection_adapters/postgresql_adapter.rb +75 -0
- data/lib/schema_plus/functions/active_record/migration/command_recorder.rb +23 -0
- data/lib/schema_plus/functions/middleware.rb +45 -0
- data/lib/schema_plus/functions/version.rb +7 -0
- data/lib/schema_plus_functions.rb +3 -0
- data/schema_dev.yml +6 -0
- data/schema_plus_functions.gemspec +31 -0
- data/spec/migration_spec.rb +40 -0
- data/spec/schema_dumper_spec.rb +46 -0
- data/spec/spec_helper.rb +51 -0
- metadata +191 -0
checksums.yaml
ADDED
@@ -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
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
@@ -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
data/LICENSE.txt
ADDED
@@ -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.
|
data/README.md
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
[](http://badge.fury.io/rb/schema_plus_functions)
|
2
|
+
[](http://travis-ci.org/SchemaPlus/schema_plus_functions)
|
3
|
+
[](https://coveralls.io/r/SchemaPlus/schema_plus_functions)
|
4
|
+
[](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 -->
|
data/Rakefile
ADDED
@@ -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
|
data/schema_dev.yml
ADDED
@@ -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
|
data/spec/spec_helper.rb
ADDED
@@ -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
|