deli 0.5.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.
- data/Rakefile +77 -0
- data/lib/deli.rb +18 -0
- data/lib/deli/adapters.rb +9 -0
- data/lib/deli/adapters/active_record.rb +251 -0
- data/lib/deli/adapters/cassandra.rb +52 -0
- data/lib/deli/adapters/mongoid.rb +180 -0
- data/lib/deli/adapters/neo4j.rb +54 -0
- data/lib/deli/adapters/simple.rb +39 -0
- data/lib/deli/configuration.rb +47 -0
- data/lib/deli/controller.rb +75 -0
- data/lib/deli/helper.rb +61 -0
- data/lib/deli/model.rb +13 -0
- data/lib/deli/pagination.rb +117 -0
- data/lib/deli/param.rb +189 -0
- data/lib/deli/query.rb +133 -0
- data/lib/deli/railtie.rb +14 -0
- data/spec/active_record_spec.rb +358 -0
- data/spec/cassandra_spec.rb +40 -0
- data/spec/mongoid_spec.rb +40 -0
- data/spec/neo4j_spec.rb +40 -0
- data/spec/param_spec.rb +318 -0
- data/spec/spec_helper.rb +33 -0
- data/spec/support/database.rb +69 -0
- data/spec/support/models.rb +27 -0
- metadata +77 -0
data/Rakefile
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require "rake/rdoctask"
|
3
|
+
require 'rake/gempackagetask'
|
4
|
+
|
5
|
+
spec = Gem::Specification.new do |s|
|
6
|
+
s.name = "deli"
|
7
|
+
s.authors = ["Lance Pollard"]
|
8
|
+
s.version = "0.5.0"
|
9
|
+
s.summary = "Tasty URL Parameters for Rails"
|
10
|
+
s.homepage = "http://github.com/viatropos/deli"
|
11
|
+
s.email = "lancejpollard@gmail.com"
|
12
|
+
s.description = "Tasty URL Parameters for Rails"
|
13
|
+
s.has_rdoc = false
|
14
|
+
s.rubyforge_project = "deli"
|
15
|
+
s.platform = Gem::Platform::RUBY
|
16
|
+
s.files = %w(Rakefile) + Dir["{lib,rails,spec,app}/**/*"] - Dir["spec/tmp"]
|
17
|
+
s.require_path = "lib"
|
18
|
+
end
|
19
|
+
|
20
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
21
|
+
pkg.gem_spec = spec
|
22
|
+
end
|
23
|
+
|
24
|
+
desc 'run unit tests'
|
25
|
+
task :test do
|
26
|
+
Dir["test/**/*"].each do |file|
|
27
|
+
next unless File.basename(file) =~ /test_/
|
28
|
+
next unless File.extname(file) == ".rb"
|
29
|
+
system "ruby #{file}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
desc "Create .gemspec file (useful for github)"
|
34
|
+
task :gemspec do
|
35
|
+
File.open("#{spec.name}.gemspec", "w") do |f|
|
36
|
+
f.puts spec.to_ruby
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
desc "Build the gem into the current directory"
|
41
|
+
task :gem => :gemspec do
|
42
|
+
`gem build #{spec.name}.gemspec`
|
43
|
+
end
|
44
|
+
|
45
|
+
desc "Publish gem to rubygems"
|
46
|
+
task :publish => [:package] do
|
47
|
+
%x[gem push #{spec.name}-#{spec.version}.gem]
|
48
|
+
end
|
49
|
+
|
50
|
+
desc "Print a list of the files to be put into the gem"
|
51
|
+
task :manifest do
|
52
|
+
File.open("Manifest", "w") do |f|
|
53
|
+
spec.files.each do |file|
|
54
|
+
f.puts file
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
desc "Install the gem locally"
|
60
|
+
task :install => [:package] do
|
61
|
+
File.mkdir("pkg") unless File.exists?("pkg")
|
62
|
+
command = "gem install pkg/#{spec.name}-#{spec.version} --no-ri --no-rdoc"
|
63
|
+
command = "sudo #{command}" if ENV["SUDO"] == true
|
64
|
+
sh %{#{command}}
|
65
|
+
end
|
66
|
+
|
67
|
+
desc "Generate the rdoc"
|
68
|
+
Rake::RDocTask.new do |rdoc|
|
69
|
+
files = ["README.markdown", "lib/**/*.rb"]
|
70
|
+
rdoc.rdoc_files.add(files)
|
71
|
+
rdoc.main = "README.markdown"
|
72
|
+
rdoc.title = spec.summary
|
73
|
+
end
|
74
|
+
|
75
|
+
task :yank do
|
76
|
+
`gem yank #{spec.name} -v #{spec.version}`
|
77
|
+
end
|
data/lib/deli.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'time'
|
3
|
+
require 'date'
|
4
|
+
require 'active_support'
|
5
|
+
require 'active_support/core_ext'
|
6
|
+
require 'uri'
|
7
|
+
|
8
|
+
$:.unshift File.dirname(__FILE__)
|
9
|
+
|
10
|
+
require "deli/configuration"
|
11
|
+
require "deli/railtie" if defined?(::Rails)
|
12
|
+
require "deli/query"
|
13
|
+
require "deli/model"
|
14
|
+
require "deli/controller"
|
15
|
+
require "deli/helper"
|
16
|
+
require "deli/pagination"
|
17
|
+
require "deli/param"
|
18
|
+
require "deli/adapters"
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module Deli
|
2
|
+
module Adapters
|
3
|
+
autoload :ActiveRecord, "deli/adapters/active_record"
|
4
|
+
autoload :Cassandra, "deli/adapters/cassandra"
|
5
|
+
autoload :Mongoid, "deli/adapters/mongoid"
|
6
|
+
autoload :Neo4j, "deli/adapters/neo4j"
|
7
|
+
autoload :Simple, "deli/adapters/simple"
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,251 @@
|
|
1
|
+
module Deli
|
2
|
+
module Adapters
|
3
|
+
module ActiveRecord
|
4
|
+
class Model < Deli::Model
|
5
|
+
def model_type(key, options = {})
|
6
|
+
default = options[:type]
|
7
|
+
|
8
|
+
if default.present?
|
9
|
+
value = default.to_sym
|
10
|
+
else
|
11
|
+
value = model_class.columns.detect { |i| i.name == key }
|
12
|
+
value = value.present? ? value.type : nil
|
13
|
+
end
|
14
|
+
|
15
|
+
raise ::ArgumentError.new("Must specify type, such as: `match :#{key}, :type => :string`") if value.blank?
|
16
|
+
|
17
|
+
case value
|
18
|
+
when :datetime, :time
|
19
|
+
:time
|
20
|
+
when :date
|
21
|
+
:date
|
22
|
+
when :integer, :float, :decimal, :count
|
23
|
+
:number
|
24
|
+
when :sort, :order
|
25
|
+
:order
|
26
|
+
when :string, :text
|
27
|
+
:string
|
28
|
+
else
|
29
|
+
value
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class Query < ::Deli::Query
|
35
|
+
# Converts request parameters into an options Hash for ActiveRecord finder methods.# Outputs a query hash for Mongoid.
|
36
|
+
#
|
37
|
+
# @example Declare the queries you want to make in your controller.
|
38
|
+
#
|
39
|
+
# queries :order => "created_at desc" do
|
40
|
+
# match :full_name
|
41
|
+
# match :created, :field => :created_at, :strict => true
|
42
|
+
# match :status, :operators => [:in] # should ultimately have full-on validations
|
43
|
+
# match :product, :type => :string, :scope => :with_bookmarked_products
|
44
|
+
# end
|
45
|
+
#
|
46
|
+
# @example Request with all possible parameters
|
47
|
+
#
|
48
|
+
# "/users?full_name=^lance&created=2011-08-01..t&status=active&product=laptop"
|
49
|
+
#
|
50
|
+
# @param [Hash] params ({}) The query params hash from the controller.
|
51
|
+
#
|
52
|
+
# @option params [::Symbol] :type Defaults to the database field type. If you use named scopes
|
53
|
+
# to reference assiated models, as of now you must specify the type manually. Haven't looked
|
54
|
+
# through the Rails 3 scoping code to figure out how use reflection to get join keys.
|
55
|
+
# @option params [::String, ::Symbol] :field If a ::Symbol, the table/collection attribute
|
56
|
+
# to query, if a ::String, the fully qualified table/collection + attribute string.
|
57
|
+
# @option params [::Array] :operators Optional, refines the allowable query value formats.
|
58
|
+
# @option params [::Boolean] :strict (+false) If true, it will raise an error if the
|
59
|
+
# URL parameter is not properly formatted (e.g. "2011.." vs. "2011..t")
|
60
|
+
# @option params [::Symbol] :scope Optional, a class method on the model for the controller,
|
61
|
+
# used as a named scope. In here place your +joins(:x).where(:y)+ code.
|
62
|
+
#
|
63
|
+
# @return [Hash]
|
64
|
+
def render(params)
|
65
|
+
hash = super
|
66
|
+
|
67
|
+
hash["sort"] = default_sort if hash["sort"].blank? && default_sort.present?
|
68
|
+
|
69
|
+
sort = hash.delete("sort")
|
70
|
+
limit = hash.delete("limit") || 20
|
71
|
+
page = hash.delete("page") || 1
|
72
|
+
|
73
|
+
offset = limit.present? && page.present? ? ((page - 1) * limit).to_i : 0
|
74
|
+
|
75
|
+
keys = []
|
76
|
+
values = []
|
77
|
+
|
78
|
+
hash.values.collect do |array|
|
79
|
+
keys << array[0]
|
80
|
+
values << array[1..-1]
|
81
|
+
end
|
82
|
+
|
83
|
+
keys.map! {|i| "(#{i})"} if keys.length > 1
|
84
|
+
keys = keys.join(" AND ")
|
85
|
+
values.flatten!
|
86
|
+
conditions = [keys, *values]
|
87
|
+
|
88
|
+
result = {}
|
89
|
+
result[:conditions] = conditions if conditions.present?
|
90
|
+
result[:limit] = limit if limit.present? && limit > 0
|
91
|
+
result[:offset] = offset if offset.present? && offset > 0
|
92
|
+
result[:order] = sort if sort.present?
|
93
|
+
|
94
|
+
result
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
class Param < ::Deli::Param
|
99
|
+
attr_accessor :table_key
|
100
|
+
|
101
|
+
def initialize(key, options = {})
|
102
|
+
super(key, options)
|
103
|
+
configure_clauses(options)
|
104
|
+
end
|
105
|
+
|
106
|
+
def parse(value)
|
107
|
+
[value]
|
108
|
+
end
|
109
|
+
|
110
|
+
def configure_clauses(options)
|
111
|
+
case options[:to]
|
112
|
+
when ::String
|
113
|
+
self.table_key = options[:to]
|
114
|
+
when ::Hash
|
115
|
+
join_key = options[:as] || options[:to].keys.first
|
116
|
+
join_class = join_key.to_s.singularize.camelize.constantize
|
117
|
+
attribute = options[:to].values.first.to_sym
|
118
|
+
self.table_key = "#{join_class.table_name}.#{attribute}"
|
119
|
+
else
|
120
|
+
if model_class.respond_to?(:table_name)
|
121
|
+
if association = find_association
|
122
|
+
self.table_key = "#{model_class.table_name}.#{key}_id"
|
123
|
+
else
|
124
|
+
self.table_key = "#{model_class.table_name}.#{key}"
|
125
|
+
end
|
126
|
+
else
|
127
|
+
self.table_key = key
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# what this responds to
|
133
|
+
def operators
|
134
|
+
[:equals, :contains, :start, :end]
|
135
|
+
end
|
136
|
+
|
137
|
+
def find_association
|
138
|
+
key = self.key.to_sym
|
139
|
+
model_class.reflect_on_all_associations.detect do |association|
|
140
|
+
association.name == key
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def render(value)
|
145
|
+
keys, values = [], []
|
146
|
+
|
147
|
+
parse(value).each do |and_collection|
|
148
|
+
and_keys = []
|
149
|
+
|
150
|
+
and_collection.each do |item|
|
151
|
+
and_keys << "#{table_key} #{render_operator(item[:operators][0])} ?"
|
152
|
+
values << render_value(item[:value], item[:operators][1] || item[:operators][0])
|
153
|
+
end
|
154
|
+
|
155
|
+
keys << and_keys
|
156
|
+
end
|
157
|
+
|
158
|
+
keys.map! { |and_keys| and_keys.join(" AND ") }
|
159
|
+
|
160
|
+
if keys.length > 1
|
161
|
+
[parenthesize!(keys).join(" OR "), *values]
|
162
|
+
else
|
163
|
+
[keys.join(" OR "), *values]
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def render_name(*names)
|
168
|
+
names.flatten.compact.join(".")
|
169
|
+
end
|
170
|
+
|
171
|
+
def render_value(value, operator = nil)
|
172
|
+
value
|
173
|
+
end
|
174
|
+
|
175
|
+
def render_operator(value)
|
176
|
+
case value
|
177
|
+
when "=~"
|
178
|
+
match_operator
|
179
|
+
when "!~"
|
180
|
+
"NOT #{match_operator}"
|
181
|
+
else
|
182
|
+
value
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def match_operator
|
187
|
+
postgres? ? "ILIKE" : "LIKE"
|
188
|
+
end
|
189
|
+
|
190
|
+
def parenthesize!(items)
|
191
|
+
items.map! { |i| "(#{i})" } if items.length > 1
|
192
|
+
items
|
193
|
+
end
|
194
|
+
|
195
|
+
def postgres?
|
196
|
+
if @postgres.nil?
|
197
|
+
@postgres = defined?(::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter) && ::ActiveRecord::Base.connection.is_a?(::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
|
198
|
+
end
|
199
|
+
@postgres
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
class Time < Param
|
204
|
+
include Deli::Param::Time
|
205
|
+
end
|
206
|
+
|
207
|
+
class Date < Time
|
208
|
+
include Deli::Param::Date
|
209
|
+
end
|
210
|
+
|
211
|
+
class String < Param
|
212
|
+
include Deli::Param::String
|
213
|
+
|
214
|
+
def render_value(value, operator = nil)
|
215
|
+
case operator
|
216
|
+
when "=", "!="
|
217
|
+
value
|
218
|
+
when "^"
|
219
|
+
"%#{value}"
|
220
|
+
when "$"
|
221
|
+
"#{value}%"
|
222
|
+
else
|
223
|
+
"%#{value}%"
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
class Number < Param
|
229
|
+
include Deli::Param::Number
|
230
|
+
end
|
231
|
+
|
232
|
+
class Limit < Param
|
233
|
+
include Deli::Param::Limit
|
234
|
+
end
|
235
|
+
|
236
|
+
class Order < Param
|
237
|
+
include Deli::Param::Order
|
238
|
+
|
239
|
+
def render(value)
|
240
|
+
parse(value).map do |item|
|
241
|
+
"#{render_name(item[:namespace], item[:key])} #{item[:operators][0] == "+" ? "ASC" : "DESC"}"
|
242
|
+
end.join(", ")
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
class Offset < Param
|
247
|
+
include Deli::Param::Offset
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Deli
|
2
|
+
module Adapters
|
3
|
+
# @todo
|
4
|
+
module Cassandra
|
5
|
+
class Query < ::Deli::Query
|
6
|
+
def render(params)
|
7
|
+
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class Param < ::Deli::Param
|
12
|
+
def render(value)
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
def render_value(value, operator = nil)
|
17
|
+
value
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class Time < Param
|
22
|
+
include Deli::Param::Time
|
23
|
+
end
|
24
|
+
|
25
|
+
class Date < Time
|
26
|
+
include Deli::Param::Date
|
27
|
+
end
|
28
|
+
|
29
|
+
class String < Param
|
30
|
+
include Deli::Param::String
|
31
|
+
end
|
32
|
+
|
33
|
+
class Number < Param
|
34
|
+
include Deli::Param::Number
|
35
|
+
end
|
36
|
+
|
37
|
+
class Limit < Param
|
38
|
+
include Deli::Param::Limit
|
39
|
+
end
|
40
|
+
|
41
|
+
class Order < Param
|
42
|
+
include Deli::Param::Order
|
43
|
+
|
44
|
+
def render(value)
|
45
|
+
parse(value).map do |item|
|
46
|
+
[render_name(item[:namespace], item[:key]), item[:operators][0] == "+" ? :asc : :desc]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,180 @@
|
|
1
|
+
module Deli
|
2
|
+
module Adapters
|
3
|
+
# http://mongoid.org/docs/querying/criteria.html
|
4
|
+
module Mongoid
|
5
|
+
class Model < Deli::Model
|
6
|
+
def model_type(key, options = {})
|
7
|
+
default = options[:type]
|
8
|
+
|
9
|
+
if default.present?
|
10
|
+
value = default.to_sym
|
11
|
+
else
|
12
|
+
value = model_class.fields[key.to_s]
|
13
|
+
value = value.present? ? value.type.to_s.underscore.to_sym : nil
|
14
|
+
end
|
15
|
+
|
16
|
+
raise ::ArgumentError.new("Must specify type, such as: `match :#{key}, :type => :string`") if value.blank?
|
17
|
+
|
18
|
+
case value
|
19
|
+
when :datetime, :time
|
20
|
+
:time
|
21
|
+
when :date
|
22
|
+
:date
|
23
|
+
when :integer, :float, :decimal, :count
|
24
|
+
:number
|
25
|
+
when :sort, :order
|
26
|
+
:order
|
27
|
+
when :string, :text
|
28
|
+
:string
|
29
|
+
else
|
30
|
+
value
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Outputs a query hash for Mongoid.
|
36
|
+
#
|
37
|
+
# @example Declare the queries you want to make in your controller.
|
38
|
+
#
|
39
|
+
# queries :order => "created_at desc" do
|
40
|
+
# match :full_name
|
41
|
+
# match :created, :field => :created_at
|
42
|
+
# match :status, :type => :array
|
43
|
+
# match :product, :type => :string, :field => "products.title"
|
44
|
+
# match :favorites, :type => :string, :scope => :favorite_products # does the joins / default conditions work
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# @example Query for +"title=Hello+World"+
|
48
|
+
#
|
49
|
+
# {:full_name => {"$in" => "John"}}
|
50
|
+
class Query < ::Deli::Query
|
51
|
+
def render(params)
|
52
|
+
params = super
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
class Param < ::Deli::Param
|
57
|
+
def render_value(value, operator = nil)
|
58
|
+
value
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class Time < Param
|
63
|
+
include ::Mongoid::Fields::Serializable::Timekeeping
|
64
|
+
include Deli::Param::Time
|
65
|
+
|
66
|
+
def render(value)
|
67
|
+
result = {}
|
68
|
+
|
69
|
+
parse(value).flatten.each do |item|
|
70
|
+
case item[:operators][0]
|
71
|
+
when ">="
|
72
|
+
result["$gte"] = serialize(item[:value]) #time.to_mongo
|
73
|
+
when ">"
|
74
|
+
result["$gt"] = serialize(item[:value])
|
75
|
+
when "<="
|
76
|
+
result["$lte"] = serialize(item[:value]) #time.to_mongo
|
77
|
+
when "<"
|
78
|
+
result["$lt"] = serialize(item[:value])
|
79
|
+
when
|
80
|
+
result = serialize(item[:value])
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
result
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
class Date < Time
|
89
|
+
include Deli::Param::Date
|
90
|
+
end
|
91
|
+
|
92
|
+
class String < Param
|
93
|
+
include Deli::Param::String
|
94
|
+
|
95
|
+
def render(value)
|
96
|
+
result = parse(value).map do |children|
|
97
|
+
regex = []
|
98
|
+
includes = []
|
99
|
+
excludes = []
|
100
|
+
hash = {}
|
101
|
+
|
102
|
+
children.each do |item|
|
103
|
+
start_operator = item[:operators][1] == "^" ? "^" : ""
|
104
|
+
end_operator = item[:operators][1] == "$" ? "$" : ""
|
105
|
+
|
106
|
+
case item[:operators][0]
|
107
|
+
#when "="
|
108
|
+
# includes << item[:value]
|
109
|
+
#when "!="
|
110
|
+
# excludes << item[:value]
|
111
|
+
when "!~", "!="
|
112
|
+
regex << Regexp.new("(?!#{start_operator}#{item[:value]}#{end_operator})", "i")
|
113
|
+
when "=~", "="
|
114
|
+
regex << Regexp.new("#{start_operator}#{item[:value]}#{end_operator}", "i")
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
#hash["$in"] = includes if includes.present?
|
119
|
+
#hash["$nin"] = excludes if excludes.present?
|
120
|
+
hash["$regex"] = Regexp.union(*regex) if regex.present?
|
121
|
+
hash
|
122
|
+
end
|
123
|
+
|
124
|
+
result.length > 1 ? {"$or" => result} : result[0]
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
class Number < Param
|
129
|
+
include Deli::Param::Number
|
130
|
+
end
|
131
|
+
|
132
|
+
class Limit < Param
|
133
|
+
include Deli::Param::Limit
|
134
|
+
end
|
135
|
+
|
136
|
+
class Order < Param
|
137
|
+
include Deli::Param::Order
|
138
|
+
|
139
|
+
def render(value)
|
140
|
+
parse(value).map do |item|
|
141
|
+
[item[:key].to_sym, item[:operators][0] == "+" ? :asc : :desc]
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
class Offset < Param
|
147
|
+
include Deli::Param::Offset
|
148
|
+
end
|
149
|
+
|
150
|
+
# # Match all people with first name Emmanuel using Javascript.
|
151
|
+
# { "$where" : "this.first_name == 'Emmanuel'" }
|
152
|
+
#
|
153
|
+
# # Match all people who live in Berlin, where address is embedded.
|
154
|
+
# { "addresses.city" : "Berlin" }
|
155
|
+
#
|
156
|
+
# # Example queries using symbol h4s to perform more complex criteria.
|
157
|
+
# { "title" : { "$all" : [ "Sir" ] } }
|
158
|
+
# { "age" : { "$exists" : true } }
|
159
|
+
# { "age" : { "$gt" : 18 } }
|
160
|
+
# { "age" : { "$gte" : 18 } }
|
161
|
+
# { "title" : { "$in" : [ "Sir", "Madam" ] } }
|
162
|
+
# { "age" : { "$lt" : 55 } }
|
163
|
+
# { "age" : { "$lte" : 55 } }
|
164
|
+
# { "title" : { "$ne" : "Mr" } }
|
165
|
+
# { "title" : { "$nin" : [ "Esquire" ] } }
|
166
|
+
# { "aliases" : { "$size" : 2 } }
|
167
|
+
# { "location" : { "$near" : [ 22.50, -21.33 ] } }
|
168
|
+
# { "location" : { "$within" : { "$center" => [ [ 50, -40 ], 1 ] } } }
|
169
|
+
# 3rd number can be a radius: "22.50,-21.33,7"
|
170
|
+
# - if not null, if null
|
171
|
+
class Geo < Param
|
172
|
+
include Deli::Param::Geo
|
173
|
+
|
174
|
+
def render(value)
|
175
|
+
{"$near" => parse(value).reverse}
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|