rom-sql 3.7.0 → 4.0.0.alpha1
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.md +11 -65
- data/LICENSE +1 -1
- data/README.md +3 -2
- data/lib/rom/plugins/relation/sql/auto_restrictions.rb +10 -12
- data/lib/rom/plugins/relation/sql/default_views.rb +75 -0
- data/lib/rom/plugins/relation/sql/instrumentation.rb +8 -17
- data/lib/rom/plugins/relation/sql/postgres/explain.rb +5 -5
- data/lib/rom/plugins/relation/sql/postgres/full_text_search.rb +20 -37
- data/lib/rom/plugins/relation/sql/postgres/streaming.rb +17 -14
- data/lib/rom/sql/associations/many_to_many.rb +4 -7
- data/lib/rom/sql/associations/many_to_one.rb +3 -6
- data/lib/rom/sql/associations/one_to_many.rb +3 -3
- data/lib/rom/sql/associations/one_to_one.rb +1 -1
- data/lib/rom/sql/associations/one_to_one_through.rb +1 -1
- data/lib/rom/sql/associations/self_ref.rb +1 -1
- data/lib/rom/sql/associations.rb +5 -5
- data/lib/rom/sql/attribute.rb +17 -31
- data/lib/rom/sql/attribute_aliasing.rb +4 -6
- data/lib/rom/sql/commands/create.rb +5 -5
- data/lib/rom/sql/commands/delete.rb +2 -2
- data/lib/rom/sql/commands/update.rb +5 -5
- data/lib/rom/sql/commands.rb +4 -4
- data/lib/rom/sql/dsl.rb +4 -6
- data/lib/rom/sql/errors.rb +3 -3
- data/lib/rom/sql/extensions/active_support_notifications.rb +3 -3
- data/lib/rom/sql/extensions/mysql/type_builder.rb +5 -5
- data/lib/rom/sql/extensions/mysql.rb +1 -1
- data/lib/rom/sql/extensions/postgres/commands.rb +13 -31
- data/lib/rom/sql/extensions/postgres/type_builder.rb +28 -31
- data/lib/rom/sql/extensions/postgres/type_serializer.rb +24 -25
- data/lib/rom/sql/extensions/postgres/types/array.rb +4 -4
- data/lib/rom/sql/extensions/postgres/types/array_types.rb +1 -1
- data/lib/rom/sql/extensions/postgres/types/geometric.rb +19 -19
- data/lib/rom/sql/extensions/postgres/types/json.rb +12 -18
- data/lib/rom/sql/extensions/postgres/types/ltree.rb +54 -97
- data/lib/rom/sql/extensions/postgres/types/network.rb +4 -17
- data/lib/rom/sql/extensions/postgres/types/range.rb +30 -30
- data/lib/rom/sql/extensions/postgres/types.rb +14 -14
- data/lib/rom/sql/extensions/postgres.rb +6 -6
- data/lib/rom/sql/extensions/rails_log_subscriber.rb +6 -21
- data/lib/rom/sql/extensions/sqlite/types.rb +1 -1
- data/lib/rom/sql/extensions/sqlite.rb +2 -2
- data/lib/rom/sql/extensions.rb +6 -6
- data/lib/rom/sql/foreign_key.rb +3 -1
- data/lib/rom/sql/function.rb +19 -42
- data/lib/rom/sql/gateway.rb +41 -15
- data/lib/rom/sql/group_dsl.rb +3 -8
- data/lib/rom/sql/index.rb +2 -0
- data/lib/rom/sql/join_dsl.rb +1 -1
- data/lib/rom/sql/mapper_compiler.rb +2 -2
- data/lib/rom/sql/migration/inline_runner.rb +2 -8
- data/lib/rom/sql/migration/migrator.rb +12 -12
- data/lib/rom/sql/migration/recorder.rb +4 -10
- data/lib/rom/sql/migration/runner.rb +4 -5
- data/lib/rom/sql/migration/schema_diff.rb +4 -10
- data/lib/rom/sql/migration/writer.rb +7 -7
- data/lib/rom/sql/migration.rb +9 -13
- data/lib/rom/sql/order_dsl.rb +3 -7
- data/lib/rom/sql/plugin/associates.rb +45 -21
- data/lib/rom/sql/plugin/pagination.rb +3 -1
- data/lib/rom/sql/plugin/schema_indexes.rb +35 -0
- data/lib/rom/sql/plugins.rb +9 -6
- data/lib/rom/sql/projection_dsl.rb +5 -5
- data/lib/rom/sql/rake_task.rb +2 -2
- data/lib/rom/sql/relation/reading.rb +78 -83
- data/lib/rom/sql/relation/writing.rb +4 -9
- data/lib/rom/sql/relation.rb +58 -136
- data/lib/rom/sql/restriction_dsl.rb +4 -8
- data/lib/rom/sql/schema/attributes_inferrer.rb +2 -2
- data/lib/rom/sql/schema/dsl.rb +6 -4
- data/lib/rom/sql/schema/index_dsl.rb +6 -7
- data/lib/rom/sql/schema/inferrer.rb +22 -24
- data/lib/rom/sql/schema/type_builder.rb +4 -20
- data/lib/rom/sql/schema.rb +17 -29
- data/lib/rom/sql/spec/support.rb +5 -5
- data/lib/rom/sql/tasks/migration_tasks.rake +14 -21
- data/lib/rom/sql/transaction.rb +4 -3
- data/lib/rom/sql/type_dsl.rb +3 -7
- data/lib/rom/sql/type_extensions.rb +6 -4
- data/lib/rom/sql/type_serializer.rb +9 -9
- data/lib/rom/sql/types.rb +6 -6
- data/lib/rom/sql/version.rb +1 -1
- data/lib/rom/sql/wrap.rb +1 -1
- data/lib/rom/sql.rb +13 -12
- data/lib/rom/types/values.rb +5 -3
- data/lib/rom-sql.rb +1 -1
- metadata +17 -12
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require "rom/support/inflector"
|
4
|
+
require "rom/sql/join_dsl"
|
5
5
|
|
6
6
|
module ROM
|
7
7
|
module SQL
|
@@ -9,22 +9,20 @@ module ROM
|
|
9
9
|
# Query API for SQL::Relation
|
10
10
|
#
|
11
11
|
# @api public
|
12
|
-
#
|
13
|
-
# rubocop:disable Metrics/ModuleLength
|
14
12
|
module Reading
|
15
13
|
# Row-level lock modes
|
16
|
-
ROW_LOCK_MODES = Hash.new(
|
14
|
+
ROW_LOCK_MODES = Hash.new(update: "FOR UPDATE").update(
|
17
15
|
# https://www.postgresql.org/docs/current/static/sql-select.html#SQL-FOR-UPDATE-SHARE
|
18
16
|
postgres: {
|
19
|
-
update:
|
20
|
-
no_key_update:
|
21
|
-
share:
|
22
|
-
key_share:
|
17
|
+
update: "FOR UPDATE",
|
18
|
+
no_key_update: "FOR NO KEY UPDATE",
|
19
|
+
share: "FOR SHARE",
|
20
|
+
key_share: "FOR KEY SHARE"
|
23
21
|
},
|
24
22
|
# https://dev.mysql.com/doc/refman/5.7/en/innodb-locking-reads.html
|
25
23
|
mysql: {
|
26
|
-
update:
|
27
|
-
share:
|
24
|
+
update: "FOR UPDATE",
|
25
|
+
share: "LOCK IN SHARE MODE"
|
28
26
|
}
|
29
27
|
).freeze
|
30
28
|
|
@@ -142,11 +140,11 @@ module ROM
|
|
142
140
|
# from tuples
|
143
141
|
#
|
144
142
|
# @api public
|
145
|
-
def map(key = nil, &)
|
143
|
+
def map(key = nil, &block)
|
146
144
|
if key
|
147
|
-
dataset.map(key, &)
|
145
|
+
dataset.map(key, &block)
|
148
146
|
else
|
149
|
-
dataset.map(&)
|
147
|
+
dataset.map(&block)
|
150
148
|
end
|
151
149
|
end
|
152
150
|
|
@@ -273,8 +271,8 @@ module ROM
|
|
273
271
|
# @return [Relation]
|
274
272
|
#
|
275
273
|
# @api public
|
276
|
-
def distinct(
|
277
|
-
new(dataset.__send__(__method__,
|
274
|
+
def distinct(*args, &block)
|
275
|
+
new(dataset.__send__(__method__, *args, &block))
|
278
276
|
end
|
279
277
|
|
280
278
|
# Returns a result of SQL SUM clause.
|
@@ -361,9 +359,9 @@ module ROM
|
|
361
359
|
# @return [Relation]
|
362
360
|
#
|
363
361
|
# @api public
|
364
|
-
def where(*args, &)
|
365
|
-
if
|
366
|
-
where(*args).where(schema.canonical.restriction(&))
|
362
|
+
def where(*args, &block)
|
363
|
+
if block
|
364
|
+
where(*args).where(schema.canonical.restriction(&block))
|
367
365
|
elsif args.size == 1 && args[0].is_a?(Hash)
|
368
366
|
new(dataset.where(coerce_conditions(args[0])))
|
369
367
|
elsif !args.empty?
|
@@ -383,8 +381,8 @@ module ROM
|
|
383
381
|
# @return [Relation]
|
384
382
|
#
|
385
383
|
# @api public
|
386
|
-
def exclude(
|
387
|
-
new(dataset.__send__(__method__,
|
384
|
+
def exclude(*args, &block)
|
385
|
+
new(dataset.__send__(__method__, *args, &block))
|
388
386
|
end
|
389
387
|
|
390
388
|
# Restrict a relation to match grouping criteria
|
@@ -420,9 +418,9 @@ module ROM
|
|
420
418
|
# @return [Relation]
|
421
419
|
#
|
422
420
|
# @api public
|
423
|
-
def having(*args, &)
|
424
|
-
if
|
425
|
-
new(dataset.having(*args, *schema.canonical.restriction(&)))
|
421
|
+
def having(*args, &block)
|
422
|
+
if block
|
423
|
+
new(dataset.having(*args, *schema.canonical.restriction(&block)))
|
426
424
|
else
|
427
425
|
new(dataset.__send__(__method__, *args))
|
428
426
|
end
|
@@ -475,11 +473,11 @@ module ROM
|
|
475
473
|
# @return [Relation]
|
476
474
|
#
|
477
475
|
# @api public
|
478
|
-
def order(*args, &)
|
479
|
-
if
|
480
|
-
new(dataset.order(*args, *schema.canonical.order(&)))
|
476
|
+
def order(*args, &block)
|
477
|
+
if block
|
478
|
+
new(dataset.order(*args, *schema.canonical.order(&block)))
|
481
479
|
else
|
482
|
-
new(dataset.__send__(__method__, *args, &))
|
480
|
+
new(dataset.__send__(__method__, *args, &block))
|
483
481
|
end
|
484
482
|
end
|
485
483
|
|
@@ -503,8 +501,8 @@ module ROM
|
|
503
501
|
# @return [Relation]
|
504
502
|
#
|
505
503
|
# @api public
|
506
|
-
def reverse(
|
507
|
-
new(dataset.__send__(__method__,
|
504
|
+
def reverse(*args, &block)
|
505
|
+
new(dataset.__send__(__method__, *args, &block))
|
508
506
|
end
|
509
507
|
|
510
508
|
# Limit a relation to a specific number of tuples
|
@@ -592,8 +590,8 @@ module ROM
|
|
592
590
|
# @return [Relation]
|
593
591
|
#
|
594
592
|
# @api public
|
595
|
-
def join(
|
596
|
-
__join__(__method__,
|
593
|
+
def join(*args, &block)
|
594
|
+
__join__(__method__, *args, &block)
|
597
595
|
end
|
598
596
|
alias_method :inner_join, :join
|
599
597
|
|
@@ -642,8 +640,8 @@ module ROM
|
|
642
640
|
# @return [Relation]
|
643
641
|
#
|
644
642
|
# @api public
|
645
|
-
def left_join(
|
646
|
-
__join__(__method__,
|
643
|
+
def left_join(*args, &block)
|
644
|
+
__join__(__method__, *args, &block)
|
647
645
|
end
|
648
646
|
|
649
647
|
# Join with another relation using RIGHT JOIN
|
@@ -691,8 +689,8 @@ module ROM
|
|
691
689
|
# @return [Relation]
|
692
690
|
#
|
693
691
|
# @api public
|
694
|
-
def right_join(
|
695
|
-
__join__(__method__,
|
692
|
+
def right_join(*args, &block)
|
693
|
+
__join__(__method__, *args, &block)
|
696
694
|
end
|
697
695
|
|
698
696
|
# Group by specific columns
|
@@ -724,12 +722,12 @@ module ROM
|
|
724
722
|
# @return [Relation]
|
725
723
|
#
|
726
724
|
# @api public
|
727
|
-
def group(*args, &)
|
728
|
-
if
|
725
|
+
def group(*args, &block)
|
726
|
+
if block
|
729
727
|
if args.size.positive?
|
730
|
-
group(*args).group_append(&)
|
728
|
+
group(*args).group_append(&block)
|
731
729
|
else
|
732
|
-
new(dataset.__send__(__method__, *schema.canonical.group(&)))
|
730
|
+
new(dataset.__send__(__method__, *schema.canonical.group(&block)))
|
733
731
|
end
|
734
732
|
else
|
735
733
|
new(dataset.__send__(__method__, *schema.canonical.project(*args)))
|
@@ -763,12 +761,12 @@ module ROM
|
|
763
761
|
# @return [Relation]
|
764
762
|
#
|
765
763
|
# @api public
|
766
|
-
def group_append(*args, &)
|
767
|
-
if
|
764
|
+
def group_append(*args, &block)
|
765
|
+
if block
|
768
766
|
if args.size.positive?
|
769
|
-
group_append(*args).group_append(&)
|
767
|
+
group_append(*args).group_append(&block)
|
770
768
|
else
|
771
|
-
new(dataset.group_append(*schema.canonical.group(&)))
|
769
|
+
new(dataset.group_append(*schema.canonical.group(&block)))
|
772
770
|
end
|
773
771
|
else
|
774
772
|
new(dataset.group_append(*args))
|
@@ -786,8 +784,8 @@ module ROM
|
|
786
784
|
# @return [Relation]
|
787
785
|
#
|
788
786
|
# @api public
|
789
|
-
def group_and_count(
|
790
|
-
new(dataset.__send__(__method__,
|
787
|
+
def group_and_count(*args, &block)
|
788
|
+
new(dataset.__send__(__method__, *args, &block))
|
791
789
|
end
|
792
790
|
|
793
791
|
# Select and group by specific columns
|
@@ -801,8 +799,8 @@ module ROM
|
|
801
799
|
# @return [Relation]
|
802
800
|
#
|
803
801
|
# @api public
|
804
|
-
def select_group(
|
805
|
-
new_schema = schema.project(
|
802
|
+
def select_group(*args, &block)
|
803
|
+
new_schema = schema.project(*args, &block)
|
806
804
|
new_schema.(self).group(*new_schema)
|
807
805
|
end
|
808
806
|
|
@@ -815,27 +813,26 @@ module ROM
|
|
815
813
|
# @param [Relation] relation Another relation
|
816
814
|
#
|
817
815
|
# @param [Hash] options Options for union
|
818
|
-
# @option options [Symbol] :alias
|
819
|
-
#
|
820
|
-
#
|
821
|
-
#
|
822
|
-
#
|
823
|
-
# Set to false to not wrap the returned dataset in a #from_self, use with care.
|
816
|
+
# @option options [Symbol] :alias Use the given value as the #from_self alias
|
817
|
+
# @option options [TrueClass, FalseClass] :all Set to true to use UNION ALL instead of UNION, so duplicate rows
|
818
|
+
# can occur
|
819
|
+
# @option options [TrueClass, FalseClass] :from_self Set to false to not wrap the returned dataset in a
|
820
|
+
# #from_self, use with care.
|
824
821
|
#
|
825
822
|
# @returRelation]
|
826
823
|
#
|
827
824
|
# @api public
|
828
|
-
def union(relation, options = EMPTY_HASH, &)
|
825
|
+
def union(relation, options = EMPTY_HASH, &block)
|
829
826
|
# We use the original relation name here if both relations have the
|
830
827
|
# same name. This makes it so if the user at some point references
|
831
828
|
# the relation directly by name later on things won't break in
|
832
829
|
# confusing ways.
|
833
830
|
same_relation = name == relation.name
|
834
831
|
alias_name = same_relation ? name : "#{name.to_sym}__#{relation.name.to_sym}"
|
835
|
-
opts = {
|
832
|
+
opts = {alias: alias_name.to_sym, **options}
|
836
833
|
|
837
834
|
new_schema = schema.qualified(opts[:alias])
|
838
|
-
new_schema.(new(dataset.__send__(__method__, relation.dataset, opts, &)))
|
835
|
+
new_schema.(new(dataset.__send__(__method__, relation.dataset, opts, &block)))
|
839
836
|
end
|
840
837
|
|
841
838
|
# Checks whether a relation has at least one tuple
|
@@ -910,12 +907,12 @@ module ROM
|
|
910
907
|
# @yieldparam relation [Array]
|
911
908
|
#
|
912
909
|
# @api public
|
913
|
-
def lock(**options, &)
|
910
|
+
def lock(**options, &block)
|
914
911
|
clause = lock_clause(**options)
|
915
912
|
|
916
|
-
if
|
913
|
+
if block
|
917
914
|
transaction do
|
918
|
-
|
915
|
+
block.call(dataset.lock_style(clause).to_a)
|
919
916
|
end
|
920
917
|
else
|
921
918
|
new(dataset.lock_style(clause))
|
@@ -963,7 +960,7 @@ module ROM
|
|
963
960
|
pks = schema.primary_key
|
964
961
|
|
965
962
|
if pks.size > 1
|
966
|
-
raise ArgumentError,
|
963
|
+
raise ArgumentError, "Composite primary keys are not supported yet"
|
967
964
|
end
|
968
965
|
|
969
966
|
source = order(pks[0]).limit(size)
|
@@ -1052,18 +1049,18 @@ module ROM
|
|
1052
1049
|
# @api private
|
1053
1050
|
def lock_clause(mode: :update, skip_locked: false, of: nil, wait: nil)
|
1054
1051
|
stmt = ROW_LOCK_MODES[dataset.db.database_type].fetch(mode).dup
|
1055
|
-
stmt <<
|
1052
|
+
stmt << " OF " << Array(of).join(", ") if of
|
1056
1053
|
|
1057
1054
|
if skip_locked
|
1058
|
-
raise ArgumentError,
|
1055
|
+
raise ArgumentError, "SKIP LOCKED cannot be used with (NO)WAIT clause" unless wait.nil?
|
1059
1056
|
|
1060
|
-
stmt <<
|
1057
|
+
stmt << " SKIP LOCKED"
|
1061
1058
|
else
|
1062
1059
|
case wait
|
1063
1060
|
when Integer
|
1064
|
-
stmt <<
|
1061
|
+
stmt << " WAIT " << wait.to_s
|
1065
1062
|
when false
|
1066
|
-
stmt <<
|
1063
|
+
stmt << " NOWAIT"
|
1067
1064
|
else
|
1068
1065
|
stmt
|
1069
1066
|
end
|
@@ -1073,8 +1070,6 @@ module ROM
|
|
1073
1070
|
# Apply input types to condition values
|
1074
1071
|
#
|
1075
1072
|
# @api private
|
1076
|
-
#
|
1077
|
-
# rubocop:disable Metrics/AbcSize
|
1078
1073
|
def coerce_conditions(conditions)
|
1079
1074
|
conditions.each_with_object({}) { |(k, v), h|
|
1080
1075
|
if k.is_a?(Symbol) && schema.canonical.key?(k)
|
@@ -1087,31 +1082,31 @@ module ROM
|
|
1087
1082
|
end
|
1088
1083
|
}
|
1089
1084
|
end
|
1090
|
-
# rubocop:enable Metrics/AbcSize
|
1091
1085
|
|
1092
1086
|
# Common join method used by other join methods
|
1093
1087
|
#
|
1094
1088
|
# @api private
|
1095
1089
|
#
|
1096
|
-
# rubocop:disable Metrics/AbcSize
|
1097
|
-
|
1090
|
+
# rubocop:disable Metrics/AbcSize
|
1091
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
1092
|
+
def __join__(type, other, join_cond = EMPTY_HASH, opts = EMPTY_HASH, &block)
|
1098
1093
|
if other.is_a?(Symbol) || other.is_a?(ROM::Relation::Name)
|
1099
|
-
if join_cond.equal?(EMPTY_HASH) && !
|
1094
|
+
if join_cond.equal?(EMPTY_HASH) && !block
|
1100
1095
|
assoc = associations[other]
|
1101
1096
|
assoc.join(type, self)
|
1102
|
-
elsif
|
1103
|
-
__join__(type, other, JoinDSL.new(schema).(&), opts)
|
1097
|
+
elsif block
|
1098
|
+
__join__(type, other, JoinDSL.new(schema).(&block), opts)
|
1104
1099
|
else
|
1105
|
-
new(dataset.__send__(type, other.to_sym, join_cond, opts, &))
|
1100
|
+
new(dataset.__send__(type, other.to_sym, join_cond, opts, &block))
|
1106
1101
|
end
|
1107
|
-
elsif other.is_a?(
|
1108
|
-
new(dataset.__send__(type, other, join_cond, opts, &))
|
1102
|
+
elsif other.is_a?(Sequel::SQL::AliasedExpression)
|
1103
|
+
new(dataset.__send__(type, other, join_cond, opts, &block))
|
1109
1104
|
elsif other.respond_to?(:name) && other.name.is_a?(Relation::Name)
|
1110
|
-
if
|
1111
|
-
join_cond = JoinDSL.new(schema).(&)
|
1105
|
+
if block
|
1106
|
+
join_cond = JoinDSL.new(schema).(&block)
|
1112
1107
|
|
1113
1108
|
if other.name.aliaz
|
1114
|
-
join_opts = {
|
1109
|
+
join_opts = {table_alias: other.name.aliaz}
|
1115
1110
|
else
|
1116
1111
|
join_opts = EMPTY_HASH
|
1117
1112
|
end
|
@@ -1121,12 +1116,12 @@ module ROM
|
|
1121
1116
|
associations[other.name.key].join(type, self, other)
|
1122
1117
|
end
|
1123
1118
|
else
|
1124
|
-
raise ArgumentError,
|
1125
|
-
"+other+ must be either a symbol or a relation, #{other.class} given"
|
1119
|
+
raise ArgumentError, "+other+ must be either a symbol or a relation, #{other.class} given"
|
1126
1120
|
end
|
1127
1121
|
end
|
1122
|
+
# rubocop:enable Metrics/AbcSize
|
1123
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
1128
1124
|
end
|
1129
|
-
# rubocop:enable Metrics/AbcSize, Metrics/PerceivedComplexity, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/ModuleLength
|
1130
1125
|
end
|
1131
1126
|
end
|
1132
1127
|
end
|
@@ -16,7 +16,7 @@ module ROM
|
|
16
16
|
# @return [Integer] Number of affected rows
|
17
17
|
#
|
18
18
|
# @api public
|
19
|
-
def upsert(*args, &)
|
19
|
+
def upsert(*args, &block)
|
20
20
|
if args.size > 1 && args[-1].is_a?(Hash)
|
21
21
|
*values, opts = args
|
22
22
|
else
|
@@ -24,7 +24,7 @@ module ROM
|
|
24
24
|
opts = EMPTY_HASH
|
25
25
|
end
|
26
26
|
|
27
|
-
dataset.insert_conflict(opts).insert(*values, &)
|
27
|
+
dataset.insert_conflict(opts).insert(*values, &block)
|
28
28
|
end
|
29
29
|
|
30
30
|
# Insert tuple into relation
|
@@ -119,13 +119,8 @@ module ROM
|
|
119
119
|
dataset.import(columns, other.dataset, options)
|
120
120
|
else
|
121
121
|
keys = columns.map(&:to_sym)
|
122
|
-
|
123
|
-
|
124
|
-
other.to_a.map { |record|
|
125
|
-
record.to_h.values_at(*keys)
|
126
|
-
},
|
127
|
-
options
|
128
|
-
)
|
122
|
+
|
123
|
+
dataset.import(columns, other.to_a.map { |record| record.to_h.values_at(*keys) }, options)
|
129
124
|
end
|
130
125
|
end
|
131
126
|
end
|
data/lib/rom/sql/relation.rb
CHANGED
@@ -1,13 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require 'rom/sql/schema'
|
5
|
-
require 'rom/sql/attribute'
|
6
|
-
require 'rom/sql/wrap'
|
7
|
-
require 'rom/sql/transaction'
|
3
|
+
require "rom/relation"
|
8
4
|
|
9
|
-
require
|
10
|
-
require
|
5
|
+
require "rom/sql/types"
|
6
|
+
require "rom/sql/schema"
|
7
|
+
require "rom/sql/attribute"
|
8
|
+
require "rom/sql/wrap"
|
9
|
+
require "rom/sql/transaction"
|
10
|
+
|
11
|
+
require "rom/sql/relation/reading"
|
12
|
+
require "rom/sql/relation/writing"
|
13
|
+
require "rom/sql/schema/dsl"
|
11
14
|
|
12
15
|
module ROM
|
13
16
|
module SQL
|
@@ -15,99 +18,36 @@ module ROM
|
|
15
18
|
#
|
16
19
|
# @api public
|
17
20
|
class Relation < ROM::Relation
|
18
|
-
|
21
|
+
extend Dry::Core::ClassAttributes # TODO: only needed by pagination plugin
|
19
22
|
|
20
23
|
include SQL
|
21
24
|
include Writing
|
22
25
|
include Reading
|
23
26
|
|
24
|
-
|
25
|
-
|
26
|
-
schema_class SQL::Schema
|
27
|
-
schema_attr_class SQL::Attribute
|
28
|
-
schema_inferrer ROM::SQL::Schema::Inferrer.new.freeze
|
29
|
-
schema_dsl SQL::Schema::DSL
|
30
|
-
wrap_class SQL::Wrap
|
31
|
-
|
32
|
-
subscribe('configuration.relations.schema.set', adapter: :sql) do |event|
|
33
|
-
schema = event[:schema]
|
34
|
-
relation = event[:relation]
|
35
|
-
|
36
|
-
relation.dataset do
|
37
|
-
table = opts[:from].first
|
27
|
+
config.wrap_class = SQL::Wrap
|
38
28
|
|
39
|
-
|
40
|
-
|
41
|
-
*schema.project(*schema.primary_key_names).qualified
|
42
|
-
)
|
43
|
-
else
|
44
|
-
self
|
45
|
-
end
|
46
|
-
end
|
29
|
+
configure(:component) do |config|
|
30
|
+
config.adapter = :sql
|
47
31
|
end
|
48
32
|
|
49
|
-
|
50
|
-
|
33
|
+
configure(:schema) do |config|
|
34
|
+
config.constant = SQL::Schema
|
35
|
+
config.attr_class = SQL::Attribute
|
36
|
+
config.inferrer = ROM::SQL::Schema::Inferrer.new.freeze
|
37
|
+
config.plugins << :indexes
|
38
|
+
config.dsl_class = SQL::Schema::DSL
|
51
39
|
end
|
52
40
|
|
53
|
-
|
54
|
-
|
55
|
-
# rubocop:disable Metrics/MethodLength
|
56
|
-
def self.define_default_views!
|
57
|
-
undef_method :by_pk if method_defined?(:by_pk)
|
41
|
+
dataset(abstract: true) do |schema|
|
42
|
+
table = opts[:from].first
|
58
43
|
|
59
|
-
if
|
60
|
-
|
61
|
-
|
62
|
-
# Return a relation restricted by its composite primary key
|
63
|
-
#
|
64
|
-
# @param [Array] args A list with composite pk values
|
65
|
-
#
|
66
|
-
# @return [SQL::Relation]
|
67
|
-
#
|
68
|
-
# @api public
|
69
|
-
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
70
|
-
def by_pk(#{pks.map(&:name).join(", ")}) # def by_pk(val1, val2)
|
71
|
-
s = schema.canonical # s = schema.canonical
|
72
|
-
where( # where(
|
73
|
-
#{pks.map { "s[:#{_1.name}] => #{_1.name}" }.join(", ")} # s[:val1] => val1, s[:val2] => val2
|
74
|
-
) # )
|
75
|
-
end # end
|
76
|
-
RUBY
|
44
|
+
if db.table_exists?(table)
|
45
|
+
select(*schema.qualified_projection)
|
46
|
+
.order(*schema.project(*schema.primary_key_names).qualified)
|
77
47
|
else
|
78
|
-
|
79
|
-
# Return a relation restricted by its primary key
|
80
|
-
#
|
81
|
-
# @param [Object] pk The primary key value
|
82
|
-
#
|
83
|
-
# @return [SQL::Relation]
|
84
|
-
#
|
85
|
-
# @api public
|
86
|
-
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
87
|
-
def by_pk(pk) # def by_pk(pk)
|
88
|
-
s = schema.canonical # s = schema.canonical
|
89
|
-
if primary_key.nil? # if primary_key.nil?
|
90
|
-
raise MissingPrimaryKeyError.new( # raise MissingPrimaryKeyError.new(
|
91
|
-
"Missing primary key for :\#{schema.name}" # "Missing primary key for :#{schema.name}"
|
92
|
-
) # )
|
93
|
-
end # end
|
94
|
-
where(s[s.primary_key_name].qualified => pk) # where(s[s.primary_key_name].qualified => pk)
|
95
|
-
end # end
|
96
|
-
RUBY
|
48
|
+
self
|
97
49
|
end
|
98
50
|
end
|
99
|
-
# rubocop:enable Metrics/MethodLength
|
100
|
-
|
101
|
-
# @api private
|
102
|
-
def self.associations
|
103
|
-
schema.associations
|
104
|
-
end
|
105
|
-
|
106
|
-
# @api private
|
107
|
-
def self.primary_key_columns(db, table)
|
108
|
-
names = db.respond_to?(:primary_key) ? Array(db.primary_key(table)) : [:id]
|
109
|
-
names.map { |col| :"#{table}__#{col}" }
|
110
|
-
end
|
111
51
|
|
112
52
|
option :primary_key, default: -> { schema.primary_key_name }
|
113
53
|
|
@@ -131,62 +71,44 @@ module ROM
|
|
131
71
|
# Open a database transaction
|
132
72
|
#
|
133
73
|
# @param [Hash] opts
|
134
|
-
# @option opts [Boolean] :auto_savepoint
|
135
|
-
#
|
136
|
-
#
|
137
|
-
#
|
138
|
-
#
|
139
|
-
#
|
140
|
-
#
|
141
|
-
#
|
142
|
-
#
|
143
|
-
#
|
144
|
-
#
|
145
|
-
#
|
146
|
-
# @option opts [
|
147
|
-
#
|
148
|
-
#
|
149
|
-
#
|
150
|
-
# @option opts [
|
151
|
-
#
|
152
|
-
#
|
153
|
-
#
|
154
|
-
#
|
155
|
-
#
|
156
|
-
#
|
157
|
-
#
|
158
|
-
#
|
159
|
-
# @option opts [
|
160
|
-
#
|
161
|
-
#
|
162
|
-
#
|
163
|
-
#
|
164
|
-
# The server to use for the transaction. Set to :default, :read_only,
|
165
|
-
# or whatever symbol you used in the connect string when naming
|
166
|
-
# your servers.
|
167
|
-
# @option opts [Boolean] :savepoint
|
168
|
-
# Whether to create a new savepoint for this transaction, only
|
169
|
-
# respected if the database/adapter supports savepoints. By default
|
170
|
-
# Sequel will reuse an existing transaction, so if you want to use a
|
171
|
-
# savepoint you must use this option. If the surrounding transaction
|
172
|
-
# uses :auto_savepoint, you can set this to false to not use a savepoint.
|
173
|
-
# If the value given for this option is :only, it will only create a
|
174
|
-
# savepoint if it is inside a transacation.
|
175
|
-
# @option opts [Boolean] :deferrable
|
176
|
-
# If present, set to DEFERRABLE if true or NOT DEFERRABLE if false.
|
177
|
-
# @option opts [Boolean] :read_only
|
178
|
-
# **PG only** If present, set to READ ONLY if true or READ WRITE if false.
|
179
|
-
# @option opts [Symbol] :synchronous
|
180
|
-
# **PG only** If non-nil, set synchronous_commit appropriately.
|
181
|
-
# Valid values true, :on, false, :off, :local, and :remote_write.
|
74
|
+
# @option opts [Boolean] :auto_savepoint Automatically use a savepoint for Database#transaction calls inside
|
75
|
+
# this transaction block.
|
76
|
+
# @option opts [Symbol] :isolation The transaction isolation level to use for this transaction, should be
|
77
|
+
# :uncommitted, :committed, :repeatable, or :serializable, used if given and the database/adapter supports
|
78
|
+
# customizable transaction isolation levels.
|
79
|
+
# @option opts [Integer] :num_retries The number of times to retry if the :retry_on option is used. The default is
|
80
|
+
# 5 times. Can be set to nil to retry indefinitely, but that is not recommended.
|
81
|
+
# @option opts [Proc] :before_retry Proc to execute before rertrying if the :retry_on option is used. Called with
|
82
|
+
# two arguments: the number of retry attempts (counting the current one) and the error the last attempt failed
|
83
|
+
# with.
|
84
|
+
# @option opts [String] :prepare A string to use as the transaction identifier for a prepared transaction
|
85
|
+
# (two-phase commit), if the database/adapter supports prepared transactions.
|
86
|
+
# @option opts [Class] :retry_on An exception class or array of exception classes for which to automatically retry
|
87
|
+
# the transaction. Can only be set if not inside an existing transaction. Note that this should not be used
|
88
|
+
# unless the entire transaction block is idempotent, as otherwise it can cause non-idempotent behavior to
|
89
|
+
# execute multiple times.
|
90
|
+
# @option opts [Symbol] :rollback Can the set to :reraise to reraise any Sequel::Rollback exceptions raised, or
|
91
|
+
# :always to always rollback even if no exceptions occur (useful for testing).
|
92
|
+
# @option opts [Symbol] :server The server to use for the transaction. Set to :default, :read_only, or whatever
|
93
|
+
# symbol you used in the connect string when naming your servers.
|
94
|
+
# @option opts [Boolean] :savepoint Whether to create a new savepoint for this transaction, only respected if the
|
95
|
+
# database/adapter supports savepoints. By default Sequel will reuse an existing transaction, so if you want to
|
96
|
+
# use a savepoint you must use this option. If the surrounding transaction uses :auto_savepoint, you can set
|
97
|
+
# this to false to not use a savepoint. If the value given for this option is :only, it will only create
|
98
|
+
# a savepoint if it is inside a transacation.
|
99
|
+
# @option opts [Boolean] :deferrable **PG 9.1+ only** If present, set to DEFERRABLE if true or NOT DEFERRABLE if
|
100
|
+
# false.
|
101
|
+
# @option opts [Boolean] :read_only **PG only** If present, set to READ ONLY if true or READ WRITE if false.
|
102
|
+
# @option opts [Symbol] :synchronous **PG only** if non-nil, set synchronous_commit appropriately. Valid values
|
103
|
+
# true, :on, false, :off, :local (9.1+), and :remote_write (9.2+).
|
182
104
|
#
|
183
105
|
# @yield [t] Transaction
|
184
106
|
#
|
185
107
|
# @return [Mixed]
|
186
108
|
#
|
187
109
|
# @api public
|
188
|
-
def transaction(opts
|
189
|
-
Transaction.new(dataset.db).run(opts, &)
|
110
|
+
def transaction(**opts, &block)
|
111
|
+
Transaction.new(dataset.db).run(**opts, &block)
|
190
112
|
end
|
191
113
|
|
192
114
|
# Return raw column names
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "rom/sql/dsl"
|
4
4
|
|
5
5
|
module ROM
|
6
6
|
module SQL
|
@@ -19,21 +19,17 @@ module ROM
|
|
19
19
|
|
20
20
|
private
|
21
21
|
|
22
|
-
def respond_to_missing?(_meth, _include_private = false)
|
23
|
-
true
|
24
|
-
end
|
25
|
-
|
26
22
|
# @api private
|
27
|
-
def method_missing(meth,
|
23
|
+
def method_missing(meth, *args, &block)
|
28
24
|
if schema.key?(meth)
|
29
25
|
schema[meth]
|
30
26
|
else
|
31
27
|
type = type(meth)
|
32
28
|
|
33
29
|
if type
|
34
|
-
::ROM::SQL::Function.new(type)
|
30
|
+
::ROM::SQL::Function.new(type)
|
35
31
|
else
|
36
|
-
::Sequel::VIRTUAL_ROW.__send__(meth,
|
32
|
+
::Sequel::VIRTUAL_ROW.__send__(meth, *args, &block)
|
37
33
|
end
|
38
34
|
end
|
39
35
|
end
|