sequel 4.10.0 → 4.11.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.
- checksums.yaml +4 -4
- data/CHANGELOG +58 -0
- data/doc/association_basics.rdoc +1 -1
- data/doc/cheat_sheet.rdoc +0 -1
- data/doc/core_extensions.rdoc +2 -2
- data/doc/dataset_filtering.rdoc +5 -5
- data/doc/model_hooks.rdoc +9 -0
- data/doc/object_model.rdoc +7 -13
- data/doc/opening_databases.rdoc +3 -1
- data/doc/querying.rdoc +8 -8
- data/doc/release_notes/4.11.0.txt +147 -0
- data/doc/sql.rdoc +11 -7
- data/doc/virtual_rows.rdoc +4 -5
- data/lib/sequel/adapters/ibmdb.rb +24 -16
- data/lib/sequel/adapters/jdbc/h2.rb +5 -0
- data/lib/sequel/adapters/jdbc/hsqldb.rb +5 -0
- data/lib/sequel/adapters/mock.rb +14 -2
- data/lib/sequel/adapters/shared/access.rb +6 -9
- data/lib/sequel/adapters/shared/cubrid.rb +5 -0
- data/lib/sequel/adapters/shared/db2.rb +5 -0
- data/lib/sequel/adapters/shared/firebird.rb +5 -0
- data/lib/sequel/adapters/shared/mssql.rb +23 -16
- data/lib/sequel/adapters/shared/mysql.rb +12 -2
- data/lib/sequel/adapters/shared/oracle.rb +31 -15
- data/lib/sequel/adapters/shared/postgres.rb +28 -4
- data/lib/sequel/adapters/shared/sqlanywhere.rb +5 -0
- data/lib/sequel/adapters/shared/sqlite.rb +12 -1
- data/lib/sequel/ast_transformer.rb +9 -7
- data/lib/sequel/connection_pool.rb +10 -4
- data/lib/sequel/database/features.rb +15 -0
- data/lib/sequel/database/schema_generator.rb +2 -2
- data/lib/sequel/database/schema_methods.rb +21 -3
- data/lib/sequel/database/transactions.rb +8 -4
- data/lib/sequel/dataset/actions.rb +13 -7
- data/lib/sequel/dataset/features.rb +7 -0
- data/lib/sequel/dataset/query.rb +28 -11
- data/lib/sequel/dataset/sql.rb +90 -14
- data/lib/sequel/extensions/constraint_validations.rb +2 -2
- data/lib/sequel/extensions/date_arithmetic.rb +1 -1
- data/lib/sequel/extensions/eval_inspect.rb +12 -6
- data/lib/sequel/extensions/pg_array_ops.rb +11 -2
- data/lib/sequel/extensions/pg_json.rb +130 -23
- data/lib/sequel/extensions/pg_json_ops.rb +196 -28
- data/lib/sequel/extensions/to_dot.rb +5 -7
- data/lib/sequel/model/associations.rb +0 -50
- data/lib/sequel/plugins/class_table_inheritance.rb +49 -21
- data/lib/sequel/plugins/many_through_many.rb +10 -11
- data/lib/sequel/plugins/serialization.rb +4 -1
- data/lib/sequel/plugins/sharding.rb +0 -9
- data/lib/sequel/plugins/single_table_inheritance.rb +4 -2
- data/lib/sequel/plugins/timestamps.rb +2 -2
- data/lib/sequel/sql.rb +166 -44
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/postgres_spec.rb +199 -133
- data/spec/core/connection_pool_spec.rb +6 -0
- data/spec/core/database_spec.rb +12 -0
- data/spec/core/dataset_spec.rb +58 -3
- data/spec/core/expression_filters_spec.rb +67 -5
- data/spec/core/mock_adapter_spec.rb +8 -4
- data/spec/core/schema_spec.rb +7 -0
- data/spec/core_extensions_spec.rb +14 -0
- data/spec/extensions/class_table_inheritance_spec.rb +23 -3
- data/spec/extensions/core_refinements_spec.rb +14 -0
- data/spec/extensions/eval_inspect_spec.rb +8 -4
- data/spec/extensions/pg_array_ops_spec.rb +6 -0
- data/spec/extensions/pg_json_ops_spec.rb +99 -0
- data/spec/extensions/pg_json_spec.rb +104 -4
- data/spec/extensions/serialization_spec.rb +19 -0
- data/spec/extensions/single_table_inheritance_spec.rb +11 -3
- data/spec/extensions/timestamps_spec.rb +10 -0
- data/spec/extensions/to_dot_spec.rb +8 -4
- data/spec/integration/database_test.rb +1 -1
- data/spec/integration/dataset_test.rb +9 -0
- data/spec/integration/schema_test.rb +27 -0
- metadata +4 -2
data/doc/virtual_rows.rdoc
CHANGED
@@ -95,8 +95,8 @@ local variable access. This is mostly useful in instance_evaled procs:
|
|
95
95
|
|
96
96
|
== VirtualRow Methods
|
97
97
|
|
98
|
-
VirtualRow is a class that returns SQL::Identifiers, SQL::QualifiedIdentifiers,
|
99
|
-
SQL::Functions
|
98
|
+
VirtualRow is a class that returns SQL::Identifiers, SQL::QualifiedIdentifiers, or
|
99
|
+
SQL::Functions depending on how it is called.
|
100
100
|
|
101
101
|
== SQL::Identifiers - Regular columns
|
102
102
|
|
@@ -165,10 +165,9 @@ distinct method on the returned Function:
|
|
165
165
|
ds.select{count(col1, col2).distinct}
|
166
166
|
# SELECT count(DISTINCT col1, col2)
|
167
167
|
|
168
|
-
== SQL::
|
168
|
+
== SQL::Functions with windows - SQL window function calls
|
169
169
|
|
170
|
-
|
171
|
-
all databases support them, but they are very helpful for certain types of
|
170
|
+
Not all databases support window functions, but they are very helpful for certain types of
|
172
171
|
queries. To use them, you should just call the over method on the Function
|
173
172
|
object returned, with the options for the window:
|
174
173
|
|
@@ -43,8 +43,13 @@ module Sequel
|
|
43
43
|
end
|
44
44
|
|
45
45
|
# Create the underlying IBM_DB connection.
|
46
|
-
def initialize(
|
47
|
-
@conn =
|
46
|
+
def initialize(connection_param)
|
47
|
+
@conn = if connection_param.class == String
|
48
|
+
IBM_DB.connect(connection_param, '', '')
|
49
|
+
else # connect using catalog
|
50
|
+
IBM_DB.connect(*connection_param)
|
51
|
+
end
|
52
|
+
|
48
53
|
self.autocommit = true
|
49
54
|
@prepared_statements = {}
|
50
55
|
end
|
@@ -193,19 +198,22 @@ module Sequel
|
|
193
198
|
# Create a new connection object for the given server.
|
194
199
|
def connect(server)
|
195
200
|
opts = server_opts(server)
|
196
|
-
|
197
|
-
# use uncataloged connection so that host and port can be supported
|
198
|
-
connection_string = ( \
|
199
|
-
'Driver={IBM DB2 ODBC DRIVER};' \
|
200
|
-
"Database=#{opts[:database]};" \
|
201
|
-
"Hostname=#{opts[:host]};" \
|
202
|
-
"Port=#{opts[:port] || 50000};" \
|
203
|
-
'Protocol=TCPIP;' \
|
204
|
-
"Uid=#{opts[:user]};" \
|
205
|
-
"Pwd=#{opts[:password]};" \
|
206
|
-
)
|
207
201
|
|
208
|
-
|
202
|
+
connection_params = if opts[:host].nil? && opts[:port].nil? && opts[:database]
|
203
|
+
# use a cataloged connection
|
204
|
+
opts.values_at(:database, :user, :password)
|
205
|
+
else
|
206
|
+
# use uncataloged connection so that host and port can be supported
|
207
|
+
'Driver={IBM DB2 ODBC DRIVER};' \
|
208
|
+
"Database=#{opts[:database]};" \
|
209
|
+
"Hostname=#{opts[:host]};" \
|
210
|
+
"Port=#{opts[:port] || 50000};" \
|
211
|
+
'Protocol=TCPIP;' \
|
212
|
+
"Uid=#{opts[:user]};" \
|
213
|
+
"Pwd=#{opts[:password]};" \
|
214
|
+
end
|
215
|
+
|
216
|
+
Connection.new(connection_params)
|
209
217
|
end
|
210
218
|
|
211
219
|
# Execute the given SQL on the database.
|
@@ -432,9 +440,9 @@ module Sequel
|
|
432
440
|
stmt.num_fields.times do |i|
|
433
441
|
k = stmt.field_name i
|
434
442
|
key = output_identifier(k)
|
435
|
-
type = stmt.field_type(
|
443
|
+
type = stmt.field_type(i).downcase.to_sym
|
436
444
|
# decide if it is a smallint from precision
|
437
|
-
type = :boolean if type == :int && convert && stmt.field_precision(
|
445
|
+
type = :boolean if type == :int && convert && stmt.field_precision(i) < 8
|
438
446
|
type = :blob if type == :clob && Sequel::DB2.use_clob_as_blob
|
439
447
|
columns << [key, cps[type]]
|
440
448
|
end
|
data/lib/sequel/adapters/mock.rb
CHANGED
@@ -34,6 +34,7 @@ module Sequel
|
|
34
34
|
# mock adapters for specific database types.
|
35
35
|
SHARED_ADAPTERS = {
|
36
36
|
'access'=>'Access',
|
37
|
+
'cubrid'=>'Cubrid',
|
37
38
|
'db2'=>'DB2',
|
38
39
|
'firebird'=>'Firebird',
|
39
40
|
'informix'=>'Informix',
|
@@ -41,6 +42,7 @@ module Sequel
|
|
41
42
|
'mysql'=>'MySQL',
|
42
43
|
'oracle'=>'Oracle',
|
43
44
|
'postgres'=>'Postgres',
|
45
|
+
'sqlanywhere'=>'SqlAnywhere',
|
44
46
|
'sqlite'=>'SQLite'
|
45
47
|
}
|
46
48
|
|
@@ -49,7 +51,7 @@ module Sequel
|
|
49
51
|
SHARED_ADAPTER_SETUP = {
|
50
52
|
'postgres' => lambda do |db|
|
51
53
|
db.instance_eval do
|
52
|
-
@server_version =
|
54
|
+
@server_version = 90400
|
53
55
|
initialize_postgres_adapter
|
54
56
|
end
|
55
57
|
db.extend(Module.new do
|
@@ -67,9 +69,19 @@ module Sequel
|
|
67
69
|
@primary_key_sequences = {}
|
68
70
|
end
|
69
71
|
end,
|
72
|
+
'mysql' => lambda do |db|
|
73
|
+
db.instance_eval do
|
74
|
+
@server_version = 50617
|
75
|
+
end
|
76
|
+
end,
|
70
77
|
'mssql' => lambda do |db|
|
71
78
|
db.instance_eval do
|
72
|
-
@server_version =
|
79
|
+
@server_version = 11000000
|
80
|
+
end
|
81
|
+
end,
|
82
|
+
'sqlite' => lambda do |db|
|
83
|
+
db.instance_eval do
|
84
|
+
@sqlite_version = 30804
|
73
85
|
end
|
74
86
|
end
|
75
87
|
}
|
@@ -112,6 +112,7 @@ module Sequel
|
|
112
112
|
TIME_FUNCTION = 'Time()'.freeze
|
113
113
|
CAST_TYPES = {String=>:CStr, Integer=>:CLng, Date=>:CDate, Time=>:CDate, DateTime=>:CDate, Numeric=>:CDec, BigDecimal=>:CDec, File=>:CStr, Float=>:CDbl, TrueClass=>:CBool, FalseClass=>:CBool}
|
114
114
|
|
115
|
+
EMULATED_FUNCTION_MAP = {:char_length=>:len}
|
115
116
|
EXTRACT_MAP = {:year=>"'yyyy'", :month=>"'m'", :day=>"'d'", :hour=>"'h'", :minute=>"'n'", :second=>"'s'"}
|
116
117
|
COMMA = Dataset::COMMA
|
117
118
|
DATEPART_OPEN = "datepart(".freeze
|
@@ -189,15 +190,6 @@ module Sequel
|
|
189
190
|
clone(:from=>@opts[:from] + [table])
|
190
191
|
end
|
191
192
|
|
192
|
-
def emulated_function_sql_append(sql, f)
|
193
|
-
case f.f
|
194
|
-
when :char_length
|
195
|
-
literal_append(sql, SQL::Function.new(:len, f.args.first))
|
196
|
-
else
|
197
|
-
super
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
193
|
# Access uses [] to escape metacharacters, instead of backslashes.
|
202
194
|
def escape_like(string)
|
203
195
|
string.gsub(/[\\*#?\[]/){|m| "[#{m}]"}
|
@@ -208,6 +200,11 @@ module Sequel
|
|
208
200
|
clone(:into => table)
|
209
201
|
end
|
210
202
|
|
203
|
+
# Access does not support derived column lists.
|
204
|
+
def supports_derived_column_lists?
|
205
|
+
false
|
206
|
+
end
|
207
|
+
|
211
208
|
# Access doesn't support INTERSECT or EXCEPT
|
212
209
|
def supports_intersect_except?
|
213
210
|
false
|
@@ -146,6 +146,11 @@ module Sequel
|
|
146
146
|
def type_literal_generic_string(column)
|
147
147
|
column[:text] ? :"BLOB SUB_TYPE TEXT" : super
|
148
148
|
end
|
149
|
+
|
150
|
+
# Firebird supports views with check option, but not local.
|
151
|
+
def view_with_check_option_support
|
152
|
+
true
|
153
|
+
end
|
149
154
|
end
|
150
155
|
|
151
156
|
module DatasetMethods
|
@@ -301,7 +301,7 @@ module Sequel
|
|
301
301
|
def begin_transaction_sql
|
302
302
|
SQL_BEGIN
|
303
303
|
end
|
304
|
-
|
304
|
+
|
305
305
|
# Handle MSSQL specific default format.
|
306
306
|
def column_schema_normalize_default(default, type)
|
307
307
|
if m = MSSQL_DEFAULT_RE.match(default)
|
@@ -487,6 +487,11 @@ module Sequel
|
|
487
487
|
def type_literal_generic_file(column)
|
488
488
|
:'varbinary(max)'
|
489
489
|
end
|
490
|
+
|
491
|
+
# MSSQL supports views with check option, but not local.
|
492
|
+
def view_with_check_option_support
|
493
|
+
true
|
494
|
+
end
|
490
495
|
end
|
491
496
|
|
492
497
|
module DatasetMethods
|
@@ -609,21 +614,6 @@ module Sequel
|
|
609
614
|
string.gsub(/[\\%_\[\]]/){|m| "\\#{m}"}
|
610
615
|
end
|
611
616
|
|
612
|
-
# There is no function on Microsoft SQL Server that does character length
|
613
|
-
# and respects trailing spaces (datalength respects trailing spaces, but
|
614
|
-
# counts bytes instead of characters). Use a hack to work around the
|
615
|
-
# trailing spaces issue.
|
616
|
-
def emulated_function_sql_append(sql, f)
|
617
|
-
case f.f
|
618
|
-
when :char_length
|
619
|
-
literal_append(sql, SQL::Function.new(:len, Sequel.join([f.args.first, 'x'])) - 1)
|
620
|
-
when :trim
|
621
|
-
literal_append(sql, SQL::Function.new(:ltrim, SQL::Function.new(:rtrim, f.args.first)))
|
622
|
-
else
|
623
|
-
super
|
624
|
-
end
|
625
|
-
end
|
626
|
-
|
627
617
|
# MSSQL uses the CONTAINS keyword for full text search
|
628
618
|
def full_text_search(cols, terms, opts = OPTS)
|
629
619
|
terms = "\"#{terms.join('" OR "')}\"" if terms.is_a?(Array)
|
@@ -825,6 +815,23 @@ module Sequel
|
|
825
815
|
end
|
826
816
|
alias update_from_sql delete_from2_sql
|
827
817
|
|
818
|
+
# There is no function on Microsoft SQL Server that does character length
|
819
|
+
# and respects trailing spaces (datalength respects trailing spaces, but
|
820
|
+
# counts bytes instead of characters). Use a hack to work around the
|
821
|
+
# trailing spaces issue.
|
822
|
+
def emulate_function?(name)
|
823
|
+
name == :char_length || name == :trim
|
824
|
+
end
|
825
|
+
|
826
|
+
def emulate_function_sql_append(sql, f)
|
827
|
+
case f.name
|
828
|
+
when :char_length
|
829
|
+
literal_append(sql, SQL::Function.new(:len, Sequel.join([f.args.first, 'x'])) - 1)
|
830
|
+
when :trim
|
831
|
+
literal_append(sql, SQL::Function.new(:ltrim, SQL::Function.new(:rtrim, f.args.first)))
|
832
|
+
end
|
833
|
+
end
|
834
|
+
|
828
835
|
# Microsoft SQL Server 2012 has native support for offsets, but only for ordered datasets.
|
829
836
|
def emulate_offset_with_row_number?
|
830
837
|
super && !(is_2012_or_later? && @opts[:order])
|
@@ -129,12 +129,12 @@ module Sequel
|
|
129
129
|
true
|
130
130
|
end
|
131
131
|
|
132
|
-
# MySQL supports prepared transactions (two-phase commit) using XA
|
132
|
+
# MySQL 5+ supports prepared transactions (two-phase commit) using XA
|
133
133
|
def supports_prepared_transactions?
|
134
134
|
server_version >= 50000
|
135
135
|
end
|
136
136
|
|
137
|
-
# MySQL supports savepoints
|
137
|
+
# MySQL 5+ supports savepoints
|
138
138
|
def supports_savepoints?
|
139
139
|
server_version >= 50000
|
140
140
|
end
|
@@ -540,6 +540,11 @@ module Sequel
|
|
540
540
|
def type_literal_generic_trueclass(column)
|
541
541
|
:'tinyint(1)'
|
542
542
|
end
|
543
|
+
|
544
|
+
# MySQL 5.0.2+ supports views with check option.
|
545
|
+
def view_with_check_option_support
|
546
|
+
:local if server_version >= 50002
|
547
|
+
end
|
543
548
|
end
|
544
549
|
|
545
550
|
# Dataset methods shared by datasets that use MySQL databases.
|
@@ -755,6 +760,11 @@ module Sequel
|
|
755
760
|
sql << BACKTICK << c.to_s.gsub(BACKTICK_RE, DOUBLE_BACKTICK) << BACKTICK
|
756
761
|
end
|
757
762
|
|
763
|
+
# MySQL does not support derived column lists
|
764
|
+
def supports_derived_column_lists?
|
765
|
+
false
|
766
|
+
end
|
767
|
+
|
758
768
|
# MySQL can emulate DISTINCT ON with its non-standard GROUP BY implementation,
|
759
769
|
# though the rows returned cannot be made deterministic through ordering.
|
760
770
|
def supports_distinct_on?
|
@@ -244,6 +244,11 @@ module Sequel
|
|
244
244
|
def uses_clob_for_text?
|
245
245
|
true
|
246
246
|
end
|
247
|
+
|
248
|
+
# Oracle supports views with check option, but not local.
|
249
|
+
def view_with_check_option_support
|
250
|
+
true
|
251
|
+
end
|
247
252
|
end
|
248
253
|
|
249
254
|
module DatasetMethods
|
@@ -295,20 +300,6 @@ module Sequel
|
|
295
300
|
end
|
296
301
|
end
|
297
302
|
|
298
|
-
# Oracle treats empty strings like NULL values, and doesn't support
|
299
|
-
# char_length, so make char_length use length with a nonempty string.
|
300
|
-
# Unfortunately, as Oracle treats the empty string as NULL, there is
|
301
|
-
# no way to get trim to return an empty string instead of nil if
|
302
|
-
# the string only contains spaces.
|
303
|
-
def emulated_function_sql_append(sql, f)
|
304
|
-
case f.f
|
305
|
-
when :char_length
|
306
|
-
literal_append(sql, Sequel::SQL::Function.new(:length, Sequel.join([f.args.first, 'x'])) - 1)
|
307
|
-
else
|
308
|
-
super
|
309
|
-
end
|
310
|
-
end
|
311
|
-
|
312
303
|
# Oracle uses MINUS instead of EXCEPT, and doesn't support EXCEPT ALL
|
313
304
|
def except(dataset, opts=OPTS)
|
314
305
|
raise(Sequel::Error, "EXCEPT ALL not supported") if opts[:all]
|
@@ -373,6 +364,11 @@ module Sequel
|
|
373
364
|
type == :select
|
374
365
|
end
|
375
366
|
|
367
|
+
# Oracle does not support derived column lists
|
368
|
+
def supports_derived_column_lists?
|
369
|
+
false
|
370
|
+
end
|
371
|
+
|
376
372
|
# Oracle supports GROUP BY CUBE
|
377
373
|
def supports_group_cube?
|
378
374
|
true
|
@@ -427,7 +423,8 @@ module Sequel
|
|
427
423
|
|
428
424
|
# Oracle doesn't support the use of AS when aliasing a dataset. It doesn't require
|
429
425
|
# the use of AS anywhere, so this disables it in all cases.
|
430
|
-
def as_sql_append(sql, aliaz)
|
426
|
+
def as_sql_append(sql, aliaz, column_aliases=nil)
|
427
|
+
raise Error, "oracle does not support derived column lists" if column_aliases
|
431
428
|
sql << SPACE
|
432
429
|
quote_identifier_append(sql, aliaz)
|
433
430
|
end
|
@@ -441,6 +438,25 @@ module Sequel
|
|
441
438
|
DUAL
|
442
439
|
end
|
443
440
|
|
441
|
+
# There is no function on Microsoft SQL Server that does character length
|
442
|
+
# and respects trailing spaces (datalength respects trailing spaces, but
|
443
|
+
# counts bytes instead of characters). Use a hack to work around the
|
444
|
+
# trailing spaces issue.
|
445
|
+
def emulate_function?(name)
|
446
|
+
name == :char_length
|
447
|
+
end
|
448
|
+
|
449
|
+
# Oracle treats empty strings like NULL values, and doesn't support
|
450
|
+
# char_length, so make char_length use length with a nonempty string.
|
451
|
+
# Unfortunately, as Oracle treats the empty string as NULL, there is
|
452
|
+
# no way to get trim to return an empty string instead of nil if
|
453
|
+
# the string only contains spaces.
|
454
|
+
def emulate_function_sql_append(sql, f)
|
455
|
+
if f.name == :char_length
|
456
|
+
literal_append(sql, Sequel::SQL::Function.new(:length, Sequel.join([f.args.first, 'x'])) - 1)
|
457
|
+
end
|
458
|
+
end
|
459
|
+
|
444
460
|
# If this dataset is associated with a sequence, return the most recently
|
445
461
|
# inserted sequence value.
|
446
462
|
def execute_insert(sql, opts=OPTS)
|
@@ -402,8 +402,10 @@ module Sequel
|
|
402
402
|
#
|
403
403
|
# DB.refresh_view(:items_view)
|
404
404
|
# # REFRESH MATERIALIZED VIEW items_view
|
405
|
+
# DB.refresh_view(:items_view, :concurrently=>true)
|
406
|
+
# # REFRESH MATERIALIZED VIEW CONCURRENTLY items_view
|
405
407
|
def refresh_view(name, opts=OPTS)
|
406
|
-
run "REFRESH MATERIALIZED VIEW #{quote_schema_table(name)}"
|
408
|
+
run "REFRESH MATERIALIZED VIEW#{' CONCURRENTLY' if opts[:concurrently]} #{quote_schema_table(name)}"
|
407
409
|
end
|
408
410
|
|
409
411
|
# Reset the database's conversion procs, requires a server query if there
|
@@ -588,6 +590,15 @@ module Sequel
|
|
588
590
|
end
|
589
591
|
end
|
590
592
|
|
593
|
+
# Set the READ ONLY transaction setting per savepoint, as PostgreSQL supports that.
|
594
|
+
def begin_savepoint(conn, opts)
|
595
|
+
super
|
596
|
+
|
597
|
+
unless (read_only = opts[:read_only]).nil?
|
598
|
+
log_connection_execute(conn, "SET TRANSACTION READ #{read_only ? 'ONLY' : 'WRITE'}")
|
599
|
+
end
|
600
|
+
end
|
601
|
+
|
591
602
|
# Handle PostgreSQL specific default format.
|
592
603
|
def column_schema_normalize_default(default, type)
|
593
604
|
if m = POSTGRES_DEFAULT_RE.match(default)
|
@@ -1094,6 +1105,11 @@ module Sequel
|
|
1094
1105
|
:text
|
1095
1106
|
end
|
1096
1107
|
end
|
1108
|
+
|
1109
|
+
# PostgreSQL 9.4+ supports views with check option.
|
1110
|
+
def view_with_check_option_support
|
1111
|
+
:local if server_version >= 90400
|
1112
|
+
end
|
1097
1113
|
end
|
1098
1114
|
|
1099
1115
|
# Instance methods for datasets that connect to a PostgreSQL database.
|
@@ -1227,17 +1243,25 @@ module Sequel
|
|
1227
1243
|
# contains all of the words in terms. This ignores search operators in terms.
|
1228
1244
|
# :phrase :: Similar to :plain, but also adding an ILIKE filter to ensure that
|
1229
1245
|
# returned rows also include the exact phrase used.
|
1246
|
+
# :rank :: Set to true to order by the rank, so that closer matches are returned first.
|
1230
1247
|
def full_text_search(cols, terms, opts = OPTS)
|
1231
|
-
lang = opts[:language] || 'simple'
|
1248
|
+
lang = Sequel.cast(opts[:language] || 'simple', :regconfig)
|
1232
1249
|
terms = terms.join(' | ') if terms.is_a?(Array)
|
1233
|
-
|
1250
|
+
columns = full_text_string_join(cols)
|
1251
|
+
query_func = (opts[:phrase] || opts[:plain]) ? :plainto_tsquery : :to_tsquery
|
1252
|
+
vector = Sequel.function(:to_tsvector, lang, columns)
|
1253
|
+
query = Sequel.function(query_func, lang, terms)
|
1234
1254
|
|
1235
|
-
ds = where(Sequel.lit(["(
|
1255
|
+
ds = where(Sequel.lit(["(", " @@ ", ")"], vector, query))
|
1236
1256
|
|
1237
1257
|
if opts[:phrase]
|
1238
1258
|
ds = ds.grep(cols, "%#{escape_like(terms)}%", :case_insensitive=>true)
|
1239
1259
|
end
|
1240
1260
|
|
1261
|
+
if opts[:rank]
|
1262
|
+
ds = ds.order{ts_rank_cd(vector, query)}
|
1263
|
+
end
|
1264
|
+
|
1241
1265
|
ds
|
1242
1266
|
end
|
1243
1267
|
|