torque-postgresql 4.1.0 → 4.1.1
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/Rakefile +28 -0
- data/lib/generators/torque/skill_generator.rb +17 -0
- data/lib/generators/torque/templates/trigger.sql.erb +3 -0
- data/lib/generators/torque/trigger_generator.rb +13 -0
- data/lib/torque/postgresql/adapter/database_statements.rb +9 -0
- data/lib/torque/postgresql/adapter/oid/array.rb +0 -4
- data/lib/torque/postgresql/adapter/oid/composite.rb +2 -1
- data/lib/torque/postgresql/adapter/oid/enum.rb +1 -1
- data/lib/torque/postgresql/adapter/oid/enum_set.rb +2 -2
- data/lib/torque/postgresql/adapter/oid/interval.rb +1 -1
- data/lib/torque/postgresql/adapter/oid/lquery.rb +45 -28
- data/lib/torque/postgresql/adapter/oid/ltree.rb +67 -9
- data/lib/torque/postgresql/adapter/oid/struct.rb +1 -1
- data/lib/torque/postgresql/adapter/oid.rb +13 -0
- data/lib/torque/postgresql/adapter/schema_definitions.rb +5 -0
- data/lib/torque/postgresql/adapter/schema_dumper.rb +1 -0
- data/lib/torque/postgresql/arel/nodes.rb +51 -0
- data/lib/torque/postgresql/arel/visitors.rb +46 -0
- data/lib/torque/postgresql/attributes/base.rb +10 -7
- data/lib/torque/postgresql/attributes/composite.rb +1 -5
- data/lib/torque/postgresql/attributes/enum.rb +1 -6
- data/lib/torque/postgresql/attributes/lquery.rb +67 -127
- data/lib/torque/postgresql/attributes/ltree.rb +35 -83
- data/lib/torque/postgresql/base.rb +9 -1
- data/lib/torque/postgresql/config.rb +21 -3
- data/lib/torque/postgresql/geometry_builder.rb +4 -10
- data/lib/torque/postgresql/inheritance.rb +5 -5
- data/lib/torque/postgresql/predicate_builder/arel_attribute_handler.rb +1 -1
- data/lib/torque/postgresql/predicate_builder/array_handler.rb +16 -8
- data/lib/torque/postgresql/predicate_builder/composite_handler.rb +18 -5
- data/lib/torque/postgresql/predicate_builder/ltree_handler.rb +86 -18
- data/lib/torque/postgresql/predicate_builder/struct_handler.rb +29 -9
- data/lib/torque/postgresql/predicate_builder.rb +38 -11
- data/lib/torque/postgresql/railtie.rb +17 -0
- data/lib/torque/postgresql/relation/auxiliary_statement.rb +7 -3
- data/lib/torque/postgresql/relation/buckets.rb +2 -1
- data/lib/torque/postgresql/relation/cross_join.rb +193 -0
- data/lib/torque/postgresql/relation/inheritance.rb +1 -2
- data/lib/torque/postgresql/relation/join_series.rb +1 -0
- data/lib/torque/postgresql/relation/merger.rb +9 -0
- data/lib/torque/postgresql/relation/segments.rb +140 -0
- data/lib/torque/postgresql/relation.rb +23 -4
- data/lib/torque/postgresql/version.rb +1 -1
- data/lib/torque/postgresql/versioned_commands/command_migration.rb +23 -0
- data/lib/torque/postgresql/versioned_commands.rb +39 -0
- data/lib/torque/postgresql.rb +0 -2
- data/sig/generators/torque/function_generator.rbs +9 -0
- data/sig/generators/torque/skill_generator.rbs +7 -0
- data/sig/generators/torque/trigger_generator.rbs +9 -0
- data/sig/generators/torque/type_generator.rbs +9 -0
- data/sig/generators/torque/view_generator.rbs +9 -0
- data/sig/manifest.yaml +7 -0
- data/sig/torque/postgresql/adapter/database_statements.rbs +42 -0
- data/sig/torque/postgresql/adapter/inheritance_statements.rbs +36 -0
- data/sig/torque/postgresql/adapter/oid/array.rbs +20 -0
- data/sig/torque/postgresql/adapter/oid/box.rbs +28 -0
- data/sig/torque/postgresql/adapter/oid/circle.rbs +33 -0
- data/sig/torque/postgresql/adapter/oid/composite.rbs +35 -0
- data/sig/torque/postgresql/adapter/oid/enum.rbs +28 -0
- data/sig/torque/postgresql/adapter/oid/enum_set.rbs +19 -0
- data/sig/torque/postgresql/adapter/oid/interval.rbs +20 -0
- data/sig/torque/postgresql/adapter/oid/line.rbs +33 -0
- data/sig/torque/postgresql/adapter/oid/lquery.rbs +21 -0
- data/sig/torque/postgresql/adapter/oid/ltree.rbs +32 -0
- data/sig/torque/postgresql/adapter/oid/range.rbs +28 -0
- data/sig/torque/postgresql/adapter/oid/segment.rbs +38 -0
- data/sig/torque/postgresql/adapter/oid/struct.rbs +41 -0
- data/sig/torque/postgresql/adapter/oid/struct_list.rbs +20 -0
- data/sig/torque/postgresql/adapter/oid/struct_set.rbs +18 -0
- data/sig/torque/postgresql/adapter/oid.rbs +9 -0
- data/sig/torque/postgresql/adapter/quoting.rbs +20 -0
- data/sig/torque/postgresql/adapter/schema_creation.rbs +13 -0
- data/sig/torque/postgresql/adapter/schema_definitions.rbs +55 -0
- data/sig/torque/postgresql/adapter/schema_dumper.rbs +37 -0
- data/sig/torque/postgresql/adapter/schema_overrides.rbs +46 -0
- data/sig/torque/postgresql/adapter/schema_statements.rbs +50 -0
- data/sig/torque/postgresql/adapter.rbs +24 -0
- data/sig/torque/postgresql/arel/infix_operation.rbs +79 -0
- data/sig/torque/postgresql/arel/join_source.rbs +19 -0
- data/sig/torque/postgresql/arel/nodes.rbs +83 -0
- data/sig/torque/postgresql/arel/operations.rbs +28 -0
- data/sig/torque/postgresql/arel/select_manager.rbs +15 -0
- data/sig/torque/postgresql/arel/visitors.rbs +30 -0
- data/sig/torque/postgresql/arel.rbs +6 -0
- data/sig/torque/postgresql/associations/association_scope.rbs +28 -0
- data/sig/torque/postgresql/associations/belongs_to_many_association.rbs +51 -0
- data/sig/torque/postgresql/associations/builder/belongs_to_many.rbs +24 -0
- data/sig/torque/postgresql/associations/builder/has_many.rbs +15 -0
- data/sig/torque/postgresql/associations/builder.rbs +8 -0
- data/sig/torque/postgresql/associations/foreign_association.rbs +16 -0
- data/sig/torque/postgresql/associations/join_dependency.rbs +16 -0
- data/sig/torque/postgresql/associations/preloader/association.rbs +32 -0
- data/sig/torque/postgresql/associations/preloader/loader_query.rbs +20 -0
- data/sig/torque/postgresql/associations/preloader.rbs +8 -0
- data/sig/torque/postgresql/associations.rbs +17 -0
- data/sig/torque/postgresql/attributes/base.rbs +37 -0
- data/sig/torque/postgresql/attributes/builder/enum.rbs +38 -0
- data/sig/torque/postgresql/attributes/builder/full_text_search.rbs +27 -0
- data/sig/torque/postgresql/attributes/builder/period.rbs +106 -0
- data/sig/torque/postgresql/attributes/builder.rbs +19 -0
- data/sig/torque/postgresql/attributes/composite.rbs +28 -0
- data/sig/torque/postgresql/attributes/enum.rbs +69 -0
- data/sig/torque/postgresql/attributes/enum_set.rbs +75 -0
- data/sig/torque/postgresql/attributes/full_text_search.rbs +13 -0
- data/sig/torque/postgresql/attributes/lazy.rbs +17 -0
- data/sig/torque/postgresql/attributes/lquery.rbs +48 -0
- data/sig/torque/postgresql/attributes/ltree.rbs +46 -0
- data/sig/torque/postgresql/attributes/period.rbs +13 -0
- data/sig/torque/postgresql/attributes/simple_enum.rbs +39 -0
- data/sig/torque/postgresql/attributes/struct.rbs +38 -0
- data/sig/torque/postgresql/attributes.rbs +6 -0
- data/sig/torque/postgresql/autosave_association.rbs +16 -0
- data/sig/torque/postgresql/auxiliary_statement/recursive.rbs +22 -0
- data/sig/torque/postgresql/auxiliary_statement/settings.rbs +63 -0
- data/sig/torque/postgresql/auxiliary_statement.rbs +57 -0
- data/sig/torque/postgresql/base.rbs +41 -0
- data/sig/torque/postgresql/collector.rbs +7 -0
- data/sig/torque/postgresql/config.rbs +9 -0
- data/sig/torque/postgresql/function.rbs +21 -0
- data/sig/torque/postgresql/geometry_builder.rbs +20 -0
- data/sig/torque/postgresql/i18n.rbs +15 -0
- data/sig/torque/postgresql/inheritance/expander.rbs +23 -0
- data/sig/torque/postgresql/inheritance/record.rbs +20 -0
- data/sig/torque/postgresql/inheritance.rbs +47 -0
- data/sig/torque/postgresql/insert_all.rbs +22 -0
- data/sig/torque/postgresql/migration/command_recorder.rbs +30 -0
- data/sig/torque/postgresql/migration.rbs +6 -0
- data/sig/torque/postgresql/predicate_builder/arel_attribute_handler.rbs +15 -0
- data/sig/torque/postgresql/predicate_builder/array_handler.rbs +26 -0
- data/sig/torque/postgresql/predicate_builder/composite_handler.rbs +26 -0
- data/sig/torque/postgresql/predicate_builder/enumerator_lazy_handler.rbs +18 -0
- data/sig/torque/postgresql/predicate_builder/ltree_handler.rbs +36 -0
- data/sig/torque/postgresql/predicate_builder/regexp_handler.rbs +16 -0
- data/sig/torque/postgresql/predicate_builder/struct_handler.rbs +24 -0
- data/sig/torque/postgresql/predicate_builder.rbs +23 -0
- data/sig/torque/postgresql/predicate_table.rbs +24 -0
- data/sig/torque/postgresql/railtie.rbs +10 -0
- data/sig/torque/postgresql/reflection/abstract_reflection.rbs +22 -0
- data/sig/torque/postgresql/reflection/association_reflection.rbs +18 -0
- data/sig/torque/postgresql/reflection/belongs_to_many_reflection.rbs +30 -0
- data/sig/torque/postgresql/reflection/has_many_reflection.rbs +14 -0
- data/sig/torque/postgresql/reflection/runtime_reflection.rbs +18 -0
- data/sig/torque/postgresql/reflection/through_reflection.rbs +14 -0
- data/sig/torque/postgresql/reflection.rbs +11 -0
- data/sig/torque/postgresql/relation/auxiliary_statement.rbs +29 -0
- data/sig/torque/postgresql/relation/buckets.rbs +35 -0
- data/sig/torque/postgresql/relation/cross_join.rbs +63 -0
- data/sig/torque/postgresql/relation/distinct_on.rbs +16 -0
- data/sig/torque/postgresql/relation/inheritance.rbs +48 -0
- data/sig/torque/postgresql/relation/join_series.rbs +28 -0
- data/sig/torque/postgresql/relation/merger.rbs +23 -0
- data/sig/torque/postgresql/relation/segments.rbs +27 -0
- data/sig/torque/postgresql/relation.rbs +48 -0
- data/sig/torque/postgresql/schema_cache/bound_schema_reflection.rbs +14 -0
- data/sig/torque/postgresql/schema_cache/inheritance.rbs +12 -0
- data/sig/torque/postgresql/schema_cache/schema_reflection.rbs +14 -0
- data/sig/torque/postgresql/schema_cache.rbs +43 -0
- data/sig/torque/postgresql/table_name.rbs +20 -0
- data/sig/torque/postgresql/validations.rbs +13 -0
- data/sig/torque/postgresql/version.rbs +5 -0
- data/sig/torque/postgresql/versioned_commands/command_migration.rbs +54 -0
- data/sig/torque/postgresql/versioned_commands/generator.rbs +17 -0
- data/sig/torque/postgresql/versioned_commands/migration_context.rbs +30 -0
- data/sig/torque/postgresql/versioned_commands/migrator.rbs +19 -0
- data/sig/torque/postgresql/versioned_commands/schema_table.rbs +23 -0
- data/sig/torque/postgresql/versioned_commands.rbs +25 -0
- data/sig/torque/postgresql.rbs +26 -0
- data/skills/torque-postgresql/SKILL.md +70 -0
- data/spec/fixtures/migrations/20250101000008_create_trigger_audit_users_v1.sql +3 -0
- data/spec/initialize.rb +9 -0
- data/spec/mocks/cache_query.rb +1 -1
- data/spec/rbs_helper.rb +8 -0
- data/spec/schema.rb +2 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/tests/arel_spec.rb +1 -3
- data/spec/tests/auxiliary_statement_spec.rb +12 -0
- data/spec/tests/buckets_spec.rb +122 -0
- data/spec/tests/composite_spec.rb +67 -0
- data/spec/tests/cross_join_spec.rb +185 -0
- data/spec/tests/distinct_on_spec.rb +5 -0
- data/spec/tests/enum_set_spec.rb +4 -0
- data/spec/tests/enum_spec.rb +20 -4
- data/spec/tests/geometric_builder_spec.rb +16 -5
- data/spec/tests/has_many_spec.rb +2 -1
- data/spec/tests/interval_spec.rb +6 -0
- data/spec/tests/ltree_spec.rb +398 -64
- data/spec/tests/predicate_builder_spec.rb +120 -0
- data/spec/tests/relation_spec.rb +25 -69
- data/spec/tests/segments_spec.rb +264 -0
- data/spec/tests/struct_spec.rb +202 -0
- data/spec/tests/table_inheritance_spec.rb +10 -0
- data/spec/tests/versioned_commands_spec.rb +145 -0
- metadata +153 -2
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Torque
|
|
4
|
+
module PostgreSQL
|
|
5
|
+
module Relation
|
|
6
|
+
module Segments
|
|
7
|
+
|
|
8
|
+
# :nodoc:
|
|
9
|
+
def segments_value
|
|
10
|
+
@values.fetch(:segments, ::ActiveRecord::QueryMethods::FROZEN_EMPTY_HASH)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# :nodoc:
|
|
14
|
+
def segments_value=(value)
|
|
15
|
+
assert_modifiable!
|
|
16
|
+
@values[:segments] = value
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Maps names to conditions so that the next calculation returns one
|
|
20
|
+
# value per name, each aggregate filtered by its condition. Anything
|
|
21
|
+
# that can become a relation is accepted as a condition, an array
|
|
22
|
+
# applies each of its items in order, and +nil+ means the aggregate is
|
|
23
|
+
# not filtered at all. For example:
|
|
24
|
+
#
|
|
25
|
+
# User.segments(all: nil, adults: { age: 18.. }).count
|
|
26
|
+
# # Returns { all: 15, adults: 12 }
|
|
27
|
+
#
|
|
28
|
+
# User.group(:role).segments(adults: { age: 18.. }).sum(:age)
|
|
29
|
+
# # Returns { 'visitor' => { adults: 480 }, ... }
|
|
30
|
+
def segments(**map)
|
|
31
|
+
spawn.segments!(**map)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Like #segments, but modifies relation in place.
|
|
35
|
+
def segments!(**map)
|
|
36
|
+
predicates = map.to_h { |name, condition| [name, segment_predicate_for(name, condition)] }
|
|
37
|
+
self.segments_value = segments_value.merge(predicates)
|
|
38
|
+
self
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def execute_simple_calculation(operation, column_name, distinct)
|
|
44
|
+
return super if segments_value.blank?
|
|
45
|
+
|
|
46
|
+
execute_segments_calculation(operation, column_name, distinct)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def execute_grouped_calculation(operation, column_name, distinct)
|
|
50
|
+
return super if segments_value.blank?
|
|
51
|
+
|
|
52
|
+
execute_segments_calculation(operation, column_name, distinct)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def execute_segments_calculation(operation, column_name, distinct)
|
|
56
|
+
column_name = primary_key if operation == 'count' && column_name == :all && distinct
|
|
57
|
+
column = aggregate_column(column_name)
|
|
58
|
+
aggregate = operation_over_aggregate_column(column, operation, distinct)
|
|
59
|
+
|
|
60
|
+
relation = except(:group, :select).distinct!(false)
|
|
61
|
+
relation.order_values = [] if group_values.empty?
|
|
62
|
+
|
|
63
|
+
groups = relation.arel_columns(group_values)
|
|
64
|
+
relation.group_values = groups
|
|
65
|
+
|
|
66
|
+
result = skip_query_cache_if_necessary do
|
|
67
|
+
klass.with_connection do |connection|
|
|
68
|
+
relation.select_values = segments_projections(groups, aggregate, connection)
|
|
69
|
+
connection.select_all(relation.arel, "#{klass.name} Segments", async: @async)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
result.then { |data| segments_result(data, groups, column, operation) }
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def segments_projections(groups, aggregate, connection)
|
|
77
|
+
tracker = ::ActiveRecord::Calculations::ColumnAliasTracker.new(connection)
|
|
78
|
+
projections = groups.map do |group|
|
|
79
|
+
name = tracker.alias_for(connection.visitor.compile(group).downcase)
|
|
80
|
+
group.as(connection.quote_column_name(name))
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
segments_value.each_with_object(projections) do |(name, predicate), list|
|
|
84
|
+
node = predicate.nil? ? aggregate.dup : aggregate.filter(predicate)
|
|
85
|
+
list << node.as(connection.quote_column_name(name.to_s))
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def segments_result(data, groups, column, operation)
|
|
90
|
+
type = column.try(:type_caster) || ::ActiveRecord::Type.default_value
|
|
91
|
+
type = type.subtype if ::ActiveRecord::Enum::EnumType === type
|
|
92
|
+
|
|
93
|
+
key_types = groups.each_with_index.to_h do |group, index|
|
|
94
|
+
name = data.columns[index]
|
|
95
|
+
key_type = group.try(:type_caster)
|
|
96
|
+
key_type ||= type_for(group) { data.column_types.fetch(name, ::ActiveRecord::Type.default_value) }
|
|
97
|
+
[name, key_type]
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
rows = data.cast_values(key_types)
|
|
101
|
+
rows = rows.map { |value| [value] } if data.columns.size == 1
|
|
102
|
+
|
|
103
|
+
rows = rows.to_h do |row|
|
|
104
|
+
key = row.take(groups.size)
|
|
105
|
+
key = key.first if key.size == 1
|
|
106
|
+
|
|
107
|
+
values = row.drop(groups.size).map do |value|
|
|
108
|
+
type_cast_calculated_value(value, operation, type)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
[key, segments_value.keys.zip(values).to_h]
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
groups.empty? ? rows.values.first : rows
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def segment_predicate_for(name, condition)
|
|
118
|
+
return if !condition.is_a?(::ActiveRecord::Relation) && condition.blank?
|
|
119
|
+
|
|
120
|
+
items = condition.is_a?(::Array) ? condition : [condition]
|
|
121
|
+
relation = items.reduce(klass.unscoped) do |result, item|
|
|
122
|
+
case item
|
|
123
|
+
when ::ActiveRecord::Relation then result.merge(item)
|
|
124
|
+
when Symbol then result.public_send(item)
|
|
125
|
+
when Proc then item.arity.zero? ? result.instance_exec(&item) : item.call(result)
|
|
126
|
+
else result.where(item)
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
raise ArgumentError, <<~MSG.squish if relation.where_clause.empty?
|
|
131
|
+
Segment #{name} does not filter anything, use nil for an unfiltered segment.
|
|
132
|
+
MSG
|
|
133
|
+
|
|
134
|
+
relation.where_clause.ast
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
@@ -13,7 +13,9 @@ module Torque
|
|
|
13
13
|
include DistinctOn
|
|
14
14
|
include Inheritance
|
|
15
15
|
|
|
16
|
-
SINGLE_VALUE_METHODS = %i[
|
|
16
|
+
SINGLE_VALUE_METHODS = %i[
|
|
17
|
+
itself_only buckets segments expand_records_eager_load expand_records_scoped
|
|
18
|
+
]
|
|
17
19
|
MULTI_VALUE_METHODS = %i[
|
|
18
20
|
select_extra distinct_on auxiliary_statements expand_records
|
|
19
21
|
]
|
|
@@ -76,6 +78,9 @@ module Torque
|
|
|
76
78
|
return unless relation
|
|
77
79
|
|
|
78
80
|
table = predicate_builder.send(:table)
|
|
81
|
+
part = part_table_for(table, relation.to_s)
|
|
82
|
+
return part if part
|
|
83
|
+
|
|
79
84
|
associated = AR810 ? table.associated_with(relation.to_s) : table.associated_with?(relation.to_s)
|
|
80
85
|
if associated
|
|
81
86
|
table.associated_table(relation.to_s).send(:klass)
|
|
@@ -88,8 +93,11 @@ module Torque
|
|
|
88
93
|
# the given column
|
|
89
94
|
def cast_for_condition(column, value)
|
|
90
95
|
column = columns_hash[column.to_s] unless column.is_a?(ARColumn)
|
|
91
|
-
|
|
92
|
-
connection
|
|
96
|
+
|
|
97
|
+
klass.with_connection do |connection|
|
|
98
|
+
caster = connection.lookup_cast_type_for_column(column)
|
|
99
|
+
connection.type_cast(caster.serialize(value))
|
|
100
|
+
end
|
|
93
101
|
end
|
|
94
102
|
|
|
95
103
|
private
|
|
@@ -100,6 +108,16 @@ module Torque
|
|
|
100
108
|
arel
|
|
101
109
|
end
|
|
102
110
|
|
|
111
|
+
def part_table_for(table, name)
|
|
112
|
+
return unless table.has_column?(name)
|
|
113
|
+
|
|
114
|
+
type = Adapter::OID.unwrap(table.type(name))
|
|
115
|
+
handler = PredicateBuilder.handler_for(type)
|
|
116
|
+
return if handler.nil?
|
|
117
|
+
|
|
118
|
+
handler.new(predicate_builder).table_for(table.arel_table[name], type)
|
|
119
|
+
end
|
|
120
|
+
|
|
103
121
|
class_methods do
|
|
104
122
|
# Easy and storable way to access the name used to get the record table
|
|
105
123
|
# name when using inheritance tables
|
|
@@ -144,7 +162,8 @@ module Torque
|
|
|
144
162
|
ActiveRecord::Relation::MULTI_VALUE_METHODS.concat(Relation::MULTI_VALUE_METHODS)
|
|
145
163
|
ActiveRecord::Relation::VALUE_METHODS.concat(Relation::VALUE_METHODS)
|
|
146
164
|
ActiveRecord::QueryMethods::VALID_UNSCOPING_VALUES.merge(%i[expand_records itself_only
|
|
147
|
-
expand_records_eager_load expand_records_scoped distinct_on auxiliary_statements buckets
|
|
165
|
+
expand_records_eager_load expand_records_scoped distinct_on auxiliary_statements buckets
|
|
166
|
+
segments])
|
|
148
167
|
|
|
149
168
|
end
|
|
150
169
|
end
|
|
@@ -131,6 +131,29 @@ module Torque
|
|
|
131
131
|
execute "DROP TYPE #{name.first.first};"
|
|
132
132
|
end
|
|
133
133
|
|
|
134
|
+
# Drop the trigger and any function bundled with it
|
|
135
|
+
def drop_trigger
|
|
136
|
+
content = File.read(filename)
|
|
137
|
+
trigger, table = content.scan(Regexp.new([
|
|
138
|
+
'^\s*CREATE\s+(?:OR\s+REPLACE\s+)?',
|
|
139
|
+
"TRIGGER\\s+#{NAME_MATCH}",
|
|
140
|
+
'.*?\bON\s+',
|
|
141
|
+
NAME_MATCH,
|
|
142
|
+
].join, 'mi')).first
|
|
143
|
+
|
|
144
|
+
execute "DROP TRIGGER #{trigger} ON #{table};"
|
|
145
|
+
|
|
146
|
+
definitions = content.scan(Regexp.new([
|
|
147
|
+
'^\s*CREATE\s+(?:OR\s+REPLACE\s+)?',
|
|
148
|
+
"FUNCTION\\s+#{NAME_MATCH}",
|
|
149
|
+
'\s*(\([_a-z0-9 ,]*\))?',
|
|
150
|
+
].join, 'mi'))
|
|
151
|
+
return if definitions.empty?
|
|
152
|
+
|
|
153
|
+
functions = definitions.map(&:join).join(', ')
|
|
154
|
+
execute "DROP FUNCTION #{functions};"
|
|
155
|
+
end
|
|
156
|
+
|
|
134
157
|
# Drop view or materialized view
|
|
135
158
|
def drop_view
|
|
136
159
|
mat, name = File.read(filename).scan(Regexp.new([
|
|
@@ -117,6 +117,45 @@ module Torque
|
|
|
117
117
|
MSG
|
|
118
118
|
end
|
|
119
119
|
|
|
120
|
+
# Validate that the content of the command is correct
|
|
121
|
+
def validate_trigger!(content, name)
|
|
122
|
+
result = content.scan(Regexp.new([
|
|
123
|
+
'^\s*CREATE\s+(OR\s+REPLACE)?\s*',
|
|
124
|
+
"TRIGGER\\s+#{NAME_MATCH}",
|
|
125
|
+
].join, 'mi'))
|
|
126
|
+
|
|
127
|
+
raise ArgumentError, <<~MSG.squish if result.empty?
|
|
128
|
+
Missing or invalid trigger definition.
|
|
129
|
+
MSG
|
|
130
|
+
|
|
131
|
+
raise ArgumentError, <<~MSG.squish if result.size > 1
|
|
132
|
+
More than one trigger definition found.
|
|
133
|
+
MSG
|
|
134
|
+
|
|
135
|
+
raise ArgumentError, <<~MSG.squish unless result.all?(&:first)
|
|
136
|
+
'OR REPLACE' is required for proper migration support.
|
|
137
|
+
MSG
|
|
138
|
+
|
|
139
|
+
trigger_name = result.first.last.downcase.sub('.', '_')
|
|
140
|
+
raise ArgumentError, <<~MSG.squish if trigger_name != name.downcase
|
|
141
|
+
Trigger name must match file name.
|
|
142
|
+
MSG
|
|
143
|
+
|
|
144
|
+
functions = content.scan(Regexp.new([
|
|
145
|
+
'^\s*CREATE\s+(OR\s+REPLACE)?\s*',
|
|
146
|
+
"FUNCTION\\s+#{NAME_MATCH}",
|
|
147
|
+
].join, 'mi'))
|
|
148
|
+
return if functions.empty?
|
|
149
|
+
|
|
150
|
+
raise ArgumentError, <<~MSG.squish if functions.map(&:last).uniq(&:downcase).many?
|
|
151
|
+
Only one function can be bundled with a trigger.
|
|
152
|
+
MSG
|
|
153
|
+
|
|
154
|
+
raise ArgumentError, <<~MSG.squish unless functions.all?(&:first)
|
|
155
|
+
'OR REPLACE' is required for proper migration support.
|
|
156
|
+
MSG
|
|
157
|
+
end
|
|
158
|
+
|
|
120
159
|
# Validate that the content of the command is correct
|
|
121
160
|
def validate_view!(content, name)
|
|
122
161
|
result = content.scan(Regexp.new([
|
data/lib/torque/postgresql.rb
CHANGED
|
@@ -14,8 +14,6 @@ require 'torque/postgresql/config'
|
|
|
14
14
|
require 'torque/postgresql/version'
|
|
15
15
|
require 'torque/postgresql/collector'
|
|
16
16
|
require 'torque/postgresql/geometry_builder'
|
|
17
|
-
require 'torque/postgresql/attributes/ltree'
|
|
18
|
-
require 'torque/postgresql/attributes/lquery'
|
|
19
17
|
require 'torque/postgresql/predicate_table'
|
|
20
18
|
require 'torque/postgresql/predicate_builder'
|
|
21
19
|
|
data/sig/manifest.yaml
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module Torque
|
|
2
|
+
module PostgreSQL
|
|
3
|
+
module Adapter
|
|
4
|
+
module DatabaseStatements
|
|
5
|
+
EXTENDED_DATABASE_TYPES: Array[Symbol]
|
|
6
|
+
|
|
7
|
+
@_dump_mode: bool
|
|
8
|
+
@schemas_blacklist: Array[String]
|
|
9
|
+
@schemas_whitelist: Array[String]
|
|
10
|
+
@schemas_search_path_sanitized: Array[String]
|
|
11
|
+
|
|
12
|
+
def dump_mode!: () -> bool
|
|
13
|
+
def schemas_blacklist: () -> Array[String]
|
|
14
|
+
def schemas_whitelist: () -> Array[String]
|
|
15
|
+
def schemas_search_path_sanitized: () -> Array[String]
|
|
16
|
+
def valid_type?: (Symbol | String type) -> bool
|
|
17
|
+
def extended_types: () -> Array[Symbol]
|
|
18
|
+
def schema_exists?: (table_ref name, ?filtered: bool) -> bool
|
|
19
|
+
def type_exists?: (table_ref name) -> bool
|
|
20
|
+
alias data_type_exists? type_exists?
|
|
21
|
+
def initialize_type_map: (?untyped m) -> untyped
|
|
22
|
+
def load_additional_types: (?Array[Integer]? oids) -> untyped
|
|
23
|
+
def torque_load_additional_types: (?Array[Integer]? oids) -> untyped
|
|
24
|
+
def torque_load_additional_types?: () -> bool
|
|
25
|
+
def composite_column_types: (table_ref name) -> Hash[String, type_caster]
|
|
26
|
+
def composite_types: () -> Array[String]
|
|
27
|
+
def user_defined_types: (*String? categories) -> Hash[String, String]
|
|
28
|
+
def inherited_tables: () -> Hash[String, Array[String]]
|
|
29
|
+
def user_defined_schemas: () -> Array[String]
|
|
30
|
+
def user_defined_schemas_sql: () -> String
|
|
31
|
+
def column_definitions: (table_ref table_name) -> Array[Array[untyped]]
|
|
32
|
+
def list_versioned_commands: (Symbol type) -> Array[[String, String]]
|
|
33
|
+
def filter_by_schema: () -> Array[String]
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def composite_type_dependencies: () -> Hash[String, Array[String]]
|
|
38
|
+
def sort_composite_type: (String name, Hash[String, Array[String]] dependencies, Array[String] result) -> Array[String]?
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module Torque
|
|
2
|
+
module PostgreSQL
|
|
3
|
+
module Adapter
|
|
4
|
+
module InheritanceStatements
|
|
5
|
+
type features = Hash[Symbol, bool]
|
|
6
|
+
type tree = Array[[String, Array[String]]]
|
|
7
|
+
|
|
8
|
+
SYNC_MARKER: String
|
|
9
|
+
SYNC_FEATURES: Array[Symbol]
|
|
10
|
+
|
|
11
|
+
def sync_inheritance_features: (table_ref table_name, ?table_ref | Array[table_ref] | nil children, ?prune: bool, **bool features) -> tree
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
def sync_inheritance_tree: (table_ref table_name, table_ref | Array[table_ref] | nil children) -> tree
|
|
16
|
+
def sync_inheritance_descendants: (Hash[String, Array[String]] dependencies, String table_name) -> Array[String]
|
|
17
|
+
def sync_inheritance_selection: (Hash[Symbol, bool] | bool features) -> features
|
|
18
|
+
def sync_inheritance_into: (String child, Array[String] parents, features features, bool prune) -> untyped
|
|
19
|
+
def sync_inheritance_primary_key: (String child, Array[String] parents) -> untyped
|
|
20
|
+
def sync_inheritance_indexes: (String child, Array[String] parents, features features, bool prune) -> untyped
|
|
21
|
+
def sync_inheritance_unique_constraints: (String child, Array[String] parents, bool prune) -> untyped
|
|
22
|
+
def sync_inheritance_exclusion_constraints: (String child, Array[String] parents, bool prune) -> untyped
|
|
23
|
+
def sync_inheritance_foreign_keys: (String child, Array[String] parents, bool prune) -> untyped
|
|
24
|
+
def sync_inheritance_name: (String child, String parent, String source) -> String
|
|
25
|
+
def sync_inheritance_copy?: (String | Symbol name) -> bool
|
|
26
|
+
def sync_inheritance_stale: (Array[untyped] existing, Hash[String, untyped] expected) -> Array[String]
|
|
27
|
+
def sync_inheritance_constraint_indexes: (String table_name, ?features? features) -> Array[String]
|
|
28
|
+
def sync_inheritance_index_options: (ActiveRecord::ConnectionAdapters::IndexDefinition index) -> Hash[Symbol, untyped]
|
|
29
|
+
def sync_inheritance_index?: (ActiveRecord::ConnectionAdapters::IndexDefinition current, ActiveRecord::ConnectionAdapters::IndexDefinition source) -> bool
|
|
30
|
+
def sync_inheritance_exclusion?: (untyped current, untyped source) -> bool
|
|
31
|
+
def sync_inheritance_foreign_key?: (untyped current, untyped source) -> bool
|
|
32
|
+
def sync_inheritance_parent_primary_key?: (table_ref table_name) -> bool
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module Torque
|
|
2
|
+
module PostgreSQL
|
|
3
|
+
module Adapter
|
|
4
|
+
module OID
|
|
5
|
+
module Array
|
|
6
|
+
def force_equality?: (untyped value) -> bool
|
|
7
|
+
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
def type_cast_array: (untyped value, Symbol method) -> untyped
|
|
11
|
+
def path_subtype?: () -> bool
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
class ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Array[unchecked out Elem]
|
|
19
|
+
prepend Torque::PostgreSQL::Adapter::OID::Array
|
|
20
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module Torque
|
|
2
|
+
module PostgreSQL
|
|
3
|
+
class Box < ::Struct[untyped]
|
|
4
|
+
def x1: () -> Numeric
|
|
5
|
+
def x1=: (Numeric value) -> Numeric
|
|
6
|
+
def y1: () -> Numeric
|
|
7
|
+
def y1=: (Numeric value) -> Numeric
|
|
8
|
+
def x2: () -> Numeric
|
|
9
|
+
def x2=: (Numeric value) -> Numeric
|
|
10
|
+
def y2: () -> Numeric
|
|
11
|
+
def y2=: (Numeric value) -> Numeric
|
|
12
|
+
|
|
13
|
+
def points: () -> Array[untyped]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
module Adapter
|
|
17
|
+
module OID
|
|
18
|
+
class Box < Torque::PostgreSQL::GeometryBuilder
|
|
19
|
+
PIECES: ::Array[Symbol]
|
|
20
|
+
FORMATION: String
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
class ActiveRecord::Box < Torque::PostgreSQL::Box
|
|
28
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module Torque
|
|
2
|
+
module PostgreSQL
|
|
3
|
+
class Circle < ::Struct[untyped]
|
|
4
|
+
def x: () -> Numeric
|
|
5
|
+
def x=: (Numeric value) -> Numeric
|
|
6
|
+
def y: () -> Numeric
|
|
7
|
+
def y=: (Numeric value) -> Numeric
|
|
8
|
+
def r: () -> Numeric
|
|
9
|
+
def r=: (Numeric value) -> Numeric
|
|
10
|
+
alias radius r
|
|
11
|
+
alias radius= r=
|
|
12
|
+
|
|
13
|
+
def center: () -> untyped
|
|
14
|
+
def center=: (untyped value) -> Numeric
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def point_class: () -> Class
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
module Adapter
|
|
22
|
+
module OID
|
|
23
|
+
class Circle < Torque::PostgreSQL::GeometryBuilder
|
|
24
|
+
PIECES: ::Array[Symbol]
|
|
25
|
+
FORMATION: String
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
class ActiveRecord::Circle < Torque::PostgreSQL::Circle
|
|
33
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module Torque
|
|
2
|
+
module PostgreSQL
|
|
3
|
+
module Adapter
|
|
4
|
+
module OID
|
|
5
|
+
class Composite < ActiveModel::Type::Value
|
|
6
|
+
ARRAY: singleton(ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Array)
|
|
7
|
+
DATA: untyped
|
|
8
|
+
ENCODER: untyped
|
|
9
|
+
DECODER: untyped
|
|
10
|
+
|
|
11
|
+
attr_reader name: String
|
|
12
|
+
|
|
13
|
+
def self.from: (untyped type) -> Composite?
|
|
14
|
+
def self.create: (Hash[String, untyped] row, ActiveRecord::Type::HashLookupTypeMap type_map) -> untyped
|
|
15
|
+
def initialize: (table_ref name) -> void
|
|
16
|
+
def klass: () -> singleton(Attributes::Composite)
|
|
17
|
+
def columns: () -> Hash[String, type_caster]
|
|
18
|
+
def type: () -> :composite
|
|
19
|
+
def cast: (untyped value) -> untyped
|
|
20
|
+
def deserialize: (untyped value) -> Attributes::Composite?
|
|
21
|
+
def serialize: (untyped value) -> untyped
|
|
22
|
+
def changed_in_place?: (untyped raw_old_value, untyped new_value) -> bool
|
|
23
|
+
def ==: (untyped other) -> bool
|
|
24
|
+
alias eql? ==
|
|
25
|
+
def hash: () -> Integer
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def build: (Hash[column_ref, untyped] attrs) -> Attributes::Composite
|
|
30
|
+
def attributes_of: (Attributes::Composite record) -> ActiveModel::AttributeSet
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module Torque
|
|
2
|
+
module PostgreSQL
|
|
3
|
+
module Adapter
|
|
4
|
+
module OID
|
|
5
|
+
class Enum < ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Enum
|
|
6
|
+
type row = Hash[String, untyped]
|
|
7
|
+
|
|
8
|
+
attr_reader name: String
|
|
9
|
+
attr_reader klass: singleton(Attributes::Enum) | singleton(Attributes::EnumSet)
|
|
10
|
+
attr_reader set_klass: EnumSet?
|
|
11
|
+
attr_reader enum_klass: Enum | singleton(Attributes::Enum)
|
|
12
|
+
|
|
13
|
+
def self.create: (row row, ActiveRecord::Type::HashLookupTypeMap type_map) -> untyped
|
|
14
|
+
def initialize: (String name) -> void
|
|
15
|
+
def hash: () -> Integer
|
|
16
|
+
def serialize: (untyped value) -> String?
|
|
17
|
+
def assert_valid_value: (untyped value) -> untyped
|
|
18
|
+
def type_cast_for_schema: (untyped value) -> String
|
|
19
|
+
def ==: (untyped other) -> bool
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def cast_value: (untyped value) -> untyped
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Torque
|
|
2
|
+
module PostgreSQL
|
|
3
|
+
module Adapter
|
|
4
|
+
module OID
|
|
5
|
+
class EnumSet < Enum
|
|
6
|
+
def initialize: (String name, singleton(Attributes::Enum) enum_klass) -> void
|
|
7
|
+
def type: () -> :enum
|
|
8
|
+
def deserialize: (untyped value) -> untyped
|
|
9
|
+
def serialize: (untyped value) -> String?
|
|
10
|
+
def type_cast_for_schema: (untyped value) -> String
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
def cast_value: (untyped value) -> untyped
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module Torque
|
|
2
|
+
module PostgreSQL
|
|
3
|
+
module Adapter
|
|
4
|
+
module OID
|
|
5
|
+
class Interval < ActiveModel::Type::Value
|
|
6
|
+
CAST_PARTS: ::Array[Symbol]
|
|
7
|
+
|
|
8
|
+
def type: () -> :interval
|
|
9
|
+
def cast: (untyped value) -> untyped
|
|
10
|
+
def deserialize: (String? value) -> ActiveSupport::Duration?
|
|
11
|
+
def serialize: (untyped value) -> String?
|
|
12
|
+
def type_cast_for_schema: (untyped value) -> String
|
|
13
|
+
def assert_valid_value: (untyped value) -> nil
|
|
14
|
+
def parts_to_duration: (Hash[untyped, untyped] | ::Array[untyped] parts) -> ActiveSupport::Duration
|
|
15
|
+
def remove_weeks: (ActiveSupport::Duration value) -> ActiveSupport::Duration
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module Torque
|
|
2
|
+
module PostgreSQL
|
|
3
|
+
class Line < ::Struct[untyped]
|
|
4
|
+
def slope: () -> (Rational | Float)
|
|
5
|
+
def slope=: (Rational | Float value) -> (Rational | Float)
|
|
6
|
+
def intercept: () -> Numeric
|
|
7
|
+
def intercept=: (Numeric value) -> Numeric
|
|
8
|
+
alias c intercept
|
|
9
|
+
alias c= intercept=
|
|
10
|
+
|
|
11
|
+
def a=: (Numeric value) -> (Rational | Float)
|
|
12
|
+
def a: () -> Numeric
|
|
13
|
+
def b=: (Numeric value) -> (Rational | Float)
|
|
14
|
+
def b: () -> Numeric
|
|
15
|
+
def horizontal?: () -> bool
|
|
16
|
+
def vertical?: () -> bool
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
module Adapter
|
|
20
|
+
module OID
|
|
21
|
+
class Line < Torque::PostgreSQL::GeometryBuilder
|
|
22
|
+
PIECES: ::Array[Symbol]
|
|
23
|
+
FORMATION: String
|
|
24
|
+
|
|
25
|
+
def build_klass: (*untyped args) -> untyped
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
class ActiveRecord::Line < Torque::PostgreSQL::Line
|
|
33
|
+
end
|