sequel 4.7.0 → 4.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +46 -0
- data/README.rdoc +25 -1
- data/doc/active_record.rdoc +1 -1
- data/doc/advanced_associations.rdoc +143 -17
- data/doc/association_basics.rdoc +80 -59
- data/doc/release_notes/4.8.0.txt +175 -0
- data/lib/sequel/adapters/odbc.rb +1 -1
- data/lib/sequel/adapters/odbc/mssql.rb +4 -2
- data/lib/sequel/adapters/shared/postgres.rb +19 -3
- data/lib/sequel/adapters/shared/sqlite.rb +3 -3
- data/lib/sequel/ast_transformer.rb +1 -1
- data/lib/sequel/dataset/actions.rb +1 -1
- data/lib/sequel/dataset/graph.rb +23 -9
- data/lib/sequel/dataset/misc.rb +2 -2
- data/lib/sequel/dataset/sql.rb +3 -3
- data/lib/sequel/extensions/columns_introspection.rb +1 -1
- data/lib/sequel/extensions/mssql_emulate_lateral_with_apply.rb +1 -1
- data/lib/sequel/extensions/pg_array.rb +1 -1
- data/lib/sequel/extensions/pg_array_ops.rb +6 -0
- data/lib/sequel/extensions/pg_hstore_ops.rb +7 -0
- data/lib/sequel/extensions/pg_json_ops.rb +5 -0
- data/lib/sequel/extensions/query.rb +8 -2
- data/lib/sequel/extensions/to_dot.rb +1 -1
- data/lib/sequel/model/associations.rb +476 -152
- data/lib/sequel/plugins/class_table_inheritance.rb +11 -3
- data/lib/sequel/plugins/dataset_associations.rb +21 -18
- data/lib/sequel/plugins/many_through_many.rb +87 -20
- data/lib/sequel/plugins/nested_attributes.rb +12 -0
- data/lib/sequel/plugins/pg_array_associations.rb +31 -12
- data/lib/sequel/plugins/single_table_inheritance.rb +9 -1
- data/lib/sequel/sql.rb +1 -0
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mssql_spec.rb +2 -2
- data/spec/adapters/postgres_spec.rb +7 -0
- data/spec/core/object_graph_spec.rb +250 -196
- data/spec/extensions/core_refinements_spec.rb +1 -1
- data/spec/extensions/dataset_associations_spec.rb +100 -6
- data/spec/extensions/many_through_many_spec.rb +1002 -19
- data/spec/extensions/nested_attributes_spec.rb +24 -0
- data/spec/extensions/pg_array_associations_spec.rb +17 -12
- data/spec/extensions/pg_array_spec.rb +4 -2
- data/spec/extensions/spec_helper.rb +1 -1
- data/spec/integration/associations_test.rb +1003 -48
- data/spec/integration/dataset_test.rb +12 -5
- data/spec/integration/prepared_statement_test.rb +1 -1
- data/spec/integration/type_test.rb +1 -1
- data/spec/model/associations_spec.rb +467 -130
- data/spec/model/eager_loading_spec.rb +332 -5
- metadata +5 -3
@@ -0,0 +1,175 @@
|
|
1
|
+
= New Features
|
2
|
+
|
3
|
+
* A one_through_one association type has been added. This is similar
|
4
|
+
to the many_to_many association type in that it uses a join table,
|
5
|
+
but it returns a single record instead of an array of records.
|
6
|
+
This is designed for cases where the foreign key in the join table
|
7
|
+
that references the current table has a unique constraint, or where
|
8
|
+
you want to use an order to just pick the first matching record.
|
9
|
+
|
10
|
+
Similarly, the many_through_many plugin now also offers a
|
11
|
+
one_through_many association.
|
12
|
+
|
13
|
+
* An association_join method has been added to model datasets, for
|
14
|
+
setting up joins based on associations. This basically does the
|
15
|
+
same join that eager_graph would do, but does not make the other
|
16
|
+
changes that eager_graph makes.
|
17
|
+
|
18
|
+
Unlike eager_graph (which uses LEFT OUTER JOINs by default),
|
19
|
+
association_join uses INNER JOINs, but there are also
|
20
|
+
association_*_join methods (e.g. association_left_join) for
|
21
|
+
using different join types.
|
22
|
+
|
23
|
+
Similar to eager_graph, you can use cascading of associations or
|
24
|
+
multiple associations.
|
25
|
+
|
26
|
+
Album.association_join(:artist, :tracks)
|
27
|
+
Artist.association_left_join(:albums=>:tracks)
|
28
|
+
|
29
|
+
* Dataset#eager_graph_with_options has been added for model
|
30
|
+
datasets. It currently supports a :join_type option, for
|
31
|
+
overriding the type of join to use on a per-call basis, as well
|
32
|
+
as a :limit_strategy option. The API is similar to eager_graph,
|
33
|
+
except that the associations to eagerly load are passed in as
|
34
|
+
a single argument, and it takes an options hash.
|
35
|
+
|
36
|
+
The :limit_strategy option works similarly to the
|
37
|
+
:eager_limit_strategy option when eagerly loading. If set to
|
38
|
+
true and the database supports window functions, it will join
|
39
|
+
the current dataset to a subquery that uses a window function
|
40
|
+
to correctly restrict the join to only those objects that fall
|
41
|
+
within the association's limit/offset.
|
42
|
+
|
43
|
+
The :limit_strategy option is not on by default. It is possible
|
44
|
+
for it to perform significantly worse than the default strategy
|
45
|
+
(which uses array slicing in ruby). The :limit_strategy
|
46
|
+
significantly changes the SQL used, and can change the results
|
47
|
+
of the query if any filters/orders related to the association
|
48
|
+
are used.
|
49
|
+
|
50
|
+
It's recommended you only use the :limit_strategy option if you
|
51
|
+
are experiencing a bottleneck and you have benchmarked that it
|
52
|
+
is faster and still produces the desired results.
|
53
|
+
|
54
|
+
Artist.eager_graph_with_options(:first_10_albums,
|
55
|
+
:limit_strategy=>true)
|
56
|
+
# SELECT artists.id, artists.name,
|
57
|
+
# first_10_albums.id AS first_10_albums_id,
|
58
|
+
# first_10_albums.name AS first_10_albums_name,
|
59
|
+
# first_10_albums.artist_id,
|
60
|
+
# first_10_albums.release_date
|
61
|
+
# FROM artists
|
62
|
+
# LEFT OUTER JOIN (
|
63
|
+
# SELECT id, name, artist_id, release_date
|
64
|
+
# FROM (
|
65
|
+
# SELECT *, row_number() OVER (PARTITION BY tracks.album_id)
|
66
|
+
# AS x_sequel_row_number_x
|
67
|
+
# FROM albums
|
68
|
+
# ) AS t1 WHERE (x_sequel_row_number_x <= 10)
|
69
|
+
# ) AS first_10_albums ON (first_10_albums.artist_id = artists.id)
|
70
|
+
|
71
|
+
* Dataset#full_text_search on PostgreSQL now supports :plain and
|
72
|
+
:phrase options. :plain takes the search terms as a single
|
73
|
+
string, and searches for rows where all terms are used.
|
74
|
+
:phrase is similar to :plain, but also adds a substring search
|
75
|
+
to ensure that the string given appears verbatim in the text.
|
76
|
+
|
77
|
+
* A :graph_order association option has been added, for using a
|
78
|
+
different order when using eager_graph. This is mostly
|
79
|
+
designed for cases where :order should be qualified in other
|
80
|
+
cases, but using a qualification breaks eager_graph because the
|
81
|
+
correct qualifier is not known until runtime.
|
82
|
+
|
83
|
+
* SQL::AliasedExpression#alias has been added as an alias for #aliaz.
|
84
|
+
|
85
|
+
= Other Improvements
|
86
|
+
|
87
|
+
* Sequel will now automatically use an eager limit strategy for
|
88
|
+
*_one associations that use an :order option. For associations
|
89
|
+
that are truly one-to-one, an :order option is not needed, so it
|
90
|
+
only makes sense to have an :order option if the association
|
91
|
+
could theoretically return multiple results (in which case an
|
92
|
+
eager limit strategy is helpful).
|
93
|
+
|
94
|
+
* The queries that Sequel uses to filter by associations when
|
95
|
+
those associations have conditions are now simpler and easier
|
96
|
+
for the database to execute.
|
97
|
+
|
98
|
+
* The queries that Sequel uses for dataset associations now handle
|
99
|
+
cases where unqualified identifiers were used in the receiving
|
100
|
+
dataset that would be made ambiguous by a join.
|
101
|
+
|
102
|
+
* A limit strategy is now used when filtering by associations if
|
103
|
+
the association has a limit and the database supports window
|
104
|
+
functions. This allows Sequel to setup a correct filter in
|
105
|
+
such cases.
|
106
|
+
|
107
|
+
Artist.where(:first_10_albums=>Album[1]).all
|
108
|
+
# SELECT *
|
109
|
+
# FROM artists
|
110
|
+
# WHERE (artists.id IN (
|
111
|
+
# SELECT albums.artist_id
|
112
|
+
# FROM albums
|
113
|
+
# WHERE ((albums.artist_id IS NOT NULL) AND (albums.id IN (
|
114
|
+
# SELECT id FROM (
|
115
|
+
# SELECT albums.id, row_number() OVER
|
116
|
+
# (PARTITION BY albums.artist_id ORDER BY release_date)
|
117
|
+
# AS x_sequel_row_number_x
|
118
|
+
# FROM albums
|
119
|
+
# ) AS t1
|
120
|
+
# WHERE (x_sequel_row_number_x <= 10)
|
121
|
+
# )) AND (albums.id = 1))))
|
122
|
+
|
123
|
+
* A limit strategy is now used in the dataset_associations plugin
|
124
|
+
if the association has a limit and the database supports window
|
125
|
+
functions. This makes the resulting datasets return correct
|
126
|
+
results.
|
127
|
+
|
128
|
+
Artist.first_10_albums
|
129
|
+
# SELECT *
|
130
|
+
# FROM albums
|
131
|
+
# WHERE ((albums.artist_id IN (
|
132
|
+
# SELECT artists.id FROM artists)
|
133
|
+
# ) AND (albums.id IN (
|
134
|
+
# SELECT id FROM (
|
135
|
+
# SELECT albums.id, row_number() OVER
|
136
|
+
# (PARTITION BY albums.artist_id ORDER BY release_date)
|
137
|
+
# AS x_sequel_row_number_x
|
138
|
+
# FROM albums
|
139
|
+
# ) AS t1
|
140
|
+
# WHERE (x_sequel_row_number_x <= 10)
|
141
|
+
# )))
|
142
|
+
# ORDER BY release_date
|
143
|
+
|
144
|
+
* You can now pass symbols with embedded qualifiers or aliases,
|
145
|
+
as well as SQL::Identifier, SQL::QualifiedIdentifier, and
|
146
|
+
SQL::AliasedExpression objects as the first argument to
|
147
|
+
Dataset#graph.
|
148
|
+
|
149
|
+
* The nested_attributes plugin now automatically handles presence
|
150
|
+
validations on foreign keys when creating associated objects.
|
151
|
+
It now sets the foreign key value (or a placeholder value)
|
152
|
+
before validating such objects.
|
153
|
+
|
154
|
+
* Offsets on *_one associations are now respected when using
|
155
|
+
eager_graph.
|
156
|
+
|
157
|
+
* eager graphing *_many associations with offsets no longer breaks
|
158
|
+
if there are no associated results.
|
159
|
+
|
160
|
+
* Database#register_array_type in the pg_array extension now works
|
161
|
+
correctly if there is no existing scalar conversion proc for
|
162
|
+
the type.
|
163
|
+
|
164
|
+
* Unique, foreign key, and not null constraint violations are now
|
165
|
+
recognized correctly on SQLite 3.8.2+.
|
166
|
+
|
167
|
+
* The odbc adapter now returns fractional seconds in timestamps.
|
168
|
+
|
169
|
+
* The obdc/mssql adapter now inputs timestamps with 3 decimal
|
170
|
+
places.
|
171
|
+
|
172
|
+
= Backwards Compatibility
|
173
|
+
|
174
|
+
* The private Model.apply_window_function_eager_limit_strategy
|
175
|
+
method has been removed.
|
data/lib/sequel/adapters/odbc.rb
CHANGED
@@ -127,7 +127,7 @@ module Sequel
|
|
127
127
|
# ODBCColumn#mapSqlTypeToGenericType and Column#klass.
|
128
128
|
case v
|
129
129
|
when ::ODBC::TimeStamp
|
130
|
-
db.to_application_timestamp([v.year, v.month, v.day, v.hour, v.minute, v.second])
|
130
|
+
db.to_application_timestamp([v.year, v.month, v.day, v.hour, v.minute, v.second, v.fraction])
|
131
131
|
when ::ODBC::Time
|
132
132
|
Sequel::SQLTime.create(v.hour, v.minute, v.second)
|
133
133
|
when ::ODBC::Date
|
@@ -32,10 +32,12 @@ module Sequel
|
|
32
32
|
class Dataset < ODBC::Dataset
|
33
33
|
include Sequel::MSSQL::DatasetMethods
|
34
34
|
|
35
|
+
# Use ODBC format, not Microsoft format, as the ODBC layer does
|
36
|
+
# some translation. MSSQL version is over-ridden to allow 3 millisecond decimal places
|
37
|
+
TIMESTAMP_FORMAT="{ts '%Y-%m-%d %H:%M:%S%N'}".freeze
|
38
|
+
|
35
39
|
private
|
36
40
|
|
37
|
-
# Use ODBC format, not Microsoft format, as the ODBC layer does
|
38
|
-
# some translation.
|
39
41
|
def default_timestamp_format
|
40
42
|
TIMESTAMP_FORMAT
|
41
43
|
end
|
@@ -1193,12 +1193,28 @@ module Sequel
|
|
1193
1193
|
lock_style(:share)
|
1194
1194
|
end
|
1195
1195
|
|
1196
|
-
#
|
1197
|
-
#
|
1196
|
+
# Run a full text search on PostgreSQL. By default, searching for the inclusion
|
1197
|
+
# of any of the terms in any of the cols.
|
1198
|
+
#
|
1199
|
+
# Options:
|
1200
|
+
# :language :: The language to use for the search (default: 'simple')
|
1201
|
+
# :plain :: Whether a plain search should be used (default: false). In this case,
|
1202
|
+
# terms should be a single string, and it will do a search where cols
|
1203
|
+
# contains all of the words in terms. This ignores search operators in terms.
|
1204
|
+
# :phrase :: Similar to :plain, but also adding an ILIKE filter to ensure that
|
1205
|
+
# returned rows also include the exact phrase used.
|
1198
1206
|
def full_text_search(cols, terms, opts = OPTS)
|
1199
1207
|
lang = opts[:language] || 'simple'
|
1200
1208
|
terms = terms.join(' | ') if terms.is_a?(Array)
|
1201
|
-
|
1209
|
+
to_tsquery = (opts[:phrase] || opts[:plain]) ? 'plainto_tsquery' : 'to_tsquery'
|
1210
|
+
|
1211
|
+
ds = where(Sequel.lit(["(to_tsvector(", "::regconfig, ", ") @@ #{to_tsquery}(", "::regconfig, ", "))"], lang, full_text_string_join(cols), lang, terms))
|
1212
|
+
|
1213
|
+
if opts[:phrase]
|
1214
|
+
ds = ds.grep(cols, "%#{escape_like(terms)}%", :case_insensitive=>true)
|
1215
|
+
end
|
1216
|
+
|
1217
|
+
ds
|
1202
1218
|
end
|
1203
1219
|
|
1204
1220
|
# Insert given values into the database.
|
@@ -332,10 +332,10 @@ module Sequel
|
|
332
332
|
end
|
333
333
|
|
334
334
|
DATABASE_ERROR_REGEXPS = {
|
335
|
-
/(is|are) not unique\z/ => UniqueConstraintViolation,
|
336
|
-
/foreign key constraint failed\z/ => ForeignKeyConstraintViolation,
|
335
|
+
/(is|are) not unique\z|UNIQUE constraint failed: .+\z/ => UniqueConstraintViolation,
|
336
|
+
/foreign key constraint failed\z|FOREIGN KEY constraint failed\z/ => ForeignKeyConstraintViolation,
|
337
337
|
/\A(SQLITE ERROR 19 \(CONSTRAINT\) : )?constraint failed\z/ => ConstraintViolation,
|
338
|
-
/may not be NULL\z/ => NotNullConstraintViolation,
|
338
|
+
/may not be NULL\z|NOT NULL constraint failed: .+\z/ => NotNullConstraintViolation,
|
339
339
|
}.freeze
|
340
340
|
def database_error_regexps
|
341
341
|
DATABASE_ERROR_REGEXPS
|
@@ -33,7 +33,7 @@ module Sequel
|
|
33
33
|
when SQL::OrderedExpression
|
34
34
|
SQL::OrderedExpression.new(v(o.expression), o.descending, :nulls=>o.nulls)
|
35
35
|
when SQL::AliasedExpression
|
36
|
-
SQL::AliasedExpression.new(v(o.expression), o.
|
36
|
+
SQL::AliasedExpression.new(v(o.expression), o.alias)
|
37
37
|
when SQL::CaseExpression
|
38
38
|
args = [v(o.conditions), v(o.default)]
|
39
39
|
args << v(o.expression) if o.expression?
|
data/lib/sequel/dataset/graph.rb
CHANGED
@@ -26,7 +26,7 @@ module Sequel
|
|
26
26
|
#
|
27
27
|
# Arguments:
|
28
28
|
# dataset :: Can be a symbol (specifying a table), another dataset,
|
29
|
-
# or an
|
29
|
+
# or an SQL::Identifier, SQL::QualifiedIdentifier, or SQL::AliasedExpression.
|
30
30
|
# join_conditions :: Any condition(s) allowed by +join_table+.
|
31
31
|
# block :: A block that is passed to +join_table+.
|
32
32
|
#
|
@@ -50,22 +50,36 @@ module Sequel
|
|
50
50
|
# Allow the use of a dataset or symbol as the first argument
|
51
51
|
# Find the table name/dataset based on the argument
|
52
52
|
table_alias = options[:table_alias]
|
53
|
+
table = dataset
|
54
|
+
create_dataset = true
|
55
|
+
|
53
56
|
case dataset
|
54
57
|
when Symbol
|
55
|
-
table
|
56
|
-
|
57
|
-
table_alias ||= table
|
58
|
-
when
|
58
|
+
# let alias be the same as the table name (sans any optional schema)
|
59
|
+
# unless alias explicitly given in the symbol using ___ notation
|
60
|
+
table_alias ||= split_symbol(table).compact.last
|
61
|
+
when Dataset
|
59
62
|
if dataset.simple_select_all?
|
60
63
|
table = dataset.opts[:from].first
|
61
64
|
table_alias ||= table
|
62
65
|
else
|
63
|
-
table = dataset
|
64
66
|
table_alias ||= dataset_alias((@opts[:num_dataset_sources] || 0)+1)
|
65
67
|
end
|
68
|
+
create_dataset = false
|
69
|
+
when SQL::Identifier
|
70
|
+
table_alias ||= table.value
|
71
|
+
when SQL::QualifiedIdentifier
|
72
|
+
table_alias ||= split_qualifiers(table).last
|
73
|
+
when SQL::AliasedExpression
|
74
|
+
return graph(table.expression, join_conditions, {:table_alias=>table.alias}.merge(options), &block)
|
66
75
|
else
|
67
76
|
raise Error, "The dataset argument should be a symbol or dataset"
|
68
77
|
end
|
78
|
+
table_alias = table_alias.to_sym
|
79
|
+
|
80
|
+
if create_dataset
|
81
|
+
dataset = db.from(table)
|
82
|
+
end
|
69
83
|
|
70
84
|
# Raise Sequel::Error with explanation that the table alias has been used
|
71
85
|
raise_alias_error = lambda do
|
@@ -76,8 +90,8 @@ module Sequel
|
|
76
90
|
# Only allow table aliases that haven't been used
|
77
91
|
raise_alias_error.call if @opts[:graph] && @opts[:graph][:table_aliases] && @opts[:graph][:table_aliases].include?(table_alias)
|
78
92
|
|
79
|
-
# Use a from_self if this is already a joined table
|
80
|
-
ds = (!@opts[:graph] && (@opts[:from].length > 1 || @opts[:join])) ? from_self(:alias=>options[:from_self_alias] || first_source) : self
|
93
|
+
# Use a from_self if this is already a joined table (or from_self specifically disabled for graphs)
|
94
|
+
ds = (@opts[:graph_from_self] != false && !@opts[:graph] && (@opts[:from].length > 1 || @opts[:join])) ? from_self(:alias=>options[:from_self_alias] || first_source) : self
|
81
95
|
|
82
96
|
# Join the table early in order to avoid cloning the dataset twice
|
83
97
|
ds = ds.join_table(options[:join_type] || :left_outer, table, join_conditions, :table_alias=>table_alias, :implicit_qualifier=>options[:implicit_qualifier], :qualify=>options[:qualify], &block)
|
@@ -121,7 +135,7 @@ module Sequel
|
|
121
135
|
column = column.value if column.is_a?(SQL::Identifier)
|
122
136
|
column.to_sym
|
123
137
|
when SQL::AliasedExpression
|
124
|
-
column = sel.
|
138
|
+
column = sel.alias
|
125
139
|
column = column.value if column.is_a?(SQL::Identifier)
|
126
140
|
column.to_sym
|
127
141
|
else
|
data/lib/sequel/dataset/misc.rb
CHANGED
@@ -97,7 +97,7 @@ module Sequel
|
|
97
97
|
end
|
98
98
|
case s = source.first
|
99
99
|
when SQL::AliasedExpression
|
100
|
-
s.
|
100
|
+
s.alias
|
101
101
|
when Symbol
|
102
102
|
_, _, aliaz = split_symbol(s)
|
103
103
|
aliaz ? aliaz.to_sym : s
|
@@ -178,7 +178,7 @@ module Sequel
|
|
178
178
|
c_table, column, aliaz = split_symbol(c)
|
179
179
|
[c_table ? SQL::QualifiedIdentifier.new(c_table, column.to_sym) : column.to_sym, aliaz]
|
180
180
|
when SQL::AliasedExpression
|
181
|
-
[c.expression, c.
|
181
|
+
[c.expression, c.alias]
|
182
182
|
when SQL::JoinClause
|
183
183
|
[c.table, c.table_alias]
|
184
184
|
else
|
data/lib/sequel/dataset/sql.rb
CHANGED
@@ -298,7 +298,7 @@ module Sequel
|
|
298
298
|
# SQL fragment for AliasedExpression
|
299
299
|
def aliased_expression_sql_append(sql, ae)
|
300
300
|
literal_append(sql, ae.expression)
|
301
|
-
as_sql_append(sql, ae.
|
301
|
+
as_sql_append(sql, ae.alias)
|
302
302
|
end
|
303
303
|
|
304
304
|
# SQL fragment for Array
|
@@ -801,7 +801,7 @@ module Sequel
|
|
801
801
|
when SQL::QualifiedIdentifier
|
802
802
|
alias_symbol(sym.column)
|
803
803
|
when SQL::AliasedExpression
|
804
|
-
alias_alias_symbol(sym.
|
804
|
+
alias_alias_symbol(sym.alias)
|
805
805
|
else
|
806
806
|
raise Error, "Invalid alias for alias_symbol: #{sym.inspect}"
|
807
807
|
end
|
@@ -1183,7 +1183,7 @@ module Sequel
|
|
1183
1183
|
schema, table, t_alias = split_symbol(table)
|
1184
1184
|
t_alias ||= Sequel::SQL::QualifiedIdentifier.new(schema, table) if schema
|
1185
1185
|
when Sequel::SQL::AliasedExpression
|
1186
|
-
t_alias = table.
|
1186
|
+
t_alias = table.alias
|
1187
1187
|
end
|
1188
1188
|
c_table = t_alias || table
|
1189
1189
|
end
|
@@ -185,7 +185,7 @@ module Sequel
|
|
185
185
|
|
186
186
|
if soid = opts[:scalar_oid]
|
187
187
|
raise Error, "can't provide both a converter and :scalar_oid option to register" if converter
|
188
|
-
|
188
|
+
converter = type_procs[soid]
|
189
189
|
end
|
190
190
|
|
191
191
|
array_type = (opts[:array_type] || db_type).to_s.dup.freeze
|
@@ -42,6 +42,8 @@
|
|
42
42
|
# ia.any # ANY(int_array_column)
|
43
43
|
# ia.all # ALL(int_array_column)
|
44
44
|
# ia.dims # array_dims(int_array_column)
|
45
|
+
# ia.hstore # hstore(int_array_column)
|
46
|
+
# ia.hstore(:a) # hstore(int_array_column, a)
|
45
47
|
# ia.length # array_length(int_array_column, 1)
|
46
48
|
# ia.length(2) # array_length(int_array_column, 2)
|
47
49
|
# ia.lower # array_lower(int_array_column, 1)
|
@@ -57,6 +59,10 @@
|
|
57
59
|
# If you are also using the pg_array extension, you should load it before
|
58
60
|
# loading this extension. Doing so will allow you to use PGArray#op to get
|
59
61
|
# an ArrayOp, allowing you to perform array operations on array literals.
|
62
|
+
#
|
63
|
+
# In order for #hstore to automatically wrap the returned value correctly in
|
64
|
+
# an HStoreOp, you need to load the pg_hstore_ops extension.
|
65
|
+
|
60
66
|
module Sequel
|
61
67
|
module Postgres
|
62
68
|
# The ArrayOp class is a simple container for a single object that
|
@@ -58,6 +58,13 @@
|
|
58
58
|
# If you are also using the pg_hstore extension, you should load it before
|
59
59
|
# loading this extension. Doing so will allow you to use HStore#op to get
|
60
60
|
# an HStoreOp, allowing you to perform hstore operations on hstore literals.
|
61
|
+
#
|
62
|
+
# Some of these methods will accept ruby arrays and convert them automatically to
|
63
|
+
# PostgreSQL arrays if you have the pg_array extension loaded. Some of these methods
|
64
|
+
# will accept ruby hashes and convert them automatically to PostgreSQL hstores if the
|
65
|
+
# pg_hstore extension is loaded. Methods representing expressions that return
|
66
|
+
# PostgreSQL arrays will have the returned expression automatically wrapped in a
|
67
|
+
# Postgres::ArrayOp if the pg_array_ops extension is loaded.
|
61
68
|
|
62
69
|
module Sequel
|
63
70
|
module Postgres
|
@@ -49,6 +49,11 @@
|
|
49
49
|
# loading this extension. Doing so will allow you to use JSONHash#op and
|
50
50
|
# JSONArray#op to get a JSONOp, allowing you to perform json operations
|
51
51
|
# on json literals.
|
52
|
+
#
|
53
|
+
# In order to get the automatic conversion from a ruby array to a PostgreSQL array
|
54
|
+
# (as shown in the #[] and #get_text examples above), you need to load the pg_array
|
55
|
+
# extension.
|
56
|
+
|
52
57
|
module Sequel
|
53
58
|
module Postgres
|
54
59
|
# The JSONOp class is a simple container for a single object that
|