dm-persevere-adapter 0.52.1 → 0.60.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/Rakefile +4 -14
- data/VERSION +1 -1
- data/lib/dm/associations/many_to_many.rb +270 -0
- data/lib/dm/model.rb +48 -0
- data/lib/dm/property.rb +19 -0
- data/lib/dm/query.rb +166 -0
- data/lib/dm/resource.rb +97 -0
- data/lib/persevere.rb +0 -1
- data/lib/persevere_adapter.rb +189 -233
- data/spec/persevere_adapter_spec.rb +448 -404
- data/tasks/{spec.rb → spec.rake} +0 -0
- metadata +10 -9
- data/lib/model_json_support.rb +0 -53
- data/lib/types/json_reference.rb +0 -53
- data/lib/types/json_reference_collection.rb +0 -80
- data/lib/types/property.rb +0 -22
data/.gitignore
CHANGED
data/Rakefile
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'rubygems'
|
2
|
+
require 'rake'
|
2
3
|
require 'pathname'
|
3
4
|
|
4
5
|
begin
|
@@ -14,18 +15,9 @@ begin
|
|
14
15
|
gemspec.add_dependency(%q<dm-core>, [">= 0.10.1"])
|
15
16
|
gemspec.add_dependency(%q<extlib>)
|
16
17
|
end
|
17
|
-
|
18
|
-
# gemspec.name = %q{persevere}
|
19
|
-
# gemspec.summary = %q{A ruby wrapper for persevere}
|
20
|
-
# gemspec.description = %q{A ruby wrapper for persevere}
|
21
|
-
# gemspec.email = ["irjudson [a] gmail [d] com"]
|
22
|
-
# gemspec.homepage = %q{http://github.com/yogo/persevere}
|
23
|
-
# gemspec.authors = ["Ivan R. Judson", "The Yogo Data Management Development Team" ]
|
24
|
-
# gemspec.rdoc_options = ["--main", "persevere/README.txt"]
|
25
|
-
# gemspec.files = ["LICENSE.txt", "persevere/History.txt", "persevere/README.txt", "Rakefile", "lib/persevere.rb"]
|
26
|
-
# gemspec.test_files = ["spec/persevere_spec.rb", "spec/spec.opts", "spec/spec_helper.rb"]
|
27
|
-
# end
|
18
|
+
|
28
19
|
Jeweler::GemcutterTasks.new
|
20
|
+
FileList['tasks/**/*.rake'].each { |task| import task }
|
29
21
|
rescue LoadError
|
30
22
|
puts "Jeweler not available. Install it with: gem install jeweler"
|
31
23
|
end
|
@@ -33,6 +25,4 @@ end
|
|
33
25
|
ROOT = Pathname(__FILE__).dirname.expand_path
|
34
26
|
JRUBY = RUBY_PLATFORM =~ /java/
|
35
27
|
WINDOWS = Gem.win_platform?
|
36
|
-
SUDO = (WINDOWS || JRUBY) ? '' : ('sudo' unless ENV['SUDOLESS'])
|
37
|
-
|
38
|
-
Pathname.glob(ROOT.join('tasks/**/*.rb').to_s).each { |f| require f }
|
28
|
+
SUDO = (WINDOWS || JRUBY) ? '' : ('sudo' unless ENV['SUDOLESS'])
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.60.0
|
@@ -0,0 +1,270 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module Associations
|
3
|
+
module ManyToMany #:nodoc:
|
4
|
+
class Relationship < Associations::OneToMany::Relationship
|
5
|
+
|
6
|
+
OPTIONS.delete(:via)
|
7
|
+
OPTIONS.delete(:through)
|
8
|
+
|
9
|
+
remove_method :through
|
10
|
+
remove_method :via
|
11
|
+
remove_method :lazy_load
|
12
|
+
remove_method :source_scope
|
13
|
+
remove_method :inverted_options
|
14
|
+
remove_method :valid_target?
|
15
|
+
remove_method :valid_source?
|
16
|
+
|
17
|
+
#
|
18
|
+
# @api private
|
19
|
+
def query
|
20
|
+
@query
|
21
|
+
end
|
22
|
+
|
23
|
+
def set(source, target)
|
24
|
+
assert_kind_of 'source', source, source_model
|
25
|
+
assert_kind_of 'target', target, target_model
|
26
|
+
lazy_load(source) unless loaded?(source)
|
27
|
+
get!(source).replace([target])
|
28
|
+
end
|
29
|
+
|
30
|
+
# Loads association targets and sets resulting value on
|
31
|
+
# given source resource
|
32
|
+
#
|
33
|
+
# @param [Resource] source
|
34
|
+
# the source resource for the association
|
35
|
+
#
|
36
|
+
# @return [undefined]
|
37
|
+
#
|
38
|
+
# @api private
|
39
|
+
def lazy_load(source)
|
40
|
+
|
41
|
+
# SEL: load all related resources in the source collection
|
42
|
+
collection = source.collection
|
43
|
+
# if source.saved? && collection.size > 1 #OLD LINE --IRJ
|
44
|
+
if source.saved?
|
45
|
+
eager_load(collection)
|
46
|
+
end
|
47
|
+
|
48
|
+
unless loaded?(source)
|
49
|
+
set!(source, collection_for(source))
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Eager load the collection using the source as a base
|
54
|
+
#
|
55
|
+
# @param [Collection] source
|
56
|
+
# the source collection to query with
|
57
|
+
# @param [Query, Hash] query
|
58
|
+
# optional query to restrict the collection
|
59
|
+
#
|
60
|
+
# @return [Collection]
|
61
|
+
# the loaded collection for the source
|
62
|
+
#
|
63
|
+
# @api private
|
64
|
+
def eager_load(source, query = nil)
|
65
|
+
|
66
|
+
targets = source.model.all(query_for(source, query))
|
67
|
+
|
68
|
+
# FIXME: cannot associate targets to m:m collection yet, maybe we fixed it.
|
69
|
+
# if source.loaded? && !source.kind_of?(ManyToMany::Collection) WE CHANGED THIS: IRJ/RL
|
70
|
+
if source.loaded?
|
71
|
+
associate_targets(source, targets)
|
72
|
+
end
|
73
|
+
|
74
|
+
targets
|
75
|
+
end
|
76
|
+
|
77
|
+
def associate_targets(source, targets)
|
78
|
+
# TODO: create an object that wraps this logic, and when the first
|
79
|
+
# kicker is fired, then it'll load up the collection, and then
|
80
|
+
# populate all the other methods
|
81
|
+
target_maps = Hash.new { |hash, key| hash[key] = [] }
|
82
|
+
|
83
|
+
targets.each do |target|
|
84
|
+
target_maps[target_key.get(target)] << target
|
85
|
+
end
|
86
|
+
|
87
|
+
Array(source).each do |source|
|
88
|
+
key = source_key.get(source)
|
89
|
+
# eager_load_targets(source, target_maps[key], query)
|
90
|
+
|
91
|
+
set!(source, collection_for(source, query).set(targets))
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
# Returns the inverse relationship class
|
98
|
+
#
|
99
|
+
# @api private
|
100
|
+
def inverse_class
|
101
|
+
self.class
|
102
|
+
end
|
103
|
+
|
104
|
+
def inverse_name
|
105
|
+
Extlib::Inflection.underscore(Extlib::Inflection.demodulize(source_model.name)).pluralize.to_sym
|
106
|
+
end
|
107
|
+
|
108
|
+
# @api private
|
109
|
+
def invert
|
110
|
+
inverse_class.new(inverse_name, parent_model, child_model, inverted_options)
|
111
|
+
end
|
112
|
+
|
113
|
+
# @api semipublic
|
114
|
+
def initialize(name, target_model, source_model, options = {})
|
115
|
+
options.delete(:through)
|
116
|
+
super
|
117
|
+
end
|
118
|
+
|
119
|
+
# Returns collection class used by this type of
|
120
|
+
# relationship
|
121
|
+
#
|
122
|
+
# @api private
|
123
|
+
def collection_class
|
124
|
+
ManyToMany::Collection
|
125
|
+
end
|
126
|
+
end # class Relationship
|
127
|
+
|
128
|
+
class Collection < Associations::OneToMany::Collection
|
129
|
+
remove_method :_save
|
130
|
+
remove_method :_create
|
131
|
+
|
132
|
+
def inverse_add(*resources)
|
133
|
+
resources.each do |r|
|
134
|
+
r.send(relationship.inverse.name)._original_add(source)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
alias :_original_add :"<<"
|
139
|
+
def <<(resource)
|
140
|
+
resource.send(relationship.inverse.name)._original_add(source)
|
141
|
+
_original_add(resource)
|
142
|
+
end
|
143
|
+
|
144
|
+
alias :_original_concat :concat
|
145
|
+
def concat(resources)
|
146
|
+
inverse_add(*resources)
|
147
|
+
_original_concat(resources)
|
148
|
+
end
|
149
|
+
|
150
|
+
alias :_original_push :push
|
151
|
+
def push(*resources)
|
152
|
+
inverse_add(*resources)
|
153
|
+
_original_push(*resources)
|
154
|
+
end
|
155
|
+
|
156
|
+
|
157
|
+
alias :_original_unshift :unshift
|
158
|
+
def unshift(*resources)
|
159
|
+
inverse_add(*resources)
|
160
|
+
_original_unshift(*resources)
|
161
|
+
end
|
162
|
+
|
163
|
+
alias :_original_insert :insert
|
164
|
+
def insert(offset, *resources)
|
165
|
+
inverse_add(*resources)
|
166
|
+
_original_insert(offset, *resources)
|
167
|
+
end
|
168
|
+
|
169
|
+
alias :_original_delete :delete
|
170
|
+
def delete(resource)
|
171
|
+
result = _original_delete(resource)
|
172
|
+
resource.send(relationship.inverse.name)._original_delete(source)
|
173
|
+
result
|
174
|
+
end
|
175
|
+
|
176
|
+
alias :_original_pop :pop
|
177
|
+
def pop(*)
|
178
|
+
removed = _original_pop
|
179
|
+
removed._original_delete(source) unless removed.nil?
|
180
|
+
removed
|
181
|
+
end
|
182
|
+
|
183
|
+
alias :_original_shift :shift
|
184
|
+
def shift(*)
|
185
|
+
removed = _original_pop
|
186
|
+
removed._original_delete(source) unless removed.nil?
|
187
|
+
removed
|
188
|
+
end
|
189
|
+
|
190
|
+
alias :_original_delete_at :delete_at
|
191
|
+
def delete_at(offset)
|
192
|
+
resource = _original_delete_at(offset)
|
193
|
+
resource._original_delete(source) unless removed.nil?
|
194
|
+
resource
|
195
|
+
end
|
196
|
+
|
197
|
+
# alias :_original_delete_if :delete_if
|
198
|
+
def delete_if
|
199
|
+
results = super { |resource| yield(resource) && resource_removed(resource) }
|
200
|
+
results.each{|r| r._original_delete(source) }
|
201
|
+
results
|
202
|
+
end
|
203
|
+
|
204
|
+
def reject!
|
205
|
+
results = super { |resource| yield(resource) && resource_removed(resource) }
|
206
|
+
results.each{|r| r._original_delete(source) }
|
207
|
+
results
|
208
|
+
end
|
209
|
+
|
210
|
+
def replace(other)
|
211
|
+
other = resources_added(other)
|
212
|
+
removed = entries - other
|
213
|
+
new_resources = other - removed
|
214
|
+
resources_removed(removed)
|
215
|
+
removed.each{|r| r._original_delete(source) }
|
216
|
+
new_resources.each{|r| r._original_add(source) }
|
217
|
+
super(other)
|
218
|
+
end
|
219
|
+
|
220
|
+
alias :_original_clear :clear
|
221
|
+
def clear
|
222
|
+
self.each{|r| r._original_delete(source) }
|
223
|
+
_original_clear
|
224
|
+
end
|
225
|
+
|
226
|
+
# TODO: Add these
|
227
|
+
# slice!, splice, collect!
|
228
|
+
|
229
|
+
def _save(safe)
|
230
|
+
loaded_entries = self.loaded_entries
|
231
|
+
@removed.clear
|
232
|
+
loaded_entries.all? { |resource| resource.__send__(safe ? :save : :save!) }
|
233
|
+
end
|
234
|
+
|
235
|
+
private
|
236
|
+
|
237
|
+
# Track the added resource
|
238
|
+
#
|
239
|
+
# @param [Resource] resource
|
240
|
+
# the resource that was added
|
241
|
+
#
|
242
|
+
# @return [Resource]
|
243
|
+
# the resource that was added
|
244
|
+
#
|
245
|
+
# @api private
|
246
|
+
def resource_added(resource)
|
247
|
+
resource = initialize_resource(resource)
|
248
|
+
|
249
|
+
if resource.saved?
|
250
|
+
@identity_map[resource.key] = resource
|
251
|
+
@removed.delete(resource)
|
252
|
+
else
|
253
|
+
resource.save
|
254
|
+
end
|
255
|
+
resource
|
256
|
+
end
|
257
|
+
|
258
|
+
# @api private
|
259
|
+
def resource_removed(resource)
|
260
|
+
if resource.saved?
|
261
|
+
@identity_map.delete(resource.key)
|
262
|
+
@removed << resource
|
263
|
+
end
|
264
|
+
|
265
|
+
resource
|
266
|
+
end
|
267
|
+
end # class Collection
|
268
|
+
end # module ManyToMany
|
269
|
+
end # module Associations
|
270
|
+
end # module DataMapper
|
data/lib/dm/model.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module Model
|
3
|
+
# module Json
|
4
|
+
def to_json_schema(repository_name = default_repository_name)
|
5
|
+
to_json_schema_hash(repository_name).to_json
|
6
|
+
end
|
7
|
+
|
8
|
+
#TODO: Add various options in.
|
9
|
+
def to_json_schema_hash(repository_name = default_repository_name)
|
10
|
+
schema_hash = {
|
11
|
+
'id' => self.storage_name(repository_name),
|
12
|
+
'prototype' => Hash.new,
|
13
|
+
'properties' => Hash.new
|
14
|
+
}
|
15
|
+
|
16
|
+
# Handle properties
|
17
|
+
properties.select { |prop| prop.field != 'id' }.each do |prop|
|
18
|
+
schema_hash['properties'][prop.field] = prop.to_json_schema_hash(repository_name)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Handle relationships
|
22
|
+
relationships.each_pair do |nom,relation|
|
23
|
+
next if self.name.downcase == nom
|
24
|
+
child = relation.child_model
|
25
|
+
parent = relation.parent_model
|
26
|
+
|
27
|
+
case relation
|
28
|
+
when DataMapper::Associations::OneToMany::Relationship, DataMapper::Associations::ManyToMany::Relationship
|
29
|
+
schema_hash['properties'][nom] = { "type" => "array",
|
30
|
+
"optional" => true,
|
31
|
+
"items" => {"$ref" => "../#{child.storage_name}"},
|
32
|
+
"minItems" => relation.min,
|
33
|
+
}
|
34
|
+
|
35
|
+
schema_hash['properties'][nom]["maxItems"] = relation.max if relation.max != Infinity
|
36
|
+
when DataMapper::Associations::ManyToOne::Relationship, DataMapper::Associations::OneToOne::Relationship
|
37
|
+
if self == relation.child_model
|
38
|
+
ref = "../#{parent.storage_name}"
|
39
|
+
else
|
40
|
+
ref = "../#{child.storage_name}"
|
41
|
+
end
|
42
|
+
schema_hash['properties'][nom] = { "type" => { "$ref" => ref }, "optional" => true }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
return schema_hash
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/dm/property.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
module DataMapper
|
2
|
+
class Property
|
3
|
+
|
4
|
+
def to_json_schema_hash(repo)
|
5
|
+
tm = repository(repo).adapter.type_map
|
6
|
+
json_hash = Hash.new
|
7
|
+
json_hash = { "type" => tm[type][:primitive] }
|
8
|
+
json_hash.merge!({ "optional" => true }) unless required?
|
9
|
+
json_hash.merge!({ "unique" => true}) if unique?
|
10
|
+
json_hash.merge!({ "position" => @position }) unless @position.nil?
|
11
|
+
json_hash.merge!({ "prefix" => @prefix }) unless @prefix.nil?
|
12
|
+
json_hash.merge!({ "separator" => @separator }) unless @separator.nil?
|
13
|
+
json_hash.merge!( tm[type].reject{ |key,value| key == :primitive } )
|
14
|
+
|
15
|
+
json_hash
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
data/lib/dm/query.rb
ADDED
@@ -0,0 +1,166 @@
|
|
1
|
+
module DataMapper
|
2
|
+
class Query
|
3
|
+
##
|
4
|
+
def munge_condition(condition)
|
5
|
+
loaded_value = condition.loaded_value
|
6
|
+
return_value = ""
|
7
|
+
|
8
|
+
if condition.subject.is_a?(DataMapper::Property)
|
9
|
+
rhs = case loaded_value
|
10
|
+
when String then "\"#{loaded_value}\""
|
11
|
+
when DateTime then "date(%10.f)" % (Time.parse(loaded_value.to_s).to_f * 1000)
|
12
|
+
when nil then "undefined"
|
13
|
+
else loaded_value
|
14
|
+
end
|
15
|
+
return_value = "#{condition.subject.field}#{condition.__send__(:comparator_string)}#{rhs}"
|
16
|
+
end
|
17
|
+
|
18
|
+
return_value = _fugly_munger(condition, loaded_value) if condition.subject.is_a?(DataMapper::Associations::Relationship)
|
19
|
+
return_value
|
20
|
+
end
|
21
|
+
|
22
|
+
def _fugly_munger(condition, loaded_value)
|
23
|
+
subject = condition.subject
|
24
|
+
case subject
|
25
|
+
when DataMapper::Associations::ManyToMany::Relationship then
|
26
|
+
return_value = "#{condition.subject.field}.contains(/#{subject.child_model.storage_name}/#{loaded_value.key.first})"
|
27
|
+
when DataMapper::Associations::OneToMany::Relationship then
|
28
|
+
return_value = "#{condition.subject.field}.contains(/#{subject.parent_model.storage_name}/#{loaded_value.key.first})"
|
29
|
+
when DataMapper::Associations::OneToOne::Relationship then
|
30
|
+
return_value = "#{condition.subject.field}#{condition.__send__(:comparator_string)}/#{subject.parent_model.storage_name}/#{loaded_value.key.first}"
|
31
|
+
when DataMapper::Associations::ManyToOne::Relationship then
|
32
|
+
if self.model != subject.child_model
|
33
|
+
return_value = "#{condition.subject.field}.contains(/#{subject.parent_model.storage_name}/#{loaded_value.key.first})"
|
34
|
+
else
|
35
|
+
return_value = "#{condition.subject.field}#{condition.__send__(:comparator_string)}/#{subject.parent_model.storage_name}/#{loaded_value.key.first}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
##
|
41
|
+
def process_condition(condition)
|
42
|
+
case condition
|
43
|
+
# Persevere 1.0 regular expressions are disable for security so we pass them back for DataMapper query filtering
|
44
|
+
# without regular expressions, the like operator is inordinately challenging hence we pass it back
|
45
|
+
# when :regexp then "RegExp(\"#{condition.value.source}\").test(#{condition.subject.name})"
|
46
|
+
when DataMapper::Query::Conditions::RegexpComparison then []
|
47
|
+
when DataMapper::Query::Conditions::LikeComparison then "#{condition.subject.field}='#{condition.loaded_value.gsub('%', '*')}'"
|
48
|
+
when DataMapper::Query::Conditions::AndOperation then
|
49
|
+
inside = condition.operands.map { |op| process_condition(op) }.flatten
|
50
|
+
inside.empty? ? [] : "(#{inside.join("&")})"
|
51
|
+
when DataMapper::Query::Conditions::OrOperation then "(#{condition.operands.map { |op| process_condition(op) }.join("|")})"
|
52
|
+
when DataMapper::Query::Conditions::NotOperation then
|
53
|
+
inside = process_condition(condition.operand)
|
54
|
+
inside.empty? ? [] : "!(%s)" % inside
|
55
|
+
when DataMapper::Query::Conditions::InclusionComparison then
|
56
|
+
result_string = Array.new
|
57
|
+
condition.value.to_a.each do |candidate|
|
58
|
+
if condition.subject.is_a?(DataMapper::Associations::Relationship)
|
59
|
+
# debugger
|
60
|
+
result_string << _fugly_munger(condition, candidate)
|
61
|
+
else
|
62
|
+
result_string << "#{condition.subject.name}=#{candidate}"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
if result_string.length > 0
|
66
|
+
"(#{result_string.join("|")})"
|
67
|
+
else
|
68
|
+
"#{condition.subject.name}=''"
|
69
|
+
end
|
70
|
+
when DataMapper::Query::Conditions::EqualToComparison,
|
71
|
+
DataMapper::Query::Conditions::GreaterThanComparison,
|
72
|
+
DataMapper::Query::Conditions::LessThanComparison,
|
73
|
+
DataMapper::Query::Conditions::GreaterThanOrEqualToComparison,
|
74
|
+
DataMapper::Query::Conditions::LessThanOrEqualToComparison then
|
75
|
+
munge_condition(condition)
|
76
|
+
when DataMapper::Query::Conditions::NullOperation then []
|
77
|
+
when Array then
|
78
|
+
old_statement, bind_values = condition
|
79
|
+
statement = old_statement.dup
|
80
|
+
bind_values.each{ |bind_value| statement.sub!('?', bind_value.to_s) }
|
81
|
+
statement.gsub(' ', '')
|
82
|
+
else condition.to_s.gsub(' ', '')
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
##
|
87
|
+
# Convert a DataMapper Query to a JSON Query.
|
88
|
+
#
|
89
|
+
# @param [Query] query
|
90
|
+
# The DataMapper query object passed in
|
91
|
+
#
|
92
|
+
# @api semipublic
|
93
|
+
def to_json_query
|
94
|
+
|
95
|
+
# Body of main function
|
96
|
+
json_query = ""
|
97
|
+
query_terms = Array.new
|
98
|
+
order_operations = Array.new
|
99
|
+
field_ops = Array.new
|
100
|
+
outfields = Array.new
|
101
|
+
headers = Hash.new
|
102
|
+
|
103
|
+
query_terms << process_condition(conditions)
|
104
|
+
|
105
|
+
if query_terms.flatten.length != 0
|
106
|
+
json_query += "[?#{query_terms.join("][?")}]"
|
107
|
+
end
|
108
|
+
|
109
|
+
self.fields.each do |field|
|
110
|
+
if field.respond_to?(:operator)
|
111
|
+
field_ops << case field.operator
|
112
|
+
when :count then
|
113
|
+
if field.target.is_a?(DataMapper::Property)
|
114
|
+
"[?#{field.target.field}!=undefined].length"
|
115
|
+
else # field.target is all.
|
116
|
+
".length"
|
117
|
+
end
|
118
|
+
when :min
|
119
|
+
if field.target.type == DateTime || field.target.type == Time || field.target.type == Date
|
120
|
+
"[=#{field.target.field}]"
|
121
|
+
else
|
122
|
+
".min(?#{field.target.field})"
|
123
|
+
end
|
124
|
+
when :max
|
125
|
+
if field.target.type == DateTime || field.target.type == Time || field.target.type == Date
|
126
|
+
"[=#{field.target.field}]"
|
127
|
+
else
|
128
|
+
".max(?#{field.target.field})"
|
129
|
+
end
|
130
|
+
when :sum
|
131
|
+
".sum(?#{field.target.field})"
|
132
|
+
when :avg
|
133
|
+
"[=#{field.target.field}]"
|
134
|
+
end
|
135
|
+
else
|
136
|
+
outfields << "'#{field.field}':#{field.field}"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
json_query += field_ops.join("")
|
141
|
+
|
142
|
+
if order && order.any?
|
143
|
+
order.map do |direction|
|
144
|
+
order_operations << case direction.operator
|
145
|
+
when :asc then "[\/#{direction.target.field}]"
|
146
|
+
when :desc then "[\\#{direction.target.field}]"
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
json_query += order_operations.join("")
|
152
|
+
|
153
|
+
json_query += "[={" + outfields.join(',') + "}]" unless outfields.empty?
|
154
|
+
|
155
|
+
offset = self.offset.to_i
|
156
|
+
limit = self.limit.nil? ? nil : self.limit.to_i + offset - 1
|
157
|
+
|
158
|
+
if offset != 0 || !limit.nil?
|
159
|
+
headers.merge!({"Range", "items=#{offset}-#{limit}"})
|
160
|
+
end
|
161
|
+
# puts "#{inspect}"
|
162
|
+
# puts json_query, headers
|
163
|
+
return json_query, headers
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|