sql_mapper 1.0.1 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|