rom-sql 3.6.5 → 3.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +1 -2
- data/lib/rom/plugins/relation/sql/auto_restrictions.rb +4 -1
- data/lib/rom/plugins/relation/sql/instrumentation.rb +6 -2
- data/lib/rom/plugins/relation/sql/postgres/explain.rb +1 -1
- data/lib/rom/plugins/relation/sql/postgres/full_text_search.rb +31 -12
- data/lib/rom/plugins/relation/sql/postgres/streaming.rb +6 -6
- data/lib/rom/sql/associations/many_to_many.rb +6 -3
- data/lib/rom/sql/associations/many_to_one.rb +3 -0
- data/lib/rom/sql/attribute.rb +22 -8
- data/lib/rom/sql/attribute_aliasing.rb +7 -6
- data/lib/rom/sql/commands/create.rb +4 -3
- data/lib/rom/sql/commands/update.rb +4 -3
- data/lib/rom/sql/dsl.rb +3 -1
- data/lib/rom/sql/extensions/active_support_notifications.rb +1 -1
- data/lib/rom/sql/extensions/postgres/type_builder.rb +7 -7
- data/lib/rom/sql/extensions/postgres/type_serializer.rb +2 -2
- data/lib/rom/sql/extensions/postgres/types/geometric.rb +12 -12
- data/lib/rom/sql/extensions/postgres/types/json.rb +9 -3
- data/lib/rom/sql/extensions/postgres/types/ltree.rb +106 -36
- data/lib/rom/sql/extensions/postgres/types/range.rb +18 -18
- data/lib/rom/sql/extensions/rails_log_subscriber.rb +4 -4
- data/lib/rom/sql/function.rb +37 -18
- data/lib/rom/sql/gateway.rb +8 -7
- data/lib/rom/sql/group_dsl.rb +7 -2
- data/lib/rom/sql/migration/inline_runner.rb +8 -2
- data/lib/rom/sql/migration/migrator.rb +5 -5
- data/lib/rom/sql/migration/recorder.rb +10 -4
- data/lib/rom/sql/migration/runner.rb +5 -4
- data/lib/rom/sql/migration/schema_diff.rb +15 -10
- data/lib/rom/sql/migration/writer.rb +8 -8
- data/lib/rom/sql/migration.rb +5 -5
- data/lib/rom/sql/order_dsl.rb +6 -2
- data/lib/rom/sql/plugin/associates.rb +21 -7
- data/lib/rom/sql/plugin/pagination.rb +2 -2
- data/lib/rom/sql/projection_dsl.rb +1 -1
- data/lib/rom/sql/relation/reading.rb +83 -71
- data/lib/rom/sql/relation/writing.rb +19 -13
- data/lib/rom/sql/relation.rb +74 -28
- data/lib/rom/sql/restriction_dsl.rb +6 -2
- data/lib/rom/sql/schema/attributes_inferrer.rb +2 -2
- data/lib/rom/sql/schema/dsl.rb +2 -2
- data/lib/rom/sql/schema/index_dsl.rb +5 -6
- data/lib/rom/sql/schema/inferrer.rb +23 -19
- data/lib/rom/sql/schema/type_builder.rb +5 -2
- data/lib/rom/sql/schema.rb +10 -10
- data/lib/rom/sql/tasks/migration_tasks.rake +4 -5
- data/lib/rom/sql/transaction.rb +1 -0
- data/lib/rom/sql/type_dsl.rb +7 -3
- data/lib/rom/sql/type_extensions.rb +4 -4
- data/lib/rom/sql/type_serializer.rb +2 -2
- data/lib/rom/sql/types.rb +2 -2
- data/lib/rom/sql/version.rb +1 -1
- data/lib/rom/types/values.rb +2 -4
- metadata +9 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1a9c8d40ae3b5ea461ba889492c74ad82533ac881777d6aa2d8b120cb9c0196d
|
4
|
+
data.tar.gz: 3965d8abb7bf6a215b9c76ffe1acc4e697d9e9c4c07cd0ed1f33840cb089111f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 10ccbbcb73895cb55a998ff673666878f7ae4d103aca84ba286fa0f0b4b0a0ce068524a6d110cf9ffd0139f5b9eef8a6c7b7f40e407d4f9b6a72eba314d6af28
|
7
|
+
data.tar.gz: 2c4aa7721bb02e20edd71d574ab878c405a6325a53602e77a71d30c72eb0c249033aa20944aca2460047c0a0be0def9534dd0ef611d627e4f6710743cb829df5
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
<!--- DO NOT EDIT THIS FILE - IT'S AUTOMATICALLY GENERATED VIA DEVTOOLS --->
|
2
2
|
|
3
|
+
## 3.7.0 2025-01-08
|
4
|
+
|
5
|
+
### Changed
|
6
|
+
|
7
|
+
- Minimum Ruby version is now 3.1 (@flash-gordon)
|
8
|
+
|
9
|
+
[Compare v3.6.5...v3.7.0](https://github.com/rom-rb/rom-sql/compare/v3.6.5...v3.7.0)
|
10
|
+
|
3
11
|
## 3.6.5 2024-12-25
|
4
12
|
|
5
13
|
|
data/README.md
CHANGED
@@ -39,6 +39,8 @@ module ROM
|
|
39
39
|
end
|
40
40
|
|
41
41
|
# @api private
|
42
|
+
#
|
43
|
+
# rubocop:disable Metrics/AbcSize
|
42
44
|
def self.restriction_methods(schema)
|
43
45
|
mod = Module.new
|
44
46
|
|
@@ -46,7 +48,7 @@ module ROM
|
|
46
48
|
next if index.partial?
|
47
49
|
|
48
50
|
attributes = index.to_a
|
49
|
-
meth_name = :"by_#{
|
51
|
+
meth_name = :"by_#{attributes.map(&:name).join("_and_")}"
|
50
52
|
|
51
53
|
next if generated.include?(meth_name)
|
52
54
|
|
@@ -72,6 +74,7 @@ module ROM
|
|
72
74
|
[methods, mod]
|
73
75
|
end
|
74
76
|
end
|
77
|
+
# rubocop:enable Metrics/AbcSize
|
75
78
|
end
|
76
79
|
end
|
77
80
|
end
|
@@ -31,8 +31,12 @@ module ROM
|
|
31
31
|
subscribe('configuration.relations.registry.created') do |event|
|
32
32
|
registry = event[:registry]
|
33
33
|
|
34
|
-
relations = registry.select { |_, r|
|
35
|
-
|
34
|
+
relations = registry.select { |_, r|
|
35
|
+
r.adapter == :sql && r.respond_to?(:notifications)
|
36
|
+
}.to_h
|
37
|
+
db_notifications = relations.values.map { |r|
|
38
|
+
[r.dataset.db, r.notifications]
|
39
|
+
}.uniq.to_h
|
36
40
|
|
37
41
|
db_notifications.each do |db, notifications|
|
38
42
|
next if db.respond_to?(:rom_instrumentation?)
|
@@ -26,7 +26,7 @@ module ROM
|
|
26
26
|
#
|
27
27
|
# @api public
|
28
28
|
def explain(format: :text, **options)
|
29
|
-
bool_options = options.map {
|
29
|
+
bool_options = options.map { "#{_1.to_s.upcase} #{!!_2}" } # rubocop:disable Style/DoubleNegation
|
30
30
|
format_option = "FORMAT #{format.to_s.upcase}"
|
31
31
|
explain_value = [format_option, *bool_options].join(', ')
|
32
32
|
|
@@ -13,31 +13,48 @@ module ROM
|
|
13
13
|
# By default, searching for the inclusion of any of the terms in any of the cols.
|
14
14
|
#
|
15
15
|
# @example
|
16
|
-
# posts.full_text_search([:title, :content], 'apples', language: 'english')
|
16
|
+
# posts.full_text_search([:title, :content], 'apples', language: 'english')
|
17
|
+
# # => Relation which match the 'apples' phrase
|
17
18
|
#
|
18
|
-
# @option :headline [String]
|
19
|
+
# @option :headline [String]
|
20
|
+
# Append a expression to the selected columns aliased
|
21
|
+
# to headline that contains an extract of the matched text.
|
19
22
|
#
|
20
|
-
# @option :language [String]
|
23
|
+
# @option :language [String]
|
24
|
+
# The language to use for the search (default: 'simple')
|
21
25
|
#
|
22
|
-
# @option :plain [Boolean]
|
26
|
+
# @option :plain [Boolean]
|
27
|
+
# Whether a plain search should be used (default: false).
|
28
|
+
# In this case, terms should be a single string, and it will do a search
|
29
|
+
# where cols contains all of the words in terms.
|
30
|
+
# This ignores search operators in terms.
|
23
31
|
#
|
24
|
-
# @option :phrase [Boolean]
|
32
|
+
# @option :phrase [Boolean]
|
33
|
+
# Similar to :plain, but also adding an ILIKE filter to ensure
|
34
|
+
# that returned rows also include the exact phrase used.
|
25
35
|
#
|
26
|
-
# @option :rank [Boolean]
|
36
|
+
# @option :rank [Boolean]
|
37
|
+
# Set to true to order by the rank, so that closer matches are returned first.
|
27
38
|
#
|
28
|
-
# @option :to_tsquery [Symbol]
|
39
|
+
# @option :to_tsquery [Symbol]
|
40
|
+
# Can be set to :plain or :phrase to specify the function to use
|
41
|
+
# to convert the terms to a ts_query.
|
29
42
|
#
|
30
|
-
# @option :tsquery [Boolean]
|
43
|
+
# @option :tsquery [Boolean]
|
44
|
+
# Specifies the terms argument is already a valid SQL expression returning a tsquery,
|
45
|
+
# and can be used directly in the query.
|
31
46
|
#
|
32
|
-
# @option :tsvector [Boolean]
|
47
|
+
# @option :tsvector [Boolean]
|
48
|
+
# Specifies the cols argument is already a valid SQL expression returning a tsvector,
|
49
|
+
# and can be used directly in the query.
|
33
50
|
#
|
34
51
|
# @return [Relation]
|
35
52
|
#
|
36
53
|
# @see https://www.postgresql.org/docs/current/textsearch.html PostgreSQL docs
|
37
54
|
#
|
38
55
|
# @api public
|
39
|
-
def full_text_search(
|
40
|
-
new dataset.__send__(__method__,
|
56
|
+
def full_text_search(...)
|
57
|
+
new dataset.__send__(__method__, ...)
|
41
58
|
end
|
42
59
|
end
|
43
60
|
end
|
@@ -48,6 +65,8 @@ end
|
|
48
65
|
|
49
66
|
ROM.plugins do
|
50
67
|
adapter :sql do
|
51
|
-
register :pg_full_text_search,
|
68
|
+
register :pg_full_text_search,
|
69
|
+
ROM::Plugins::Relation::SQL::Postgres::FullTextSearch,
|
70
|
+
type: :relation
|
52
71
|
end
|
53
72
|
end
|
@@ -13,7 +13,7 @@ module ROM
|
|
13
13
|
|
14
14
|
class StreamingNotSupportedError < StandardError; end
|
15
15
|
|
16
|
-
subscribe(
|
16
|
+
subscribe('configuration.gateway.connected') do |opts|
|
17
17
|
conn = opts[:connection]
|
18
18
|
|
19
19
|
next unless conn.database_type.to_sym == :postgres
|
@@ -21,13 +21,13 @@ module ROM
|
|
21
21
|
next if defined?(JRUBY_VERSION)
|
22
22
|
|
23
23
|
begin
|
24
|
-
require
|
24
|
+
require 'sequel_pg'
|
25
25
|
rescue LoadError
|
26
|
-
raise StreamingNotSupportedError,
|
26
|
+
raise StreamingNotSupportedError, 'add sequel_pg to Gemfile to use pg_streaming'
|
27
27
|
end
|
28
28
|
|
29
29
|
unless Sequel::Postgres.supports_streaming?
|
30
|
-
raise StreamingNotSupportedError,
|
30
|
+
raise StreamingNotSupportedError, 'postgres version does not support streaming'
|
31
31
|
end
|
32
32
|
|
33
33
|
conn.extension(:pg_streaming)
|
@@ -52,7 +52,7 @@ module ROM
|
|
52
52
|
#
|
53
53
|
# @api publicY_VERSION
|
54
54
|
def stream_each
|
55
|
-
raise StreamingNotSupportedError,
|
55
|
+
raise StreamingNotSupportedError, 'not supported on jruby'
|
56
56
|
end
|
57
57
|
else
|
58
58
|
# Allows you to stream returned rows one at a time, instead of
|
@@ -80,7 +80,7 @@ module ROM
|
|
80
80
|
|
81
81
|
module Combined
|
82
82
|
def stream_each
|
83
|
-
raise StreamingNotSupportedError,
|
83
|
+
raise StreamingNotSupportedError, 'not supported on combined relations'
|
84
84
|
end
|
85
85
|
end
|
86
86
|
|
@@ -12,15 +12,17 @@ module ROM
|
|
12
12
|
include Associations::SelfRef
|
13
13
|
|
14
14
|
# @api public
|
15
|
+
#
|
16
|
+
# rubocop:disable Metrics/AbcSize
|
15
17
|
def call(target: self.target)
|
16
18
|
left = join_assoc.(target: target)
|
17
19
|
|
18
20
|
schema =
|
19
21
|
if left.schema.key?(foreign_key)
|
20
|
-
if target
|
21
|
-
target.schema.merge(join_schema)
|
22
|
-
else
|
22
|
+
if target == self.target
|
23
23
|
left.schema.uniq.project(*columns)
|
24
|
+
else
|
25
|
+
target.schema.merge(join_schema)
|
24
26
|
end
|
25
27
|
else
|
26
28
|
target_schema
|
@@ -34,6 +36,7 @@ module ROM
|
|
34
36
|
schema.(relation)
|
35
37
|
end
|
36
38
|
end
|
39
|
+
# rubocop:enable Metrics/AbcSize
|
37
40
|
|
38
41
|
# @api public
|
39
42
|
def join(type, source = self.source, target = self.target)
|
@@ -12,6 +12,8 @@ module ROM
|
|
12
12
|
include Associations::SelfRef
|
13
13
|
|
14
14
|
# @api public
|
15
|
+
#
|
16
|
+
# rubocop:disable Metrics/AbcSize
|
15
17
|
def call(target: self.target, preload: false)
|
16
18
|
if preload
|
17
19
|
schema = target.schema.qualified
|
@@ -41,6 +43,7 @@ module ROM
|
|
41
43
|
schema.(relation)
|
42
44
|
end
|
43
45
|
end
|
46
|
+
# rubocop:enable Metrics/AbcSize
|
44
47
|
|
45
48
|
# @api public
|
46
49
|
def join(type, source = self.source, target = self.target)
|
data/lib/rom/sql/attribute.rb
CHANGED
@@ -15,6 +15,8 @@ module ROM
|
|
15
15
|
# Extended schema attributes tailored for SQL databases
|
16
16
|
#
|
17
17
|
# @api public
|
18
|
+
#
|
19
|
+
# rubocop:disable Metrics/ClassLength
|
18
20
|
class Attribute < ROM::Attribute
|
19
21
|
include AttributeWrapping
|
20
22
|
include AttributeAliasing
|
@@ -59,7 +61,9 @@ module ROM
|
|
59
61
|
return meta(qualified: false) unless qualifiable?
|
60
62
|
|
61
63
|
case sql_expr
|
62
|
-
when Sequel::SQL::AliasedExpression,
|
64
|
+
when ::Sequel::SQL::AliasedExpression,
|
65
|
+
::Sequel::SQL::Identifier,
|
66
|
+
::Sequel::SQL::QualifiedIdentifier
|
63
67
|
attr = meta(qualified: table_alias || true)
|
64
68
|
attr.meta(sql_expr: attr.to_sql_name)
|
65
69
|
else
|
@@ -263,8 +267,8 @@ module ROM
|
|
263
267
|
# @return [SQL::Function]
|
264
268
|
#
|
265
269
|
# @api public
|
266
|
-
def func(&
|
267
|
-
ProjectionDSL.new(name => self).call(&
|
270
|
+
def func(&)
|
271
|
+
ProjectionDSL.new(name => self).call(&).first
|
268
272
|
end
|
269
273
|
|
270
274
|
# Create a CONCAT function from the attribute
|
@@ -334,7 +338,7 @@ module ROM
|
|
334
338
|
#
|
335
339
|
# @api private
|
336
340
|
def unwrap
|
337
|
-
cleaned_meta = meta.
|
341
|
+
cleaned_meta = meta.except(*META_KEYS)
|
338
342
|
type = optional? ? right : self.type
|
339
343
|
|
340
344
|
self.class.new(type.with(meta: cleaned_meta), **options)
|
@@ -380,19 +384,28 @@ module ROM
|
|
380
384
|
#
|
381
385
|
# @api private
|
382
386
|
def sql_expr
|
383
|
-
@sql_expr ||=
|
387
|
+
@sql_expr ||= meta[:sql_expr] || to_sql_name
|
388
|
+
end
|
389
|
+
|
390
|
+
# @api private
|
391
|
+
def respond_to_missing?(meth, _include_private = false)
|
392
|
+
if OPERATORS.include?(meth) || extensions.key?(meth) || sql_expr.respond_to?(meth)
|
393
|
+
true
|
394
|
+
else
|
395
|
+
super
|
396
|
+
end
|
384
397
|
end
|
385
398
|
|
386
399
|
# Delegate to sql expression if it responds to a given method
|
387
400
|
#
|
388
401
|
# @api private
|
389
|
-
def method_missing(meth, *args, &
|
402
|
+
def method_missing(meth, *args, &)
|
390
403
|
if OPERATORS.include?(meth)
|
391
404
|
__cmp__(meth, args[0])
|
392
405
|
elsif extensions.key?(meth)
|
393
|
-
extensions[meth].(type, sql_expr, *args, &
|
406
|
+
extensions[meth].(type, sql_expr, *args, &)
|
394
407
|
elsif sql_expr.respond_to?(meth)
|
395
|
-
meta(sql_expr: sql_expr.__send__(meth, *args, &
|
408
|
+
meta(sql_expr: sql_expr.__send__(meth, *args, &))
|
396
409
|
else
|
397
410
|
super
|
398
411
|
end
|
@@ -436,5 +449,6 @@ module ROM
|
|
436
449
|
|
437
450
|
memoize :joined, :to_sql_name, :table_name, :canonical
|
438
451
|
end
|
452
|
+
# rubocop:enable Metrics/ClassLength
|
439
453
|
end
|
440
454
|
end
|
@@ -19,8 +19,7 @@ module ROM
|
|
19
19
|
sql_expr: alias_sql_expr(sql_expr, new_alias_name)
|
20
20
|
)
|
21
21
|
end
|
22
|
-
|
23
|
-
|
22
|
+
alias_method :as, :aliased
|
24
23
|
|
25
24
|
# Return true if this attribute is an aliased projection
|
26
25
|
#
|
@@ -46,7 +45,7 @@ module ROM
|
|
46
45
|
#
|
47
46
|
# @api private
|
48
47
|
def aliased_projection?
|
49
|
-
|
48
|
+
meta[:sql_expr].is_a?(::Sequel::SQL::AliasedExpression)
|
50
49
|
end
|
51
50
|
|
52
51
|
private
|
@@ -54,8 +53,10 @@ module ROM
|
|
54
53
|
# @api private
|
55
54
|
def alias_sql_expr(sql_expr, new_alias)
|
56
55
|
case sql_expr
|
57
|
-
when Sequel::SQL::AliasedExpression
|
58
|
-
Sequel::SQL::AliasedExpression.new(
|
56
|
+
when ::Sequel::SQL::AliasedExpression
|
57
|
+
::Sequel::SQL::AliasedExpression.new(
|
58
|
+
sql_expr.expression, new_alias, sql_expr.columns
|
59
|
+
)
|
59
60
|
else
|
60
61
|
sql_expr.as(new_alias)
|
61
62
|
end
|
@@ -70,7 +71,7 @@ module ROM
|
|
70
71
|
# attribute in a way that will map the the requested alias name.
|
71
72
|
# Without this, the attribute will silently ignore the requested alias
|
72
73
|
# name and default to the pre-existing name.
|
73
|
-
new_name = "#{meta[:wrapped]}_#{options[:alias]}"
|
74
|
+
new_name = :"#{meta[:wrapped]}_#{options[:alias]}"
|
74
75
|
|
75
76
|
# Essentially, this makes it so "wrapped" attributes aren't true
|
76
77
|
# aliases, in that we actually alias the wrapped attribute, we use
|
@@ -60,10 +60,11 @@ module ROM
|
|
60
60
|
# Yields tuples for insertion or return an enumerator
|
61
61
|
#
|
62
62
|
# @api private
|
63
|
-
def with_input_tuples(tuples)
|
64
|
-
input_tuples =
|
63
|
+
def with_input_tuples(tuples, &)
|
64
|
+
input_tuples = [tuples].flatten(1).map
|
65
65
|
return input_tuples unless block_given?
|
66
|
-
|
66
|
+
|
67
|
+
input_tuples.each(&)
|
67
68
|
end
|
68
69
|
end
|
69
70
|
end
|
@@ -52,10 +52,11 @@ module ROM
|
|
52
52
|
# Yields tuples for insertion or return an enumerator
|
53
53
|
#
|
54
54
|
# @api private
|
55
|
-
def with_input_tuples(tuples)
|
56
|
-
input_tuples =
|
55
|
+
def with_input_tuples(tuples, &)
|
56
|
+
input_tuples = [tuples].flatten(1).map
|
57
57
|
return input_tuples unless block_given?
|
58
|
-
|
58
|
+
|
59
|
+
input_tuples.each(&)
|
59
60
|
end
|
60
61
|
end
|
61
62
|
end
|
data/lib/rom/sql/dsl.rb
CHANGED
@@ -59,7 +59,9 @@ module ROM
|
|
59
59
|
#
|
60
60
|
# @example
|
61
61
|
# users.where { exists(users.where(name: 'John')) }
|
62
|
-
# users.select_append { |r|
|
62
|
+
# users.select_append { |r|
|
63
|
+
# exists(r[:posts].where(r[:posts][:user_id] => id)).as(:has_posts)
|
64
|
+
# }
|
63
65
|
#
|
64
66
|
# @api public
|
65
67
|
def exists(relation)
|
@@ -6,17 +6,17 @@ module ROM
|
|
6
6
|
class TypeBuilder < Schema::TypeBuilder
|
7
7
|
defines :db_numeric_types, :db_type_mapping, :db_array_type_matcher
|
8
8
|
|
9
|
-
db_numeric_types
|
10
|
-
smallint integer bigint
|
11
|
-
decimal numeric real
|
12
|
-
double
|
9
|
+
db_numeric_types [
|
10
|
+
'smallint', 'integer', 'bigint',
|
11
|
+
'decimal', 'numeric', 'real',
|
12
|
+
'double precision', 'serial', 'bigserial'
|
13
13
|
].to_set.freeze
|
14
14
|
|
15
15
|
db_type_mapping(
|
16
|
-
'uuid'
|
16
|
+
'uuid' => Types::UUID,
|
17
17
|
'money' => Types::Money,
|
18
18
|
'bytea' => Types::Bytea,
|
19
|
-
'json'
|
19
|
+
'json' => Types::JSON,
|
20
20
|
'jsonb' => Types::JSONB,
|
21
21
|
'xml' => Types::XML,
|
22
22
|
'inet' => Types::IPAddress,
|
@@ -39,7 +39,7 @@ module ROM
|
|
39
39
|
'ltree' => Types::LTree
|
40
40
|
).freeze
|
41
41
|
|
42
|
-
db_array_type_matcher '[]'
|
42
|
+
db_array_type_matcher '[]'
|
43
43
|
|
44
44
|
def map_pk_type(type, db_type, **options)
|
45
45
|
if numeric?(type, db_type)
|
@@ -36,8 +36,8 @@ module ROM
|
|
36
36
|
|
37
37
|
def call(type)
|
38
38
|
super do
|
39
|
-
if type.respond_to?(:primitive) && type.primitive.equal?(Array)
|
40
|
-
"#{
|
39
|
+
if type.respond_to?(:primitive) && type.primitive.equal?(::Array)
|
40
|
+
"#{type.meta[:type]}[]"
|
41
41
|
end
|
42
42
|
end
|
43
43
|
end
|
@@ -37,7 +37,7 @@ module ROM
|
|
37
37
|
Point = Type('point') do
|
38
38
|
SQL::Types.define(Values::Point) do
|
39
39
|
input do |point|
|
40
|
-
"(#{
|
40
|
+
"(#{point.x},#{point.y})"
|
41
41
|
end
|
42
42
|
|
43
43
|
output do |point|
|
@@ -50,7 +50,7 @@ module ROM
|
|
50
50
|
Line = Type('line') do
|
51
51
|
SQL::Types.define(Values::Line) do
|
52
52
|
input do |line|
|
53
|
-
"{#{
|
53
|
+
"{#{line.a},#{line.b},#{line.c}}"
|
54
54
|
end
|
55
55
|
|
56
56
|
output do |line|
|
@@ -63,7 +63,7 @@ module ROM
|
|
63
63
|
Circle = Type('circle') do
|
64
64
|
SQL::Types.define(Values::Circle) do
|
65
65
|
input do |circle|
|
66
|
-
"<(#{
|
66
|
+
"<(#{circle.center.x},#{circle.center.y}),#{circle.radius}>"
|
67
67
|
end
|
68
68
|
|
69
69
|
output do |circle|
|
@@ -77,8 +77,8 @@ module ROM
|
|
77
77
|
Box = Type('box') do
|
78
78
|
SQL::Types.define(Values::Box) do
|
79
79
|
input do |box|
|
80
|
-
"((#{
|
81
|
-
|
80
|
+
"((#{box.upper_right.x},#{box.upper_right.y})," \
|
81
|
+
"(#{box.lower_left.x},#{box.lower_left.y}))"
|
82
82
|
end
|
83
83
|
|
84
84
|
output do |box|
|
@@ -93,8 +93,8 @@ module ROM
|
|
93
93
|
LineSegment = Type('lseg') do
|
94
94
|
SQL::Types.define(Values::LineSegment) do
|
95
95
|
input do |segment|
|
96
|
-
"[(#{
|
97
|
-
|
96
|
+
"[(#{segment.begin.x},#{segment.begin.y})," \
|
97
|
+
"(#{segment.end.x},#{segment.end.y})]"
|
98
98
|
end
|
99
99
|
|
100
100
|
output do |segment|
|
@@ -109,8 +109,8 @@ module ROM
|
|
109
109
|
Polygon = Type('polygon') do
|
110
110
|
SQL::Types.define(::Array) do
|
111
111
|
input do |points|
|
112
|
-
points_joined = points.map { |p| "(#{
|
113
|
-
"(#{
|
112
|
+
points_joined = points.map { |p| "(#{p.x},#{p.y})" }.join(',')
|
113
|
+
"(#{points_joined})"
|
114
114
|
end
|
115
115
|
|
116
116
|
output do |polygon|
|
@@ -123,12 +123,12 @@ module ROM
|
|
123
123
|
Path = Type('path') do
|
124
124
|
SQL::Types.define(Values::Path) do
|
125
125
|
input do |path|
|
126
|
-
points_joined = path.to_a.map { |p| "(#{
|
126
|
+
points_joined = path.to_a.map { |p| "(#{p.x},#{p.y})" }.join(',')
|
127
127
|
|
128
128
|
if path.open?
|
129
|
-
"[#{
|
129
|
+
"[#{points_joined}]"
|
130
130
|
else
|
131
|
-
"(#{
|
131
|
+
"(#{points_joined})"
|
132
132
|
end
|
133
133
|
end
|
134
134
|
|
@@ -77,11 +77,15 @@ module ROM
|
|
77
77
|
end
|
78
78
|
else
|
79
79
|
JSON = Type('json') do
|
80
|
-
(SQL::Types::Array | SQL::Types::Hash).constructor(
|
80
|
+
(SQL::Types::Array | SQL::Types::Hash).constructor(
|
81
|
+
::Sequel.method(:pg_json)
|
82
|
+
).meta(read: JSONRead)
|
81
83
|
end
|
82
84
|
|
83
85
|
JSONB = Type('jsonb') do
|
84
|
-
(SQL::Types::Array | SQL::Types::Hash).constructor(
|
86
|
+
(SQL::Types::Array | SQL::Types::Hash).constructor(
|
87
|
+
::Sequel.method(:pg_jsonb)
|
88
|
+
).meta(read: JSONRead)
|
85
89
|
end
|
86
90
|
end
|
87
91
|
|
@@ -265,7 +269,9 @@ module ROM
|
|
265
269
|
end
|
266
270
|
|
267
271
|
def has_key(_type, expr, key)
|
268
|
-
Attribute[SQL::Types::Bool].meta(
|
272
|
+
Attribute[SQL::Types::Bool].meta(
|
273
|
+
sql_expr: wrap(expr).has_key?(key) # rubocop:disable Style/PreferredHashMethods
|
274
|
+
)
|
269
275
|
end
|
270
276
|
|
271
277
|
def has_any_key(_type, expr, *keys)
|