mongo-search 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+
15
+ # YARD artifacts
16
+ .yardoc
17
+ _yardoc
18
+ doc/
19
+
20
+ # Vim
21
+ *.swo
22
+ *.swp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in mongo-search.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,33 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ mongo-search (0.0.1)
5
+
6
+ GEM
7
+ remote: http://rubygems.org/
8
+ specs:
9
+ diff-lcs (1.1.3)
10
+ ffi (1.0.11)
11
+ guard (1.0.3)
12
+ ffi (>= 0.5.0)
13
+ thor (>= 0.14.6)
14
+ guard-rspec (0.7.0)
15
+ guard (>= 0.10.0)
16
+ rspec (2.10.0)
17
+ rspec-core (~> 2.10.0)
18
+ rspec-expectations (~> 2.10.0)
19
+ rspec-mocks (~> 2.10.0)
20
+ rspec-core (2.10.1)
21
+ rspec-expectations (2.10.0)
22
+ diff-lcs (~> 1.1.3)
23
+ rspec-mocks (2.10.1)
24
+ thor (0.14.6)
25
+
26
+ PLATFORMS
27
+ ruby
28
+
29
+ DEPENDENCIES
30
+ guard
31
+ guard-rspec
32
+ mongo-search!
33
+ rspec
data/Guardfile ADDED
@@ -0,0 +1,19 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'rspec', :version => 2 do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+
9
+ # Rails example
10
+ watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
11
+ watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
12
+ watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
13
+ watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
14
+ watch('config/routes.rb') { "spec/routing" }
15
+ watch('app/controllers/application_controller.rb') { "spec/controllers" }
16
+ # Capybara request specs
17
+ watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/requests/#{m[1]}_spec.rb" }
18
+ end
19
+
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ task :default => :spec
5
+
6
+ RSpec::Core::RakeTask.new
@@ -0,0 +1,31 @@
1
+ module MongoSearch
2
+ class Builder
3
+ def initialize(search)
4
+ @search = search
5
+ end
6
+
7
+ def match(attr)
8
+ @search << Matchers::PartialMatcher.new(attr)
9
+ end
10
+
11
+ def exact(attr)
12
+ @search << Matchers::ExactMatcher.new(attr)
13
+ end
14
+
15
+ def intersect(attr)
16
+ @search << Matchers::IntersectMatcher.new(attr)
17
+ end
18
+
19
+ def greater_than(attr, opts = nil)
20
+ @search << Matchers::GreaterThanMatcher.new(attr, opts)
21
+ end
22
+
23
+ def less_than(attr, opts = nil)
24
+ @search << Matchers::LessThanMatcher.new(attr, opts)
25
+ end
26
+
27
+ def sort_with(attr, opts = nil)
28
+ @search.sorter = Sorter.new(attr, opts)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,20 @@
1
+ module MongoSearch
2
+ # Hash of proc converter objects, defaults to identity func
3
+ Converters = Hash.new { |h,k| lambda { |i| i } }
4
+
5
+ Converters[:time] = lambda do |v|
6
+ if v.is_a?(Time)
7
+ v
8
+ else
9
+ Time.parse(v.to_s)
10
+ end
11
+ end
12
+
13
+ Converters[:array] = lambda do |v|
14
+ if v.is_a?(String)
15
+ v.split(/\s*,\s*/)
16
+ else
17
+ Array(v)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,29 @@
1
+ module MongoSearch
2
+ class Definition
3
+ def initialize
4
+ @filters = []
5
+ @sorter = nil
6
+ yield Builder.new(self) if block_given?
7
+ end
8
+
9
+ def <<(filter)
10
+ @filters << filter
11
+ end
12
+
13
+ def sorter=(sorter)
14
+ @sorter = sorter
15
+ end
16
+
17
+ def criteria_for(params)
18
+ conditions = {}
19
+
20
+ @filters.each do |filter|
21
+ conditions.merge! filter.call(params)
22
+ end
23
+
24
+ sort = @sorter ? @sorter.call(params) : []
25
+
26
+ [conditions, sort]
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,15 @@
1
+ module MongoSearch
2
+ module Matchers
3
+ class ExactMatcher
4
+ def initialize(attr)
5
+ @attr = attr
6
+ end
7
+
8
+ def call(params)
9
+ filters = {}
10
+ filters[@attr] = params[@attr] if params[@attr]
11
+ filters
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,19 @@
1
+ module MongoSearch
2
+ module Matchers
3
+ class GreaterThanMatcher
4
+ def initialize(attr, opts = nil)
5
+ opts ||= {}
6
+ @attr = attr
7
+ @field = opts[:field] || attr
8
+ @operator = opts[:equal] ? :$gte : :$gt
9
+ @conv = Converters[opts[:type]]
10
+ end
11
+
12
+ def call(params)
13
+ filters = {}
14
+ filters[@field] = {@operator => @conv.call(params[@attr])} if params[@attr]
15
+ filters
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,20 @@
1
+ module MongoSearch
2
+ module Matchers
3
+ class IntersectMatcher
4
+ def initialize(attr)
5
+ @attr = attr
6
+ end
7
+
8
+ def call(params)
9
+ filters = {}
10
+
11
+ if params[@attr]
12
+ value = params[@attr]
13
+ filters[@attr] = {:$all => Converters[:array].call(value)}
14
+ end
15
+
16
+ filters
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,19 @@
1
+ module MongoSearch
2
+ module Matchers
3
+ class LessThanMatcher
4
+ def initialize(attr, opts = nil)
5
+ opts ||= {}
6
+ @attr = attr
7
+ @field = opts[:field] || attr
8
+ @operator = opts[:equal] ? :$lte : :$lt
9
+ @conv = Converters[opts[:type]]
10
+ end
11
+
12
+ def call(params)
13
+ filters = {}
14
+ filters[@field] = {@operator => @conv.call(params[@attr])} if params[@attr]
15
+ filters
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,15 @@
1
+ module MongoSearch
2
+ module Matchers
3
+ class PartialMatcher
4
+ def initialize(attr)
5
+ @attr = attr
6
+ end
7
+
8
+ def call(params)
9
+ filters = {}
10
+ filters[@attr] = /#{Regexp.escape(params[@attr])}/i if params[@attr]
11
+ filters
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,25 @@
1
+ module MongoSearch
2
+ class Sorter
3
+ def initialize(attr, opts = nil)
4
+ @attr, @opts = attr, opts || {}
5
+ end
6
+
7
+ def call(params)
8
+ sort = []
9
+
10
+ if order_by = params[@attr] || @opts[:default]
11
+ order_by.split(/\s*,\s*/).each do |attr_order|
12
+ if attr_order =~ /([^\s]+)(?:\s*(asc|desc)?)$/
13
+ attr_name, dir = $1, ($2 || :asc)
14
+ sort << [:"#{attr_name}_ordenacao", :"#{dir}"]
15
+ sort << [:"#{attr_name}", :"#{dir}"]
16
+ else
17
+ raise ArgumentError, "invalid sorting parameters: #{order_by}"
18
+ end
19
+ end
20
+ end
21
+
22
+ sort
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,5 @@
1
+ module Mongo
2
+ module Search
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,10 @@
1
+ require "time"
2
+ require "mongo-search/sorter"
3
+ require "mongo-search/converters"
4
+ require "mongo-search/matchers/exact_matcher"
5
+ require "mongo-search/matchers/partial_matcher"
6
+ require "mongo-search/matchers/intersect_matcher"
7
+ require "mongo-search/matchers/greater_than_matcher"
8
+ require "mongo-search/matchers/less_than_matcher"
9
+ require "mongo-search/definition"
10
+ require "mongo-search/builder"
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "mongo-search/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "mongo-search"
7
+ s.version = Mongo::Search::VERSION
8
+ s.authors = ["Rodrigo Kochenburger <divoxx@gmail.com>", "Tomas Mattia <tomas.mattia@gmail.com>"]
9
+ s.email = ["abril_vejasp_dev@thoughtworks.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{Easy search for mongodb}
12
+
13
+ s.rubyforge_project = "mongo-search"
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+
20
+ # specify any dependencies here; for example:
21
+ s.add_development_dependency "rspec"
22
+ s.add_development_dependency "guard"
23
+ s.add_development_dependency "guard-rspec"
24
+ # s.add_runtime_dependency "rest-client"
25
+ end
@@ -0,0 +1,70 @@
1
+ require "spec_helper"
2
+
3
+ describe "Search integration" do
4
+ let :klass do
5
+ mock(:collection => collection)
6
+ end
7
+
8
+ let :collection do
9
+ mock(:collection)
10
+ end
11
+
12
+ subject do
13
+ MongoSearch::Definition.new do |c|
14
+ c.match :name
15
+ c.exact :status
16
+ c.intersect :tags
17
+ c.less_than :updated_before, :field => :updated_at, :type => :time, :equal => true
18
+ c.greater_than :updated_since, :field => :updated_at, :type => :time, :equal => true
19
+ c.sort_with :order, :default => "name asc"
20
+ end
21
+ end
22
+
23
+ it "matches partial string with case-insensitive regexp" do
24
+ c, _ = subject.criteria_for :name => "foo"
25
+ c.should == {:name => /foo/i}
26
+ end
27
+
28
+ it "matches exact string" do
29
+ c, _ = subject.criteria_for :status => 'published'
30
+ c.should == {:status => 'published'}
31
+ end
32
+
33
+ it "matches intersection of list items" do
34
+ c, _ = subject.criteria_for :tags => ['foo', 'bar']
35
+ c.should == {:tags => {:$all => ['foo', 'bar']}}
36
+ end
37
+
38
+ it "matches intersection of comma separate string" do
39
+ c, _ = subject.criteria_for :tags => "foo,bar"
40
+ c.should == {:tags => {:$all => ['foo', 'bar']}}
41
+ end
42
+
43
+ it "matches a parameter against a field using greater than op" do
44
+ time = Time.parse("2012-01-10T22:10:01Z")
45
+ c, _ = subject.criteria_for :updated_since => time.strftime("%Y-%m-%dT%H:%M:%SZ")
46
+ c.should == {:updated_at => {:$gte => time}}
47
+ end
48
+
49
+ it "matches a parameter against a field using less than op" do
50
+ time = Time.parse("2012-01-10T22:10:01Z")
51
+ c, _ = subject.criteria_for :updated_before => time.strftime("%Y-%m-%dT%H:%M:%SZ")
52
+ c.should == {:updated_at => {:$lte => time}}
53
+ end
54
+
55
+ it "uses specified sorting and includes a _ordenacao prefix also" do
56
+ _, s = subject.criteria_for :order => "titulo desc"
57
+ s.should == [[:titulo_ordenacao, :desc], [:titulo, :desc]]
58
+ end
59
+
60
+ it "defaults sorting direction to asc if not specified" do
61
+ _, s = subject.criteria_for :order => "titulo, categoria"
62
+ s.should include([:titulo, :asc])
63
+ s.should include([:categoria, :asc])
64
+ end
65
+
66
+ it "uses default sorting if no specified" do
67
+ _, s = subject.criteria_for({})
68
+ s.should == [[:name_ordenacao, :asc], [:name, :asc]]
69
+ end
70
+ end
@@ -0,0 +1,4 @@
1
+ require "mongo-search"
2
+
3
+ RSpec.configure do |c|
4
+ end
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mongo-search
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Rodrigo Kochenburger <divoxx@gmail.com>
9
+ - Tomas Mattia <tomas.mattia@gmail.com>
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2012-05-22 00:00:00.000000000Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rspec
17
+ requirement: &70097252840100 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: *70097252840100
26
+ - !ruby/object:Gem::Dependency
27
+ name: guard
28
+ requirement: &70097252839420 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: *70097252839420
37
+ - !ruby/object:Gem::Dependency
38
+ name: guard-rspec
39
+ requirement: &70097252838860 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ! '>='
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ type: :development
46
+ prerelease: false
47
+ version_requirements: *70097252838860
48
+ description:
49
+ email:
50
+ - abril_vejasp_dev@thoughtworks.com
51
+ executables: []
52
+ extensions: []
53
+ extra_rdoc_files: []
54
+ files:
55
+ - .gitignore
56
+ - Gemfile
57
+ - Gemfile.lock
58
+ - Guardfile
59
+ - Rakefile
60
+ - lib/mongo-search.rb
61
+ - lib/mongo-search/builder.rb
62
+ - lib/mongo-search/converters.rb
63
+ - lib/mongo-search/definition.rb
64
+ - lib/mongo-search/matchers/exact_matcher.rb
65
+ - lib/mongo-search/matchers/greater_than_matcher.rb
66
+ - lib/mongo-search/matchers/intersect_matcher.rb
67
+ - lib/mongo-search/matchers/less_than_matcher.rb
68
+ - lib/mongo-search/matchers/partial_matcher.rb
69
+ - lib/mongo-search/sorter.rb
70
+ - lib/mongo-search/version.rb
71
+ - mongo-search.gemspec
72
+ - spec/search_spec.rb
73
+ - spec/spec_helper.rb
74
+ homepage: ''
75
+ licenses: []
76
+ post_install_message:
77
+ rdoc_options: []
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ none: false
88
+ requirements:
89
+ - - ! '>='
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ requirements: []
93
+ rubyforge_project: mongo-search
94
+ rubygems_version: 1.8.10
95
+ signing_key:
96
+ specification_version: 3
97
+ summary: Easy search for mongodb
98
+ test_files:
99
+ - spec/search_spec.rb
100
+ - spec/spec_helper.rb
101
+ has_rdoc: