sql_mapper 1.0.1 → 1.0.2
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.
- data/lib/sql_mapper.rb +80 -38
- metadata +1 -1
data/lib/sql_mapper.rb
CHANGED
@@ -3,11 +3,25 @@ require 'active_record'
|
|
3
3
|
|
4
4
|
module ActiveRecord
|
5
5
|
module SqlMapper
|
6
|
+
def self.config(&block)
|
7
|
+
Context.instance.instance_exec &block
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.fetch(opts={})
|
11
|
+
strategy = get_strategy_for(*sql_and_result_class_for(opts))
|
12
|
+
strategy.do_fetch
|
13
|
+
strategy.process_results
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.fetch_one(opts={})
|
17
|
+
fetch(opts)[0]
|
18
|
+
end
|
19
|
+
|
6
20
|
class Context
|
7
21
|
include Singleton
|
8
22
|
|
9
23
|
def initialize
|
10
|
-
@
|
24
|
+
@default_result_class = Struct
|
11
25
|
@queries = {}
|
12
26
|
end
|
13
27
|
|
@@ -15,14 +29,18 @@ module ActiveRecord
|
|
15
29
|
@queries.dup
|
16
30
|
end
|
17
31
|
|
32
|
+
def named_query_exists?(sym)
|
33
|
+
@queries.include? sym
|
34
|
+
end
|
35
|
+
|
18
36
|
def map(name, sql, result_class=nil)
|
19
37
|
mapping = QueryMapping.new name, sql, result_class
|
20
38
|
@queries[name] = mapping
|
21
39
|
end
|
22
40
|
|
23
41
|
def result_class(clazz=nil)
|
24
|
-
@
|
25
|
-
@
|
42
|
+
@default_result_class = clazz if not clazz.nil? and clazz.is_a? Class
|
43
|
+
@default_result_class
|
26
44
|
end
|
27
45
|
end
|
28
46
|
|
@@ -37,7 +55,7 @@ module ActiveRecord
|
|
37
55
|
end
|
38
56
|
end
|
39
57
|
|
40
|
-
class
|
58
|
+
class ObjectExecStrategy
|
41
59
|
def initialize(sql, result_class)
|
42
60
|
@sql = sql
|
43
61
|
@result_class = result_class
|
@@ -48,19 +66,32 @@ module ActiveRecord
|
|
48
66
|
end
|
49
67
|
|
50
68
|
def process_results
|
51
|
-
@raw_results.rows.map
|
69
|
+
@raw_results.rows.map &instantiate_result_using_row
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
def instantiate_result_using_row
|
74
|
+
lambda {|row| @result_class.new *row}
|
52
75
|
end
|
53
76
|
end
|
54
77
|
|
55
|
-
class StructExecStrategy <
|
78
|
+
class StructExecStrategy < ObjectExecStrategy
|
56
79
|
def initialize(sql, result_class)
|
57
80
|
super(sql, result_class)
|
58
81
|
end
|
59
82
|
|
60
83
|
def do_fetch
|
61
84
|
@raw_results = ActiveRecord::Base.connection.exec_query(@sql)
|
62
|
-
|
63
|
-
|
85
|
+
@result_class = create_struct_instance_from_col_names(@raw_results)
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
def create_struct_instance_from_col_names(raw_results)
|
90
|
+
Struct.new *extract_col_names_from(raw_results)
|
91
|
+
end
|
92
|
+
|
93
|
+
def extract_col_names_from(raw_results)
|
94
|
+
raw_results.columns.map{|c| c.to_sym}
|
64
95
|
end
|
65
96
|
end
|
66
97
|
|
@@ -86,54 +117,65 @@ module ActiveRecord
|
|
86
117
|
|
87
118
|
# Json execution strategy?
|
88
119
|
EXEC_STRATEGIES = {
|
89
|
-
:
|
120
|
+
:object => ObjectExecStrategy,
|
90
121
|
Struct => StructExecStrategy,
|
91
122
|
Hash => HashExecStrategy
|
92
123
|
}
|
93
124
|
|
94
|
-
|
95
|
-
|
125
|
+
private
|
126
|
+
def self.sql_and_result_class_for(opts={})
|
127
|
+
raise ":query option must be specified" if not opts.include? :query
|
128
|
+
sql, result_class = obtain_sql_and_result_class_for(opts[:query], opts[:result_class])
|
129
|
+
sql = inject_params_into(sql, opts[:params])
|
130
|
+
[sql, result_class]
|
96
131
|
end
|
97
132
|
|
98
|
-
def self.
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
133
|
+
def self.wrap_non_arrays_in_array(val)
|
134
|
+
if val.kind_of? Array
|
135
|
+
val
|
136
|
+
else
|
137
|
+
[val]
|
138
|
+
end
|
104
139
|
end
|
105
140
|
|
106
|
-
def self.
|
107
|
-
|
108
|
-
results[0]
|
141
|
+
def self.get_strategy_for(sql, result_class)
|
142
|
+
get_strategy_class_for(result_class).new(sql, result_class)
|
109
143
|
end
|
110
144
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
sql = opts[:query]
|
145
|
+
def self.get_strategy_class_for(result_class)
|
146
|
+
(EXEC_STRATEGIES[result_class] || EXEC_STRATEGIES[:object])
|
147
|
+
end
|
115
148
|
|
116
|
-
|
117
|
-
if
|
118
|
-
mapping = Context.instance.queries[
|
119
|
-
raise "No query named #{opts[:query]} found" if mapping.nil?
|
149
|
+
def self.obtain_sql_and_result_class_for(query, result_class)
|
150
|
+
if is_named_query(query)
|
151
|
+
mapping = Context.instance.queries[query]
|
120
152
|
sql = mapping.sql
|
121
|
-
result_class = mapping.result_class || result_class
|
153
|
+
result_class = result_class || mapping.result_class || Context.instance.result_class
|
154
|
+
else
|
155
|
+
sql = query
|
156
|
+
result_class = result_class || Context.instance.result_class
|
122
157
|
end
|
158
|
+
[sql, result_class]
|
159
|
+
end
|
123
160
|
|
124
|
-
|
125
|
-
|
126
|
-
|
161
|
+
def self.is_named_query(query)
|
162
|
+
result = false
|
163
|
+
if query.kind_of? Symbol
|
164
|
+
if Context.instance.named_query_exists?(query)
|
165
|
+
result = true
|
166
|
+
else
|
167
|
+
raise "No query named #{query} found"
|
168
|
+
end
|
127
169
|
end
|
128
|
-
|
170
|
+
result
|
129
171
|
end
|
130
172
|
|
131
|
-
def self.
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
[val]
|
173
|
+
def self.inject_params_into(sql, params)
|
174
|
+
unless params.nil?
|
175
|
+
sql_array = [sql] + wrap_non_arrays_in_array(params)
|
176
|
+
sql = ActiveRecord::Base.send :sanitize_sql_array, sql_array
|
136
177
|
end
|
178
|
+
sql
|
137
179
|
end
|
138
180
|
end
|
139
181
|
end
|