db_text_search 0.1.1 → 0.1.2
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.
- checksums.yaml +4 -4
- data/CHANGES.md +4 -0
- data/README.md +1 -1
- data/lib/db_text_search/case_insensitive_eq/abstract_adapter.rb +4 -1
- data/lib/db_text_search/case_insensitive_eq/collate_nocase_adapter.rb +7 -9
- data/lib/db_text_search/case_insensitive_eq/insensitive_column_adapter.rb +2 -0
- data/lib/db_text_search/case_insensitive_eq/lower_adapter.rb +12 -14
- data/lib/db_text_search/case_insensitive_eq.rb +16 -7
- data/lib/db_text_search/full_text_search/abstract_adapter.rb +7 -20
- data/lib/db_text_search/full_text_search/mysql_adapter.rb +11 -8
- data/lib/db_text_search/full_text_search/postgres_adapter.rb +13 -14
- data/lib/db_text_search/full_text_search/sqlite_adapter.rb +12 -7
- data/lib/db_text_search/full_text_search.rb +24 -10
- data/lib/db_text_search/query_building.rb +21 -0
- data/lib/db_text_search/version.rb +2 -1
- data/lib/db_text_search.rb +5 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2c4d97cd16283ff2c47726a56e36fee85c3eb922
|
4
|
+
data.tar.gz: 06b3ca789b57a423f9ffc33840903e8028377263
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e1ef0f9d45289ed1623f73cded6a2bd3c2f7ad88928364af7b7e94077eb79bcb93c5842c9f772e64b003d5039c64d3028242395d4263ad7574ebdf41e7854231
|
7
|
+
data.tar.gz: 027a5ebcfc61f1d017aee0bd61b66e7327132667085556d60fe3453b92f266093bad59e9f248dde4ec9ff1e6539716a468b3e8805f9a3f8957cf3335c592acb6
|
data/CHANGES.md
CHANGED
data/README.md
CHANGED
@@ -2,6 +2,8 @@ require 'db_text_search/query_building'
|
|
2
2
|
module DbTextSearch
|
3
3
|
class CaseInsensitiveEq
|
4
4
|
# A base class for CaseInsensitiveStringFinder adapters.
|
5
|
+
# @abstract
|
6
|
+
# @api private
|
5
7
|
class AbstractAdapter
|
6
8
|
include ::DbTextSearch::QueryBuilding
|
7
9
|
|
@@ -25,7 +27,8 @@ module DbTextSearch
|
|
25
27
|
# @param table_name [String, Symbol]
|
26
28
|
# @param column_name [String, Symbol]
|
27
29
|
# @param options [Hash] passed down to ActiveRecord::ConnectionAdapters::SchemaStatements#add_index.
|
28
|
-
# @
|
30
|
+
# @option options name [String] index name
|
31
|
+
# @option options unique [Boolean] default: false
|
29
32
|
# @abstract
|
30
33
|
def self.add_index(connection, table_name, column_name, options = {})
|
31
34
|
fail 'abstract'
|
@@ -1,25 +1,23 @@
|
|
1
1
|
require 'db_text_search/case_insensitive_eq/abstract_adapter'
|
2
2
|
module DbTextSearch
|
3
3
|
class CaseInsensitiveEq
|
4
|
+
# Provides case-insensitive string-in-set querying via COLLATE NOCASE.
|
5
|
+
# @api private
|
4
6
|
class CollateNocaseAdapter < AbstractAdapter
|
5
7
|
# (see AbstractAdapter#find)
|
6
8
|
def find(values)
|
7
9
|
conn = @scope.connection
|
8
|
-
@scope.where
|
9
|
-
#{quoted_scope_column} COLLATE NOCASE IN (#{values.map { |v| conn.quote(v.to_s) }.join(', ')})
|
10
|
-
SQL
|
10
|
+
@scope.where "#{quoted_scope_column} COLLATE NOCASE IN (#{values.map { |v| conn.quote(v.to_s) }.join(', ')})"
|
11
11
|
end
|
12
12
|
|
13
13
|
# (see AbstractAdapter.add_index)
|
14
14
|
def self.add_index(connection, table_name, column_name, options = {})
|
15
15
|
# TODO: Switch to the native Rails solution once it's landed, as the current one requires SQL dump format.
|
16
16
|
# https://github.com/rails/rails/pull/18499
|
17
|
-
options.
|
18
|
-
|
19
|
-
connection.
|
20
|
-
|
21
|
-
(#{connection.quote_column_name(column_name)} COLLATE NOCASE);
|
22
|
-
SQL
|
17
|
+
options = options.dup
|
18
|
+
options[:name] ||= "#{column_name}_nocase"
|
19
|
+
options[:expression] = "(#{connection.quote_column_name(column_name)} COLLATE NOCASE)"
|
20
|
+
connection.exec_query quoted_create_index(connection, table_name, **options)
|
23
21
|
end
|
24
22
|
end
|
25
23
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'db_text_search/case_insensitive_eq/abstract_adapter'
|
2
2
|
module DbTextSearch
|
3
3
|
class CaseInsensitiveEq
|
4
|
+
# Provides case-insensitive string-in-set querying for case-insensitive columns.
|
5
|
+
# @api private
|
4
6
|
class InsensitiveColumnAdapter < AbstractAdapter
|
5
7
|
# (see AbstractAdapter#find)
|
6
8
|
def find(values)
|
@@ -1,13 +1,13 @@
|
|
1
1
|
require 'db_text_search/case_insensitive_eq/abstract_adapter'
|
2
2
|
module DbTextSearch
|
3
3
|
class CaseInsensitiveEq
|
4
|
+
# Provides case-insensitive string-in-set querying by applying the database LOWER function.
|
5
|
+
# @api private
|
4
6
|
class LowerAdapter < AbstractAdapter
|
5
7
|
# (see AbstractAdapter#find)
|
6
8
|
def find(values)
|
7
9
|
conn = @scope.connection
|
8
|
-
@scope.where
|
9
|
-
LOWER(#{quoted_scope_column}) IN (#{values.map { |v| "LOWER(#{conn.quote(v.to_s)})" }.join(', ')})
|
10
|
-
SQL
|
10
|
+
@scope.where "LOWER(#{quoted_scope_column}) IN (#{values.map { |v| "LOWER(#{conn.quote(v.to_s)})" }.join(', ')})"
|
11
11
|
end
|
12
12
|
|
13
13
|
# (see AbstractAdapter.add_index)
|
@@ -15,21 +15,19 @@ module DbTextSearch
|
|
15
15
|
if connection.adapter_name =~ /postgres/i
|
16
16
|
# TODO: Switch to native Rails support once it lands.
|
17
17
|
# https://github.com/rails/rails/pull/18499
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
18
|
+
options = options.dup
|
19
|
+
options[:name] ||= "#{table_name}_#{column_name}_lower"
|
20
|
+
options[:expression] = "(LOWER(#{connection.quote_column_name(column_name)}))"
|
21
|
+
if defined?(::SchemaPlus)
|
22
|
+
connection.add_index(table_name, column_name, options)
|
22
23
|
else
|
23
|
-
|
24
|
-
connection.exec_query <<-SQL.strip
|
25
|
-
CREATE #{'UNIQUE ' if options[:unique]}INDEX #{index_name} ON #{connection.quote_table_name(table_name)}
|
26
|
-
(LOWER(#{connection.quote_column_name(column_name)}));
|
27
|
-
SQL
|
24
|
+
connection.exec_query quoted_create_index(connection, table_name, **options)
|
28
25
|
end
|
29
26
|
elsif connection.adapter_name =~ /mysql/i
|
30
|
-
fail 'MySQL case-insensitive index creation for case-sensitive columns is not supported.'
|
27
|
+
fail ArgumentError.new('MySQL case-insensitive index creation for case-sensitive columns is not supported.')
|
31
28
|
else
|
32
|
-
fail
|
29
|
+
fail ArgumentError.new(
|
30
|
+
"Cannot create a case-insensitive index for case-sensitive column on #{connection.adapter_name}.")
|
33
31
|
end
|
34
32
|
end
|
35
33
|
end
|
@@ -5,14 +5,15 @@ require 'db_text_search/case_insensitive_eq/collate_nocase_adapter'
|
|
5
5
|
module DbTextSearch
|
6
6
|
# Provides case-insensitive string-in-set querying, and CI index creation.
|
7
7
|
class CaseInsensitiveEq
|
8
|
-
#
|
8
|
+
# @param scope [ActiveRecord::Relation, Class<ActiveRecord::Base>]
|
9
|
+
# @param column [Symbol] name
|
9
10
|
def initialize(scope, column)
|
10
11
|
@adapter = self.class.adapter_class(scope.connection, scope.table_name, column).new(scope, column)
|
11
12
|
@scope = scope
|
12
13
|
end
|
13
14
|
|
14
15
|
# @param value_or_values [String, Array<String>]
|
15
|
-
# @return
|
16
|
+
# @return [ActiveRecord::Relation]
|
16
17
|
def find(value_or_values)
|
17
18
|
values = Array(value_or_values)
|
18
19
|
return @scope.none if values.empty?
|
@@ -23,14 +24,14 @@ module DbTextSearch
|
|
23
24
|
# @param connection [ActiveRecord::ConnectionAdapters::AbstractAdapter]
|
24
25
|
# @param table_name [String, Symbol]
|
25
26
|
# @param column_name [String, Symbol]
|
26
|
-
# @param options [Hash]
|
27
|
+
# @param options [Hash] passed to ActiveRecord::ConnectionAdapters::SchemaStatements#add_index
|
27
28
|
def self.add_ci_text_column(connection, table_name, column_name, options = {})
|
28
29
|
case connection.adapter_name.downcase
|
29
30
|
when /mysql/
|
30
31
|
connection.add_column(table_name, column_name, :text, options)
|
31
32
|
when /postgres/
|
32
33
|
connection.enable_extension 'citext'
|
33
|
-
if ActiveRecord::VERSION::
|
34
|
+
if ActiveRecord::VERSION::STRING >= '4.2.0'
|
34
35
|
connection.add_column(table_name, column_name, :citext, options)
|
35
36
|
else
|
36
37
|
connection.add_column(table_name, column_name, 'CITEXT', options)
|
@@ -42,11 +43,18 @@ module DbTextSearch
|
|
42
43
|
connection.add_column(table_name, column_name, 'TEXT COLLATE NOCASE', options)
|
43
44
|
end
|
44
45
|
else
|
45
|
-
fail "Unsupported adapter #{connection.adapter_name}"
|
46
|
+
fail ArgumentError.new("Unsupported adapter #{connection.adapter_name}")
|
46
47
|
end
|
47
48
|
end
|
48
49
|
|
49
|
-
#
|
50
|
+
# Add an index for case-insensitive string search.
|
51
|
+
#
|
52
|
+
# @param connection [ActiveRecord::ConnectionAdapters::AbstractAdapter]
|
53
|
+
# @param table_name [String, Symbol]
|
54
|
+
# @param column_name [String, Symbol]
|
55
|
+
# @param options [Hash]
|
56
|
+
# @option options name [String] index name
|
57
|
+
# @option options unique [Boolean] default: false
|
50
58
|
def self.add_index(connection, table_name, column_name, options = {})
|
51
59
|
adapter_class(connection, table_name, column_name).add_index(connection, table_name, column_name, options)
|
52
60
|
end
|
@@ -55,6 +63,7 @@ module DbTextSearch
|
|
55
63
|
# @param table_name [String, Symbol]
|
56
64
|
# @param column_name [String, Symbol]
|
57
65
|
# @return [Class<AbstractAdapter>]
|
66
|
+
# @api private
|
58
67
|
def self.adapter_class(connection, table_name, column_name)
|
59
68
|
if connection.adapter_name.downcase =~ /sqlite/
|
60
69
|
# Always use COLLATE NOCASE for SQLite, as we can't check if the column is case-sensitive.
|
@@ -81,7 +90,7 @@ module DbTextSearch
|
|
81
90
|
when /postgres/
|
82
91
|
column.sql_type !~ /citext/i
|
83
92
|
else
|
84
|
-
fail "Unsupported adapter #{connection.adapter_name}"
|
93
|
+
fail ArgumentError.new("Unsupported adapter #{connection.adapter_name}")
|
85
94
|
end
|
86
95
|
end
|
87
96
|
end
|
@@ -1,9 +1,10 @@
|
|
1
1
|
module DbTextSearch
|
2
2
|
class FullTextSearch
|
3
3
|
# A base class for FullTextSearch adapters.
|
4
|
+
# @abstract
|
5
|
+
# @api private
|
4
6
|
class AbstractAdapter
|
5
7
|
include ::DbTextSearch::QueryBuilding
|
6
|
-
DEFAULT_PG_TS_CONFIG = %q('english')
|
7
8
|
|
8
9
|
# @param scope [ActiveRecord::Relation, Class<ActiveRecord::Base>]
|
9
10
|
# @param column [Symbol] name
|
@@ -13,17 +14,10 @@ module DbTextSearch
|
|
13
14
|
end
|
14
15
|
|
15
16
|
# @param terms [Array<String>]
|
17
|
+
# @param pg_ts_config [String] a pg text search config
|
16
18
|
# @return [ActiveRecord::Relation]
|
17
|
-
def find(terms)
|
18
|
-
@scope.where(*where_args(terms))
|
19
|
-
end
|
20
|
-
|
21
|
-
# @param terms [Array<String>]
|
22
|
-
# @param options [Hash]
|
23
|
-
# @option options pg_ts_config [String] a pg text search config. Default: 'english'
|
24
|
-
# @return [query fragment, binds]
|
25
19
|
# @abstract
|
26
|
-
def
|
20
|
+
def find(terms, pg_ts_config:)
|
27
21
|
fail 'abstract'
|
28
22
|
end
|
29
23
|
|
@@ -32,19 +26,12 @@ module DbTextSearch
|
|
32
26
|
# @param connection [ActiveRecord::ConnectionAdapters::AbstractAdapter]
|
33
27
|
# @param table_name [String, Symbol]
|
34
28
|
# @param column_name [String, Symbol]
|
35
|
-
# @param
|
36
|
-
# @
|
29
|
+
# @param name [String, Symbol] index name
|
30
|
+
# @param pg_ts_config [String] for Postgres, the TS config to use; ignored for non-postgres.
|
37
31
|
# @abstract
|
38
|
-
def self.add_index(connection, table_name, column_name,
|
32
|
+
def self.add_index(connection, table_name, column_name, name:, pg_ts_config:)
|
39
33
|
fail 'abstract'
|
40
34
|
end
|
41
|
-
|
42
|
-
protected
|
43
|
-
|
44
|
-
def parse_search_options(options = {})
|
45
|
-
options.assert_valid_keys(:pg_ts_config)
|
46
|
-
options.reverse_merge(pg_ts_config: DEFAULT_PG_TS_CONFIG)
|
47
|
-
end
|
48
35
|
end
|
49
36
|
end
|
50
37
|
end
|
@@ -1,18 +1,21 @@
|
|
1
1
|
require 'db_text_search/full_text_search/abstract_adapter'
|
2
2
|
module DbTextSearch
|
3
3
|
class FullTextSearch
|
4
|
+
# Provides basic FTS support for MySQL.
|
5
|
+
#
|
6
|
+
# Runs a `MATCH AGAINST` query against a `FULLTEXT` index.
|
7
|
+
#
|
8
|
+
# @note MySQL v5.6.4+ is required.
|
9
|
+
# @api private
|
4
10
|
class MysqlAdapter < AbstractAdapter
|
5
|
-
# (see AbstractAdapter#
|
6
|
-
def
|
7
|
-
|
8
|
-
conn = @scope.connection
|
9
|
-
["MATCH (#{conn.quote_table_name(@scope.table_name)}.#{conn.quote_column_name(@column)}) AGAINST (?)",
|
10
|
-
terms.uniq.join(' ')]
|
11
|
+
# (see AbstractAdapter#find)
|
12
|
+
def find(terms, pg_ts_config:)
|
13
|
+
@scope.where("MATCH (#{quoted_scope_column}) AGAINST (?)", terms.uniq.join(' '))
|
11
14
|
end
|
12
15
|
|
13
16
|
# (see AbstractAdapter.add_index)
|
14
|
-
def self.add_index(connection, table_name, column_name,
|
15
|
-
connection.add_index table_name, column_name,
|
17
|
+
def self.add_index(connection, table_name, column_name, name:, pg_ts_config:)
|
18
|
+
connection.add_index table_name, column_name, name: name, type: :fulltext
|
16
19
|
end
|
17
20
|
end
|
18
21
|
end
|
@@ -1,24 +1,23 @@
|
|
1
1
|
require 'db_text_search/full_text_search/abstract_adapter'
|
2
2
|
module DbTextSearch
|
3
3
|
class FullTextSearch
|
4
|
+
# Provides basic FTS support for PostgreSQL.
|
5
|
+
#
|
6
|
+
# Runs a `@@ plainto_tsquery` query against a `gist(to_tsvector(...))` index.
|
7
|
+
#
|
8
|
+
# @see DbTextSearch::FullTextSearch::DEFAULT_PG_TS_CONFIG
|
9
|
+
# @api private
|
4
10
|
class PostgresAdapter < AbstractAdapter
|
5
|
-
# (see AbstractAdapter#
|
6
|
-
def
|
7
|
-
|
8
|
-
|
9
|
-
["to_tsvector(#{pg_ts_config}, #{quoted_scope_column}::text) @@ plainto_tsquery(#{pg_ts_config}, ?)",
|
10
|
-
terms.uniq.join(' ')]
|
11
|
+
# (see AbstractAdapter#find)
|
12
|
+
def find(terms, pg_ts_config:)
|
13
|
+
@scope.where("to_tsvector(#{pg_ts_config}, #{quoted_scope_column}) @@ plainto_tsquery(#{pg_ts_config}, ?)",
|
14
|
+
terms.uniq.join(' '))
|
11
15
|
end
|
12
16
|
|
13
17
|
# (see AbstractAdapter.add_index)
|
14
|
-
def self.add_index(connection, table_name, column_name,
|
15
|
-
|
16
|
-
|
17
|
-
index_name = options[:name] || "#{table_name}_#{column_name}_fts"
|
18
|
-
connection.exec_query <<-SQL.strip
|
19
|
-
CREATE INDEX #{index_name} ON #{connection.quote_table_name(table_name)}
|
20
|
-
USING gist(to_tsvector(#{pg_ts_config}, #{connection.quote_column_name column_name}))
|
21
|
-
SQL
|
18
|
+
def self.add_index(connection, table_name, column_name, name:, pg_ts_config:)
|
19
|
+
expression = "USING gist(to_tsvector(#{pg_ts_config}, #{connection.quote_column_name column_name}))"
|
20
|
+
connection.exec_query quoted_create_index(connection, table_name, name: name, expression: expression)
|
22
21
|
end
|
23
22
|
end
|
24
23
|
end
|
@@ -1,19 +1,24 @@
|
|
1
1
|
require 'db_text_search/full_text_search/abstract_adapter'
|
2
2
|
module DbTextSearch
|
3
3
|
class FullTextSearch
|
4
|
+
# Provides very basic FTS support for SQLite.
|
5
|
+
#
|
6
|
+
# Runs a `LIKE %term%` query for each term, joined with `AND`.
|
7
|
+
# Cannot use an index.
|
8
|
+
#
|
9
|
+
# @note .add_index is a no-op.
|
10
|
+
# @api private
|
4
11
|
class SqliteAdapter < AbstractAdapter
|
5
|
-
# (see AbstractAdapter
|
6
|
-
def
|
7
|
-
parse_search_options(options)
|
12
|
+
# (see AbstractAdapter#find)
|
13
|
+
def find(terms, pg_ts_config:)
|
8
14
|
quoted_col = quoted_scope_column
|
9
|
-
|
10
|
-
|
15
|
+
terms.map(&:downcase).uniq.inject(@scope) do |scope, term|
|
16
|
+
scope.where("#{quoted_col} COLLATE NOCASE LIKE ?", "%#{sanitize_sql_like term}%")
|
11
17
|
end
|
12
|
-
[term_args.map(&:first).join(' AND '), *term_args.map(&:second)]
|
13
18
|
end
|
14
19
|
|
15
20
|
# (see AbstractAdapter.add_index)
|
16
|
-
def self.add_index(connection, table_name, column_name,
|
21
|
+
def self.add_index(connection, table_name, column_name, name:, pg_ts_config:)
|
17
22
|
# A no-op, as we just use LIKE for sqlite.
|
18
23
|
end
|
19
24
|
end
|
@@ -3,31 +3,45 @@ require 'db_text_search/full_text_search/mysql_adapter'
|
|
3
3
|
require 'db_text_search/full_text_search/sqlite_adapter'
|
4
4
|
|
5
5
|
module DbTextSearch
|
6
|
-
# Provides
|
6
|
+
# Provides basic full-text search for a list of terms, and FTS index creation.
|
7
7
|
class FullTextSearch
|
8
|
-
#
|
8
|
+
# The default Postgres text search config.
|
9
|
+
DEFAULT_PG_TS_CONFIG = %q('english')
|
10
|
+
|
11
|
+
# @param scope [ActiveRecord::Relation, Class<ActiveRecord::Base>]
|
12
|
+
# @param column [Symbol] name
|
9
13
|
def initialize(scope, column)
|
10
14
|
@adapter = self.class.adapter_class(scope.connection, scope.table_name, column).new(scope, column)
|
11
15
|
@scope = scope
|
12
16
|
end
|
13
17
|
|
14
18
|
# @param term_or_terms [String, Array<String>]
|
15
|
-
# @
|
16
|
-
|
17
|
-
|
19
|
+
# @param pg_ts_config [String] for Postgres, the TS config to use; ignored for non-postgres.
|
20
|
+
# @return [ActiveRecord::Relation]
|
21
|
+
def find(term_or_terms, pg_ts_config: DEFAULT_PG_TS_CONFIG)
|
22
|
+
values = Array(term_or_terms)
|
18
23
|
return @scope.none if values.empty?
|
19
|
-
@adapter.find(values)
|
24
|
+
@adapter.find(values, pg_ts_config: pg_ts_config)
|
20
25
|
end
|
21
26
|
|
22
|
-
#
|
23
|
-
|
24
|
-
|
27
|
+
# Add an index for full text search.
|
28
|
+
#
|
29
|
+
# @param connection [ActiveRecord::ConnectionAdapters::AbstractAdapter]
|
30
|
+
# @param table_name [String, Symbol]
|
31
|
+
# @param column_name [String, Symbol]
|
32
|
+
# @param name [String, Symbol] index name
|
33
|
+
# @param pg_ts_config [String] for Postgres, the TS config to use; ignored for non-postgres.
|
34
|
+
def self.add_index(connection, table_name, column_name, name: "#{table_name}_#{column_name}_fts",
|
35
|
+
pg_ts_config: DEFAULT_PG_TS_CONFIG)
|
36
|
+
adapter_class(connection, table_name, column_name)
|
37
|
+
.add_index(connection, table_name, column_name, name: name, pg_ts_config: pg_ts_config)
|
25
38
|
end
|
26
39
|
|
27
40
|
# @param connection [ActiveRecord::ConnectionAdapters::AbstractAdapter]
|
28
41
|
# @param _table_name [String, Symbol]
|
29
42
|
# @param _column_name [String, Symbol]
|
30
43
|
# @return [Class<AbstractAdapter>]
|
44
|
+
# @api private
|
31
45
|
def self.adapter_class(connection, _table_name, _column_name)
|
32
46
|
case connection.adapter_name
|
33
47
|
when /mysql/i
|
@@ -37,7 +51,7 @@ module DbTextSearch
|
|
37
51
|
when /sqlite/i
|
38
52
|
SqliteAdapter
|
39
53
|
else
|
40
|
-
fail "
|
54
|
+
fail ArgumentError.new("Unsupported adapter #{connection.adapter_name}")
|
41
55
|
end
|
42
56
|
end
|
43
57
|
end
|
@@ -1,22 +1,43 @@
|
|
1
1
|
module DbTextSearch
|
2
|
+
# Common methods for building SQL that use @scope and @column instance variables.
|
3
|
+
# @api private
|
2
4
|
module QueryBuilding
|
5
|
+
def self.included(base) # :nodoc:
|
6
|
+
base.extend ClassMethods
|
7
|
+
end
|
8
|
+
|
3
9
|
protected
|
4
10
|
|
11
|
+
# @return [String] SQL-quoted scope table name.
|
5
12
|
def quoted_scope_table
|
6
13
|
@scope.connection.quote_table_name(@scope.table_name)
|
7
14
|
end
|
8
15
|
|
16
|
+
# @return [String] SQL-quoted column (without the table name).
|
9
17
|
def quoted_column
|
10
18
|
@scope.connection.quote_column_name(@column)
|
11
19
|
end
|
12
20
|
|
21
|
+
# @return [String] SQL-quoted column fully-qualified with the scope table name.
|
13
22
|
def quoted_scope_column
|
14
23
|
"#{quoted_scope_table}.#{quoted_column}"
|
15
24
|
end
|
16
25
|
|
26
|
+
# @return [String] SQL-quoted string suitable for use in a LIKE statement, with % and _ escaped.
|
17
27
|
def sanitize_sql_like(string, escape_character = "\\")
|
18
28
|
pattern = Regexp.union(escape_character, '%', '_')
|
19
29
|
string.gsub(pattern) { |x| [escape_character, x].join }
|
20
30
|
end
|
31
|
+
|
32
|
+
# Common methods for building SQL
|
33
|
+
# @api private
|
34
|
+
module ClassMethods
|
35
|
+
protected
|
36
|
+
|
37
|
+
# @return [String] a CREATE INDEX statement
|
38
|
+
def quoted_create_index(connection, table_name, name:, expression:, unique: false)
|
39
|
+
"CREATE #{'UNIQUE ' if unique}INDEX #{name} ON #{connection.quote_table_name(table_name)} #{expression}"
|
40
|
+
end
|
41
|
+
end
|
21
42
|
end
|
22
43
|
end
|
data/lib/db_text_search.rb
CHANGED
@@ -5,5 +5,10 @@ require 'db_text_search/version'
|
|
5
5
|
require 'db_text_search/case_insensitive_eq'
|
6
6
|
require 'db_text_search/full_text_search'
|
7
7
|
|
8
|
+
# DbTextSearch provides a unified interface on top of ActiveRecord for SQLite, MySQL, and PostgreSQL to do:
|
9
|
+
# * Case-insensitive string-in-set querying, and CI index creation.
|
10
|
+
# * Basic full-text search for a list of terms, and FTS index creation.
|
11
|
+
# @see DbTextSearch::CaseInsensitiveEq
|
12
|
+
# @see DbTextSearch::FullTextSearch
|
8
13
|
module DbTextSearch
|
9
14
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: db_text_search
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gleb Mazovetskiy
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-03-
|
11
|
+
date: 2016-03-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -170,3 +170,4 @@ specification_version: 4
|
|
170
170
|
summary: A unified interface on top of ActiveRecord for SQLite, MySQL, and PostgreSQL
|
171
171
|
for case-insensitive string search and basic full-text search.
|
172
172
|
test_files: []
|
173
|
+
has_rdoc:
|