dusen 0.2.2 → 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/.gitignore +1 -0
- data/.travis.yml +3 -0
- data/README.md +176 -47
- data/documents/fulltext_vs_like_benchmark/all_records_and_scope/fulltext.csv +22 -0
- data/documents/fulltext_vs_like_benchmark/all_records_and_scope/fulltext_vs_like.xls +0 -0
- data/documents/fulltext_vs_like_benchmark/all_records_and_scope/like.csv +22 -0
- data/documents/fulltext_vs_like_benchmark/benchmark.rb +70 -0
- data/documents/fulltext_vs_like_benchmark/exact_number_of_records/fulltext.csv +22 -0
- data/documents/fulltext_vs_like_benchmark/exact_number_of_records/fulltext_vs_like.png +0 -0
- data/documents/fulltext_vs_like_benchmark/exact_number_of_records/fulltext_vs_like.xls +0 -0
- data/documents/fulltext_vs_like_benchmark/exact_number_of_records/like.csv +21 -0
- data/dusen.gemspec +1 -1
- data/lib/dusen/active_record/base_ext.rb +104 -0
- data/lib/dusen/active_record/search_text.rb +50 -0
- data/lib/dusen/description.rb +5 -4
- data/lib/dusen/query.rb +24 -4
- data/lib/dusen/railtie.rb +9 -0
- data/lib/dusen/syntax.rb +5 -0
- data/lib/dusen/tasks.rb +31 -0
- data/lib/dusen/token.rb +4 -0
- data/lib/dusen/util.rb +86 -1
- data/lib/dusen/version.rb +1 -1
- data/lib/dusen.rb +7 -1
- data/spec/rails-2.3/Gemfile +3 -1
- data/spec/rails-2.3/Rakefile +1 -1
- data/spec/rails-2.3/app_root/config/database.yml +4 -19
- data/spec/rails-2.3/app_root/config/environments/{in_memory.rb → test.rb} +0 -0
- data/spec/rails-2.3/spec/spec_helper.rb +7 -9
- data/spec/rails-3.0/Gemfile +3 -1
- data/spec/rails-3.0/Rakefile +1 -1
- data/spec/rails-3.0/app_root/config/database.yml +5 -3
- data/spec/rails-3.0/spec/spec_helper.rb +6 -7
- data/spec/rails-3.2/Gemfile +2 -1
- data/spec/rails-3.2/Rakefile +1 -1
- data/spec/rails-3.2/app_root/config/database.yml +5 -3
- data/spec/rails-3.2/spec/spec_helper.rb +3 -7
- data/spec/shared/app_root/app/models/recipe/category.rb +13 -0
- data/spec/shared/app_root/app/models/recipe/ingredient.rb +13 -0
- data/spec/shared/app_root/app/models/recipe.rb +14 -0
- data/spec/shared/app_root/app/models/user/with_fulltext.rb +35 -0
- data/spec/shared/app_root/app/models/user/without_fulltext.rb +34 -0
- data/spec/shared/app_root/config/database.sample.yml +6 -0
- data/spec/shared/app_root/db/migrate/001_create_search_text.rb +19 -0
- data/spec/shared/app_root/db/migrate/002_create_user_variants.rb +25 -0
- data/spec/shared/app_root/db/migrate/003_create_recipe_models.rb +23 -0
- data/spec/shared/spec/dusen/active_record/base_ext_spec.rb +138 -0
- data/spec/shared/spec/dusen/active_record/search_text_spec.rb +23 -0
- data/spec/shared/spec/dusen/parser_spec.rb +14 -0
- data/spec/shared/spec/dusen/query_spec.rb +20 -0
- data/spec/shared/spec/dusen/util_spec.rb +21 -0
- metadata +80 -46
- data/lib/dusen/active_record_ext.rb +0 -35
- data/spec/rails-2.3/app_root/config/environments/mysql.rb +0 -0
- data/spec/rails-2.3/app_root/config/environments/postgresql.rb +0 -0
- data/spec/rails-2.3/app_root/config/environments/sqlite.rb +0 -0
- data/spec/rails-2.3/app_root/config/environments/sqlite3.rb +0 -0
- data/spec/shared/app_root/app/models/user.rb +0 -22
- data/spec/shared/app_root/db/migrate/001_create_users.rb +0 -17
- data/spec/shared/dusen/active_record_spec.rb +0 -55
data/lib/dusen/description.rb
CHANGED
@@ -1,20 +1,21 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
+
# This is the DSL to describe a Syntax.
|
3
4
|
module Dusen
|
4
5
|
class Description
|
5
6
|
|
6
7
|
attr_reader :syntax
|
7
8
|
|
8
|
-
def initialize
|
9
|
-
@syntax =
|
9
|
+
def initialize(syntax)
|
10
|
+
@syntax = syntax
|
10
11
|
end
|
11
12
|
|
12
13
|
def search_by(field, &scoper)
|
13
14
|
@syntax.learn_field(field, &scoper)
|
14
15
|
end
|
15
16
|
|
16
|
-
def self.
|
17
|
-
description = new
|
17
|
+
def self.parse_syntax(syntax, &dsl)
|
18
|
+
description = new(syntax)
|
18
19
|
description.instance_eval(&dsl)
|
19
20
|
description.syntax
|
20
21
|
end
|
data/lib/dusen/query.rb
CHANGED
@@ -5,20 +5,40 @@ module Dusen
|
|
5
5
|
|
6
6
|
include Enumerable
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
attr_reader :tokens
|
9
|
+
|
10
|
+
def initialize(initial_tokens = [])
|
11
|
+
@tokens = initial_tokens
|
10
12
|
end
|
11
13
|
|
12
14
|
def <<(token)
|
13
|
-
|
15
|
+
tokens << token
|
16
|
+
end
|
17
|
+
|
18
|
+
def [](index)
|
19
|
+
tokens[index]
|
14
20
|
end
|
15
21
|
|
22
|
+
#def +(tokens)
|
23
|
+
# tokens.each do |token|
|
24
|
+
# self << token
|
25
|
+
# end
|
26
|
+
#end
|
27
|
+
|
16
28
|
def to_s
|
17
29
|
collect(&:to_s).join(" + ")
|
18
30
|
end
|
19
31
|
|
20
32
|
def each(&block)
|
21
|
-
|
33
|
+
tokens.each(&block)
|
34
|
+
end
|
35
|
+
|
36
|
+
def condensed
|
37
|
+
texts = tokens.select(&:text?).collect(&:value)
|
38
|
+
field_tokens = tokens.reject(&:text?)
|
39
|
+
condensed_tokens = field_tokens
|
40
|
+
condensed_tokens << Token.new(texts) if texts.present?
|
41
|
+
self.class.new(condensed_tokens)
|
22
42
|
end
|
23
43
|
|
24
44
|
end
|
data/lib/dusen/syntax.rb
CHANGED
@@ -19,6 +19,7 @@ module Dusen
|
|
19
19
|
def search(root_scope, query)
|
20
20
|
scope = root_scope
|
21
21
|
query = parse(query) if query.is_a?(String)
|
22
|
+
query = query.condensed
|
22
23
|
query.each do |token|
|
23
24
|
scoper = @scopers[token.field] || unknown_scoper
|
24
25
|
scope = scoper.call(scope, token.value)
|
@@ -26,6 +27,10 @@ module Dusen
|
|
26
27
|
scope
|
27
28
|
end
|
28
29
|
|
30
|
+
def fields
|
31
|
+
@scopers
|
32
|
+
end
|
33
|
+
|
29
34
|
def parse(query)
|
30
35
|
Parser.parse(query)
|
31
36
|
end
|
data/lib/dusen/tasks.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
#namespace :dusen do
|
2
|
+
#
|
3
|
+
# desc 'Creates a MyISAM table "search_texts" for fast Dusen searches'
|
4
|
+
# task :create_search_text do
|
5
|
+
# generator = File.exists?('script/generate') ? 'script/generate' : 'rails generate'
|
6
|
+
# output = `#{generator} migration CreateSearchText`
|
7
|
+
# output =~ %r{(db/migrate/.+?\.rb)} or raise "Could not create migration: #{output}"
|
8
|
+
# path = $1
|
9
|
+
# File.open(path, 'w') do |file|
|
10
|
+
# file.write(
|
11
|
+
#"
|
12
|
+
#class CreateSearchText < ActiveRecord::Migration
|
13
|
+
# def up
|
14
|
+
# create_table :search_texts, :options => 'ENGINE=MyISAM' do |t|
|
15
|
+
# t.integer :model_id
|
16
|
+
# t.string :model_type
|
17
|
+
# t.text :words
|
18
|
+
# end
|
19
|
+
# add_index :search_texts, [:model_type, :model_id] # for deletion
|
20
|
+
# execute 'CREATE FULLTEXT INDEX fulltext_index_body ON search_texts (words)' # for search
|
21
|
+
# end
|
22
|
+
# def down
|
23
|
+
# drop_table :search_texts
|
24
|
+
# end
|
25
|
+
#end
|
26
|
+
#"
|
27
|
+
# )
|
28
|
+
# end
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
#end
|
data/lib/dusen/token.rb
CHANGED
data/lib/dusen/util.rb
CHANGED
@@ -8,8 +8,33 @@ module Dusen
|
|
8
8
|
"%#{escape_for_like_query(phrase)}%"
|
9
9
|
end
|
10
10
|
|
11
|
+
def escape_with_backslash(phrase, characters)
|
12
|
+
characters << '\\'
|
13
|
+
pattern = /[#{characters.collect(&Regexp.method(:quote)).join('')}]/
|
14
|
+
# debugger
|
15
|
+
phrase.gsub(pattern) do |match|
|
16
|
+
"\\#{match}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
11
20
|
def escape_for_like_query(phrase)
|
12
|
-
phrase.gsub("%", "\\%").gsub("_", "\\_")
|
21
|
+
# phrase.gsub("%", "\\%").gsub("_", "\\_")
|
22
|
+
escape_with_backslash(phrase, ['%', '_'])
|
23
|
+
end
|
24
|
+
|
25
|
+
def escape_for_boolean_fulltext_query(phrase)
|
26
|
+
escape_with_backslash(phrase, ['+', '-', '<', '>', '(', ')', '~', '*', '"'])
|
27
|
+
end
|
28
|
+
|
29
|
+
def boolean_fulltext_query(phrases)
|
30
|
+
phrases.collect do |word|
|
31
|
+
escaped_word = Dusen::Util.escape_for_boolean_fulltext_query(word)
|
32
|
+
if escaped_word =~ /\s/
|
33
|
+
%{+"#{escaped_word}"} # no prefixed wildcard possible for phrases
|
34
|
+
else
|
35
|
+
%{+#{escaped_word}*}
|
36
|
+
end
|
37
|
+
end.join(' ')
|
13
38
|
end
|
14
39
|
|
15
40
|
def qualify_column_name(model, column_name)
|
@@ -32,5 +57,65 @@ module Dusen
|
|
32
57
|
end
|
33
58
|
end
|
34
59
|
|
60
|
+
def select_scope_fields(scope, fields)
|
61
|
+
if scope.respond_to?(:select)
|
62
|
+
# Rails 3
|
63
|
+
scope.select(fields)
|
64
|
+
else
|
65
|
+
# Rails 2
|
66
|
+
scope.scoped(:select => fields)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def drop_all_tables
|
71
|
+
connection = ::ActiveRecord::Base.connection
|
72
|
+
connection.tables.each do |table|
|
73
|
+
connection.drop_table table
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def migrate_test_database
|
78
|
+
print "\033[30m" # dark gray text
|
79
|
+
drop_all_tables
|
80
|
+
::ActiveRecord::Migrator.migrate("#{Rails.root}/db/migrate")
|
81
|
+
print "\033[0m"
|
82
|
+
end
|
83
|
+
|
84
|
+
#def scope_to_sql(scope)
|
85
|
+
# query = if scope.respond_to?(:to_sql)
|
86
|
+
# scope.to_sql
|
87
|
+
# else
|
88
|
+
# scope.construct_finder_sql({})
|
89
|
+
# end
|
90
|
+
#end
|
91
|
+
|
92
|
+
def scope_to_sql(options = {})
|
93
|
+
if Rails.version < '3'
|
94
|
+
scope.construct_finder_sql(options)
|
95
|
+
else
|
96
|
+
scope.scoped(options).to_sql
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def collect_column(scope, column_name, find_options = {})
|
101
|
+
distinct = find_options.delete(:distinct)
|
102
|
+
qualified_column_name = "`#{scope.table_name}`.`#{column_name}`"
|
103
|
+
select = distinct ? "DISTINCT #{qualified_column_name}" : qualified_column_name
|
104
|
+
query = if Rails.version.to_i < 3
|
105
|
+
scope.construct_finder_sql(find_options.merge(:select => select))
|
106
|
+
else
|
107
|
+
scope.scoped(find_options.merge(:select => select)).to_sql
|
108
|
+
end
|
109
|
+
raw_values = scope.connection.select_values(query)
|
110
|
+
column = scope.columns_hash[column_name.to_s] or raise "Could not retrieve column information: #{column_name}"
|
111
|
+
raw_values.collect { |value| column.type_cast(value) }
|
112
|
+
end
|
113
|
+
|
114
|
+
#def collect_ids(scope)
|
115
|
+
# scope = select_scope_fields(scope, "`#{scope.table_name}`.`id`")
|
116
|
+
# query = scope_to_sql(scope)
|
117
|
+
# ::ActiveRecord::Base.connection.select_values(query).collect(&:to_i)
|
118
|
+
#end
|
119
|
+
|
35
120
|
end
|
36
121
|
end
|
data/lib/dusen/version.rb
CHANGED
data/lib/dusen.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
+
require 'dusen/version'
|
3
4
|
require 'dusen/util'
|
4
5
|
require 'dusen/token'
|
5
6
|
require 'dusen/description'
|
@@ -8,5 +9,10 @@ require 'dusen/query'
|
|
8
9
|
require 'dusen/syntax'
|
9
10
|
|
10
11
|
if defined?(ActiveRecord)
|
11
|
-
require 'dusen/
|
12
|
+
require 'dusen/active_record/base_ext'
|
13
|
+
require 'dusen/active_record/search_text'
|
12
14
|
end
|
15
|
+
|
16
|
+
#if defined?(Rails::Railstie)
|
17
|
+
# require 'dusen/railtie'
|
18
|
+
#end
|
data/spec/rails-2.3/Gemfile
CHANGED
@@ -3,8 +3,10 @@ source :rubygems
|
|
3
3
|
gem 'rails', '~>2.3'
|
4
4
|
gem 'rspec', '~>1.3'
|
5
5
|
gem 'rspec-rails', '~>1.3'
|
6
|
-
gem '
|
6
|
+
gem 'mysql2', '~>0.2.0'
|
7
7
|
gem 'ruby-debug', :platforms => :ruby_18
|
8
8
|
gem 'test-unit', '~>1.2', :platforms => :ruby_19
|
9
|
+
gem 'database_cleaner'
|
10
|
+
gem 'andand'
|
9
11
|
|
10
12
|
gem 'dusen', :path => '../..'
|
data/spec/rails-2.3/Rakefile
CHANGED
@@ -7,5 +7,5 @@ task :default => :spec
|
|
7
7
|
desc "Run all specs for a specific rails version"
|
8
8
|
Spec::Rake::SpecTask.new() do |t|
|
9
9
|
t.spec_opts = ['--options', "\"spec.opts\""]
|
10
|
-
t.spec_files = defined?(SPEC) ? SPEC : FileList['**/*_spec.rb', '../shared/**/*_spec.rb']
|
10
|
+
t.spec_files = defined?(SPEC) ? SPEC : FileList['**/*_spec.rb', '../shared/spec/**/*_spec.rb']
|
11
11
|
end
|
@@ -1,21 +1,6 @@
|
|
1
|
-
|
2
|
-
adapter:
|
3
|
-
database: ":memory:"
|
4
|
-
verbosity: quiet
|
5
|
-
sqlite:
|
6
|
-
adapter: sqlite
|
7
|
-
dbfile: plugin_test.sqlite.db
|
8
|
-
sqlite3:
|
9
|
-
adapter: sqlite3
|
10
|
-
dbfile: plugin_test.sqlite3.db
|
11
|
-
postgresql:
|
12
|
-
adapter: postgresql
|
13
|
-
username: postgres
|
14
|
-
password: postgres
|
15
|
-
database: plugin_test
|
16
|
-
mysql:
|
17
|
-
adapter: mysql
|
1
|
+
test:
|
2
|
+
adapter: mysql2
|
18
3
|
host: localhost
|
19
4
|
username: root
|
20
|
-
password:
|
21
|
-
database:
|
5
|
+
password: junior
|
6
|
+
database: dusen_test
|
File without changes
|
@@ -2,25 +2,23 @@
|
|
2
2
|
|
3
3
|
$: << File.join(File.dirname(__FILE__), "/../../lib" )
|
4
4
|
|
5
|
-
|
6
|
-
ENV['RAILS_ENV'] = 'in_memory'
|
5
|
+
ENV['RAILS_ENV'] = 'test'
|
7
6
|
|
8
7
|
# Load the Rails environment and testing framework
|
9
8
|
require "#{File.dirname(__FILE__)}/../app_root/config/environment"
|
10
9
|
require 'spec/rails'
|
11
|
-
|
12
|
-
# Undo changes to RAILS_ENV
|
13
|
-
silence_warnings {RAILS_ENV = ENV['RAILS_ENV']}
|
10
|
+
DatabaseCleaner.strategy = :truncation
|
14
11
|
|
15
12
|
# Requires supporting files with custom matchers and macros, etc in ./support/ and its subdirectories.
|
16
13
|
Dir[File.expand_path(File.join(File.dirname(__FILE__),'support','**','*.rb'))].each {|f| require f}
|
17
14
|
|
18
15
|
# Run the migrations
|
19
|
-
|
20
|
-
ActiveRecord::Migrator.migrate("#{Rails.root}/db/migrate")
|
21
|
-
print "\033[0m"
|
16
|
+
Dusen::Util.migrate_test_database
|
22
17
|
|
23
18
|
Spec::Runner.configure do |config|
|
24
|
-
config.use_transactional_fixtures =
|
19
|
+
config.use_transactional_fixtures = false
|
25
20
|
config.use_instantiated_fixtures = false
|
21
|
+
config.before(:each) do
|
22
|
+
DatabaseCleaner.clean
|
23
|
+
end
|
26
24
|
end
|
data/spec/rails-3.0/Gemfile
CHANGED
data/spec/rails-3.0/Rakefile
CHANGED
@@ -6,6 +6,6 @@ task :default => :spec
|
|
6
6
|
|
7
7
|
desc "Run all specs for a specific rails version"
|
8
8
|
RSpec::Core::RakeTask.new(:spec) do |t|
|
9
|
-
t.pattern = defined?(SPEC) ? SPEC : ['**/*_spec.rb', '../shared/**/*_spec.rb']
|
9
|
+
t.pattern = defined?(SPEC) ? SPEC : ['**/*_spec.rb', '../shared/spec/**/*_spec.rb']
|
10
10
|
t.verbose = false
|
11
11
|
end
|
@@ -2,22 +2,21 @@
|
|
2
2
|
|
3
3
|
$: << File.join(File.dirname(__FILE__), "/../../lib" )
|
4
4
|
|
5
|
-
# Set the default environment to sqlite3's in_memory database
|
6
5
|
ENV['RAILS_ENV'] = 'test'
|
7
6
|
ENV['RAILS_ROOT'] = 'app_root'
|
8
7
|
|
9
8
|
# Load the Rails environment and testing framework
|
10
9
|
require "#{File.dirname(__FILE__)}/../app_root/config/environment"
|
11
10
|
require 'rspec/rails'
|
12
|
-
|
13
|
-
FileUtils.rm(Dir.glob("#{Rails.root}/db/*.db"), :force => true)
|
11
|
+
DatabaseCleaner.strategy = :truncation
|
14
12
|
|
15
13
|
# Run the migrations
|
16
|
-
|
17
|
-
ActiveRecord::Migrator.migrate("#{Rails.root}/db/migrate")
|
18
|
-
print "\033[0m"
|
14
|
+
Dusen::Util.migrate_test_database
|
19
15
|
|
20
16
|
RSpec.configure do |config|
|
21
|
-
config.use_transactional_fixtures =
|
17
|
+
config.use_transactional_fixtures = false
|
22
18
|
config.use_instantiated_fixtures = false
|
19
|
+
config.before(:each) do
|
20
|
+
DatabaseCleaner.clean
|
21
|
+
end
|
23
22
|
end
|
data/spec/rails-3.2/Gemfile
CHANGED
data/spec/rails-3.2/Rakefile
CHANGED
@@ -6,6 +6,6 @@ task :default => :spec
|
|
6
6
|
|
7
7
|
desc "Run all specs for a specific rails version"
|
8
8
|
RSpec::Core::RakeTask.new(:spec) do |t|
|
9
|
-
t.pattern = defined?(SPEC) ? SPEC : ['**/*_spec.rb', '../shared/**/*_spec.rb']
|
9
|
+
t.pattern = defined?(SPEC) ? SPEC : ['**/*_spec.rb', '../shared/spec/**/*_spec.rb']
|
10
10
|
t.verbose = false
|
11
11
|
end
|
@@ -5,19 +5,15 @@ $: << File.join(File.dirname(__FILE__), "/../../lib" )
|
|
5
5
|
ENV['RAILS_ENV'] = 'test'
|
6
6
|
ENV['RAILS_ROOT'] = 'app_root'
|
7
7
|
|
8
|
-
FileUtils.rm(Dir.glob("#{ENV['RAILS_ROOT']}/db/*.db"), :force => true)
|
9
|
-
|
10
8
|
# Load the Rails environment and testing framework
|
11
9
|
require "#{File.dirname(__FILE__)}/../app_root/config/environment"
|
12
10
|
require 'rspec/rails'
|
13
|
-
require 'database_cleaner'
|
14
|
-
|
15
11
|
DatabaseCleaner.strategy = :truncation
|
16
12
|
|
13
|
+
# Dir["#{File.dirname(__FILE__)}/../../shared/spec/shared_examples"].each {|f| require f}
|
14
|
+
|
17
15
|
# Run the migrations
|
18
|
-
|
19
|
-
ActiveRecord::Migrator.migrate("#{Rails.root}/db/migrate")
|
20
|
-
print "\033[0m"
|
16
|
+
Dusen::Util.migrate_test_database
|
21
17
|
|
22
18
|
RSpec.configure do |config|
|
23
19
|
config.use_transactional_fixtures = false
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class Recipe < ActiveRecord::Base
|
2
|
+
|
3
|
+
validates_presence_of :name
|
4
|
+
|
5
|
+
has_many :ingredients, :class_name => 'Recipe::Ingredient', :inverse_of => :recipe
|
6
|
+
belongs_to :category, :class_name => 'Recipe::Category', :inverse_of => :recipes
|
7
|
+
|
8
|
+
search_syntax
|
9
|
+
|
10
|
+
search_text do
|
11
|
+
[name, category.andand.name, ingredients.collect(&:name)]
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module User
|
4
|
+
class WithFulltext < ActiveRecord::Base
|
5
|
+
|
6
|
+
self.table_name = 'users_with_fulltext'
|
7
|
+
|
8
|
+
search_syntax do
|
9
|
+
|
10
|
+
search_by :city do |scope, city|
|
11
|
+
scope.scoped(:conditions => { :city => city })
|
12
|
+
end
|
13
|
+
|
14
|
+
search_by :email do |scope, email|
|
15
|
+
scope.scoped(:conditions => { :email => email })
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
search_syntax do # multiple search_syntax directives are allowed
|
21
|
+
|
22
|
+
search_by :role do |scope, role|
|
23
|
+
scope.scoped(:conditions => { :role => role })
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
search_text do
|
29
|
+
[name, email, city]
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module User
|
4
|
+
class WithoutFulltext < ActiveRecord::Base
|
5
|
+
|
6
|
+
self.table_name = 'users_without_fulltext'
|
7
|
+
|
8
|
+
search_syntax do
|
9
|
+
|
10
|
+
search_by :text do |scope, text|
|
11
|
+
scope.where_like([:name, :email, :city] => text)
|
12
|
+
end
|
13
|
+
|
14
|
+
search_by :city do |scope, city|
|
15
|
+
scope.scoped(:conditions => { :city => city })
|
16
|
+
end
|
17
|
+
|
18
|
+
search_by :email do |scope, email|
|
19
|
+
scope.scoped(:conditions => { :email => email })
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
search_syntax do # multiple search_syntax directives are allowed
|
25
|
+
|
26
|
+
search_by :role do |scope, role|
|
27
|
+
scope.scoped(:conditions => { :role => role })
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class CreateSearchText < ActiveRecord::Migration
|
2
|
+
|
3
|
+
def self.up
|
4
|
+
create_table :search_texts, :options => 'ENGINE=MyISAM' do |t|
|
5
|
+
t.integer :source_id
|
6
|
+
t.string :source_type
|
7
|
+
t.boolean :stale
|
8
|
+
t.text :words
|
9
|
+
end
|
10
|
+
add_index :search_texts, [:source_type, :source_id] # for updates
|
11
|
+
add_index :search_texts, [:source_type, :stale] # for refreshs
|
12
|
+
execute 'CREATE FULLTEXT INDEX fulltext_index_words ON search_texts (words)'
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.down
|
16
|
+
drop_table :search_texts
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
class CreateUserVariants < ActiveRecord::Migration
|
4
|
+
|
5
|
+
def self.user_tables
|
6
|
+
[:users_with_fulltext, :users_without_fulltext]
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.up
|
10
|
+
user_tables.each do |user_table|
|
11
|
+
create_table user_table do |t|
|
12
|
+
t.string :name
|
13
|
+
t.string :email
|
14
|
+
t.string :city
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.down
|
20
|
+
user_tables.each do |user_table|
|
21
|
+
drop_table user_table
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class CreateRecipeModels < ActiveRecord::Migration
|
2
|
+
|
3
|
+
def self.up
|
4
|
+
create_table :recipes do |t|
|
5
|
+
t.string :name
|
6
|
+
t.integer :category_id
|
7
|
+
end
|
8
|
+
create_table :recipe_ingredients do |t|
|
9
|
+
t.string :name
|
10
|
+
t.integer :recipe_id
|
11
|
+
end
|
12
|
+
create_table :recipe_categories do |t|
|
13
|
+
t.string :name
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.down
|
18
|
+
drop_table :recipes
|
19
|
+
drop_table :recipe_ingredients
|
20
|
+
drop_table :recipe_categories
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|