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