sequel 4.10.0 → 4.11.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|