xapit 0.2.7 → 0.3.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/{CHANGELOG → CHANGELOG.rdoc} +7 -2
- data/Gemfile +19 -0
- data/LICENSE +4 -4
- data/README.rdoc +61 -108
- data/Rakefile +11 -10
- data/features/facets.feature +93 -82
- data/features/finding.feature +196 -138
- data/features/indexing.feature +35 -37
- data/features/remote_server.feature +10 -0
- data/features/step_definitions/xapit_steps.rb +53 -25
- data/features/suggestions.feature +20 -14
- data/features/support/env.rb +13 -6
- data/features/support/xapit_helpers.rb +8 -9
- data/lib/generators/xapit/install_generator.rb +14 -0
- data/lib/generators/xapit/templates/xapit.ru +6 -0
- data/lib/generators/xapit/templates/xapit.yml +11 -0
- data/lib/xapit.rb +106 -64
- data/lib/xapit/client/collection.rb +150 -0
- data/lib/xapit/client/facet.rb +11 -0
- data/lib/xapit/client/facet_option.rb +29 -0
- data/lib/xapit/client/index_builder.rb +67 -0
- data/lib/xapit/client/membership.rb +46 -0
- data/lib/xapit/client/model_adapters/abstract_model_adapter.rb +30 -0
- data/lib/xapit/client/model_adapters/active_record_adapter.rb +27 -0
- data/lib/xapit/client/model_adapters/default_model_adapter.rb +7 -0
- data/lib/xapit/client/railtie.rb +18 -0
- data/lib/xapit/client/remote_database.rb +21 -0
- data/lib/xapit/client/tasks.rb +18 -0
- data/lib/xapit/server/app.rb +27 -0
- data/lib/xapit/server/database.rb +47 -0
- data/lib/xapit/server/indexer.rb +138 -0
- data/lib/xapit/server/query.rb +240 -0
- data/spec/fixtures/blankdb/flintlock +0 -0
- data/spec/fixtures/blankdb/iamchert +1 -0
- data/spec/fixtures/blankdb/postlist.DB +0 -0
- data/spec/fixtures/blankdb/postlist.baseA +0 -0
- data/spec/fixtures/blankdb/record.DB +0 -0
- data/spec/fixtures/blankdb/record.baseA +0 -0
- data/spec/fixtures/blankdb/termlist.DB +0 -0
- data/spec/fixtures/blankdb/termlist.baseA +0 -0
- data/spec/fixtures/xapit.ru +13 -0
- data/spec/fixtures/xapit.yml +4 -0
- data/spec/spec_helper.rb +8 -9
- data/spec/support/spec_macros.rb +6 -0
- data/spec/{xapit_member.rb → support/xapit_member.rb} +14 -16
- data/spec/xapit/client/collection_spec.rb +63 -0
- data/spec/xapit/client/facet_option_spec.rb +26 -0
- data/spec/xapit/client/facet_spec.rb +13 -0
- data/spec/xapit/client/index_builder_spec.rb +66 -0
- data/spec/xapit/client/membership_spec.rb +43 -0
- data/spec/xapit/client/model_adapters/active_record_adapter_spec.rb +62 -0
- data/spec/xapit/client/model_adapters/default_model_adapter_spec.rb +7 -0
- data/spec/xapit/client/remote_database_spec.rb +19 -0
- data/spec/xapit/server/app_spec.rb +22 -0
- data/spec/xapit/server/database_spec.rb +37 -0
- data/spec/xapit/server/indexer_spec.rb +82 -0
- data/spec/xapit/server/query_spec.rb +43 -0
- data/spec/xapit/xapit_spec.rb +28 -0
- metadata +124 -93
- data/Manifest +0 -60
- data/features/sorting.feature +0 -29
- data/init.rb +0 -1
- data/install.rb +0 -8
- data/lib/xapit/adapters/abstract_adapter.rb +0 -47
- data/lib/xapit/adapters/active_record_adapter.rb +0 -20
- data/lib/xapit/adapters/data_mapper_adapter.rb +0 -10
- data/lib/xapit/collection.rb +0 -187
- data/lib/xapit/config.rb +0 -84
- data/lib/xapit/facet.rb +0 -67
- data/lib/xapit/facet_blueprint.rb +0 -59
- data/lib/xapit/facet_option.rb +0 -56
- data/lib/xapit/index_blueprint.rb +0 -147
- data/lib/xapit/indexers/abstract_indexer.rb +0 -116
- data/lib/xapit/indexers/classic_indexer.rb +0 -29
- data/lib/xapit/indexers/simple_indexer.rb +0 -38
- data/lib/xapit/membership.rb +0 -137
- data/lib/xapit/query.rb +0 -89
- data/lib/xapit/query_parsers/abstract_query_parser.rb +0 -174
- data/lib/xapit/query_parsers/classic_query_parser.rb +0 -29
- data/lib/xapit/query_parsers/simple_query_parser.rb +0 -75
- data/lib/xapit/rake_tasks.rb +0 -13
- data/rails_generators/xapit/USAGE +0 -13
- data/rails_generators/xapit/templates/setup_xapit.rb +0 -1
- data/rails_generators/xapit/templates/xapit.rake +0 -4
- data/rails_generators/xapit/xapit_generator.rb +0 -20
- data/spec/xapit/adapters/active_record_adapter_spec.rb +0 -31
- data/spec/xapit/adapters/data_mapper_adapter_spec.rb +0 -10
- data/spec/xapit/collection_spec.rb +0 -176
- data/spec/xapit/config_spec.rb +0 -62
- data/spec/xapit/facet_blueprint_spec.rb +0 -29
- data/spec/xapit/facet_option_spec.rb +0 -80
- data/spec/xapit/facet_spec.rb +0 -73
- data/spec/xapit/index_blueprint_spec.rb +0 -112
- data/spec/xapit/indexers/abstract_indexer_spec.rb +0 -111
- data/spec/xapit/indexers/classic_indexer_spec.rb +0 -35
- data/spec/xapit/indexers/simple_indexer_spec.rb +0 -69
- data/spec/xapit/membership_spec.rb +0 -55
- data/spec/xapit/query_parsers/abstract_query_parser_spec.rb +0 -60
- data/spec/xapit/query_parsers/classic_query_parser_spec.rb +0 -20
- data/spec/xapit/query_parsers/simple_query_parser_spec.rb +0 -86
- data/spec/xapit/query_spec.rb +0 -60
- data/tasks/spec.rb +0 -9
- data/tasks/xapit.rake +0 -1
- data/uninstall.rb +0 -5
- data/xapit.gemspec +0 -30
|
@@ -1,17 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
Given an empty database at "tmp/xapiandatabase"
|
|
1
|
+
Feature: Suggestions
|
|
3
2
|
|
|
4
|
-
Scenario: Spelling suggestion
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
Scenario: Spelling suggestion
|
|
4
|
+
Given an empty database at "tmp/spellingdb"
|
|
5
|
+
And spelling is enabled
|
|
6
|
+
And indexed records named "Zebra, Apple, Bike"
|
|
7
|
+
When I query for "zerba bike aple"
|
|
8
|
+
Then I should have "zebra bike apple" as a spelling suggestion
|
|
8
9
|
|
|
9
|
-
Scenario:
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
Scenario: No spelling suggestion
|
|
11
|
+
Given indexed records named "Zebra, Apple, Bike"
|
|
12
|
+
When I query for "zerba bike aple"
|
|
13
|
+
Then I should have "" as a spelling suggestion
|
|
13
14
|
|
|
14
|
-
Scenario: Find similar records
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
Scenario: Find similar records
|
|
16
|
+
Given indexed records named "Jason John Smith, John Doe, Jason Smith, Jacob Johnson"
|
|
17
|
+
When I query for similar records for "Jason John Smith"
|
|
18
|
+
Then I should find records named "Jason Smith, John Doe"
|
|
19
|
+
|
|
20
|
+
Scenario: Match similar words with stemming
|
|
21
|
+
Given indexed records named "flies, fly, glider"
|
|
22
|
+
When I query for "flying"
|
|
23
|
+
Then I should find records named "flies, fly"
|
data/features/support/env.rb
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
|
-
require '
|
|
2
|
-
require 'spec'
|
|
3
|
-
require 'active_support'
|
|
4
|
-
require 'fileutils'
|
|
1
|
+
require 'bundler/setup'
|
|
5
2
|
|
|
6
|
-
require
|
|
7
|
-
|
|
3
|
+
Bundler.require(:default)
|
|
4
|
+
|
|
5
|
+
require File.expand_path('../../../spec/support/xapit_member', __FILE__)
|
|
6
|
+
|
|
7
|
+
Before do
|
|
8
|
+
Xapit.reset_config
|
|
9
|
+
Xapit.config[:spelling] = false
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
at_exit do
|
|
13
|
+
$server.close if $server
|
|
14
|
+
end
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
module XapitHelpers
|
|
2
2
|
def create_records(records, perform_index = true)
|
|
3
|
-
Xapit.remove_database
|
|
4
3
|
XapitMember.delete_all
|
|
5
|
-
XapitMember.xapit do
|
|
4
|
+
XapitMember.xapit do
|
|
6
5
|
records.first.keys.each do |attribute|
|
|
7
6
|
if block_given?
|
|
8
|
-
yield(
|
|
7
|
+
yield(self, attribute)
|
|
9
8
|
else
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
text attribute
|
|
10
|
+
field attribute
|
|
11
|
+
facet attribute
|
|
12
|
+
sortable attribute
|
|
14
13
|
end
|
|
15
14
|
end
|
|
16
15
|
end
|
|
@@ -18,9 +17,9 @@ module XapitHelpers
|
|
|
18
17
|
attributes.each do |key, value|
|
|
19
18
|
attributes[key] = value.split(', ') if value.include? ', '
|
|
20
19
|
end
|
|
21
|
-
XapitMember.new(attributes
|
|
20
|
+
member = XapitMember.new(attributes)
|
|
21
|
+
member.class.xapit_index_builder.add_document(member) if perform_index
|
|
22
22
|
end
|
|
23
|
-
Xapit.index_all if perform_index
|
|
24
23
|
end
|
|
25
24
|
end
|
|
26
25
|
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module Xapit
|
|
2
|
+
module Generators
|
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
|
4
|
+
def self.source_root
|
|
5
|
+
File.dirname(__FILE__) + "/templates"
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def copy_files
|
|
9
|
+
copy_file "xapit.yml", "config/xapit.yml"
|
|
10
|
+
copy_file "xapit.ru", "xapit.ru"
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
data/lib/xapit.rb
CHANGED
|
@@ -1,71 +1,113 @@
|
|
|
1
|
-
require 'digest/sha1'
|
|
2
|
-
require 'rubygems'
|
|
3
1
|
require 'xapian'
|
|
2
|
+
require 'digest/sha1'
|
|
3
|
+
require 'rack'
|
|
4
|
+
require 'json'
|
|
5
|
+
require 'net/http'
|
|
4
6
|
|
|
5
|
-
# Looking for more documentation? A good place to start is Xapit::Membership
|
|
6
7
|
module Xapit
|
|
7
|
-
#
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
value.
|
|
8
|
+
# A general Xapit exception
|
|
9
|
+
class Error < StandardError; end
|
|
10
|
+
|
|
11
|
+
# Raised when accessing the database when Xapit is disabled
|
|
12
|
+
class Disabled < Error; end
|
|
13
|
+
|
|
14
|
+
class << self
|
|
15
|
+
attr_reader :config
|
|
16
|
+
|
|
17
|
+
def reset_config
|
|
18
|
+
@database = nil
|
|
19
|
+
@config = {
|
|
20
|
+
:enabled => true,
|
|
21
|
+
:spelling => true,
|
|
22
|
+
:stemming => "english"
|
|
23
|
+
}
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def reload
|
|
27
|
+
reset_config
|
|
28
|
+
@config.merge!(@loaded_config) if @loaded_config
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def database
|
|
32
|
+
raise Disabled, "Unable to access Xapit database because it is disabled in configuration." unless Xapit.config[:enabled]
|
|
33
|
+
if config[:server]
|
|
34
|
+
@database ||= Xapit::Client::RemoteDatabase.new(config[:server])
|
|
35
|
+
else
|
|
36
|
+
@database ||= Xapit::Server::Database.new(config[:database_path])
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def load_config(filename, environment)
|
|
41
|
+
@loaded_config = symbolize_keys(YAML.load_file(filename)[environment.to_s])
|
|
42
|
+
raise ArgumentError, "The #{environment} environment does not exist in #{filename}" if @loaded_config.nil?
|
|
43
|
+
@config.merge!(@loaded_config)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def value_index(type, attribute)
|
|
47
|
+
Zlib.crc32(["xapit", type, attribute].join) % 99999999 # TODO: Figure out the true max of a xapian value index
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def facet_identifier(attribute, value)
|
|
51
|
+
Digest::SHA1.hexdigest(["xapit", attribute, value].join)[0..6]
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def search(*args)
|
|
55
|
+
Xapit::Client::Collection.new.not_in_classes("FacetOption").search(*args)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def serialize_value(value)
|
|
59
|
+
if value.kind_of?(Time)
|
|
60
|
+
Xapian.sortable_serialise(value.to_i)
|
|
61
|
+
elsif value.kind_of?(Numeric) || value.to_s =~ /^[0-9]+$/
|
|
62
|
+
Xapian.sortable_serialise(value.to_f)
|
|
63
|
+
else
|
|
64
|
+
value.to_s.downcase
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def enable
|
|
69
|
+
config[:enabled] = true
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def index(*models)
|
|
73
|
+
models.each do |model|
|
|
74
|
+
model.xapit_model_adapter.index_all
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# from http://snippets.dzone.com/posts/show/11121
|
|
79
|
+
# could use some refactoring
|
|
80
|
+
def symbolize_keys(arg)
|
|
81
|
+
case arg
|
|
82
|
+
when Array
|
|
83
|
+
arg.map { |elem| symbolize_keys(elem) }
|
|
84
|
+
when Hash
|
|
85
|
+
Hash[
|
|
86
|
+
arg.map { |key, value|
|
|
87
|
+
k = key.is_a?(String) ? key.to_sym : key
|
|
88
|
+
v = symbolize_keys(value)
|
|
89
|
+
[k,v]
|
|
90
|
+
}]
|
|
91
|
+
else
|
|
92
|
+
arg
|
|
93
|
+
end
|
|
51
94
|
end
|
|
52
95
|
end
|
|
96
|
+
|
|
97
|
+
reset_config
|
|
53
98
|
end
|
|
54
99
|
|
|
55
|
-
require
|
|
56
|
-
require
|
|
57
|
-
require
|
|
58
|
-
require
|
|
59
|
-
require
|
|
60
|
-
require
|
|
61
|
-
require
|
|
62
|
-
require
|
|
63
|
-
require
|
|
64
|
-
require
|
|
65
|
-
require
|
|
66
|
-
require
|
|
67
|
-
require
|
|
68
|
-
require
|
|
69
|
-
require File.dirname(__FILE__) + '/xapit/adapters/abstract_adapter'
|
|
70
|
-
require File.dirname(__FILE__) + '/xapit/adapters/active_record_adapter'
|
|
71
|
-
require File.dirname(__FILE__) + '/xapit/adapters/data_mapper_adapter'
|
|
100
|
+
require 'xapit/server/database'
|
|
101
|
+
require 'xapit/server/query'
|
|
102
|
+
require 'xapit/server/indexer'
|
|
103
|
+
require 'xapit/server/app'
|
|
104
|
+
require 'xapit/client/membership'
|
|
105
|
+
require 'xapit/client/index_builder'
|
|
106
|
+
require 'xapit/client/collection'
|
|
107
|
+
require 'xapit/client/facet'
|
|
108
|
+
require 'xapit/client/facet_option'
|
|
109
|
+
require 'xapit/client/remote_database'
|
|
110
|
+
require 'xapit/client/railtie' if defined? Rails
|
|
111
|
+
require 'xapit/client/model_adapters/abstract_model_adapter'
|
|
112
|
+
require 'xapit/client/model_adapters/default_model_adapter'
|
|
113
|
+
require 'xapit/client/model_adapters/active_record_adapter'
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
module Xapit
|
|
2
|
+
module Client
|
|
3
|
+
class Collection
|
|
4
|
+
DEFAULT_PER_PAGE = 20
|
|
5
|
+
|
|
6
|
+
attr_reader :clauses
|
|
7
|
+
|
|
8
|
+
def initialize(clauses = [])
|
|
9
|
+
@clauses = clauses
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def in_classes(*classes)
|
|
13
|
+
scope(:in_classes, classes)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def not_in_classes(*classes)
|
|
17
|
+
scope(:not_in_classes, classes)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def search(phrase = nil)
|
|
21
|
+
if phrase && !phrase.empty?
|
|
22
|
+
scope(:search, phrase)
|
|
23
|
+
else
|
|
24
|
+
self
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def where(conditions)
|
|
29
|
+
scope(:where, where_conditions(conditions))
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def not_where(conditions)
|
|
33
|
+
scope(:not_where, where_conditions(conditions))
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def or_where(conditions)
|
|
37
|
+
scope(:or_where, where_conditions(conditions))
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def order(column, direction = :asc)
|
|
41
|
+
scope(:order, [column, direction])
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def page(page_num)
|
|
45
|
+
scope(:page, page_num)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def per(per_page)
|
|
49
|
+
scope(:per_page, per_page)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def similar_to(member)
|
|
53
|
+
scope(:similar_to, member.class.xapit_index_builder.document_data(member))
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def with_facets(facets)
|
|
57
|
+
facets.to_s.length.zero? ? self : scope(:with_facets, facets.split("-"))
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def include_facets(*facets)
|
|
61
|
+
facets.empty? ? self : scope(:include_facets, facets)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def records
|
|
65
|
+
@records ||= query[:records].map { |record| Kernel.const_get(record[:class]).find(record[:id]) }
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def total_entries
|
|
69
|
+
query[:total].to_i
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def current_page
|
|
73
|
+
(clause_value(:page) || 1).to_i
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def limit_value
|
|
77
|
+
(clause_value(:per_page) || DEFAULT_PER_PAGE).to_i
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def num_pages
|
|
81
|
+
(total_entries.to_f / limit_value).ceil
|
|
82
|
+
end
|
|
83
|
+
alias_method :total_pages, :num_pages
|
|
84
|
+
|
|
85
|
+
def applied_facet_options
|
|
86
|
+
query[:applied_facet_options].map do |option|
|
|
87
|
+
FacetOption.new(option[:name], {:value => option[:value]}, applied_facet_identifiers)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def applied_facet_identifiers
|
|
92
|
+
query[:applied_facet_options].map { |option| option[:id] }
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def facets
|
|
96
|
+
@facets ||= fetch_facets.select { |f| f.options.size > 0 }
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def spelling_suggestion
|
|
100
|
+
@spelling_suggestion ||= Xapit.database.spelling_suggestion(@clauses)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def respond_to?(method, include_private = false)
|
|
104
|
+
Array.method_defined?(method) || super
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
private
|
|
108
|
+
|
|
109
|
+
def where_conditions(conditions)
|
|
110
|
+
conditions.keys.each do |key|
|
|
111
|
+
if conditions[key].kind_of? Range
|
|
112
|
+
conditions[key] = {:from => conditions[key].begin, :to => conditions[key].end}
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
conditions
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def fetch_facets
|
|
119
|
+
applied_facets = applied_facet_options.map(&:identifier)
|
|
120
|
+
query[:facets].map { |attribute, options| Facet.new(attribute, filter_facet_options(options), applied_facets) }
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def filter_facet_options(options)
|
|
124
|
+
options.select do |option|
|
|
125
|
+
option[:count].to_i < total_entries
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def clause_value(key)
|
|
130
|
+
clauses.map { |clause| clause[key] }.compact.first
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def query
|
|
134
|
+
@query ||= Xapit.database.query(@clauses)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def scope(type, args)
|
|
138
|
+
Collection.new(@clauses + [{type => args}])
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def method_missing(method, *args, &block)
|
|
142
|
+
if Array.method_defined?(method)
|
|
143
|
+
records.send(method, *args, &block)
|
|
144
|
+
else
|
|
145
|
+
super
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|