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.
Files changed (194) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +28 -0
  3. data/lib/generators/torque/skill_generator.rb +17 -0
  4. data/lib/generators/torque/templates/trigger.sql.erb +3 -0
  5. data/lib/generators/torque/trigger_generator.rb +13 -0
  6. data/lib/torque/postgresql/adapter/database_statements.rb +9 -0
  7. data/lib/torque/postgresql/adapter/oid/array.rb +0 -4
  8. data/lib/torque/postgresql/adapter/oid/composite.rb +2 -1
  9. data/lib/torque/postgresql/adapter/oid/enum.rb +1 -1
  10. data/lib/torque/postgresql/adapter/oid/enum_set.rb +2 -2
  11. data/lib/torque/postgresql/adapter/oid/interval.rb +1 -1
  12. data/lib/torque/postgresql/adapter/oid/lquery.rb +45 -28
  13. data/lib/torque/postgresql/adapter/oid/ltree.rb +67 -9
  14. data/lib/torque/postgresql/adapter/oid/struct.rb +1 -1
  15. data/lib/torque/postgresql/adapter/oid.rb +13 -0
  16. data/lib/torque/postgresql/adapter/schema_definitions.rb +5 -0
  17. data/lib/torque/postgresql/adapter/schema_dumper.rb +1 -0
  18. data/lib/torque/postgresql/arel/nodes.rb +51 -0
  19. data/lib/torque/postgresql/arel/visitors.rb +46 -0
  20. data/lib/torque/postgresql/attributes/base.rb +10 -7
  21. data/lib/torque/postgresql/attributes/composite.rb +1 -5
  22. data/lib/torque/postgresql/attributes/enum.rb +1 -6
  23. data/lib/torque/postgresql/attributes/lquery.rb +67 -127
  24. data/lib/torque/postgresql/attributes/ltree.rb +35 -83
  25. data/lib/torque/postgresql/base.rb +9 -1
  26. data/lib/torque/postgresql/config.rb +21 -3
  27. data/lib/torque/postgresql/geometry_builder.rb +4 -10
  28. data/lib/torque/postgresql/inheritance.rb +5 -5
  29. data/lib/torque/postgresql/predicate_builder/arel_attribute_handler.rb +1 -1
  30. data/lib/torque/postgresql/predicate_builder/array_handler.rb +16 -8
  31. data/lib/torque/postgresql/predicate_builder/composite_handler.rb +18 -5
  32. data/lib/torque/postgresql/predicate_builder/ltree_handler.rb +86 -18
  33. data/lib/torque/postgresql/predicate_builder/struct_handler.rb +29 -9
  34. data/lib/torque/postgresql/predicate_builder.rb +38 -11
  35. data/lib/torque/postgresql/railtie.rb +17 -0
  36. data/lib/torque/postgresql/relation/auxiliary_statement.rb +7 -3
  37. data/lib/torque/postgresql/relation/buckets.rb +2 -1
  38. data/lib/torque/postgresql/relation/cross_join.rb +193 -0
  39. data/lib/torque/postgresql/relation/inheritance.rb +1 -2
  40. data/lib/torque/postgresql/relation/join_series.rb +1 -0
  41. data/lib/torque/postgresql/relation/merger.rb +9 -0
  42. data/lib/torque/postgresql/relation/segments.rb +140 -0
  43. data/lib/torque/postgresql/relation.rb +23 -4
  44. data/lib/torque/postgresql/version.rb +1 -1
  45. data/lib/torque/postgresql/versioned_commands/command_migration.rb +23 -0
  46. data/lib/torque/postgresql/versioned_commands.rb +39 -0
  47. data/lib/torque/postgresql.rb +0 -2
  48. data/sig/generators/torque/function_generator.rbs +9 -0
  49. data/sig/generators/torque/skill_generator.rbs +7 -0
  50. data/sig/generators/torque/trigger_generator.rbs +9 -0
  51. data/sig/generators/torque/type_generator.rbs +9 -0
  52. data/sig/generators/torque/view_generator.rbs +9 -0
  53. data/sig/manifest.yaml +7 -0
  54. data/sig/torque/postgresql/adapter/database_statements.rbs +42 -0
  55. data/sig/torque/postgresql/adapter/inheritance_statements.rbs +36 -0
  56. data/sig/torque/postgresql/adapter/oid/array.rbs +20 -0
  57. data/sig/torque/postgresql/adapter/oid/box.rbs +28 -0
  58. data/sig/torque/postgresql/adapter/oid/circle.rbs +33 -0
  59. data/sig/torque/postgresql/adapter/oid/composite.rbs +35 -0
  60. data/sig/torque/postgresql/adapter/oid/enum.rbs +28 -0
  61. data/sig/torque/postgresql/adapter/oid/enum_set.rbs +19 -0
  62. data/sig/torque/postgresql/adapter/oid/interval.rbs +20 -0
  63. data/sig/torque/postgresql/adapter/oid/line.rbs +33 -0
  64. data/sig/torque/postgresql/adapter/oid/lquery.rbs +21 -0
  65. data/sig/torque/postgresql/adapter/oid/ltree.rbs +32 -0
  66. data/sig/torque/postgresql/adapter/oid/range.rbs +28 -0
  67. data/sig/torque/postgresql/adapter/oid/segment.rbs +38 -0
  68. data/sig/torque/postgresql/adapter/oid/struct.rbs +41 -0
  69. data/sig/torque/postgresql/adapter/oid/struct_list.rbs +20 -0
  70. data/sig/torque/postgresql/adapter/oid/struct_set.rbs +18 -0
  71. data/sig/torque/postgresql/adapter/oid.rbs +9 -0
  72. data/sig/torque/postgresql/adapter/quoting.rbs +20 -0
  73. data/sig/torque/postgresql/adapter/schema_creation.rbs +13 -0
  74. data/sig/torque/postgresql/adapter/schema_definitions.rbs +55 -0
  75. data/sig/torque/postgresql/adapter/schema_dumper.rbs +37 -0
  76. data/sig/torque/postgresql/adapter/schema_overrides.rbs +46 -0
  77. data/sig/torque/postgresql/adapter/schema_statements.rbs +50 -0
  78. data/sig/torque/postgresql/adapter.rbs +24 -0
  79. data/sig/torque/postgresql/arel/infix_operation.rbs +79 -0
  80. data/sig/torque/postgresql/arel/join_source.rbs +19 -0
  81. data/sig/torque/postgresql/arel/nodes.rbs +83 -0
  82. data/sig/torque/postgresql/arel/operations.rbs +28 -0
  83. data/sig/torque/postgresql/arel/select_manager.rbs +15 -0
  84. data/sig/torque/postgresql/arel/visitors.rbs +30 -0
  85. data/sig/torque/postgresql/arel.rbs +6 -0
  86. data/sig/torque/postgresql/associations/association_scope.rbs +28 -0
  87. data/sig/torque/postgresql/associations/belongs_to_many_association.rbs +51 -0
  88. data/sig/torque/postgresql/associations/builder/belongs_to_many.rbs +24 -0
  89. data/sig/torque/postgresql/associations/builder/has_many.rbs +15 -0
  90. data/sig/torque/postgresql/associations/builder.rbs +8 -0
  91. data/sig/torque/postgresql/associations/foreign_association.rbs +16 -0
  92. data/sig/torque/postgresql/associations/join_dependency.rbs +16 -0
  93. data/sig/torque/postgresql/associations/preloader/association.rbs +32 -0
  94. data/sig/torque/postgresql/associations/preloader/loader_query.rbs +20 -0
  95. data/sig/torque/postgresql/associations/preloader.rbs +8 -0
  96. data/sig/torque/postgresql/associations.rbs +17 -0
  97. data/sig/torque/postgresql/attributes/base.rbs +37 -0
  98. data/sig/torque/postgresql/attributes/builder/enum.rbs +38 -0
  99. data/sig/torque/postgresql/attributes/builder/full_text_search.rbs +27 -0
  100. data/sig/torque/postgresql/attributes/builder/period.rbs +106 -0
  101. data/sig/torque/postgresql/attributes/builder.rbs +19 -0
  102. data/sig/torque/postgresql/attributes/composite.rbs +28 -0
  103. data/sig/torque/postgresql/attributes/enum.rbs +69 -0
  104. data/sig/torque/postgresql/attributes/enum_set.rbs +75 -0
  105. data/sig/torque/postgresql/attributes/full_text_search.rbs +13 -0
  106. data/sig/torque/postgresql/attributes/lazy.rbs +17 -0
  107. data/sig/torque/postgresql/attributes/lquery.rbs +48 -0
  108. data/sig/torque/postgresql/attributes/ltree.rbs +46 -0
  109. data/sig/torque/postgresql/attributes/period.rbs +13 -0
  110. data/sig/torque/postgresql/attributes/simple_enum.rbs +39 -0
  111. data/sig/torque/postgresql/attributes/struct.rbs +38 -0
  112. data/sig/torque/postgresql/attributes.rbs +6 -0
  113. data/sig/torque/postgresql/autosave_association.rbs +16 -0
  114. data/sig/torque/postgresql/auxiliary_statement/recursive.rbs +22 -0
  115. data/sig/torque/postgresql/auxiliary_statement/settings.rbs +63 -0
  116. data/sig/torque/postgresql/auxiliary_statement.rbs +57 -0
  117. data/sig/torque/postgresql/base.rbs +41 -0
  118. data/sig/torque/postgresql/collector.rbs +7 -0
  119. data/sig/torque/postgresql/config.rbs +9 -0
  120. data/sig/torque/postgresql/function.rbs +21 -0
  121. data/sig/torque/postgresql/geometry_builder.rbs +20 -0
  122. data/sig/torque/postgresql/i18n.rbs +15 -0
  123. data/sig/torque/postgresql/inheritance/expander.rbs +23 -0
  124. data/sig/torque/postgresql/inheritance/record.rbs +20 -0
  125. data/sig/torque/postgresql/inheritance.rbs +47 -0
  126. data/sig/torque/postgresql/insert_all.rbs +22 -0
  127. data/sig/torque/postgresql/migration/command_recorder.rbs +30 -0
  128. data/sig/torque/postgresql/migration.rbs +6 -0
  129. data/sig/torque/postgresql/predicate_builder/arel_attribute_handler.rbs +15 -0
  130. data/sig/torque/postgresql/predicate_builder/array_handler.rbs +26 -0
  131. data/sig/torque/postgresql/predicate_builder/composite_handler.rbs +26 -0
  132. data/sig/torque/postgresql/predicate_builder/enumerator_lazy_handler.rbs +18 -0
  133. data/sig/torque/postgresql/predicate_builder/ltree_handler.rbs +36 -0
  134. data/sig/torque/postgresql/predicate_builder/regexp_handler.rbs +16 -0
  135. data/sig/torque/postgresql/predicate_builder/struct_handler.rbs +24 -0
  136. data/sig/torque/postgresql/predicate_builder.rbs +23 -0
  137. data/sig/torque/postgresql/predicate_table.rbs +24 -0
  138. data/sig/torque/postgresql/railtie.rbs +10 -0
  139. data/sig/torque/postgresql/reflection/abstract_reflection.rbs +22 -0
  140. data/sig/torque/postgresql/reflection/association_reflection.rbs +18 -0
  141. data/sig/torque/postgresql/reflection/belongs_to_many_reflection.rbs +30 -0
  142. data/sig/torque/postgresql/reflection/has_many_reflection.rbs +14 -0
  143. data/sig/torque/postgresql/reflection/runtime_reflection.rbs +18 -0
  144. data/sig/torque/postgresql/reflection/through_reflection.rbs +14 -0
  145. data/sig/torque/postgresql/reflection.rbs +11 -0
  146. data/sig/torque/postgresql/relation/auxiliary_statement.rbs +29 -0
  147. data/sig/torque/postgresql/relation/buckets.rbs +35 -0
  148. data/sig/torque/postgresql/relation/cross_join.rbs +63 -0
  149. data/sig/torque/postgresql/relation/distinct_on.rbs +16 -0
  150. data/sig/torque/postgresql/relation/inheritance.rbs +48 -0
  151. data/sig/torque/postgresql/relation/join_series.rbs +28 -0
  152. data/sig/torque/postgresql/relation/merger.rbs +23 -0
  153. data/sig/torque/postgresql/relation/segments.rbs +27 -0
  154. data/sig/torque/postgresql/relation.rbs +48 -0
  155. data/sig/torque/postgresql/schema_cache/bound_schema_reflection.rbs +14 -0
  156. data/sig/torque/postgresql/schema_cache/inheritance.rbs +12 -0
  157. data/sig/torque/postgresql/schema_cache/schema_reflection.rbs +14 -0
  158. data/sig/torque/postgresql/schema_cache.rbs +43 -0
  159. data/sig/torque/postgresql/table_name.rbs +20 -0
  160. data/sig/torque/postgresql/validations.rbs +13 -0
  161. data/sig/torque/postgresql/version.rbs +5 -0
  162. data/sig/torque/postgresql/versioned_commands/command_migration.rbs +54 -0
  163. data/sig/torque/postgresql/versioned_commands/generator.rbs +17 -0
  164. data/sig/torque/postgresql/versioned_commands/migration_context.rbs +30 -0
  165. data/sig/torque/postgresql/versioned_commands/migrator.rbs +19 -0
  166. data/sig/torque/postgresql/versioned_commands/schema_table.rbs +23 -0
  167. data/sig/torque/postgresql/versioned_commands.rbs +25 -0
  168. data/sig/torque/postgresql.rbs +26 -0
  169. data/skills/torque-postgresql/SKILL.md +70 -0
  170. data/spec/fixtures/migrations/20250101000008_create_trigger_audit_users_v1.sql +3 -0
  171. data/spec/initialize.rb +9 -0
  172. data/spec/mocks/cache_query.rb +1 -1
  173. data/spec/rbs_helper.rb +8 -0
  174. data/spec/schema.rb +2 -0
  175. data/spec/spec_helper.rb +1 -0
  176. data/spec/tests/arel_spec.rb +1 -3
  177. data/spec/tests/auxiliary_statement_spec.rb +12 -0
  178. data/spec/tests/buckets_spec.rb +122 -0
  179. data/spec/tests/composite_spec.rb +67 -0
  180. data/spec/tests/cross_join_spec.rb +185 -0
  181. data/spec/tests/distinct_on_spec.rb +5 -0
  182. data/spec/tests/enum_set_spec.rb +4 -0
  183. data/spec/tests/enum_spec.rb +20 -4
  184. data/spec/tests/geometric_builder_spec.rb +16 -5
  185. data/spec/tests/has_many_spec.rb +2 -1
  186. data/spec/tests/interval_spec.rb +6 -0
  187. data/spec/tests/ltree_spec.rb +398 -64
  188. data/spec/tests/predicate_builder_spec.rb +120 -0
  189. data/spec/tests/relation_spec.rb +25 -69
  190. data/spec/tests/segments_spec.rb +264 -0
  191. data/spec/tests/struct_spec.rb +202 -0
  192. data/spec/tests/table_inheritance_spec.rb +10 -0
  193. data/spec/tests/versioned_commands_spec.rb +145 -0
  194. 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[itself_only buckets expand_records_eager_load expand_records_scoped]
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
- caster = connection.lookup_cast_type_for_column(column)
92
- connection.type_cast(caster.serialize(value))
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
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Torque
4
4
  module PostgreSQL
5
- VERSION = '4.1.0'
5
+ VERSION = '4.1.1'
6
6
  end
7
7
  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([
@@ -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
 
@@ -0,0 +1,9 @@
1
+ module Torque
2
+ module Generators
3
+ class FunctionGenerator < Rails::Generators::Base
4
+ include Torque::PostgreSQL::VersionedCommands::Generator
5
+
6
+ alias create_function_file create_migration_file
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,7 @@
1
+ module Torque
2
+ module Generators
3
+ class SkillGenerator < Rails::Generators::Base
4
+ def copy_skill: () -> void
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,9 @@
1
+ module Torque
2
+ module Generators
3
+ class TriggerGenerator < Rails::Generators::Base
4
+ include Torque::PostgreSQL::VersionedCommands::Generator
5
+
6
+ alias create_trigger_file create_migration_file
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Torque
2
+ module Generators
3
+ class TypeGenerator < Rails::Generators::Base
4
+ include Torque::PostgreSQL::VersionedCommands::Generator
5
+
6
+ alias create_type_file create_migration_file
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Torque
2
+ module Generators
3
+ class ViewGenerator < Rails::Generators::Base
4
+ include Torque::PostgreSQL::VersionedCommands::Generator
5
+
6
+ alias create_view_file create_migration_file
7
+ end
8
+ end
9
+ end
data/sig/manifest.yaml ADDED
@@ -0,0 +1,7 @@
1
+ dependencies:
2
+ - name: delegate
3
+ - name: date
4
+ - name: monitor
5
+ - name: rubygems
6
+ - name: stringio
7
+ - name: timeout
@@ -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