sequel 3.48.0 → 4.0.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 +114 -0
- data/Rakefile +10 -7
- data/doc/association_basics.rdoc +25 -23
- data/doc/code_order.rdoc +7 -0
- data/doc/core_extensions.rdoc +0 -10
- data/doc/object_model.rdoc +4 -1
- data/doc/querying.rdoc +3 -3
- data/doc/release_notes/4.0.0.txt +262 -0
- data/doc/security.rdoc +0 -28
- data/doc/testing.rdoc +8 -14
- data/lib/sequel/adapters/ado.rb +7 -11
- data/lib/sequel/adapters/ado/access.rb +8 -8
- data/lib/sequel/adapters/ado/mssql.rb +4 -4
- data/lib/sequel/adapters/amalgalite.rb +6 -6
- data/lib/sequel/adapters/cubrid.rb +7 -7
- data/lib/sequel/adapters/db2.rb +5 -9
- data/lib/sequel/adapters/dbi.rb +2 -6
- data/lib/sequel/adapters/do.rb +4 -4
- data/lib/sequel/adapters/firebird.rb +4 -4
- data/lib/sequel/adapters/ibmdb.rb +8 -8
- data/lib/sequel/adapters/informix.rb +2 -10
- data/lib/sequel/adapters/jdbc.rb +17 -17
- data/lib/sequel/adapters/jdbc/as400.rb +2 -2
- data/lib/sequel/adapters/jdbc/cubrid.rb +1 -1
- data/lib/sequel/adapters/jdbc/db2.rb +1 -1
- data/lib/sequel/adapters/jdbc/derby.rb +1 -1
- data/lib/sequel/adapters/jdbc/h2.rb +2 -2
- data/lib/sequel/adapters/jdbc/hsqldb.rb +1 -1
- data/lib/sequel/adapters/jdbc/informix.rb +1 -1
- data/lib/sequel/adapters/jdbc/mssql.rb +2 -2
- data/lib/sequel/adapters/jdbc/mysql.rb +1 -1
- data/lib/sequel/adapters/jdbc/oracle.rb +5 -1
- data/lib/sequel/adapters/jdbc/postgresql.rb +3 -3
- data/lib/sequel/adapters/jdbc/sqlite.rb +3 -3
- data/lib/sequel/adapters/jdbc/transactions.rb +3 -3
- data/lib/sequel/adapters/mock.rb +7 -7
- data/lib/sequel/adapters/mysql.rb +3 -3
- data/lib/sequel/adapters/mysql2.rb +4 -4
- data/lib/sequel/adapters/odbc.rb +2 -6
- data/lib/sequel/adapters/odbc/mssql.rb +1 -1
- data/lib/sequel/adapters/openbase.rb +1 -5
- data/lib/sequel/adapters/oracle.rb +13 -17
- data/lib/sequel/adapters/postgres.rb +20 -25
- data/lib/sequel/adapters/shared/cubrid.rb +3 -3
- data/lib/sequel/adapters/shared/db2.rb +2 -2
- data/lib/sequel/adapters/shared/firebird.rb +7 -7
- data/lib/sequel/adapters/shared/mssql.rb +9 -9
- data/lib/sequel/adapters/shared/mysql.rb +29 -13
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +7 -7
- data/lib/sequel/adapters/shared/oracle.rb +22 -13
- data/lib/sequel/adapters/shared/postgres.rb +61 -46
- data/lib/sequel/adapters/shared/sqlite.rb +9 -9
- data/lib/sequel/adapters/sqlite.rb +17 -11
- data/lib/sequel/adapters/swift.rb +3 -3
- data/lib/sequel/adapters/swift/mysql.rb +1 -1
- data/lib/sequel/adapters/swift/sqlite.rb +1 -1
- data/lib/sequel/adapters/tinytds.rb +8 -8
- data/lib/sequel/ast_transformer.rb +3 -1
- data/lib/sequel/connection_pool.rb +4 -2
- data/lib/sequel/connection_pool/sharded_single.rb +2 -2
- data/lib/sequel/connection_pool/sharded_threaded.rb +5 -5
- data/lib/sequel/connection_pool/threaded.rb +7 -7
- data/lib/sequel/core.rb +4 -67
- data/lib/sequel/database.rb +1 -0
- data/lib/sequel/database/connecting.rb +2 -8
- data/lib/sequel/database/dataset.rb +2 -7
- data/lib/sequel/database/dataset_defaults.rb +0 -18
- data/lib/sequel/database/features.rb +4 -4
- data/lib/sequel/database/misc.rb +6 -8
- data/lib/sequel/database/query.rb +5 -61
- data/lib/sequel/database/schema_generator.rb +22 -20
- data/lib/sequel/database/schema_methods.rb +48 -20
- data/lib/sequel/database/transactions.rb +7 -17
- data/lib/sequel/dataset.rb +2 -0
- data/lib/sequel/dataset/actions.rb +23 -91
- data/lib/sequel/dataset/features.rb +1 -4
- data/lib/sequel/dataset/graph.rb +3 -47
- data/lib/sequel/dataset/misc.rb +4 -33
- data/lib/sequel/dataset/prepared_statements.rb +3 -1
- data/lib/sequel/dataset/query.rb +116 -240
- data/lib/sequel/dataset/sql.rb +19 -97
- data/lib/sequel/deprecated.rb +0 -16
- data/lib/sequel/exceptions.rb +0 -3
- data/lib/sequel/extensions/_pretty_table.rb +1 -1
- data/lib/sequel/extensions/columns_introspection.rb +1 -12
- data/lib/sequel/extensions/constraint_validations.rb +3 -3
- data/lib/sequel/extensions/core_extensions.rb +0 -9
- data/lib/sequel/extensions/date_arithmetic.rb +1 -2
- data/lib/sequel/extensions/graph_each.rb +11 -0
- data/lib/sequel/extensions/migration.rb +5 -5
- data/lib/sequel/extensions/null_dataset.rb +11 -13
- data/lib/sequel/extensions/pagination.rb +3 -6
- data/lib/sequel/extensions/pg_array.rb +6 -4
- data/lib/sequel/extensions/pg_array_ops.rb +35 -1
- data/lib/sequel/extensions/pg_json.rb +12 -2
- data/lib/sequel/extensions/pg_json_ops.rb +266 -0
- data/lib/sequel/extensions/pg_range.rb +2 -2
- data/lib/sequel/extensions/pg_range_ops.rb +0 -8
- data/lib/sequel/extensions/pg_row.rb +2 -2
- data/lib/sequel/extensions/pretty_table.rb +0 -4
- data/lib/sequel/extensions/query.rb +3 -8
- data/lib/sequel/extensions/schema_caching.rb +0 -7
- data/lib/sequel/extensions/schema_dumper.rb +10 -17
- data/lib/sequel/extensions/select_remove.rb +0 -4
- data/lib/sequel/extensions/set_overrides.rb +28 -0
- data/lib/sequel/extensions/to_dot.rb +6 -10
- data/lib/sequel/model.rb +6 -7
- data/lib/sequel/model/associations.rb +127 -182
- data/lib/sequel/model/base.rb +88 -211
- data/lib/sequel/model/errors.rb +0 -13
- data/lib/sequel/model/plugins.rb +2 -2
- data/lib/sequel/no_core_ext.rb +0 -1
- data/lib/sequel/plugins/after_initialize.rb +11 -17
- data/lib/sequel/plugins/association_autoreloading.rb +1 -47
- data/lib/sequel/plugins/association_dependencies.rb +2 -2
- data/lib/sequel/plugins/auto_validations.rb +2 -8
- data/lib/sequel/plugins/blacklist_security.rb +32 -2
- data/lib/sequel/plugins/caching.rb +1 -1
- data/lib/sequel/plugins/class_table_inheritance.rb +2 -2
- data/lib/sequel/plugins/composition.rb +10 -8
- data/lib/sequel/plugins/constraint_validations.rb +2 -2
- data/lib/sequel/plugins/dataset_associations.rb +4 -0
- data/lib/sequel/plugins/defaults_setter.rb +8 -6
- data/lib/sequel/plugins/dirty.rb +6 -6
- data/lib/sequel/plugins/force_encoding.rb +13 -8
- data/lib/sequel/plugins/hook_class_methods.rb +1 -7
- data/lib/sequel/plugins/json_serializer.rb +13 -74
- data/lib/sequel/plugins/lazy_attributes.rb +2 -4
- data/lib/sequel/plugins/list.rb +1 -1
- data/lib/sequel/plugins/many_through_many.rb +4 -11
- data/lib/sequel/plugins/many_to_one_pk_lookup.rb +1 -49
- data/lib/sequel/plugins/nested_attributes.rb +1 -1
- data/lib/sequel/plugins/optimistic_locking.rb +3 -5
- data/lib/sequel/plugins/pg_array_associations.rb +453 -0
- data/lib/sequel/plugins/pg_typecast_on_load.rb +23 -7
- data/lib/sequel/plugins/prepared_statements.rb +1 -1
- data/lib/sequel/plugins/prepared_statements_associations.rb +20 -14
- data/lib/sequel/plugins/prepared_statements_safe.rb +2 -2
- data/lib/sequel/plugins/rcte_tree.rb +1 -1
- data/lib/sequel/plugins/serialization.rb +5 -4
- data/lib/sequel/plugins/serialization_modification_detection.rb +1 -1
- data/lib/sequel/plugins/sharding.rb +7 -1
- data/lib/sequel/plugins/single_table_inheritance.rb +1 -1
- data/lib/sequel/plugins/timestamps.rb +1 -1
- data/lib/sequel/plugins/touch.rb +2 -2
- data/lib/sequel/plugins/tree.rb +1 -1
- data/lib/sequel/plugins/typecast_on_load.rb +19 -4
- data/lib/sequel/plugins/validation_class_methods.rb +0 -30
- data/lib/sequel/plugins/validation_helpers.rb +13 -31
- data/lib/sequel/plugins/xml_serializer.rb +18 -57
- data/lib/sequel/sql.rb +20 -22
- data/lib/sequel/version.rb +2 -2
- data/spec/adapters/db2_spec.rb +14 -23
- data/spec/adapters/firebird_spec.rb +25 -29
- data/spec/adapters/informix_spec.rb +11 -14
- data/spec/adapters/mssql_spec.rb +71 -77
- data/spec/adapters/mysql_spec.rb +165 -172
- data/spec/adapters/oracle_spec.rb +36 -39
- data/spec/adapters/postgres_spec.rb +175 -100
- data/spec/adapters/spec_helper.rb +13 -11
- data/spec/adapters/sqlite_spec.rb +36 -44
- data/spec/core/connection_pool_spec.rb +2 -1
- data/spec/core/database_spec.rb +55 -55
- data/spec/core/dataset_spec.rb +45 -249
- data/spec/core/deprecated_spec.rb +0 -8
- data/spec/core/expression_filters_spec.rb +23 -5
- data/spec/core/object_graph_spec.rb +4 -66
- data/spec/core/schema_spec.rb +35 -12
- data/spec/core/spec_helper.rb +3 -2
- data/spec/core_extensions_spec.rb +17 -19
- data/spec/extensions/arbitrary_servers_spec.rb +2 -3
- data/spec/extensions/association_dependencies_spec.rb +14 -14
- data/spec/extensions/auto_validations_spec.rb +7 -0
- data/spec/extensions/blacklist_security_spec.rb +5 -5
- data/spec/extensions/blank_spec.rb +2 -0
- data/spec/extensions/class_table_inheritance_spec.rb +2 -2
- data/spec/extensions/columns_introspection_spec.rb +2 -29
- data/spec/extensions/composition_spec.rb +10 -17
- data/spec/extensions/core_refinements_spec.rb +5 -1
- data/spec/extensions/dataset_associations_spec.rb +18 -0
- data/spec/extensions/date_arithmetic_spec.rb +2 -2
- data/spec/extensions/defaults_setter_spec.rb +9 -9
- data/spec/extensions/dirty_spec.rb +0 -5
- data/spec/extensions/eval_inspect_spec.rb +2 -0
- data/spec/extensions/force_encoding_spec.rb +2 -18
- data/spec/extensions/hash_aliases_spec.rb +8 -0
- data/spec/extensions/hook_class_methods_spec.rb +39 -58
- data/spec/extensions/inflector_spec.rb +2 -0
- data/spec/extensions/instance_filters_spec.rb +8 -8
- data/spec/extensions/json_serializer_spec.rb +1 -41
- data/spec/extensions/list_spec.rb +1 -1
- data/spec/extensions/many_through_many_spec.rb +106 -109
- data/spec/extensions/migration_spec.rb +2 -0
- data/spec/extensions/named_timezones_spec.rb +1 -0
- data/spec/extensions/pg_array_associations_spec.rb +603 -0
- data/spec/extensions/pg_array_ops_spec.rb +25 -0
- data/spec/extensions/pg_array_spec.rb +9 -1
- data/spec/extensions/pg_hstore_ops_spec.rb +13 -0
- data/spec/extensions/pg_hstore_spec.rb +1 -0
- data/spec/extensions/pg_json_ops_spec.rb +131 -0
- data/spec/extensions/pg_json_spec.rb +10 -4
- data/spec/extensions/pg_range_ops_spec.rb +2 -5
- data/spec/extensions/pg_range_spec.rb +6 -2
- data/spec/extensions/pg_row_ops_spec.rb +2 -0
- data/spec/extensions/prepared_statements_associations_spec.rb +26 -5
- data/spec/extensions/rcte_tree_spec.rb +15 -15
- data/spec/extensions/schema_dumper_spec.rb +0 -1
- data/spec/extensions/schema_spec.rb +9 -9
- data/spec/extensions/serialization_modification_detection_spec.rb +1 -1
- data/spec/extensions/serialization_spec.rb +18 -29
- data/spec/extensions/set_overrides_spec.rb +4 -0
- data/spec/extensions/{many_to_one_pk_lookup_spec.rb → shared_caching_spec.rb} +1 -4
- data/spec/extensions/single_table_inheritance_spec.rb +4 -4
- data/spec/extensions/spec_helper.rb +8 -9
- data/spec/extensions/sql_expr_spec.rb +2 -0
- data/spec/extensions/string_date_time_spec.rb +2 -0
- data/spec/extensions/string_stripper_spec.rb +2 -0
- data/spec/extensions/tactical_eager_loading_spec.rb +12 -12
- data/spec/extensions/thread_local_timezones_spec.rb +2 -0
- data/spec/extensions/timestamps_spec.rb +1 -1
- data/spec/extensions/to_dot_spec.rb +1 -1
- data/spec/extensions/touch_spec.rb +24 -24
- data/spec/extensions/tree_spec.rb +7 -7
- data/spec/extensions/typecast_on_load_spec.rb +8 -1
- data/spec/extensions/update_primary_key_spec.rb +10 -10
- data/spec/extensions/validation_class_methods_spec.rb +10 -39
- data/spec/extensions/validation_helpers_spec.rb +29 -47
- data/spec/extensions/xml_serializer_spec.rb +1 -23
- data/spec/integration/associations_test.rb +231 -40
- data/spec/integration/database_test.rb +1 -1
- data/spec/integration/dataset_test.rb +64 -64
- data/spec/integration/eager_loader_test.rb +28 -28
- data/spec/integration/migrator_test.rb +1 -1
- data/spec/integration/model_test.rb +2 -2
- data/spec/integration/plugin_test.rb +21 -21
- data/spec/integration/prepared_statement_test.rb +7 -7
- data/spec/integration/schema_test.rb +115 -110
- data/spec/integration/spec_helper.rb +17 -27
- data/spec/integration/timezone_test.rb +1 -1
- data/spec/integration/transaction_test.rb +10 -10
- data/spec/integration/type_test.rb +2 -2
- data/spec/model/association_reflection_spec.rb +2 -28
- data/spec/model/associations_spec.rb +239 -188
- data/spec/model/base_spec.rb +27 -68
- data/spec/model/dataset_methods_spec.rb +4 -4
- data/spec/model/eager_loading_spec.rb +160 -172
- data/spec/model/hooks_spec.rb +62 -79
- data/spec/model/model_spec.rb +36 -51
- data/spec/model/plugins_spec.rb +5 -19
- data/spec/model/record_spec.rb +125 -151
- data/spec/model/spec_helper.rb +8 -6
- data/spec/model/validations_spec.rb +4 -17
- data/spec/spec_config.rb +2 -10
- metadata +50 -56
- data/lib/sequel/deprecated_core_extensions.rb +0 -135
- data/lib/sequel/extensions/pg_auto_parameterize.rb +0 -185
- data/lib/sequel/extensions/pg_statement_cache.rb +0 -318
- data/lib/sequel/plugins/identity_map.rb +0 -260
- data/lib/sequel_core.rb +0 -2
- data/lib/sequel_model.rb +0 -2
- data/spec/extensions/association_autoreloading_spec.rb +0 -102
- data/spec/extensions/identity_map_spec.rb +0 -337
- data/spec/extensions/pg_auto_parameterize_spec.rb +0 -70
- data/spec/extensions/pg_statement_cache_spec.rb +0 -208
- data/spec/rcov.opts +0 -8
- data/spec/spec_config.rb.example +0 -10
|
@@ -164,7 +164,7 @@ module Sequel
|
|
|
164
164
|
# to DatabaseMethods.
|
|
165
165
|
#
|
|
166
166
|
# If a block is given, it is treated as the :converter option.
|
|
167
|
-
def self.register(db_type, opts=
|
|
167
|
+
def self.register(db_type, opts=OPTS, &block)
|
|
168
168
|
db_type = db_type.to_s
|
|
169
169
|
typecast_method = opts[:typecast_method]
|
|
170
170
|
type = (typecast_method || opts[:type_symbol] || db_type).to_sym
|
|
@@ -248,7 +248,7 @@ module Sequel
|
|
|
248
248
|
# different array types per Database. Use of this method does not
|
|
249
249
|
# affect global state, unlike PGArray.register. See PGArray.register for
|
|
250
250
|
# possible options.
|
|
251
|
-
def register_array_type(db_type, opts=
|
|
251
|
+
def register_array_type(db_type, opts=OPTS, &block)
|
|
252
252
|
opts = {:type_procs=>conversion_procs, :typecast_method_map=>@pg_array_schema_types, :typecast_methods_module=>(class << self; self; end)}.merge(opts)
|
|
253
253
|
unless (opts.has_key?(:scalar_oid) || block) && opts.has_key?(:oid)
|
|
254
254
|
array_oid, scalar_oid = from(:pg_type).where(:typname=>db_type.to_s).get([:typarray, :oid])
|
|
@@ -285,8 +285,10 @@ module Sequel
|
|
|
285
285
|
# Automatically handle array types for the given named types.
|
|
286
286
|
def convert_named_procs_to_procs(named_procs)
|
|
287
287
|
h = super
|
|
288
|
-
|
|
289
|
-
|
|
288
|
+
unless h.empty?
|
|
289
|
+
from(:pg_type).where(:oid=>h.keys).select_map([:typname, :oid, :typarray]).each do |name, scalar_oid, array_oid|
|
|
290
|
+
register_array_type(name, :type_procs=>h, :oid=>array_oid.to_i, :scalar_oid=>scalar_oid.to_i)
|
|
291
|
+
end
|
|
290
292
|
end
|
|
291
293
|
h
|
|
292
294
|
end
|
|
@@ -76,7 +76,9 @@ module Sequel
|
|
|
76
76
|
#
|
|
77
77
|
# array_op[1] # array[1]
|
|
78
78
|
def [](key)
|
|
79
|
-
Sequel::SQL::Subscript.new(self, [key])
|
|
79
|
+
s = Sequel::SQL::Subscript.new(self, [key])
|
|
80
|
+
s = ArrayOp.new(s) if key.is_a?(Range)
|
|
81
|
+
s
|
|
80
82
|
end
|
|
81
83
|
|
|
82
84
|
# Call the ALL function:
|
|
@@ -124,6 +126,23 @@ module Sequel
|
|
|
124
126
|
function(:array_dims)
|
|
125
127
|
end
|
|
126
128
|
|
|
129
|
+
# Convert the array into an hstore using the hstore function.
|
|
130
|
+
# If given an argument, use the two array form:
|
|
131
|
+
#
|
|
132
|
+
# array_op.hstore # hstore(array)
|
|
133
|
+
# array_op.hstore(:array2) # hstore(array, array2)
|
|
134
|
+
def hstore(arg=(no_arg_given=true; nil))
|
|
135
|
+
v = if no_arg_given
|
|
136
|
+
Sequel.function(:hstore, self)
|
|
137
|
+
else
|
|
138
|
+
Sequel.function(:hstore, self, wrap_array(arg))
|
|
139
|
+
end
|
|
140
|
+
if Sequel.respond_to?(:hstore_op)
|
|
141
|
+
v = Sequel.hstore_op(v)
|
|
142
|
+
end
|
|
143
|
+
v
|
|
144
|
+
end
|
|
145
|
+
|
|
127
146
|
# Call the array_length method:
|
|
128
147
|
#
|
|
129
148
|
# array_op.length # array_length(array, 1)
|
|
@@ -161,6 +180,21 @@ module Sequel
|
|
|
161
180
|
self
|
|
162
181
|
end
|
|
163
182
|
|
|
183
|
+
# Remove the given element from the array:
|
|
184
|
+
#
|
|
185
|
+
# array_op.remove(1) # array_remove(array, 1)
|
|
186
|
+
def remove(element)
|
|
187
|
+
ArrayOp.new(function(:array_remove, element))
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
# Replace the given element in the array with another
|
|
191
|
+
# element:
|
|
192
|
+
#
|
|
193
|
+
# array_op.replace(1, 2) # array_replace(array, 1, 2)
|
|
194
|
+
def replace(element, replacement)
|
|
195
|
+
ArrayOp.new(function(:array_replace, element, replacement))
|
|
196
|
+
end
|
|
197
|
+
|
|
164
198
|
# Call the array_to_string method:
|
|
165
199
|
#
|
|
166
200
|
# array_op.join # array_to_string(array, '', NULL)
|
|
@@ -100,6 +100,16 @@ module Sequel
|
|
|
100
100
|
end
|
|
101
101
|
end
|
|
102
102
|
|
|
103
|
+
# Parse JSON data coming from the database. Since PostgreSQL allows
|
|
104
|
+
# non JSON data in JSON fields (such as plain numbers and strings),
|
|
105
|
+
# we don't want to raise an exception for that.
|
|
106
|
+
def self.db_parse_json(s)
|
|
107
|
+
parse_json(s)
|
|
108
|
+
rescue Sequel::InvalidValue
|
|
109
|
+
raise unless s.is_a?(String)
|
|
110
|
+
parse_json("[#{s}]").first
|
|
111
|
+
end
|
|
112
|
+
|
|
103
113
|
# Parse the given string as json, returning either a JSONArray
|
|
104
114
|
# or JSONHash instance, and raising an error if the JSON
|
|
105
115
|
# parsing does not yield an array or hash.
|
|
@@ -174,7 +184,7 @@ module Sequel
|
|
|
174
184
|
end
|
|
175
185
|
end
|
|
176
186
|
|
|
177
|
-
PG_TYPES[114] = JSONDatabaseMethods.method(:
|
|
187
|
+
PG_TYPES[114] = JSONDatabaseMethods.method(:db_parse_json)
|
|
178
188
|
if defined?(PGArray) && PGArray.respond_to?(:register)
|
|
179
189
|
PGArray.register('json', :oid=>199, :scalar_oid=>114)
|
|
180
190
|
end
|
|
@@ -191,7 +201,7 @@ module Sequel
|
|
|
191
201
|
when Hash
|
|
192
202
|
Postgres::JSONHash.new(v)
|
|
193
203
|
else
|
|
194
|
-
|
|
204
|
+
Sequel.pg_json_op(v)
|
|
195
205
|
end
|
|
196
206
|
end
|
|
197
207
|
end
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
# The pg_json_ops extension adds support to Sequel's DSL to make
|
|
2
|
+
# it easier to call PostgreSQL JSON functions and operators (added
|
|
3
|
+
# first in PostgreSQL 9.3).
|
|
4
|
+
#
|
|
5
|
+
# To load the extension:
|
|
6
|
+
#
|
|
7
|
+
# Sequel.extension :pg_json_ops
|
|
8
|
+
#
|
|
9
|
+
# The most common usage is passing an expression to Sequel.pg_json_op:
|
|
10
|
+
#
|
|
11
|
+
# j = Sequel.pg_json_op(:json_column)
|
|
12
|
+
#
|
|
13
|
+
# If you have also loaded the pg_json extension, you can use
|
|
14
|
+
# Sequel.pg_json as well:
|
|
15
|
+
#
|
|
16
|
+
# j = Sequel.pg_json(:json_column)
|
|
17
|
+
#
|
|
18
|
+
# Also, on most Sequel expression objects, you can call the pg_json
|
|
19
|
+
# method:
|
|
20
|
+
#
|
|
21
|
+
# j = Sequel.expr(:json_column).pg_json
|
|
22
|
+
#
|
|
23
|
+
# If you have loaded the {core_extensions extension}[link:files/doc/core_extensions_rdoc.html]),
|
|
24
|
+
# or you have loaded the {core_refinements extension}[link:files/doc/core_refinements_rdoc.html])
|
|
25
|
+
# and have activated refinements for the file, you can also use Symbol#pg_json:
|
|
26
|
+
#
|
|
27
|
+
# j = :json_column.pg_json
|
|
28
|
+
#
|
|
29
|
+
# This creates a Sequel::Postgres::JSONOp object that can be used
|
|
30
|
+
# for easier querying:
|
|
31
|
+
#
|
|
32
|
+
# j[1] # (json_column -> 1)
|
|
33
|
+
# j[%w'a b'] # (json_column #> ARRAY['a','b'])
|
|
34
|
+
# j.get_text(1) # (json_column ->> 1)
|
|
35
|
+
# j.get_text(%w'a b') # (json_column #>> ARRAY['a','b'])
|
|
36
|
+
# j.extract('a', 'b') # json_extract_path(json_column, 'a', 'b')
|
|
37
|
+
# j.extract_text('a', 'b') # json_extract_path_text(json_column, 'a', 'b')
|
|
38
|
+
#
|
|
39
|
+
# j.array_length # json_array_length(json_column)
|
|
40
|
+
# j.array_elements # json_array_elements(json_column)
|
|
41
|
+
# j.each # json_each(json_column)
|
|
42
|
+
# j.each_text # json_each_text(json_column)
|
|
43
|
+
# j.keys # json_object_keys(json_column)
|
|
44
|
+
#
|
|
45
|
+
# j.populate(:a) # json_populate_record(:a, json_column)
|
|
46
|
+
# j.populate_set(:a) # json_populate_recordset(:a, json_column)
|
|
47
|
+
#
|
|
48
|
+
# If you are also using the pg_json extension, you should load it before
|
|
49
|
+
# loading this extension. Doing so will allow you to use JSONHash#op and
|
|
50
|
+
# JSONArray#op to get a JSONOp, allowing you to perform json operations
|
|
51
|
+
# on json literals.
|
|
52
|
+
module Sequel
|
|
53
|
+
module Postgres
|
|
54
|
+
# The JSONOp class is a simple container for a single object that
|
|
55
|
+
# defines methods that yield Sequel expression objects representing
|
|
56
|
+
# PostgreSQL json operators and functions.
|
|
57
|
+
#
|
|
58
|
+
# In the method documentation examples, assume that:
|
|
59
|
+
#
|
|
60
|
+
# json_op = Sequel.pg_json(:json)
|
|
61
|
+
class JSONOp < Sequel::SQL::Wrapper
|
|
62
|
+
GET = ["(".freeze, " -> ".freeze, ")".freeze].freeze
|
|
63
|
+
GET_TEXT = ["(".freeze, " ->> ".freeze, ")".freeze].freeze
|
|
64
|
+
GET_PATH = ["(".freeze, " #> ".freeze, ")".freeze].freeze
|
|
65
|
+
GET_PATH_TEXT = ["(".freeze, " #>> ".freeze, ")".freeze].freeze
|
|
66
|
+
|
|
67
|
+
# Get JSON array element or object field as json. If an array is given,
|
|
68
|
+
# gets the object at the specified path.
|
|
69
|
+
#
|
|
70
|
+
# json_op[1] # (json -> 1)
|
|
71
|
+
# json_op['a'] # (json -> 'a')
|
|
72
|
+
# json_op[%w'a b'] # (json #> ARRAY['a', 'b'])
|
|
73
|
+
def [](key)
|
|
74
|
+
if is_array?(key)
|
|
75
|
+
json_op(GET_PATH, wrap_array(key))
|
|
76
|
+
else
|
|
77
|
+
json_op(GET, key)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
alias get []
|
|
81
|
+
|
|
82
|
+
# Returns a set of json values for the elements in the json array.
|
|
83
|
+
#
|
|
84
|
+
# json_op.array_elements # json_oarray_elements(json)
|
|
85
|
+
def array_elements
|
|
86
|
+
function(:json_array_elements)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Get the length of the outermost json array.
|
|
90
|
+
#
|
|
91
|
+
# json_op.array_length # json_array_length(json)
|
|
92
|
+
def array_length
|
|
93
|
+
Sequel::SQL::NumericExpression.new(:NOOP, function(:json_array_length))
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Returns a set of key and value pairs, where the keys
|
|
97
|
+
# are text and the values are JSON.
|
|
98
|
+
#
|
|
99
|
+
# json_op.each # json_each(json)
|
|
100
|
+
def each
|
|
101
|
+
function(:json_each)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Returns a set of key and value pairs, where the keys
|
|
105
|
+
# and values are both text.
|
|
106
|
+
#
|
|
107
|
+
# json_op.each_text # json_each_text(json)
|
|
108
|
+
def each_text
|
|
109
|
+
function(:json_each_text)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Returns a json value for the object at the given path.
|
|
113
|
+
#
|
|
114
|
+
# json_op.extract('a') # json_extract_path(json, 'a')
|
|
115
|
+
# json_op.extract('a', 'b') # json_extract_path(json, 'a', 'b')
|
|
116
|
+
def extract(*a)
|
|
117
|
+
JSONOp.new(function(:json_extract_path, *a))
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Returns a text value for the object at the given path.
|
|
121
|
+
#
|
|
122
|
+
# json_op.extract_text('a') # json_extract_path_text(json, 'a')
|
|
123
|
+
# json_op.extract_text('a', 'b') # json_extract_path_text(json, 'a', 'b')
|
|
124
|
+
def extract_text(*a)
|
|
125
|
+
Sequel::SQL::StringExpression.new(:NOOP, function(:json_extract_path_text, *a))
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Get JSON array element or object field as text. If an array is given,
|
|
129
|
+
# gets the object at the specified path.
|
|
130
|
+
#
|
|
131
|
+
# json_op.get_text(1) # (json ->> 1)
|
|
132
|
+
# json_op.get_text('a') # (json ->> 'a')
|
|
133
|
+
# json_op.get_text(%w'a b') # (json #>> ARRAY['a', 'b'])
|
|
134
|
+
def get_text(key)
|
|
135
|
+
if is_array?(key)
|
|
136
|
+
json_op(GET_PATH_TEXT, wrap_array(key))
|
|
137
|
+
else
|
|
138
|
+
json_op(GET_TEXT, key)
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Returns a set of keys AS text in the json object.
|
|
143
|
+
#
|
|
144
|
+
# json_op.keys # json_object_keys(json)
|
|
145
|
+
def keys
|
|
146
|
+
function(:json_object_keys)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Return the receiver, since it is already a JSONOp.
|
|
150
|
+
def pg_json
|
|
151
|
+
self
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# Expands the given argument using the columns in the json.
|
|
155
|
+
#
|
|
156
|
+
# json_op.populate(arg) # json_populate_record(arg, json)
|
|
157
|
+
def populate(arg)
|
|
158
|
+
SQL::Function.new(:json_populate_record, arg, self)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# Expands the given argument using the columns in the json.
|
|
162
|
+
#
|
|
163
|
+
# json_op.populate_set(arg) # json_populate_recordset(arg, json)
|
|
164
|
+
def populate_set(arg)
|
|
165
|
+
SQL::Function.new(:json_populate_recordset, arg, self)
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
private
|
|
169
|
+
|
|
170
|
+
# Return a placeholder literal with the given str and args, wrapped
|
|
171
|
+
# in an JSONOp, used by operators that return json.
|
|
172
|
+
def json_op(str, args)
|
|
173
|
+
JSONOp.new(Sequel::SQL::PlaceholderLiteralString.new(str, [self, args]))
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# Return a function with the given name, and the receiver as the first
|
|
177
|
+
# argument, with any additional arguments given.
|
|
178
|
+
def function(name, *args)
|
|
179
|
+
SQL::Function.new(name, self, *args)
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Whether the given object represents an array in PostgreSQL.
|
|
183
|
+
def is_array?(a)
|
|
184
|
+
a.is_a?(Array) || (defined?(PGArray) && a.is_a?(PGArray)) || (defined?(ArrayOp) && a.is_a?(ArrayOp))
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# Return a placeholder literal with the given str and args, wrapped
|
|
188
|
+
# in an SQL::StringExpression, used by operators that return text.
|
|
189
|
+
def text_op(str, args)
|
|
190
|
+
Sequel::SQL::StringExpression.new(:NOOP, Sequel::SQL::PlaceholderLiteralString.new(str, [self, args]))
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# Automatically wrap argument in a PGArray if it is a plain Array.
|
|
194
|
+
# Requires that the pg_array extension has been loaded to work.
|
|
195
|
+
def wrap_array(arg)
|
|
196
|
+
if arg.instance_of?(Array) && Sequel.respond_to?(:pg_array)
|
|
197
|
+
Sequel.pg_array(arg)
|
|
198
|
+
else
|
|
199
|
+
arg
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
module JSONOpMethods
|
|
205
|
+
# Wrap the receiver in an JSONOp so you can easily use the PostgreSQL
|
|
206
|
+
# json functions and operators with it.
|
|
207
|
+
def pg_json
|
|
208
|
+
JSONOp.new(self)
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
if defined?(JSONArray)
|
|
213
|
+
class JSONArray
|
|
214
|
+
# Wrap the JSONHash instance in an JSONOp, allowing you to easily use
|
|
215
|
+
# the PostgreSQL json functions and operators with literal jsons.
|
|
216
|
+
def op
|
|
217
|
+
JSONOp.new(self)
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
class JSONHash
|
|
222
|
+
# Wrap the JSONHash instance in an JSONOp, allowing you to easily use
|
|
223
|
+
# the PostgreSQL json functions and operators with literal jsons.
|
|
224
|
+
def op
|
|
225
|
+
JSONOp.new(self)
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
module SQL::Builders
|
|
232
|
+
# Return the object wrapped in an Postgres::JSONOp.
|
|
233
|
+
def pg_json_op(v)
|
|
234
|
+
case v
|
|
235
|
+
when Postgres::JSONOp
|
|
236
|
+
v
|
|
237
|
+
else
|
|
238
|
+
Postgres::JSONOp.new(v)
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
class SQL::GenericExpression
|
|
244
|
+
include Sequel::Postgres::JSONOpMethods
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
class LiteralString
|
|
248
|
+
include Sequel::Postgres::JSONOpMethods
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
# :nocov:
|
|
253
|
+
if Sequel.core_extensions?
|
|
254
|
+
class Symbol
|
|
255
|
+
include Sequel::Postgres::JSONOpMethods
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
if defined?(Sequel::CoreRefinements)
|
|
260
|
+
module Sequel::CoreRefinements
|
|
261
|
+
refine Symbol do
|
|
262
|
+
include Sequel::Postgres::JSONOpMethods
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
end
|
|
266
|
+
# :nocov:
|
|
@@ -92,7 +92,7 @@ module Sequel
|
|
|
92
92
|
# proc.
|
|
93
93
|
#
|
|
94
94
|
# If a block is given, it is treated as the :converter option.
|
|
95
|
-
def self.register(db_type, opts=
|
|
95
|
+
def self.register(db_type, opts=OPTS, &block)
|
|
96
96
|
db_type = db_type.to_s.dup.freeze
|
|
97
97
|
|
|
98
98
|
if converter = opts[:converter]
|
|
@@ -328,7 +328,7 @@ module Sequel
|
|
|
328
328
|
# :empty :: Whether the range is empty (has no points)
|
|
329
329
|
# :exclude_begin :: Whether the beginning element is excluded from the range.
|
|
330
330
|
# :exclude_end :: Whether the ending element is excluded from the range.
|
|
331
|
-
def initialize(beg, en, opts=
|
|
331
|
+
def initialize(beg, en, opts=OPTS)
|
|
332
332
|
@begin = beg
|
|
333
333
|
@end = en
|
|
334
334
|
@empty = !!opts[:empty]
|
|
@@ -79,14 +79,6 @@ module Sequel
|
|
|
79
79
|
OPERATORS.keys.each do |f|
|
|
80
80
|
class_eval("def #{f}(v); operator(:#{f}, v) end", __FILE__, __LINE__)
|
|
81
81
|
end
|
|
82
|
-
def starts_before(v)
|
|
83
|
-
Sequel::Deprecation.deprecate('Postgres::PGRangeOp#starts_before', "Please switch to Postgres::PGRangeOp#ends_before")
|
|
84
|
-
ends_before(v)
|
|
85
|
-
end
|
|
86
|
-
def ends_after(v)
|
|
87
|
-
Sequel::Deprecation.deprecate('Postgres::PGRangeOp#ends_after', "Please switch to Postgres::PGRangeOp#starts_after")
|
|
88
|
-
starts_after(v)
|
|
89
|
-
end
|
|
90
82
|
|
|
91
83
|
# These operators are already supported by the wrapper, but for ranges they
|
|
92
84
|
# return ranges, so wrap the results in another RangeOp.
|
|
@@ -290,7 +290,7 @@ module Sequel
|
|
|
290
290
|
|
|
291
291
|
# Sets each of the parser's attributes, using options with
|
|
292
292
|
# the same name (e.g. :columns sets the columns attribute).
|
|
293
|
-
def initialize(h=
|
|
293
|
+
def initialize(h=OPTS)
|
|
294
294
|
@columns = h[:columns]
|
|
295
295
|
@column_converters = h[:column_converters]
|
|
296
296
|
@column_oids = h[:column_oids]
|
|
@@ -417,7 +417,7 @@ module Sequel
|
|
|
417
417
|
#
|
|
418
418
|
# :converter :: Use a custom converter for the parser.
|
|
419
419
|
# :typecaster :: Use a custom typecaster for the parser.
|
|
420
|
-
def register_row_type(db_type, opts=
|
|
420
|
+
def register_row_type(db_type, opts=OPTS)
|
|
421
421
|
procs = @conversion_procs
|
|
422
422
|
rel_oid = nil
|
|
423
423
|
array_oid = nil
|
|
@@ -23,12 +23,8 @@ module Sequel
|
|
|
23
23
|
extension :_pretty_table
|
|
24
24
|
|
|
25
25
|
module DatasetPrinter
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
class Dataset
|
|
29
26
|
# Pretty prints the records in the dataset as plain-text table.
|
|
30
27
|
def print(*cols)
|
|
31
|
-
Sequel::Deprecation.deprecate('Loading the pretty_table extension globally', "Please use Database/Dataset#extension to load the extension into this dataset") unless is_a?(DatasetPrinter)
|
|
32
28
|
ds = naked
|
|
33
29
|
rows = ds.all
|
|
34
30
|
Sequel::PrettyTable.print(rows, cols.empty? ? ds.columns : cols)
|