sequel 4.12.0 → 4.13.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 +64 -0
- data/Rakefile +3 -1
- data/bin/sequel +13 -5
- data/doc/release_notes/4.13.0.txt +169 -0
- data/doc/sql.rdoc +3 -3
- data/lib/sequel/adapters/do.rb +11 -23
- data/lib/sequel/adapters/do/mysql.rb +8 -0
- data/lib/sequel/adapters/do/postgres.rb +8 -0
- data/lib/sequel/adapters/do/{sqlite.rb → sqlite3.rb} +9 -0
- data/lib/sequel/adapters/jdbc.rb +16 -139
- data/lib/sequel/adapters/jdbc/as400.rb +9 -0
- data/lib/sequel/adapters/jdbc/cubrid.rb +9 -0
- data/lib/sequel/adapters/jdbc/db2.rb +9 -0
- data/lib/sequel/adapters/jdbc/derby.rb +9 -0
- data/lib/sequel/adapters/jdbc/{firebird.rb → firebirdsql.rb} +9 -0
- data/lib/sequel/adapters/jdbc/h2.rb +10 -0
- data/lib/sequel/adapters/jdbc/hsqldb.rb +9 -0
- data/lib/sequel/adapters/jdbc/{informix.rb → informix-sqli.rb} +9 -0
- data/lib/sequel/adapters/jdbc/{progress.rb → jdbcprogress.rb} +9 -0
- data/lib/sequel/adapters/jdbc/jtds.rb +10 -0
- data/lib/sequel/adapters/jdbc/mysql.rb +14 -0
- data/lib/sequel/adapters/jdbc/oracle.rb +9 -0
- data/lib/sequel/adapters/jdbc/postgresql.rb +9 -0
- data/lib/sequel/adapters/jdbc/sqlanywhere.rb +23 -0
- data/lib/sequel/adapters/jdbc/sqlite.rb +10 -0
- data/lib/sequel/adapters/jdbc/sqlserver.rb +10 -0
- data/lib/sequel/adapters/odbc.rb +6 -14
- data/lib/sequel/adapters/odbc/db2.rb +9 -0
- data/lib/sequel/adapters/odbc/mssql.rb +8 -0
- data/lib/sequel/adapters/odbc/progress.rb +8 -0
- data/lib/sequel/adapters/oracle.rb +1 -1
- data/lib/sequel/adapters/postgres.rb +1 -1
- data/lib/sequel/adapters/shared/firebird.rb +8 -1
- data/lib/sequel/adapters/shared/mssql.rb +68 -27
- data/lib/sequel/adapters/shared/mysql.rb +3 -5
- data/lib/sequel/adapters/shared/oracle.rb +17 -3
- data/lib/sequel/adapters/shared/postgres.rb +9 -4
- data/lib/sequel/adapters/shared/sqlanywhere.rb +6 -6
- data/lib/sequel/database/connecting.rb +38 -17
- data/lib/sequel/dataset/actions.rb +6 -2
- data/lib/sequel/dataset/graph.rb +18 -20
- data/lib/sequel/dataset/misc.rb +37 -0
- data/lib/sequel/dataset/prepared_statements.rb +1 -2
- data/lib/sequel/dataset/query.rb +1 -0
- data/lib/sequel/dataset/sql.rb +17 -10
- data/lib/sequel/extensions/dataset_source_alias.rb +90 -0
- data/lib/sequel/extensions/pg_array.rb +14 -10
- data/lib/sequel/extensions/pg_enum.rb +135 -0
- data/lib/sequel/extensions/pg_hstore.rb +4 -6
- data/lib/sequel/extensions/pg_inet.rb +4 -5
- data/lib/sequel/extensions/pg_interval.rb +3 -3
- data/lib/sequel/extensions/pg_json.rb +16 -12
- data/lib/sequel/extensions/pg_range.rb +5 -3
- data/lib/sequel/extensions/pg_row.rb +2 -2
- data/lib/sequel/extensions/round_timestamps.rb +52 -0
- data/lib/sequel/model.rb +5 -2
- data/lib/sequel/model/associations.rb +29 -3
- data/lib/sequel/model/base.rb +68 -29
- data/lib/sequel/plugins/class_table_inheritance.rb +25 -16
- data/lib/sequel/plugins/column_select.rb +57 -0
- data/lib/sequel/plugins/composition.rb +14 -16
- data/lib/sequel/plugins/dirty.rb +9 -11
- data/lib/sequel/plugins/insert_returning_select.rb +70 -0
- data/lib/sequel/plugins/instance_filters.rb +7 -9
- data/lib/sequel/plugins/lazy_attributes.rb +16 -4
- data/lib/sequel/plugins/list.rb +9 -0
- data/lib/sequel/plugins/modification_detection.rb +90 -0
- data/lib/sequel/plugins/serialization.rb +13 -15
- data/lib/sequel/plugins/serialization_modification_detection.rb +9 -9
- data/lib/sequel/plugins/single_table_inheritance.rb +3 -1
- data/lib/sequel/plugins/timestamps.rb +6 -6
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mysql_spec.rb +7 -0
- data/spec/adapters/postgres_spec.rb +41 -0
- data/spec/bin_spec.rb +4 -1
- data/spec/core/database_spec.rb +6 -0
- data/spec/core/dataset_spec.rb +100 -90
- data/spec/core/object_graph_spec.rb +5 -0
- data/spec/extensions/class_table_inheritance_spec.rb +18 -13
- data/spec/extensions/column_select_spec.rb +108 -0
- data/spec/extensions/composition_spec.rb +20 -0
- data/spec/extensions/dataset_source_alias_spec.rb +51 -0
- data/spec/extensions/insert_returning_select_spec.rb +46 -0
- data/spec/extensions/lazy_attributes_spec.rb +24 -20
- data/spec/extensions/list_spec.rb +5 -0
- data/spec/extensions/modification_detection_spec.rb +80 -0
- data/spec/extensions/pg_enum_spec.rb +64 -0
- data/spec/extensions/pg_json_spec.rb +7 -13
- data/spec/extensions/prepared_statements_spec.rb +6 -4
- data/spec/extensions/round_timestamps_spec.rb +43 -0
- data/spec/extensions/serialization_modification_detection_spec.rb +10 -1
- data/spec/extensions/serialization_spec.rb +18 -0
- data/spec/extensions/single_table_inheritance_spec.rb +5 -0
- data/spec/extensions/timestamps_spec.rb +6 -0
- data/spec/integration/plugin_test.rb +14 -8
- data/spec/integration/prepared_statement_test.rb +12 -0
- data/spec/model/associations_spec.rb +24 -0
- data/spec/model/model_spec.rb +13 -3
- data/spec/model/record_spec.rb +24 -1
- metadata +22 -6
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# The pg_array extension adds support for Sequel to handle
|
|
2
2
|
# PostgreSQL's array types.
|
|
3
3
|
#
|
|
4
|
-
# This extension integrates with Sequel's native postgres adapter
|
|
5
|
-
# that when array fields are retrieved,
|
|
6
|
-
# as instances of Sequel::Postgres::PGArray.
|
|
7
|
-
# a DelegateClass of Array, so it mostly acts like an array, but not
|
|
4
|
+
# This extension integrates with Sequel's native postgres adapter and
|
|
5
|
+
# the jdbc/postgresql adapter, so that when array fields are retrieved,
|
|
6
|
+
# they are parsed and returned as instances of Sequel::Postgres::PGArray.
|
|
7
|
+
# PGArray is a DelegateClass of Array, so it mostly acts like an array, but not
|
|
8
8
|
# completely (is_a?(Array) is false). If you want the actual array,
|
|
9
9
|
# you can call PGArray#to_a. This is done so that Sequel does not
|
|
10
10
|
# treat a PGArray like an Array by default, which would cause issues.
|
|
@@ -39,18 +39,21 @@
|
|
|
39
39
|
# See the {schema modification guide}[rdoc-ref:doc/schema_modification.rdoc]
|
|
40
40
|
# for details on using postgres array columns in CREATE/ALTER TABLE statements.
|
|
41
41
|
#
|
|
42
|
-
# If you are not using the native postgres adapter and are using array
|
|
43
|
-
# types as model column values you probably should use the
|
|
44
|
-
#
|
|
45
|
-
# regular array, and the pg_typecast_on_load plugin if the column
|
|
46
|
-
# values are returned as a string.
|
|
42
|
+
# If you are not using the native postgres or jdbc/postgresql adapter and are using array
|
|
43
|
+
# types as model column values you probably should use the the pg_typecast_on_load plugin
|
|
44
|
+
# if the column values are returned as a string.
|
|
47
45
|
#
|
|
48
46
|
# This extension by default includes handlers for array types for
|
|
49
47
|
# all scalar types that the native postgres adapter handles. It
|
|
50
48
|
# also makes it easy to add support for other array types. In
|
|
51
49
|
# general, you just need to make sure that the scalar type is
|
|
52
50
|
# handled and has the appropriate converter installed in
|
|
53
|
-
# Sequel::Postgres::PG_TYPES
|
|
51
|
+
# Sequel::Postgres::PG_TYPES or the Database instance's
|
|
52
|
+
# conversion_procs usingthe appropriate type OID. For user defined
|
|
53
|
+
# types, you can do this via:
|
|
54
|
+
#
|
|
55
|
+
# DB.conversion_procs[scalar_type_oid] = lambda{|string| ...}
|
|
56
|
+
#
|
|
54
57
|
# Then you can call
|
|
55
58
|
# Sequel::Postgres::PGArray::DatabaseMethods#register_array_type
|
|
56
59
|
# to automatically set up a handler for the array type. So if you
|
|
@@ -63,6 +66,7 @@
|
|
|
63
66
|
# Sequel::Postgres::PGArray.register. In this case, you'll have
|
|
64
67
|
# to specify the type oids:
|
|
65
68
|
#
|
|
69
|
+
# Sequel::Postgres::PG_TYPES[1234] = lambda{|string| ...}
|
|
66
70
|
# Sequel::Postgres::PGArray.register('foo', :oid=>4321, :scalar_oid=>1234)
|
|
67
71
|
#
|
|
68
72
|
# Both Sequel::Postgres::PGArray::DatabaseMethods#register_array_type
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# The pg_enum extension adds support for Sequel to handle PostgreSQL's enum
|
|
2
|
+
# types. To use this extension, first load it into your Database instance:
|
|
3
|
+
#
|
|
4
|
+
# DB.extension :pg_enum
|
|
5
|
+
#
|
|
6
|
+
# It allows creation of enum types using create_enum:
|
|
7
|
+
#
|
|
8
|
+
# DB.create_enum(:type_name, %w'value1 value2 value3')
|
|
9
|
+
#
|
|
10
|
+
# You can also add values to existing enums via add_enum_value:
|
|
11
|
+
#
|
|
12
|
+
# DB.add_enum_value(:enum_type_name, 'value4')
|
|
13
|
+
#
|
|
14
|
+
# If you want to drop an enum type, you can use drop_enum:
|
|
15
|
+
#
|
|
16
|
+
# DB.drop_enum(:type_name)
|
|
17
|
+
#
|
|
18
|
+
# Just like any user-created type, after creating the type, you
|
|
19
|
+
# can create tables that have a column of that type:
|
|
20
|
+
#
|
|
21
|
+
# DB.create_table(:table_name)
|
|
22
|
+
# enum_type_name :column_name
|
|
23
|
+
# end
|
|
24
|
+
#
|
|
25
|
+
# When parsing the schema, enum types are recognized, and available
|
|
26
|
+
# values returned in the schema hash:
|
|
27
|
+
#
|
|
28
|
+
# DB.schema(:table_name)
|
|
29
|
+
# [[:column_name, {:type=>:enum, :enum_values=>['value1', 'value2']}]]
|
|
30
|
+
#
|
|
31
|
+
# If the pg_array extension is used, arrays of enums are returned as a
|
|
32
|
+
# PGArray:
|
|
33
|
+
#
|
|
34
|
+
# DB.create_table(:table_name)
|
|
35
|
+
# column :column_name, 'enum_type_name[]'
|
|
36
|
+
# end
|
|
37
|
+
# DB[:table_name].get(:column_name)
|
|
38
|
+
# # ['value1', 'value2']
|
|
39
|
+
#
|
|
40
|
+
# Finally, typecasting for enums is setup to cast to strings, which
|
|
41
|
+
# allows you to use symbols in your model code. Similar, you can provide
|
|
42
|
+
# the enum values as symbols when creating enums using create_enum or
|
|
43
|
+
# add_enum_value.
|
|
44
|
+
|
|
45
|
+
module Sequel
|
|
46
|
+
module Postgres
|
|
47
|
+
# Methods enabling Database object integration with enum types.
|
|
48
|
+
module EnumDatabaseMethods
|
|
49
|
+
# Parse the available enum values when loading this extension into
|
|
50
|
+
# your database.
|
|
51
|
+
def self.extended(db)
|
|
52
|
+
db.send(:parse_enum_labels)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Run the SQL to add the given value to the existing enum type.
|
|
56
|
+
# Options:
|
|
57
|
+
# :after :: Add the new value after this existing value.
|
|
58
|
+
# :before :: Add the new value before this existing value.
|
|
59
|
+
# :if_not_exists :: Do not raise an error if the value already exists in the enum.
|
|
60
|
+
def add_enum_value(enum, value, opts=OPTS)
|
|
61
|
+
sql = "ALTER TYPE #{quote_schema_table(enum)} ADD VALUE#{' IF NOT EXISTS' if opts[:if_not_exists]} #{literal(value.to_s)}"
|
|
62
|
+
if v = opts[:before]
|
|
63
|
+
sql << " BEFORE #{literal(v.to_s)}"
|
|
64
|
+
elsif v = opts[:after]
|
|
65
|
+
sql << " AFTER #{literal(v.to_s)}"
|
|
66
|
+
end
|
|
67
|
+
run sql
|
|
68
|
+
parse_enum_labels
|
|
69
|
+
nil
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Run the SQL to create an enum type with the given name and values.
|
|
73
|
+
def create_enum(enum, values)
|
|
74
|
+
sql = "CREATE TYPE #{quote_schema_table(enum)} AS ENUM (#{values.map{|v| literal(v.to_s)}.join(', ')})"
|
|
75
|
+
run sql
|
|
76
|
+
parse_enum_labels
|
|
77
|
+
nil
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Run the SQL to drop the enum type with the given name.
|
|
81
|
+
# Options:
|
|
82
|
+
# :if_exists :: Do not raise an error if the enum type does not exist
|
|
83
|
+
# :cascade :: Also drop other objects that depend on the enum type
|
|
84
|
+
def drop_enum(enum, opts=OPTS)
|
|
85
|
+
sql = "DROP TYPE#{' IF EXISTS' if opts[:if_exists]} #{quote_schema_table(enum)}#{' CASCADE' if opts[:cascade]}"
|
|
86
|
+
run sql
|
|
87
|
+
parse_enum_labels
|
|
88
|
+
nil
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
private
|
|
92
|
+
|
|
93
|
+
# Parse the pg_enum table to get enum values, and
|
|
94
|
+
# the pg_type table to get names and array oids for
|
|
95
|
+
# enums.
|
|
96
|
+
def parse_enum_labels
|
|
97
|
+
@enum_labels = metadata_dataset.from(:pg_enum).
|
|
98
|
+
order(:enumtypid, :enumsortorder).
|
|
99
|
+
select_hash_groups(Sequel.cast(:enumtypid, Integer).as(:v), :enumlabel)
|
|
100
|
+
|
|
101
|
+
if respond_to?(:register_array_type)
|
|
102
|
+
array_types = metadata_dataset.
|
|
103
|
+
from(:pg_type).
|
|
104
|
+
where(:oid=>@enum_labels.keys).
|
|
105
|
+
exclude(:typarray=>0).
|
|
106
|
+
select_map([:typname, Sequel.cast(:typarray, Integer).as(:v)])
|
|
107
|
+
|
|
108
|
+
existing_oids = conversion_procs.keys
|
|
109
|
+
array_types.each do |name, oid|
|
|
110
|
+
next if existing_oids.include?(oid)
|
|
111
|
+
register_array_type(name, :oid=>oid)
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# For schema entries that are enums, set the type to
|
|
117
|
+
# :enum and add a :enum_values entry with the enum values.
|
|
118
|
+
def schema_parse_table(*)
|
|
119
|
+
super.each do |_, s|
|
|
120
|
+
if values = @enum_labels[s[:oid]]
|
|
121
|
+
s[:type] = :enum
|
|
122
|
+
s[:enum_values] = values
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Typecast the given value to a string.
|
|
128
|
+
def typecast_value_enum(value)
|
|
129
|
+
value.to_s
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
Database.register_extension(:pg_enum, Postgres::EnumDatabaseMethods)
|
|
135
|
+
end
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
# the hstore type stores an arbitrary key-value table, where the keys
|
|
4
4
|
# are strings and the values are strings or NULL.
|
|
5
5
|
#
|
|
6
|
-
# This extension integrates with Sequel's native postgres
|
|
7
|
-
# that when hstore fields are retrieved, they are parsed and returned
|
|
6
|
+
# This extension integrates with Sequel's native postgres and jdbc/postgresql
|
|
7
|
+
# adapters, so that when hstore fields are retrieved, they are parsed and returned
|
|
8
8
|
# as instances of Sequel::Postgres::HStore. HStore is
|
|
9
9
|
# a DelegateClass of Hash, so it mostly acts like a hash, but not
|
|
10
10
|
# completely (is_a?(Hash) is false). If you want the actual hash,
|
|
@@ -78,11 +78,9 @@
|
|
|
78
78
|
# See the {schema modification guide}[rdoc-ref:doc/schema_modification.rdoc]
|
|
79
79
|
# for details on using hstore columns in CREATE/ALTER TABLE statements.
|
|
80
80
|
#
|
|
81
|
-
# If you are not using the native postgres
|
|
81
|
+
# If you are not using the native postgres or jdbc/postgresql adapters and are using hstore
|
|
82
82
|
# types as model column values you probably should use the
|
|
83
|
-
#
|
|
84
|
-
# hash, and the pg_typecast_on_load plugin if the column
|
|
85
|
-
# values are returned as a string.
|
|
83
|
+
# pg_typecast_on_load plugin if the column values are returned as a string.
|
|
86
84
|
#
|
|
87
85
|
# This extension requires the delegate and strscan libraries.
|
|
88
86
|
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
# The pg_inet extension adds support for Sequel to handle
|
|
2
2
|
# PostgreSQL's inet and cidr types using ruby's IPAddr class.
|
|
3
3
|
#
|
|
4
|
-
# This extension integrates with Sequel's native postgres
|
|
5
|
-
# that when inet/cidr fields are retrieved, they are returned as
|
|
4
|
+
# This extension integrates with Sequel's native postgres and jdbc/postgresql
|
|
5
|
+
# adapters, so that when inet/cidr fields are retrieved, they are returned as
|
|
6
6
|
# IPAddr instances
|
|
7
7
|
#
|
|
8
|
-
#
|
|
9
|
-
# with a module so that it correctly handles the inet/cidr type:
|
|
8
|
+
# To use this extension, load it into your database:
|
|
10
9
|
#
|
|
11
10
|
# DB.extension :pg_inet
|
|
12
11
|
#
|
|
13
|
-
# If you are not using the native postgres
|
|
12
|
+
# If you are not using the native postgres or jdbc/postgresql adapters and are using inet/cidr
|
|
14
13
|
# types as model column values you probably should use the
|
|
15
14
|
# pg_typecast_on_load plugin if the column values are returned as a string.
|
|
16
15
|
#
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# The pg_interval extension adds support for PostgreSQL's interval type.
|
|
2
2
|
#
|
|
3
|
-
# This extension integrates with Sequel's native postgres
|
|
4
|
-
# that when interval type values are retrieved, they are parsed and returned
|
|
3
|
+
# This extension integrates with Sequel's native postgres and jdbc/postgresql
|
|
4
|
+
# adapters, so that when interval type values are retrieved, they are parsed and returned
|
|
5
5
|
# as instances of ActiveSupport::Duration.
|
|
6
6
|
#
|
|
7
7
|
# In addition to the parser, this extension adds literalizers for
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
#
|
|
16
16
|
# DB.extension :pg_interval
|
|
17
17
|
#
|
|
18
|
-
# If you are not using the native postgres
|
|
18
|
+
# If you are not using the native postgres or jdbc/postgresql adapters and are using interval
|
|
19
19
|
# types as model column values you probably should use the
|
|
20
20
|
# pg_typecast_on_load plugin if the column values are returned as a string.
|
|
21
21
|
#
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
# The pg_json extension adds support for Sequel to handle
|
|
2
|
-
# PostgreSQL's json
|
|
3
|
-
# PostgreSQL json
|
|
2
|
+
# PostgreSQL's json and jsonb types. It is slightly more strict than the
|
|
3
|
+
# PostgreSQL json types in that the object returned should be an
|
|
4
4
|
# array or object (PostgreSQL's json type considers plain numbers
|
|
5
|
-
# and
|
|
6
|
-
#
|
|
7
|
-
#
|
|
5
|
+
# strings, true, false, and null as valid). Sequel will work with
|
|
6
|
+
# PostgreSQL json values that are not arrays or objects, but support
|
|
7
|
+
# is fairly limited and the values do not roundtrip.
|
|
8
8
|
#
|
|
9
9
|
# This extension integrates with Sequel's native postgres adapter, so
|
|
10
10
|
# that when json fields are retrieved, they are parsed and returned
|
|
11
11
|
# as instances of Sequel::Postgres::JSONArray or
|
|
12
|
-
# Sequel::Postgres::JSONHash
|
|
12
|
+
# Sequel::Postgres::JSONHash (or JSONBArray or JSONBHash for jsonb
|
|
13
|
+
# columns). JSONArray and JSONHash are
|
|
13
14
|
# DelegateClasses of Array and Hash, so they mostly act the same, but
|
|
14
15
|
# not completely (json_array.is_a?(Array) is false). If you want
|
|
15
16
|
# the actual array for a JSONArray, call JSONArray#to_a. If you want
|
|
@@ -20,15 +21,15 @@
|
|
|
20
21
|
# To turn an existing Array or Hash into a JSONArray or JSONHash,
|
|
21
22
|
# use Sequel.pg_json:
|
|
22
23
|
#
|
|
23
|
-
# Sequel.pg_json(array)
|
|
24
|
-
# Sequel.pg_json(hash)
|
|
24
|
+
# Sequel.pg_json(array) # or Sequel.pg_jsonb(array) for jsonb type
|
|
25
|
+
# Sequel.pg_json(hash) # or Sequel.pg_jsonb(hash) for jsonb type
|
|
25
26
|
#
|
|
26
27
|
# If you have loaded the {core_extensions extension}[rdoc-ref:doc/core_extensions.rdoc],
|
|
27
28
|
# or you have loaded the core_refinements extension
|
|
28
29
|
# and have activated refinements for the file, you can also use Array#pg_json and Hash#pg_json:
|
|
29
30
|
#
|
|
30
|
-
# array.pg_json
|
|
31
|
-
# hash.pg_json
|
|
31
|
+
# array.pg_json # or array.pg_jsonb for jsonb type
|
|
32
|
+
# hash.pg_json # or hash.pg_jsonb for jsonb type
|
|
32
33
|
#
|
|
33
34
|
# So if you want to insert an array or hash into an json database column:
|
|
34
35
|
#
|
|
@@ -154,8 +155,9 @@ module Sequel
|
|
|
154
155
|
end
|
|
155
156
|
|
|
156
157
|
# Parse the given string as json, returning either a JSONArray
|
|
157
|
-
# or JSONHash instance
|
|
158
|
-
#
|
|
158
|
+
# or JSONHash instance (or JSONBArray or JSONBHash instance if jsonb
|
|
159
|
+
# argument is true), or a String, Numeric, true, false, or nil
|
|
160
|
+
# if the json library used supports that.
|
|
159
161
|
def self.parse_json(s, jsonb=false)
|
|
160
162
|
begin
|
|
161
163
|
value = Sequel.parse_json(s)
|
|
@@ -168,6 +170,8 @@ module Sequel
|
|
|
168
170
|
(jsonb ? JSONBArray : JSONArray).new(value)
|
|
169
171
|
when Hash
|
|
170
172
|
(jsonb ? JSONBHash : JSONHash).new(value)
|
|
173
|
+
when String, Numeric, true, false, nil
|
|
174
|
+
value
|
|
171
175
|
else
|
|
172
176
|
raise Sequel::InvalidValue, "unhandled json value: #{value.inspect} (from #{s.inspect})"
|
|
173
177
|
end
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
# unbounded beginnings and endings (which ruby's range does not
|
|
7
7
|
# support).
|
|
8
8
|
#
|
|
9
|
-
# This extension integrates with Sequel's native postgres
|
|
9
|
+
# This extension integrates with Sequel's native postgres and jdbc/postgresql adapters, so
|
|
10
10
|
# that when range type values are retrieved, they are parsed and returned
|
|
11
11
|
# as instances of Sequel::Postgres::PGRange. PGRange mostly acts
|
|
12
12
|
# like a Range, but it's not a Range as not all PostgreSQL range
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
#
|
|
46
46
|
# DB.extension :pg_range
|
|
47
47
|
#
|
|
48
|
-
# If you are not using the native postgres
|
|
48
|
+
# If you are not using the native postgres or jdbc/postgresql adapters and are using range
|
|
49
49
|
# types as model column values you probably should use the
|
|
50
50
|
# pg_typecast_on_load plugin if the column values are returned as a string.
|
|
51
51
|
#
|
|
@@ -395,7 +395,9 @@ module Sequel
|
|
|
395
395
|
end
|
|
396
396
|
end
|
|
397
397
|
|
|
398
|
-
# Whether this range is empty (has no points).
|
|
398
|
+
# Whether this range is empty (has no points). Note that for manually created ranges
|
|
399
|
+
# (ones not retrieved from the database), this will only be true if the range
|
|
400
|
+
# was created using the :empty option.
|
|
399
401
|
def empty?
|
|
400
402
|
@empty
|
|
401
403
|
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# The pg_row extension adds support for Sequel to handle
|
|
2
2
|
# PostgreSQL's row-valued/composite types.
|
|
3
3
|
#
|
|
4
|
-
# This extension integrates with Sequel's native postgres
|
|
4
|
+
# This extension integrates with Sequel's native postgres and jdbc/postgresql adapters, so
|
|
5
5
|
# that when composite fields are retrieved, they are parsed and returned
|
|
6
6
|
# as instances of Sequel::Postgres::PGRow::(HashRow|ArrayRow), or
|
|
7
7
|
# optionally a custom type. HashRow and ArrayRow are DelegateClasses of
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
# DB.conversion_procs.select{|k,v| v.is_a?(Sequel::Postgres::PGRow::Parser) && \
|
|
75
75
|
# v.converter && (v.converter.name.nil? || v.converter.name == '') }.map{|k,v| v}
|
|
76
76
|
#
|
|
77
|
-
# If you are not using the native postgres
|
|
77
|
+
# If you are not using the native postgres or jdbc/postgresql adapters and are using composite types
|
|
78
78
|
# types as model column values you probably should use the
|
|
79
79
|
# pg_typecast_on_load plugin if the column values are returned as a string.
|
|
80
80
|
#
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# The round_timestamps extension will automatically round timestamp
|
|
2
|
+
# values to the database's supported level of precision before literalizing
|
|
3
|
+
# them.
|
|
4
|
+
#
|
|
5
|
+
# For example, if the database supports microsecond precision, and you give
|
|
6
|
+
# it a Time value with greater than microsecond precision, it will round it
|
|
7
|
+
# appropriately:
|
|
8
|
+
#
|
|
9
|
+
# Time.at(1405341161.917999982833862)
|
|
10
|
+
# # default: 2014-07-14 14:32:41.917999
|
|
11
|
+
# # with extension: 2014-07-14 14:32:41.918000
|
|
12
|
+
#
|
|
13
|
+
# The round_timestamps extension correctly deals with databases that support
|
|
14
|
+
# millisecond or second precision. In addition to handling Time values, it
|
|
15
|
+
# also handles DateTime values and Sequel::SQLTime values (for the TIME type).
|
|
16
|
+
#
|
|
17
|
+
# To round timestamps for a single dataset:
|
|
18
|
+
#
|
|
19
|
+
# ds = ds.extension(:round_timestamps)
|
|
20
|
+
#
|
|
21
|
+
# To round timestamps for all datasets on a single database:
|
|
22
|
+
#
|
|
23
|
+
# DB.extension(:round_timestamps)
|
|
24
|
+
|
|
25
|
+
unless RUBY_VERSION >= '1.9'
|
|
26
|
+
# :nocov:
|
|
27
|
+
raise LoadError, 'the round_timestamps extension only works on ruby 1.9+'
|
|
28
|
+
# :nocov:
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
module Sequel
|
|
32
|
+
class Dataset
|
|
33
|
+
module RoundTimestamps
|
|
34
|
+
# Round DateTime values before literalizing
|
|
35
|
+
def literal_datetime(v)
|
|
36
|
+
super(v + Rational(5, 10**timestamp_precision)/864000)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Round Sequel::SQLTime values before literalizing
|
|
40
|
+
def literal_sqltime(v)
|
|
41
|
+
super(v.round(timestamp_precision))
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Round Time values before literalizing
|
|
45
|
+
def literal_time(v)
|
|
46
|
+
super(v.round(timestamp_precision))
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
register_extension(:round_timestamps, RoundTimestamps)
|
|
51
|
+
end
|
|
52
|
+
end
|
data/lib/sequel/model.rb
CHANGED
|
@@ -35,7 +35,7 @@ module Sequel
|
|
|
35
35
|
# dataset # => DB1[:comments]
|
|
36
36
|
# end
|
|
37
37
|
def self.Model(source)
|
|
38
|
-
if cache_anonymous_models && (klass =
|
|
38
|
+
if cache_anonymous_models && (klass = Model::ANONYMOUS_MODEL_CLASSES_MUTEX.synchronize{Model::ANONYMOUS_MODEL_CLASSES[source]})
|
|
39
39
|
return klass
|
|
40
40
|
end
|
|
41
41
|
klass = if source.is_a?(Database)
|
|
@@ -45,7 +45,7 @@ module Sequel
|
|
|
45
45
|
else
|
|
46
46
|
Class.new(Model).set_dataset(source)
|
|
47
47
|
end
|
|
48
|
-
|
|
48
|
+
Model::ANONYMOUS_MODEL_CLASSES_MUTEX.synchronize{Model::ANONYMOUS_MODEL_CLASSES[source] = klass} if cache_anonymous_models
|
|
49
49
|
klass
|
|
50
50
|
end
|
|
51
51
|
|
|
@@ -78,6 +78,9 @@ module Sequel
|
|
|
78
78
|
# of classes when dealing with code reloading.
|
|
79
79
|
ANONYMOUS_MODEL_CLASSES = {}
|
|
80
80
|
|
|
81
|
+
# Mutex protecting access to ANONYMOUS_MODEL_CLASSES
|
|
82
|
+
ANONYMOUS_MODEL_CLASSES_MUTEX = Mutex.new
|
|
83
|
+
|
|
81
84
|
# Class methods added to model that call the method of the same name on the dataset
|
|
82
85
|
DATASET_METHODS = (Dataset::ACTION_METHODS + Dataset::QUERY_METHODS +
|
|
83
86
|
[:each_server]) - [:and, :or, :[], :columns, :columns!, :delete, :update, :add_graph_aliases, :first, :first!]
|
|
@@ -1206,7 +1206,7 @@ module Sequel
|
|
|
1206
1206
|
|
|
1207
1207
|
# The columns to select when loading the association, associated_class.table_name.* by default.
|
|
1208
1208
|
def select
|
|
1209
|
-
cached_fetch(:select){
|
|
1209
|
+
cached_fetch(:select){default_select}
|
|
1210
1210
|
end
|
|
1211
1211
|
|
|
1212
1212
|
private
|
|
@@ -1215,6 +1215,17 @@ module Sequel
|
|
|
1215
1215
|
super.inner_join(self[:join_table], self[:right_keys].zip(right_primary_keys), :qualify=>:deep)
|
|
1216
1216
|
end
|
|
1217
1217
|
|
|
1218
|
+
# The default selection for associations that require joins. These do not use the default
|
|
1219
|
+
# model selection unless all entries in the select are explicitly qualified identifiers, as
|
|
1220
|
+
# other it can include unqualified columns which would be made ambiguous by joining.
|
|
1221
|
+
def default_select
|
|
1222
|
+
if (sel = associated_class.dataset.opts[:select]) && sel.all?{|c| selection_is_qualified?(c)}
|
|
1223
|
+
sel
|
|
1224
|
+
else
|
|
1225
|
+
Sequel::SQL::ColumnAll.new(associated_class.table_name)
|
|
1226
|
+
end
|
|
1227
|
+
end
|
|
1228
|
+
|
|
1218
1229
|
def filter_by_associations_conditions_associated_keys
|
|
1219
1230
|
qualify(join_table_alias, self[:left_keys])
|
|
1220
1231
|
end
|
|
@@ -1252,6 +1263,21 @@ module Sequel
|
|
|
1252
1263
|
:many_to_many
|
|
1253
1264
|
end
|
|
1254
1265
|
|
|
1266
|
+
# Whether the given expression represents a qualified identifier. Used to determine if it is
|
|
1267
|
+
# OK to use directly when joining.
|
|
1268
|
+
def selection_is_qualified?(c)
|
|
1269
|
+
case c
|
|
1270
|
+
when Symbol
|
|
1271
|
+
Sequel.split_symbol(c)[0]
|
|
1272
|
+
when Sequel::SQL::QualifiedIdentifier
|
|
1273
|
+
true
|
|
1274
|
+
when Sequel::SQL::AliasedExpression
|
|
1275
|
+
selection_is_qualified?(c.expression)
|
|
1276
|
+
else
|
|
1277
|
+
false
|
|
1278
|
+
end
|
|
1279
|
+
end
|
|
1280
|
+
|
|
1255
1281
|
# Split the join table into source and alias parts.
|
|
1256
1282
|
def split_join_table_alias
|
|
1257
1283
|
associated_class.dataset.split_alias(self[:join_table])
|
|
@@ -1478,8 +1504,8 @@ module Sequel
|
|
|
1478
1504
|
# the current association's key(s). Set to nil to not use a reciprocal.
|
|
1479
1505
|
# :remover :: Proc used to define the private _remove_* method for doing the database work
|
|
1480
1506
|
# to remove the association between the given object and the current object (*_to_many assocations).
|
|
1481
|
-
# :select :: the columns to select. Defaults to the associated class's
|
|
1482
|
-
#
|
|
1507
|
+
# :select :: the columns to select. Defaults to the associated class's table_name.* in an association
|
|
1508
|
+
# that uses joins, which means it doesn't include the attributes from the
|
|
1483
1509
|
# join table. If you want to include the join table attributes, you can
|
|
1484
1510
|
# use this option, but beware that the join table attributes can clash with
|
|
1485
1511
|
# attributes from the model table, so you should alias any attributes that have
|