spare 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 +7 -0
- data/.gitignore +14 -0
- data/.rspec +2 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +22 -0
- data/README.md +31 -0
- data/Rakefile +2 -0
- data/lib/spare/attributes.rb +11 -0
- data/lib/spare/core.rb +17 -0
- data/lib/spare/model_schema.rb +24 -0
- data/lib/spare/mysql_abstract_adapter.rb +43 -0
- data/lib/spare/schema_cache.rb +12 -0
- data/lib/spare/stored_procedure.rb +91 -0
- data/lib/spare/version.rb +3 -0
- data/lib/spare.rb +10 -0
- data/spare.gemspec +30 -0
- data/spec/database.yml +16 -0
- data/spec/helpers/database_spec_helper.rb +100 -0
- data/spec/lib/base_spec.rb +5 -0
- data/spec/lib/spare/mysql_abstract_adapter_spec.rb +62 -0
- data/spec/lib/spare/stored_procedure_spec.rb +38 -0
- data/spec/spec_helper.rb +85 -0
- metadata +183 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 873733b8d4c0bd086905e31617ac095c57ac0812
|
4
|
+
data.tar.gz: b334da59cae6adcb6e0978129c40897ea40e9e41
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1d4308c1a397c3c162d3dbc2280b1835e9a9117c0a86ad18741253b41f43270b1d70143dcb07ca59dc4e5b1b8dd00e31d48bc0e893a2be295feaf0cc9a6c8cb7
|
7
|
+
data.tar.gz: cf3653c5db93a1f14cf8bcd1ba150c86b9bc9b139f65dd85642ddc541ccee9ac72d848ba69503e6eec5823cbe774b9055e96804b4a8e4fb044fee35e7833b75f
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Joshua Mckinney
|
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,31 @@
|
|
1
|
+
# Spare
|
2
|
+
|
3
|
+
Stored procedure models for ActiveRecord. I work in an environment where stored procedures are used extensively. Many of these stored procedures implement business rules for inserting records and quite a few parameters. I needed a better way to models is objects than the current MO which was to concatenate strings can call the `ActiveRecord::Base.connection.execute` directly. This a very early version and right now only supports Rails 3.2 with Mysql.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'spare'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install spare
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
TODO: Write usage instructions here
|
24
|
+
|
25
|
+
## Contributing
|
26
|
+
|
27
|
+
1. Fork it ( https://github.com/[my-github-username]/spare/fork )
|
28
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
29
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
30
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
31
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/lib/spare/core.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
module Spare
|
2
|
+
module Core
|
3
|
+
# Returns a string like 'MyStoredProcedure(p_id:integer, p_title:string, p_body:text)'
|
4
|
+
def inspect
|
5
|
+
if self == Base
|
6
|
+
super
|
7
|
+
elsif abstract_class?
|
8
|
+
super
|
9
|
+
elsif table_exists?
|
10
|
+
super
|
11
|
+
else
|
12
|
+
"#{name}(Stored procedure doesn't exist)"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
#########################
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Spare
|
2
|
+
module ModelSchema
|
3
|
+
|
4
|
+
def schema
|
5
|
+
table_name_prefix
|
6
|
+
end
|
7
|
+
|
8
|
+
def schema=schema
|
9
|
+
self.table_name_prefix = schema
|
10
|
+
end
|
11
|
+
|
12
|
+
def stored_procedure
|
13
|
+
connection.schema_cache.stored_procedure(self.stored_procedure_name)
|
14
|
+
end
|
15
|
+
|
16
|
+
def stored_procedure_name=stored_procedure_name
|
17
|
+
self.table_name=stored_procedure_name
|
18
|
+
end
|
19
|
+
|
20
|
+
def stored_procedure_name
|
21
|
+
table_name
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'active_record/connection_adapters/abstract_mysql_adapter'
|
2
|
+
module ActiveRecord
|
3
|
+
module ConnectionAdapters
|
4
|
+
class AbstractMysqlAdapter < AbstractAdapter
|
5
|
+
|
6
|
+
# Returns hash describing the stored procedure.
|
7
|
+
def stored_procedure(name)#:nodoc:
|
8
|
+
name = name.split('.').reverse
|
9
|
+
|
10
|
+
sql = "SELECT db,specific_name,param_list,db_collation FROM mysql.proc WHERE specific_name = #{quote(name[0])}"
|
11
|
+
sql << " AND db = #{quote(name[1])}" if name[1]
|
12
|
+
|
13
|
+
result = execute(sql)
|
14
|
+
keys = result.fields.collect{|k| k.to_sym}
|
15
|
+
values = result.to_a[0]
|
16
|
+
return nil unless values
|
17
|
+
sp = Hash[keys.zip(values)]
|
18
|
+
sp[:param_list] = stored_procedure_params(sp[:param_list], sp[:db_collation])
|
19
|
+
sp
|
20
|
+
end
|
21
|
+
|
22
|
+
# Consider adding the AbstractAdapter::Column when exploring postgres integration
|
23
|
+
class AbstractMysqlAdapter::Column
|
24
|
+
attr_accessor :param_type
|
25
|
+
end
|
26
|
+
|
27
|
+
def stored_procedure_params(param_list,collation)
|
28
|
+
params = []
|
29
|
+
param_list = param_list.to_s.split("\n").collect{ |r| r.gsub(/\s+/, ' ').strip.split(" ")}
|
30
|
+
param_list.delete([])
|
31
|
+
param_list.each do |param|
|
32
|
+
param_type = param[0].upcase
|
33
|
+
field_name = param[1].to_s.underscore #set_field_encoding(param[1])
|
34
|
+
sql_type = param[2]
|
35
|
+
column = new_column(field_name, nil, sql_type, false, collation)
|
36
|
+
column.param_type = param_type
|
37
|
+
params << column
|
38
|
+
end
|
39
|
+
params
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'active_record/connection_adapters/schema_cache'
|
2
|
+
module ActiveRecord
|
3
|
+
module ConnectionAdapters
|
4
|
+
class SchemaCache
|
5
|
+
# Get the stored procedure
|
6
|
+
def stored_procedure(sp_name)
|
7
|
+
@stored_procedure ||= {}
|
8
|
+
@stored_procedure[sp_name] ||= connection.stored_procedure(sp_name)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require "active_record"
|
2
|
+
require 'byebug'
|
3
|
+
module ActiveRecord
|
4
|
+
|
5
|
+
# TODO - Refactor using only those modules necessary for things to work, should
|
6
|
+
# be a lot easier when updated to support only Rails 4. Also, move any methods here
|
7
|
+
# to their own module
|
8
|
+
class StoredProcedure < Base
|
9
|
+
|
10
|
+
extend Spare::Core
|
11
|
+
extend Spare::ModelSchema
|
12
|
+
extend Spare::Attributes
|
13
|
+
|
14
|
+
self.pluralize_table_names = false # Stored procedure names are what they are.
|
15
|
+
self.abstract_class = true
|
16
|
+
|
17
|
+
attr_accessor :call_results
|
18
|
+
|
19
|
+
def in_params
|
20
|
+
@in_params ||= in_fetch_params
|
21
|
+
end
|
22
|
+
|
23
|
+
def in_fetch_params
|
24
|
+
prms = []
|
25
|
+
self.class.stored_procedure[:param_list].each do |param|
|
26
|
+
if param.param_type == "IN"
|
27
|
+
prms << self.class.connection.quote(self.send(param.name.to_sym))
|
28
|
+
else # OUT
|
29
|
+
prms << "@#{param.name}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
prms
|
33
|
+
end
|
34
|
+
|
35
|
+
def out_params
|
36
|
+
@out_params ||= self.class.stored_procedure[:param_list].select{|param| param.param_type.to_s =~ /out/i}
|
37
|
+
end
|
38
|
+
|
39
|
+
def inout_params
|
40
|
+
@inout_params ||= self.class.stored_procedure[:param_list].select{|param| param.param_type.to_s =~ /inout/i}
|
41
|
+
end
|
42
|
+
|
43
|
+
def out_sql
|
44
|
+
"SELECT #{out_params.collect{|param| "@#{param.name}"}.join(',')};"
|
45
|
+
end
|
46
|
+
|
47
|
+
# In MySQL even with multi-statements flag set variables must be set 1 at a time, so return an array
|
48
|
+
def inout_sql
|
49
|
+
sql = []
|
50
|
+
inout_params.each do |param|
|
51
|
+
sql << "SET @#{param.name} = #{connection.quote(send(param.name))}"
|
52
|
+
end
|
53
|
+
sql
|
54
|
+
end
|
55
|
+
|
56
|
+
def call_sql
|
57
|
+
"CALL #{self.class.stored_procedure[:db]}.#{self.class.stored_procedure[:specific_name]}(#{in_params.join(',')});"
|
58
|
+
end
|
59
|
+
|
60
|
+
def to_sql(skip_valid=false)
|
61
|
+
if skip_valid || valid?
|
62
|
+
# sql = (inout_sql.blank? ? "" : inout_sql)
|
63
|
+
sql = call_sql
|
64
|
+
sql << out_sql unless out_params.blank?
|
65
|
+
sql
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def execute
|
70
|
+
if valid?
|
71
|
+
conn = self.class.connection
|
72
|
+
unless inout_params.blank?
|
73
|
+
self.inout_sql.each do |inout_to_set|
|
74
|
+
conn.execute(inout_to_set)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
self.call_results = conn.execute(self.to_sql(true))
|
78
|
+
if out_params.length != 0
|
79
|
+
clnt = conn.instance_variable_get(:@connection)
|
80
|
+
while clnt.next_result
|
81
|
+
result_array = clnt.store_result.to_a[0]
|
82
|
+
out_params.each_with_index do |param,i|
|
83
|
+
send "#{param.name}=", result_array[i]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
valid?
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
data/lib/spare.rb
ADDED
data/spare.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'spare/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "spare"
|
8
|
+
spec.version = Spare::VERSION
|
9
|
+
spec.authors = ["Joshua Mckinney"]
|
10
|
+
spec.email = ["joshmckin@gmail.com"]
|
11
|
+
spec.summary = %q{StoredProcedure models for ActiveRecord.}
|
12
|
+
spec.description = %q{Provides stored procedure modeling for ruby applications that use ActiveRecord}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_runtime_dependency 'activerecord', '~> 3.2.0' #,'>= 3.0', '< 5.0'
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
24
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
25
|
+
spec.add_development_dependency "rspec"
|
26
|
+
spec.add_development_dependency "rspec-autotest"
|
27
|
+
spec.add_development_dependency "autotest"
|
28
|
+
spec.add_development_dependency "factory_girl"
|
29
|
+
spec.add_development_dependency "mysql2"
|
30
|
+
end
|
data/spec/database.yml
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# Warning: The database defined as "test" will be erased and
|
2
|
+
# re-generated from your development database when you run "rake".
|
3
|
+
# Do not set this db to the same as development or production.
|
4
|
+
common: &common
|
5
|
+
pool: 100
|
6
|
+
timeout: 5000
|
7
|
+
adapter: mysql2
|
8
|
+
reconnect: true
|
9
|
+
username: root
|
10
|
+
|
11
|
+
without_db:
|
12
|
+
<<: *common
|
13
|
+
|
14
|
+
test:
|
15
|
+
<<: *common
|
16
|
+
database: sp_test
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'active_record/connection_adapters/mysql2_adapter.rb'
|
2
|
+
module ActiveRecord
|
3
|
+
class Base
|
4
|
+
# Establishes a connection to the database that's used by all Active Record objects.
|
5
|
+
def self.mysql2_connection(config)
|
6
|
+
config[:username] = 'root' if config[:username].nil?
|
7
|
+
if Mysql2::Client.const_defined? :FOUND_ROWS
|
8
|
+
config[:flags] = Mysql2::Client::FOUND_ROWS | Mysql2::Client::MULTI_STATEMENTS
|
9
|
+
end
|
10
|
+
client = Mysql2::Client.new(config.symbolize_keys)
|
11
|
+
options = [config[:host], config[:username], config[:password], config[:database], config[:port], config[:socket], 0]
|
12
|
+
ConnectionAdapters::Mysql2Adapter.new(client, logger, options, config)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class TestDB
|
18
|
+
def self.yml
|
19
|
+
YAML::load(File.open(File.join(File.dirname(__FILE__),'..',"database.yml")))
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.connect(logging=false)
|
23
|
+
|
24
|
+
ActiveRecord::Base.configurations = yml
|
25
|
+
ActiveRecord::Base.establish_connection(:test)
|
26
|
+
ActiveRecord::Base.logger = Logger.new(STDOUT) if logging
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.clean
|
30
|
+
DBSpecManagement.connection.execute("DELETE FROM sp_test.foos")
|
31
|
+
end
|
32
|
+
|
33
|
+
#Class to clean tables
|
34
|
+
class DBSpecManagement < ActiveRecord::Base
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
#Put all the test migrations here
|
39
|
+
class TestMigrations < ActiveRecord::Migration
|
40
|
+
# all the ups
|
41
|
+
def self.up
|
42
|
+
ActiveRecord::Base.establish_connection(:without_db)
|
43
|
+
begin
|
44
|
+
ActiveRecord::Base.connection.execute("CREATE DATABASE IF NOT EXISTS sp_test;")
|
45
|
+
rescue => e
|
46
|
+
puts "Error creating database: #{e}"
|
47
|
+
end
|
48
|
+
|
49
|
+
ActiveRecord::Base.establish_connection(:test)
|
50
|
+
begin
|
51
|
+
create_table "foos" do |t|
|
52
|
+
t.string :name
|
53
|
+
t.decimal :bar
|
54
|
+
t.date :date
|
55
|
+
end
|
56
|
+
rescue => e
|
57
|
+
puts "tables failed to create: #{e}"
|
58
|
+
end
|
59
|
+
|
60
|
+
begin
|
61
|
+
conn = ActiveRecord::Base.connection
|
62
|
+
puts "Dropping \"sp_insert\""
|
63
|
+
conn.execute("DROP procedure IF EXISTS `sp_insert`;")
|
64
|
+
puts "Creating \"sp_insert\""
|
65
|
+
conn.execute(%q{CREATE PROCEDURE `sp_insert`(
|
66
|
+
IN p_name VARCHAR(255) ,
|
67
|
+
IN p_deci DECIMAL(10,2) ,
|
68
|
+
IN p_date DATE ,
|
69
|
+
OUT o_id INT,
|
70
|
+
INOUT in_out_add INT
|
71
|
+
)
|
72
|
+
BEGIN
|
73
|
+
SET in_out_add = in_out_add + 1;
|
74
|
+
INSERT INTO foos (
|
75
|
+
name,
|
76
|
+
bar,
|
77
|
+
date
|
78
|
+
)
|
79
|
+
VALUES (
|
80
|
+
p_name,
|
81
|
+
p_deci,
|
82
|
+
p_date
|
83
|
+
);
|
84
|
+
SET o_id = LAST_INSERT_ID();
|
85
|
+
END})
|
86
|
+
|
87
|
+
rescue => e
|
88
|
+
puts "sp failed to create: #{e}"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# all the downs
|
93
|
+
def self.down
|
94
|
+
begin
|
95
|
+
drop_table "sp_test.foos"
|
96
|
+
rescue => e
|
97
|
+
puts "tables were not dropped: sp_test"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
describe ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter do
|
3
|
+
|
4
|
+
describe '#stored_procedure' do
|
5
|
+
|
6
|
+
context "stored procedure does not exist" do
|
7
|
+
it {expect(ActiveRecord::Base.connection.stored_procedure("bad")).to be_nil}
|
8
|
+
end
|
9
|
+
|
10
|
+
context "stored procedure does exist" do
|
11
|
+
before(:each) do
|
12
|
+
conn = ActiveRecord::Base.connection
|
13
|
+
conn.execute("DROP procedure IF EXISTS `sp_test_adapter`;")
|
14
|
+
conn.execute(%q{CREATE PROCEDURE `sp_test_adapter`(
|
15
|
+
IN p_name VARCHAR(255) ,
|
16
|
+
IN p_bar DECIMAL(10,2) ,
|
17
|
+
IN p_other DATE ,
|
18
|
+
OUT results INT(11)
|
19
|
+
)
|
20
|
+
BEGIN
|
21
|
+
END})
|
22
|
+
end
|
23
|
+
context "called with the stored procedure's name" do
|
24
|
+
let (:sp) {ActiveRecord::Base.connection.stored_procedure("sp_test_adapter")}
|
25
|
+
it {expect(sp).to be_a(Hash)}
|
26
|
+
it {expect(sp[:param_list]).to be_a(Array)}
|
27
|
+
end
|
28
|
+
|
29
|
+
context "called the stored procedure and database name" do
|
30
|
+
let (:sp) {ActiveRecord::Base.connection.stored_procedure("sp_test.sp_test_adapter")}
|
31
|
+
it {expect(sp).to be_a(Hash)}
|
32
|
+
it {expect(sp[:param_list]).to be_a(Array)}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe '#stored_procedure_params' do
|
38
|
+
let (:sp_params) { %q{IN p_name VARCHAR(255) ,
|
39
|
+
IN p_bar DECIMAL(10,2) ,
|
40
|
+
IN p_other DATE ,
|
41
|
+
OUT results INT(11)}
|
42
|
+
}
|
43
|
+
let (:parsed_params) {ActiveRecord::Base.connection.stored_procedure_params(sp_params, 'utf8_general_ci')}
|
44
|
+
|
45
|
+
it {expect(parsed_params).to be_a(Array)}
|
46
|
+
it {expect(parsed_params.length).to eql(4)}
|
47
|
+
it {expect(parsed_params[0]).to be_a(ActiveRecord::ConnectionAdapters::Mysql2Adapter::Column)}
|
48
|
+
it {expect(parsed_params[0].collation).to eql('utf8_general_ci')}
|
49
|
+
it {expect(parsed_params[0].param_type).to eql('IN')}
|
50
|
+
it {expect(parsed_params[0].name).to eql('p_name')}
|
51
|
+
it {expect(parsed_params[0].type).to eql(:string)}
|
52
|
+
it {expect(parsed_params[1].param_type).to eql('IN')}
|
53
|
+
it {expect(parsed_params[1].name).to eql('p_bar')}
|
54
|
+
it {expect(parsed_params[1].type).to eql(:decimal)}
|
55
|
+
it {expect(parsed_params[2].param_type).to eql('IN')}
|
56
|
+
it {expect(parsed_params[2].name).to eql('p_other')}
|
57
|
+
it {expect(parsed_params[2].type).to eql(:date)}
|
58
|
+
it {expect(parsed_params[3].param_type).to eql('OUT')}
|
59
|
+
it {expect(parsed_params[3].name).to eql('results')}
|
60
|
+
it {expect(parsed_params[3].type).to eql(:integer)}
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class SpInsert < ActiveRecord::StoredProcedure;end
|
4
|
+
|
5
|
+
class Foo < ActiveRecord::Base;end
|
6
|
+
|
7
|
+
describe ActiveRecord::StoredProcedure do
|
8
|
+
it {expect(SpInsert.stored_procedure_name).to eql('sp_insert') }
|
9
|
+
|
10
|
+
context 'attributes' do
|
11
|
+
let(:sp_insert) {SpInsert.new}
|
12
|
+
|
13
|
+
it { expect(sp_insert).to respond_to(:p_name, :p_deci, :p_date, :o_id) }
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#execute' do
|
17
|
+
let (:sp_insert) {SpInsert.new(:p_name => "foo",:p_deci => 2.0, :p_date => Date.today, :in_out_add => 4)}
|
18
|
+
it {expect(sp_insert).to be_valid}
|
19
|
+
it {expect(sp_insert.execute).to eql(true)}
|
20
|
+
it "should work" do
|
21
|
+
expect {
|
22
|
+
sp_insert.execute
|
23
|
+
}.to change(Foo, :count).by(1)
|
24
|
+
end
|
25
|
+
context "out parameters" do
|
26
|
+
it "should work" do
|
27
|
+
sp_insert.execute
|
28
|
+
expect(sp_insert.o_id).to be_a(Fixnum)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
context "inout parameters" do
|
32
|
+
it "should work" do
|
33
|
+
sp_insert.execute
|
34
|
+
expect(sp_insert.in_out_add).to eql(5)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
ENV["AR_ENV"] = "test"
|
2
|
+
require 'spare'
|
3
|
+
require 'rspec'
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'active_record'
|
6
|
+
require 'logger'
|
7
|
+
require 'helpers/database_spec_helper'
|
8
|
+
|
9
|
+
TestDB.connect
|
10
|
+
TestMigrations.down
|
11
|
+
TestMigrations.up
|
12
|
+
|
13
|
+
RSpec.configure do |config|
|
14
|
+
# rspec-expectations config goes here. You can use an alternate
|
15
|
+
# assertion/expectation library such as wrong or the stdlib/minitest
|
16
|
+
# assertions if you prefer.
|
17
|
+
config.expect_with :rspec do |expectations|
|
18
|
+
# This option will default to `true` in RSpec 4. It makes the `description`
|
19
|
+
# and `failure_message` of custom matchers include text for helper methods
|
20
|
+
# defined using `chain`, e.g.:
|
21
|
+
# be_bigger_than(2).and_smaller_than(4).description
|
22
|
+
# # => "be bigger than 2 and smaller than 4"
|
23
|
+
# ...rather than:
|
24
|
+
# # => "be bigger than 2"
|
25
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
26
|
+
end
|
27
|
+
|
28
|
+
# rspec-mocks config goes here. You can use an alternate test double
|
29
|
+
# library (such as bogus or mocha) by changing the `mock_with` option here.
|
30
|
+
config.mock_with :rspec do |mocks|
|
31
|
+
# Prevents you from mocking or stubbing a method that does not exist on
|
32
|
+
# a real object. This is generally recommended, and will default to
|
33
|
+
# `true` in RSpec 4.
|
34
|
+
mocks.verify_partial_doubles = true
|
35
|
+
end
|
36
|
+
|
37
|
+
# The settings below are suggested to provide a good initial experience
|
38
|
+
# with RSpec, but feel free to customize to your heart's content.
|
39
|
+
=begin
|
40
|
+
# These two settings work together to allow you to limit a spec run
|
41
|
+
# to individual examples or groups you care about by tagging them with
|
42
|
+
# `:focus` metadata. When nothing is tagged with `:focus`, all examples
|
43
|
+
# get run.
|
44
|
+
config.filter_run :focus
|
45
|
+
config.run_all_when_everything_filtered = true
|
46
|
+
|
47
|
+
# Limits the available syntax to the non-monkey patched syntax that is recommended.
|
48
|
+
# For more details, see:
|
49
|
+
# - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
|
50
|
+
# - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
|
51
|
+
# - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
|
52
|
+
config.disable_monkey_patching!
|
53
|
+
|
54
|
+
# This setting enables warnings. It's recommended, but in some cases may
|
55
|
+
# be too noisy due to issues in dependencies.
|
56
|
+
config.warnings = true
|
57
|
+
|
58
|
+
# Many RSpec users commonly either run the entire suite or an individual
|
59
|
+
# file, and it's useful to allow more verbose output when running an
|
60
|
+
# individual spec file.
|
61
|
+
if config.files_to_run.one?
|
62
|
+
# Use the documentation formatter for detailed output,
|
63
|
+
# unless a formatter has already been configured
|
64
|
+
# (e.g. via a command-line flag).
|
65
|
+
config.default_formatter = 'doc'
|
66
|
+
end
|
67
|
+
|
68
|
+
# Print the 10 slowest examples and example groups at the
|
69
|
+
# end of the spec run, to help surface which specs are running
|
70
|
+
# particularly slow.
|
71
|
+
config.profile_examples = 10
|
72
|
+
|
73
|
+
# Run specs in random order to surface order dependencies. If you find an
|
74
|
+
# order dependency and want to debug it, you can fix the order by providing
|
75
|
+
# the seed, which is printed after each run.
|
76
|
+
# --seed 1234
|
77
|
+
config.order = :random
|
78
|
+
|
79
|
+
# Seed global randomization in this process using the `--seed` CLI option.
|
80
|
+
# Setting this allows you to use `--seed` to deterministically reproduce
|
81
|
+
# test failures related to randomization by passing the same `--seed` value
|
82
|
+
# as the one that triggered the failure.
|
83
|
+
Kernel.srand config.seed
|
84
|
+
=end
|
85
|
+
end
|
metadata
ADDED
@@ -0,0 +1,183 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: spare
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Joshua Mckinney
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-02-03 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: 3.2.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 3.2.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.7'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.7'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.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: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec-autotest
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: autotest
|
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: factory_girl
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: mysql2
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
description: Provides stored procedure modeling for ruby applications that use ActiveRecord
|
126
|
+
email:
|
127
|
+
- joshmckin@gmail.com
|
128
|
+
executables: []
|
129
|
+
extensions: []
|
130
|
+
extra_rdoc_files: []
|
131
|
+
files:
|
132
|
+
- ".gitignore"
|
133
|
+
- ".rspec"
|
134
|
+
- Gemfile
|
135
|
+
- LICENSE.txt
|
136
|
+
- README.md
|
137
|
+
- Rakefile
|
138
|
+
- lib/spare.rb
|
139
|
+
- lib/spare/attributes.rb
|
140
|
+
- lib/spare/core.rb
|
141
|
+
- lib/spare/model_schema.rb
|
142
|
+
- lib/spare/mysql_abstract_adapter.rb
|
143
|
+
- lib/spare/schema_cache.rb
|
144
|
+
- lib/spare/stored_procedure.rb
|
145
|
+
- lib/spare/version.rb
|
146
|
+
- spare.gemspec
|
147
|
+
- spec/database.yml
|
148
|
+
- spec/helpers/database_spec_helper.rb
|
149
|
+
- spec/lib/base_spec.rb
|
150
|
+
- spec/lib/spare/mysql_abstract_adapter_spec.rb
|
151
|
+
- spec/lib/spare/stored_procedure_spec.rb
|
152
|
+
- spec/spec_helper.rb
|
153
|
+
homepage: ''
|
154
|
+
licenses:
|
155
|
+
- MIT
|
156
|
+
metadata: {}
|
157
|
+
post_install_message:
|
158
|
+
rdoc_options: []
|
159
|
+
require_paths:
|
160
|
+
- lib
|
161
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
162
|
+
requirements:
|
163
|
+
- - ">="
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: '0'
|
166
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
167
|
+
requirements:
|
168
|
+
- - ">="
|
169
|
+
- !ruby/object:Gem::Version
|
170
|
+
version: '0'
|
171
|
+
requirements: []
|
172
|
+
rubyforge_project:
|
173
|
+
rubygems_version: 2.4.3
|
174
|
+
signing_key:
|
175
|
+
specification_version: 4
|
176
|
+
summary: StoredProcedure models for ActiveRecord.
|
177
|
+
test_files:
|
178
|
+
- spec/database.yml
|
179
|
+
- spec/helpers/database_spec_helper.rb
|
180
|
+
- spec/lib/base_spec.rb
|
181
|
+
- spec/lib/spare/mysql_abstract_adapter_spec.rb
|
182
|
+
- spec/lib/spare/stored_procedure_spec.rb
|
183
|
+
- spec/spec_helper.rb
|