sql_query_executor 0.1.2 → 0.2.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 +4 -4
- data/lib/sql_query_executor/base.rb +2 -1
- data/lib/sql_query_executor/operators/base.rb +5 -1
- data/lib/sql_query_executor/operators/between.rb +4 -0
- data/lib/sql_query_executor/operators/default.rb +15 -0
- data/lib/sql_query_executor/operators/in.rb +4 -0
- data/lib/sql_query_executor/query/base.rb +4 -94
- data/lib/sql_query_executor/query/query_normalizer.rb +25 -6
- data/lib/sql_query_executor/query/sentence.rb +4 -6
- data/lib/sql_query_executor/query/sub_query.rb +20 -26
- data/lib/sql_query_executor/version.rb +1 -1
- data/spec/sql_query_executor/base_spec.rb +36 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c42f0a76b148c57bbe10c04654bbd6380cab657b
|
4
|
+
data.tar.gz: c653b58ffc9a847922c2b8b1e3d88463b9b46e84
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 48ef44419b5509ff76af6e617370350dbb7167892f0f85283d1cbd465b8349bff384319aced176870d8fbc4e42fa38ca83e8a5dc2568e2739d9170e150cd218a
|
7
|
+
data.tar.gz: 2000259b6d0931d496a8757c0f4619f185609f64d741a99d44d7451cc4a41f094a06bd2fe81334bf5cc73ec807ce79d1aedfc51e0fa07f15bb032f1ac5165089
|
@@ -18,7 +18,6 @@ module SqlQueryExecutor #:nodoc:
|
|
18
18
|
# Recursive method that divides the query in sub queries, executes each part individually
|
19
19
|
# and finally relates its results as specified in the query.
|
20
20
|
def where(*query)
|
21
|
-
raise ArgumentError.new("must pass at least one argument") if query.empty?
|
22
21
|
query = query.first if query.respond_to?(:size) && query.size == 1
|
23
22
|
|
24
23
|
message = check_query(query)
|
@@ -42,6 +41,8 @@ module SqlQueryExecutor #:nodoc:
|
|
42
41
|
end
|
43
42
|
|
44
43
|
def check_query(query)
|
44
|
+
return "must pass at least one argument" if query.empty?
|
45
|
+
|
45
46
|
if query.is_a?(Array) && !query.first.is_a?(String)
|
46
47
|
"First element from array must be a String. eg: [\"name = ?\", \"John\"]"
|
47
48
|
end
|
@@ -10,13 +10,17 @@ module SqlQueryExecutor
|
|
10
10
|
@value = get_value
|
11
11
|
end
|
12
12
|
|
13
|
+
def selector
|
14
|
+
{ @field => @value }
|
15
|
+
end
|
16
|
+
|
13
17
|
protected
|
14
18
|
def get_field
|
15
19
|
@array.first
|
16
20
|
end
|
17
21
|
|
18
22
|
def get_value
|
19
|
-
value = @array.last.gsub(
|
23
|
+
value = @array.last.gsub(SqlQueryExecutor::Query::Base::STRING_SPACE, ' ')
|
20
24
|
|
21
25
|
convert_value(value)
|
22
26
|
end
|
@@ -3,6 +3,15 @@ require 'sql_query_executor/operators/base'
|
|
3
3
|
module SqlQueryExecutor
|
4
4
|
module Operators
|
5
5
|
class Default < SqlQueryExecutor::Operators::Base
|
6
|
+
SELECTORS = {
|
7
|
+
"==" => nil,
|
8
|
+
">" => "$gt",
|
9
|
+
"<" => "$lt",
|
10
|
+
">=" => "$gte",
|
11
|
+
"<=" => "$lte",
|
12
|
+
"!=" => "$ne"
|
13
|
+
}
|
14
|
+
|
6
15
|
def initialize(query, collection)
|
7
16
|
super
|
8
17
|
convert_operator
|
@@ -16,6 +25,12 @@ module SqlQueryExecutor
|
|
16
25
|
end
|
17
26
|
end
|
18
27
|
|
28
|
+
def selector
|
29
|
+
operator = SELECTORS[@operator]
|
30
|
+
|
31
|
+
{ @field.to_sym => operator ? {operator => @value} : @value}
|
32
|
+
end
|
33
|
+
|
19
34
|
private
|
20
35
|
def convert_operator
|
21
36
|
@operator = @operator == "=" ? "==" : @operator
|
@@ -3,8 +3,6 @@ require 'sql_query_executor/query/query_normalizer'
|
|
3
3
|
module SqlQueryExecutor
|
4
4
|
module Query
|
5
5
|
class Base
|
6
|
-
attr_reader :query
|
7
|
-
|
8
6
|
STRING_SPACE = "$SS$"
|
9
7
|
QUERY_SPACE = "$QS$"
|
10
8
|
TEMP_SPACE = "$TS$"
|
@@ -18,100 +16,12 @@ module SqlQueryExecutor
|
|
18
16
|
@query.execute!
|
19
17
|
end
|
20
18
|
|
21
|
-
|
22
|
-
|
23
|
-
return query unless query.is_a?(Array)
|
24
|
-
|
25
|
-
query = query.flatten
|
26
|
-
|
27
|
-
query.size == 1 ? query.first : query
|
28
|
-
end
|
29
|
-
|
30
|
-
def get_query(query)
|
31
|
-
query
|
32
|
-
end
|
33
|
-
|
34
|
-
# Prepares query by replacing all ? by it's real values in #args
|
35
|
-
def interpolate_query(args)
|
36
|
-
args.flatten!
|
37
|
-
return args.first if args.size == 1 && args.first.is_a?(String)
|
38
|
-
|
39
|
-
query = args.first
|
40
|
-
param = args.delete_at(1)
|
41
|
-
|
42
|
-
param = convert_param(param)
|
43
|
-
|
44
|
-
args[0] = query.sub("?", param.is_a?(Numeric) ? param : "#{param}")
|
45
|
-
|
46
|
-
interpolate_query(args)
|
47
|
-
end
|
48
|
-
|
49
|
-
# Removes all accents and other non default characters
|
50
|
-
def sanitize(query)
|
51
|
-
new_query = replace_on_query(query, /(["|'].*?["|'])/, " ", STRING_SPACE)
|
52
|
-
new_query = replace_on_query(new_query, /(\(.*?\))/, " ", QUERY_SPACE)
|
53
|
-
|
54
|
-
remove_spaces(prepare_query(new_query))
|
55
|
-
end
|
56
|
-
|
57
|
-
def replace_on_query(query, regexp, pattern, replacement)
|
58
|
-
new_query = query ? query.dup : query
|
59
|
-
|
60
|
-
params = new_query.scan(regexp).flatten.compact
|
61
|
-
|
62
|
-
params.each do |param|
|
63
|
-
new_param = param.dup
|
64
|
-
|
65
|
-
new_param = new_param.gsub(pattern, replacement)
|
66
|
-
|
67
|
-
new_query = new_query.gsub(param, new_param)
|
68
|
-
end
|
69
|
-
|
70
|
-
new_query
|
19
|
+
def to_sql
|
20
|
+
@query.to_sql
|
71
21
|
end
|
72
22
|
|
73
|
-
def
|
74
|
-
|
75
|
-
query.gsub!(" #{operator} ", "#{TEMP_SPACE}#{operator}#{QUERY_SPACE}")
|
76
|
-
end
|
77
|
-
|
78
|
-
query.gsub(" ", QUERY_SPACE).gsub(TEMP_SPACE, " ")
|
79
|
-
end
|
80
|
-
|
81
|
-
def remove_spaces(query)
|
82
|
-
query.gsub!(/\[.*?\]/) { |substr| substr.gsub(' ', '') }
|
83
|
-
query
|
84
|
-
end
|
85
|
-
|
86
|
-
# Returns converted #param based on its Class, so it can be used on the query
|
87
|
-
def convert_param(param)
|
88
|
-
case param.class.name
|
89
|
-
when "String"
|
90
|
-
param = "'#{param}'"
|
91
|
-
when "Date"
|
92
|
-
param = "'#{param.strftime("%Y-%m-%d")}'"
|
93
|
-
when "Time"
|
94
|
-
param = "'#{param.strftime("%Y-%m-%d %H:%M:%S %z")}'"
|
95
|
-
else
|
96
|
-
param = param.to_s
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
def concatenate_hash(query)
|
101
|
-
return "" unless query.is_a?(Hash)
|
102
|
-
query_array = []
|
103
|
-
|
104
|
-
query.each do |key, value|
|
105
|
-
if value.is_a?(Array)
|
106
|
-
value = value.first.is_a?(Numeric) ? value : value.map{ |v| "'#{v}'" }
|
107
|
-
query_array << "#{key} in (#{value.join(',')})"
|
108
|
-
else
|
109
|
-
value = value.is_a?(Numeric) ? value : "'#{value}'"
|
110
|
-
query_array << "#{key} = #{value}"
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
query_array.join(" and ")
|
23
|
+
def selector
|
24
|
+
@query.selector
|
115
25
|
end
|
116
26
|
end
|
117
27
|
end
|
@@ -2,7 +2,7 @@ require 'sql_query_executor'
|
|
2
2
|
|
3
3
|
module SqlQueryExecutor
|
4
4
|
module Query
|
5
|
-
class
|
5
|
+
class QueryNormalizer
|
6
6
|
class << self
|
7
7
|
CONVERT_METHODS = {"String" => ["get_query", ""], "Array" => ["interpolate_query", "query.flatten"], "Hash" => ["concatenate_hash", "query"]}
|
8
8
|
|
@@ -92,7 +92,7 @@ module SqlQueryExecutor
|
|
92
92
|
def convert_param(param)
|
93
93
|
case param.class.name
|
94
94
|
when "String"
|
95
|
-
param = "'#{param}'"
|
95
|
+
param = "'#{param}'".gsub("''", "'").gsub('""', '"')
|
96
96
|
when "Date"
|
97
97
|
param = "'#{param.strftime("%Y-%m-%d")}'"
|
98
98
|
when "Time"
|
@@ -105,14 +105,33 @@ module SqlQueryExecutor
|
|
105
105
|
def concatenate_hash(query)
|
106
106
|
return "" unless query.is_a?(Hash)
|
107
107
|
query_array = []
|
108
|
+
operators = {"$gt" => '>', "$lt" => '<', "$gte" => '>=', "$lte" => '<=', "$ne" => '!=', "$in" => 'in'}
|
108
109
|
|
109
110
|
query.each do |key, value|
|
110
111
|
if value.is_a?(Array)
|
111
|
-
|
112
|
-
|
112
|
+
if [:and, :or].include?(key)
|
113
|
+
queries = []
|
114
|
+
|
115
|
+
value.each do |hash|
|
116
|
+
queries << concatenate_hash(hash)
|
117
|
+
end
|
118
|
+
|
119
|
+
query_array << queries.join(" #{key.to_s} ")
|
120
|
+
else
|
121
|
+
value = value.first.is_a?(Numeric) ? value : value.map{ |v| "'#{v}'" }
|
122
|
+
query_array << "#{key} in (#{value.join(',')})"
|
123
|
+
end
|
113
124
|
else
|
114
|
-
|
115
|
-
|
125
|
+
operator = '='
|
126
|
+
|
127
|
+
if value.is_a?(Hash)
|
128
|
+
operator = operators[value.keys.first] || operator
|
129
|
+
|
130
|
+
value = convert_param(value.values.first)
|
131
|
+
end
|
132
|
+
|
133
|
+
value = "#{convert_param(value)}"
|
134
|
+
query_array << "#{key} #{operator} #{value}"
|
116
135
|
end
|
117
136
|
end
|
118
137
|
|
@@ -37,18 +37,16 @@ module SqlQueryExecutor
|
|
37
37
|
@operator.execute!(data)
|
38
38
|
end
|
39
39
|
|
40
|
+
def selector
|
41
|
+
@operator.selector
|
42
|
+
end
|
43
|
+
|
40
44
|
private
|
41
45
|
def set_operator
|
42
46
|
operator = OPERATORS[@query.split(' ')[1]]
|
43
47
|
|
44
48
|
@operator = operator ? operator.new(@query, @collection) : nil
|
45
49
|
end
|
46
|
-
|
47
|
-
def fix_query
|
48
|
-
@array.delete_at(0)
|
49
|
-
|
50
|
-
@query = @array.join(' ')
|
51
|
-
end
|
52
50
|
end
|
53
51
|
end
|
54
52
|
end
|
@@ -4,7 +4,7 @@ module SqlQueryExecutor
|
|
4
4
|
module Query
|
5
5
|
class SubQuery
|
6
6
|
BINDING_OPERATORS = { "or" => "+", "and" => "&" }
|
7
|
-
attr_reader :
|
7
|
+
attr_reader :children, :kind, :binding_operator
|
8
8
|
ADD_CHILDREN_METHODS = { sentence: :add_sentence_children, sub_query: :add_sub_query_children }
|
9
9
|
def initialize(query, collection)
|
10
10
|
@collection = collection
|
@@ -29,6 +29,25 @@ module SqlQueryExecutor
|
|
29
29
|
result.sort_by(&:id)
|
30
30
|
end
|
31
31
|
|
32
|
+
def selector
|
33
|
+
hash = {}
|
34
|
+
|
35
|
+
@children.each do |child|
|
36
|
+
if child.respond_to?(:binding_operator) && child.binding_operator
|
37
|
+
operator = BINDING_OPERATORS.invert[child.binding_operator]
|
38
|
+
hash = {operator.to_sym => [hash,child.selector]}
|
39
|
+
else
|
40
|
+
hash.merge!(child.selector)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
hash
|
45
|
+
end
|
46
|
+
|
47
|
+
def to_sql
|
48
|
+
QueryNormalizer.clean_query(@query)
|
49
|
+
end
|
50
|
+
|
32
51
|
private
|
33
52
|
def set_binding_operator
|
34
53
|
@binding_operator = nil
|
@@ -77,31 +96,6 @@ module SqlQueryExecutor
|
|
77
96
|
array.size <= 5
|
78
97
|
end
|
79
98
|
|
80
|
-
def build_sub_query(query)
|
81
|
-
array = query.split(" ")
|
82
|
-
|
83
|
-
offset = is_binding_operator?(array.first) ? 1 : 0
|
84
|
-
operator = array[1+offset]
|
85
|
-
|
86
|
-
result = case operator
|
87
|
-
when "between"
|
88
|
-
array[0..4+offset]
|
89
|
-
when "is"
|
90
|
-
size = array[2+offset] == "not" ? 3 : 2
|
91
|
-
array[0..size+offset]
|
92
|
-
when "not"
|
93
|
-
array[0..3+offset]
|
94
|
-
else
|
95
|
-
array[0..2+offset]
|
96
|
-
end
|
97
|
-
|
98
|
-
result.join(' ')
|
99
|
-
end
|
100
|
-
|
101
|
-
def is_binding_operator?(operator)
|
102
|
-
BINDING_OPERATORS.include?(operator)
|
103
|
-
end
|
104
|
-
|
105
99
|
def replace_parentheses(query)
|
106
100
|
count = 1
|
107
101
|
string = ""
|
@@ -15,6 +15,42 @@ describe SqlQueryExecutor, "Base" do
|
|
15
15
|
|
16
16
|
subject { SqlQueryExecutor::Base.new(@data) }
|
17
17
|
|
18
|
+
describe "initialize" do
|
19
|
+
before do
|
20
|
+
class Model
|
21
|
+
attr_reader :attributes
|
22
|
+
|
23
|
+
def initialize(attributes)
|
24
|
+
@attributes = attributes
|
25
|
+
end
|
26
|
+
|
27
|
+
def id
|
28
|
+
@attributes[:id]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class Collection
|
33
|
+
def initialize(collection)
|
34
|
+
@collection = []
|
35
|
+
|
36
|
+
collection.each do |hash|
|
37
|
+
@collection << Model.new(hash)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def all
|
42
|
+
@collection
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
subject { SqlQueryExecutor::Base.new(Collection.new(@data).all) }
|
48
|
+
|
49
|
+
it 'initializes with a conforming collection' do
|
50
|
+
expect(subject.where(id: 1).first.attributes).to eq (@data.first)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
18
54
|
describe ".where" do
|
19
55
|
context "when invalid query is passed" do
|
20
56
|
it "raises an ArgumentError" do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sql_query_executor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Caio Torres
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-03-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|