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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3687167aeee2a4c5247df316603b0395d041b26b
4
- data.tar.gz: f2709f263731b76b601a6a158c36fb64a00d1932
3
+ metadata.gz: c42f0a76b148c57bbe10c04654bbd6380cab657b
4
+ data.tar.gz: c653b58ffc9a847922c2b8b1e3d88463b9b46e84
5
5
  SHA512:
6
- metadata.gz: 97c5d6546a812e34a7b6fc4246f55e92b454f59f1f3b58dae49dba2aca0d24d22145002b8feb81d8e548fc0720efe8b52168ee07d430d4a94dd52f13c0c336fd
7
- data.tar.gz: 4644918b41c5aec118c84a26a5cca0a4d6a8bfbe102ef009a171854a1bebd86ca2aeda6f7194f6cce10c606824a2a7c8d3b317e61b4e40e6173646a4bac42705
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(::SqlQueryExecutor::Query::Base::STRING_SPACE, ' ')
23
+ value = @array.last.gsub(SqlQueryExecutor::Query::Base::STRING_SPACE, ' ')
20
24
 
21
25
  convert_value(value)
22
26
  end
@@ -18,6 +18,10 @@ module SqlQueryExecutor
18
18
  end
19
19
  end
20
20
 
21
+ def selector
22
+ { @field => { "$gte" => @value.first, "$lte" => @value.last }}
23
+ end
24
+
21
25
  private
22
26
  def get_value
23
27
  value = []
@@ -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
@@ -11,6 +11,10 @@ module SqlQueryExecutor
11
11
  end
12
12
  end
13
13
 
14
+ def selector
15
+ { @field => { "$in" => @value }}
16
+ end
17
+
14
18
  private
15
19
  def get_value
16
20
  value = super
@@ -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
- private
22
- def clean_query_attribute(query)
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 prepare_query(query)
74
- SubQuery::BINDING_OPERATORS.keys.each do |operator|
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 SqlQueryExecutor::Query::QueryNormalizer
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
- value = value.first.is_a?(Numeric) ? value : value.map{ |v| "'#{v}'" }
112
- query_array << "#{key} in (#{value.join(',')})"
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
- value = value.is_a?(Numeric) ? value : "'#{value}'"
115
- query_array << "#{key} = #{value}"
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 :query, :children, :kind
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 = ""
@@ -1,3 +1,3 @@
1
1
  module SqlQueryExecutor
2
- VERSION = "0.1.2"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -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.1.2
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-02-24 00:00:00.000000000 Z
11
+ date: 2014-03-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec