spare 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 95b4a7463baf2b1727fa3a4d7cef198dbab3eb62
4
- data.tar.gz: aa448ecb6a763756efdaa0285f7ac897b1b838c8
3
+ metadata.gz: eebcabc4cfa5cc1016e4792fcb33d1d3ad3f8ecc
4
+ data.tar.gz: dd194a9dcb89d2b274f3bbe511d0545ff25320c9
5
5
  SHA512:
6
- metadata.gz: 253b3557cbf75fd7679dc9a0e37f90e549cba3e96812ddd771db46b57ac937052c6118da53224f84704a19c465cd3a49b21ed3a28f79b9b3b2fcd07b1974479f
7
- data.tar.gz: 1a1ebe0650e871f944e1b103ad5ec459d84d9a976d837143d8ea57121f7c71de288db778b975ca6a6818094814b161fbb701830735e255a9fbe3d0f9b8871080
6
+ metadata.gz: 01199811e2ceb6df16f47ee095bc9786a7d02a65172ff4f68fbbb3ed299467f1050a2a6a9976e3a153112b9de11fd2208d32a46dfa01d117995ed0f7a27643b5
7
+ data.tar.gz: 33888abe01749bd5b32c951f8e66eb7b1d5b63477417509ae41eedc0d7e643eb6bceedb1979caf4457344e57868d8d867de74c99f32c464330fc678eeed61275
@@ -1,4 +1,5 @@
1
1
  require 'active_record'
2
2
  module ActiveRecord
3
3
  class StoredProcedureNotFound < StandardError; end
4
+ class StoredProcedureNotExecuted < RecordNotSaved;end
4
5
  end
@@ -0,0 +1,62 @@
1
+ module Spare
2
+ module Execution
3
+ module ClassMethods
4
+ # Build an object (or multiple objects) and executes, if validations pass.
5
+ # The resulting object is returned whether the object was executed successfully to the database or not.
6
+ #
7
+ # The +attributes+ parameter can be either a Hash or an Array of Hashes. These Hashes describe the
8
+ # attributes on the objects that are to be created.
9
+ def execute(attributes = nil)
10
+ if attributes.is_a?(Array)
11
+ attributes.map { |attr| excute(attr) }
12
+ else
13
+ object = new(attributes)
14
+ object.execute
15
+ object
16
+ end
17
+ end
18
+ alias :call :execute
19
+
20
+ # Build an object (or multiple objects) and executes,
21
+ # if validations pass. Raises a RecordInvalid error if validations fail,
22
+ # unlike Base#create.
23
+ #
24
+ # The +attributes+ parameter can be either a Hash or an Array of Hashes.
25
+ # These describe which attributes to be created on the object, or
26
+ # multiple objects when given an Array of Hashes.
27
+ def execute!(attributes = nil)
28
+ if attributes.is_a?(Array)
29
+ attributes.collect { |attr| create!(attr) }
30
+ else
31
+ object = new(attributes)
32
+ object.execute!
33
+ object
34
+ end
35
+ end
36
+ alias :call! :execute!
37
+ end
38
+
39
+ attr_accessor :call_results
40
+
41
+ def execute
42
+ if valid?
43
+ self.class.connection_pool.with_connection do |conn|
44
+ call_results = conn.execute_stored_procedure(self)
45
+ end
46
+ end
47
+ valid?
48
+ end
49
+ alias :call :execute
50
+
51
+ def execute!
52
+ unless valid?
53
+ raise(ActiveRecord::StoredProcedureNotExecuted.new("Failed to execute the stored procedure", self))
54
+ end
55
+ end
56
+ alias :call! :execute!
57
+
58
+ def self.included(base)
59
+ base.extend(Spare::Execution::ClassMethods)
60
+ end
61
+ end
62
+ end
@@ -44,12 +44,79 @@ module ActiveRecord
44
44
  else
45
45
  column = new_column(field_name, nil, sql_type, false, collation)
46
46
  end
47
-
47
+
48
48
  column.param_type = param_type
49
49
  params << column
50
50
  end
51
51
  params
52
52
  end
53
+
54
+ def stored_procedure_to_sql(sp)
55
+ sql = []
56
+ sql << sp_inout_sql(sp)
57
+ sql << sp_call_sql(sp)
58
+ sql << sp_out_sql(sp)
59
+ sql.compact!
60
+ sql.join("\n")
61
+ end
62
+
63
+ def execute_stored_procedure(sp)
64
+
65
+ call_results = execute(stored_procedure_to_sql(sp))
66
+
67
+ if sp_out_params(sp).length != 0
68
+ clnt = instance_variable_get(:@connection)
69
+ while clnt.next_result
70
+ if result_array = clnt.store_result.to_a[0]
71
+ sp_out_params(sp).each_with_index do |param,i|
72
+ sp.__send__ "#{param.name}=", result_array[i]
73
+ end
74
+ end
75
+ end
76
+ nil
77
+ else
78
+ call_results
79
+ end
80
+ end
81
+
82
+ private
83
+
84
+ def sp_in_params(sp)
85
+ prms = []
86
+ sp.class.stored_procedure[:param_list].each do |param|
87
+ if param.param_type == "IN"
88
+ prms << quote(sp.read_attribute(param.name))
89
+ else # OUT
90
+ prms << "@#{param.name}"
91
+ end
92
+ end
93
+ prms
94
+ end
95
+
96
+ def sp_out_params(sp)
97
+ sp.class.stored_procedure[:param_list].select { |param| param.param_type.to_s =~ /out/i }
98
+ end
99
+
100
+ def sp_inout_params(sp)
101
+ sp.class.stored_procedure[:param_list].select { |param| param.param_type.to_s =~ /inout/i }
102
+ end
103
+
104
+ def sp_out_sql(sp)
105
+ "SELECT #{sp_out_params(sp).collect{|param| "@#{param.name}"}.join(',')};"
106
+ end
107
+
108
+ # In MySQL even with multi-statements flag set, variables must be set 1 at a time, so return an array
109
+ def sp_inout_sql(sp)
110
+ sql = []
111
+ sp_inout_params(sp).each do |param|
112
+ sql << "SET @#{param.name} = #{quote(sp.send(param.name))};"
113
+ end
114
+ sql
115
+ end
116
+
117
+ def sp_call_sql(sp)
118
+ "CALL #{sp.class.stored_procedure[:db]}.#{sp.class.stored_procedure[:specific_name]}(#{sp_in_params(sp).join(',')});"
119
+ end
53
120
  end
54
121
  end
55
122
  end
@@ -2,89 +2,24 @@ require "active_record"
2
2
  module ActiveRecord
3
3
 
4
4
  # TODO - Refactor using only those modules necessary for things to work, should
5
- # be a lot easier when updated to support only Rails 4. Also, move any methods here
5
+ # be a lot easier when updated to support only Rails 4. Also, move any methods here
6
6
  # to their own module
7
7
  class StoredProcedure < Base
8
8
 
9
9
  extend Spare::Core
10
10
  extend Spare::ModelSchema
11
11
  extend Spare::Attributes
12
+ include Spare::Execution
12
13
 
13
14
  self.pluralize_table_names = false # Stored procedure names are what they are.
14
15
  self.abstract_class = true
15
16
 
16
17
  attr_accessor :call_results
17
18
 
18
- def in_params
19
- @in_params ||= in_fetch_params
20
- end
21
-
22
- def in_fetch_params
23
- prms = []
24
- self.class.stored_procedure[:param_list].each do |param|
25
- if param.param_type == "IN"
26
- prms << self.class.connection.quote(self.send(param.name.to_sym))
27
- else # OUT
28
- prms << "@#{param.name}"
29
- end
30
- end
31
- prms
32
- end
33
-
34
- def out_params
35
- @out_params ||= self.class.stored_procedure[:param_list].select{|param| param.param_type.to_s =~ /out/i}
36
- end
37
-
38
- def inout_params
39
- @inout_params ||= self.class.stored_procedure[:param_list].select{|param| param.param_type.to_s =~ /inout/i}
40
- end
41
-
42
- def out_sql
43
- "SELECT #{out_params.collect{|param| "@#{param.name}"}.join(',')};"
44
- end
45
-
46
- # In MySQL even with multi-statements flag set variables must be set 1 at a time, so return an array
47
- def inout_sql
48
- sql = []
49
- inout_params.each do |param|
50
- sql << "SET @#{param.name} = #{self.class.connection.quote(send(param.name))}"
51
- end
52
- sql
53
- end
54
-
55
- def call_sql
56
- "CALL #{self.class.stored_procedure[:db]}.#{self.class.stored_procedure[:specific_name]}(#{in_params.join(',')});"
57
- end
58
-
59
19
  def to_sql(skip_valid=false)
60
20
  if skip_valid || valid?
61
- # sql = (inout_sql.blank? ? "" : inout_sql)
62
- sql = call_sql
63
- sql << out_sql unless out_params.blank?
64
- sql
65
- end
66
- end
67
-
68
- def execute
69
- if valid?
70
- conn = self.class.connection
71
- unless inout_params.blank?
72
- self.inout_sql.each do |inout_to_set|
73
- conn.execute(inout_to_set)
74
- end
75
- end
76
- self.call_results = conn.execute(self.to_sql(true))
77
- if out_params.length != 0
78
- clnt = conn.instance_variable_get(:@connection)
79
- while clnt.next_result
80
- result_array = clnt.store_result.to_a[0]
81
- out_params.each_with_index do |param,i|
82
- send "#{param.name}=", result_array[i]
83
- end
84
- end
85
- end
21
+ self.class.connection.stored_procedure_to_sql(self)
86
22
  end
87
- valid?
88
23
  end
89
24
  end
90
25
  end
data/lib/spare/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Spare
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.5"
3
3
  end
data/lib/spare.rb CHANGED
@@ -5,6 +5,7 @@ require "spare/attributes"
5
5
  require "spare/mysql_abstract_adapter"
6
6
  require "spare/model_schema"
7
7
  require "spare/schema_cache"
8
+ require "spare/execution"
8
9
  require "spare/stored_procedure"
9
10
 
10
11
  module Spare
@@ -21,13 +21,13 @@ describe ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter do
21
21
  END})
22
22
  end
23
23
  context "called with the stored procedure's name" do
24
- let (:sp) {ActiveRecord::Base.connection.stored_procedure("sp_test_adapter")}
24
+ let (:sp) { ActiveRecord::Base.connection.stored_procedure("sp_test_adapter") }
25
25
  it {expect(sp).to be_a(Hash)}
26
26
  it {expect(sp[:param_list]).to be_a(Array)}
27
27
  end
28
28
 
29
29
  context "called the stored procedure and database name" do
30
- let (:sp) {ActiveRecord::Base.connection.stored_procedure("sp_test.sp_test_adapter")}
30
+ let (:sp) { ActiveRecord::Base.connection.stored_procedure("sp_test.sp_test_adapter") }
31
31
  it {expect(sp).to be_a(Hash)}
32
32
  it {expect(sp[:param_list]).to be_a(Array)}
33
33
  end
@@ -35,12 +35,13 @@ describe ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter do
35
35
  end
36
36
 
37
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')}
38
+ let (:sp_params) do
39
+ %q{IN p_name VARCHAR(255) ,
40
+ IN p_bar DECIMAL(10,2) ,
41
+ IN p_other DATE ,
42
+ OUT results INT(11)}
43
+ end
44
+ let (:parsed_params) { ActiveRecord::Base.connection.stored_procedure_params(sp_params, 'utf8_general_ci') }
44
45
 
45
46
  it {expect(parsed_params).to be_a(Array)}
46
47
  it {expect(parsed_params.length).to eql(4)}
@@ -1,6 +1,8 @@
1
1
  require 'spec_helper'
2
2
  require 'byebug'
3
- class SpInsert < ActiveRecord::StoredProcedure;end
3
+ class SpInsert < ActiveRecord::StoredProcedure
4
+ validates :p_name, presence: true
5
+ end
4
6
 
5
7
  class Foo < ActiveRecord::Base;end
6
8
 
@@ -14,20 +16,25 @@ describe ActiveRecord::StoredProcedure do
14
16
  end
15
17
 
16
18
  describe '#execute' do
17
- let (:sp_insert) {SpInsert.new(:p_name => "foo",:p_deci => 2.0, :p_date => Date.today, :in_out_add => 4)}
19
+ let (:sp_insert) { SpInsert.new(:p_name => "foo",:p_deci => 2.0, :p_date => Date.today, :in_out_add => 4) }
20
+
18
21
  it { expect(sp_insert).to be_valid}
22
+
19
23
  it { expect(sp_insert.execute).to eql(true) }
24
+
20
25
  it "should work" do
21
26
  expect {
22
27
  sp_insert.execute
23
28
  }.to change(Foo, :count).by(1)
24
29
  end
30
+
25
31
  context "out parameters" do
26
32
  it "should work" do
27
33
  sp_insert.execute
28
34
  expect(sp_insert.o_id).to be_a(Fixnum)
29
35
  end
30
36
  end
37
+
31
38
  context "inout parameters" do
32
39
  it "should work" do
33
40
  sp_insert.execute
@@ -35,4 +42,36 @@ describe ActiveRecord::StoredProcedure do
35
42
  end
36
43
  end
37
44
  end
45
+
46
+ context "class methods" do
47
+ context "#execute" do
48
+ it "should work" do
49
+ expect {
50
+ SpInsert.execute(:p_name => "foo",:p_deci => 2.0, :p_date => Date.today, :in_out_add => 4)
51
+ }.to change(Foo, :count).by(1)
52
+ end
53
+
54
+ context "out parameters" do
55
+ it "should work" do
56
+ sp = SpInsert.execute(:p_name => "foo",:p_deci => 2.0, :p_date => Date.today, :in_out_add => 4)
57
+ expect(sp.o_id).to be_a(Fixnum)
58
+ end
59
+ end
60
+
61
+ context "inout parameters" do
62
+ it "should work" do
63
+ sp = SpInsert.execute(:p_name => "foo",:p_deci => 2.0, :p_date => Date.today, :in_out_add => 4)
64
+ expect(sp.in_out_add).to eql(5)
65
+ end
66
+ end
67
+ end
68
+
69
+ context "#execute!" do
70
+ context "not valid" do
71
+ it "should work" do
72
+ expect { SpInsert.execute! }.to raise_error(ActiveRecord::StoredProcedureNotExecuted)
73
+ end
74
+ end
75
+ end
76
+ end
38
77
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spare
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joshua Mckinney
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-03-11 00:00:00.000000000 Z
11
+ date: 2016-08-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -117,6 +117,7 @@ files:
117
117
  - lib/spare/attributes.rb
118
118
  - lib/spare/core.rb
119
119
  - lib/spare/exceptions.rb
120
+ - lib/spare/execution.rb
120
121
  - lib/spare/model_schema.rb
121
122
  - lib/spare/mysql_abstract_adapter.rb
122
123
  - lib/spare/schema_cache.rb
@@ -149,7 +150,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
149
150
  version: '0'
150
151
  requirements: []
151
152
  rubyforge_project:
152
- rubygems_version: 2.5.1
153
+ rubygems_version: 2.6.4
153
154
  signing_key:
154
155
  specification_version: 4
155
156
  summary: StoredProcedure models for ActiveRecord.