torque-postgresql 4.0.1 → 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 +52 -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 +98 -7
- data/lib/torque/postgresql/adapter/inheritance_statements.rb +297 -0
- data/lib/torque/postgresql/adapter/oid/array.rb +13 -0
- data/lib/torque/postgresql/adapter/oid/box.rb +1 -1
- data/lib/torque/postgresql/adapter/oid/circle.rb +1 -1
- data/lib/torque/postgresql/adapter/oid/composite.rb +117 -0
- 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/line.rb +1 -1
- data/lib/torque/postgresql/adapter/oid/lquery.rb +70 -0
- data/lib/torque/postgresql/adapter/oid/ltree.rb +111 -0
- data/lib/torque/postgresql/adapter/oid/segment.rb +1 -1
- data/lib/torque/postgresql/adapter/oid/struct.rb +150 -0
- data/lib/torque/postgresql/adapter/oid/struct_list.rb +52 -0
- data/lib/torque/postgresql/adapter/oid/struct_set.rb +38 -0
- data/lib/torque/postgresql/adapter/oid.rb +13 -0
- data/lib/torque/postgresql/adapter/quoting.rb +11 -2
- data/lib/torque/postgresql/adapter/schema_definitions.rb +51 -0
- data/lib/torque/postgresql/adapter/schema_dumper.rb +27 -0
- data/lib/torque/postgresql/adapter/schema_statements.rb +207 -0
- data/lib/torque/postgresql/adapter.rb +2 -5
- data/lib/torque/postgresql/arel/nodes.rb +114 -1
- data/lib/torque/postgresql/arel/visitors.rb +65 -8
- data/lib/torque/postgresql/associations/join_dependency.rb +55 -0
- data/lib/torque/postgresql/associations.rb +3 -0
- data/lib/torque/postgresql/attributes/base.rb +97 -0
- data/lib/torque/postgresql/attributes/composite.rb +98 -0
- data/lib/torque/postgresql/attributes/enum.rb +13 -7
- data/lib/torque/postgresql/attributes/lquery.rb +120 -0
- data/lib/torque/postgresql/attributes/ltree.rb +121 -0
- data/lib/torque/postgresql/attributes/simple_enum.rb +72 -0
- data/lib/torque/postgresql/attributes/struct.rb +137 -0
- data/lib/torque/postgresql/base.rb +26 -15
- data/lib/torque/postgresql/config.rb +100 -15
- data/lib/torque/postgresql/geometry_builder.rb +4 -10
- data/lib/torque/postgresql/inheritance/expander.rb +66 -0
- data/lib/torque/postgresql/inheritance/record.rb +52 -0
- data/lib/torque/postgresql/inheritance.rb +141 -68
- data/lib/torque/postgresql/migration/command_recorder.rb +76 -0
- 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 +122 -0
- data/lib/torque/postgresql/predicate_builder/ltree_handler.rb +112 -0
- data/lib/torque/postgresql/predicate_builder/struct_handler.rb +88 -0
- data/lib/torque/postgresql/predicate_builder.rb +53 -0
- data/lib/torque/postgresql/predicate_table.rb +61 -0
- data/lib/torque/postgresql/railtie.rb +52 -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 +145 -28
- data/lib/torque/postgresql/relation/join_series.rb +1 -0
- data/lib/torque/postgresql/relation/merger.rb +30 -5
- data/lib/torque/postgresql/relation/segments.rb +140 -0
- data/lib/torque/postgresql/relation.rb +32 -12
- data/lib/torque/postgresql/schema_cache.rb +1 -0
- data/lib/torque/postgresql/validations.rb +29 -0
- data/lib/torque/postgresql/version.rb +1 -1
- data/lib/torque/postgresql/versioned_commands/command_migration.rb +24 -1
- data/lib/torque/postgresql/versioned_commands.rb +39 -0
- data/lib/torque/postgresql.rb +4 -0
- 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 +29 -2
- data/spec/mocks/cache_query.rb +13 -1
- data/spec/models/author.rb +1 -1
- data/spec/models/comment.rb +2 -0
- data/spec/models/place.rb +2 -0
- data/spec/models/profile.rb +31 -0
- data/spec/rbs_helper.rb +8 -0
- data/spec/schema.rb +35 -4
- data/spec/spec_helper.rb +1 -0
- data/spec/tests/arel_spec.rb +3 -3
- data/spec/tests/auxiliary_statement_spec.rb +12 -0
- data/spec/tests/buckets_spec.rb +122 -0
- data/spec/tests/composite_spec.rb +867 -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 +886 -0
- 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 +1170 -0
- data/spec/tests/table_inheritance_spec.rb +1037 -56
- data/spec/tests/versioned_commands_spec.rb +145 -0
- metadata +198 -2
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module Torque
|
|
2
|
+
module PostgreSQL
|
|
3
|
+
module VersionedCommands
|
|
4
|
+
module Migration
|
|
5
|
+
@command: CommandMigration
|
|
6
|
+
@description: [String, String]
|
|
7
|
+
@connection: connection?
|
|
8
|
+
@execution_strategy: untyped
|
|
9
|
+
|
|
10
|
+
def initialize: (*untyped args) -> void
|
|
11
|
+
def migrate: (:up | :down direction) -> untyped
|
|
12
|
+
def exec_migration: (connection conn, :up | :down direction) -> untyped
|
|
13
|
+
def announce: (String message) -> untyped
|
|
14
|
+
def description_for: (:up | :down direction) -> [String, String]
|
|
15
|
+
def execute: (String command) -> untyped
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
class CommandMigration < ::Struct[untyped]
|
|
19
|
+
@migration: ActiveRecord::Migration?
|
|
20
|
+
|
|
21
|
+
def filename: () -> String
|
|
22
|
+
def filename=: (String value) -> String
|
|
23
|
+
def version: () -> Integer
|
|
24
|
+
def version=: (Integer value) -> Integer
|
|
25
|
+
def op: () -> String
|
|
26
|
+
def op=: (String value) -> String
|
|
27
|
+
def type: () -> String
|
|
28
|
+
def type=: (String value) -> String
|
|
29
|
+
def object_name: () -> String
|
|
30
|
+
def object_name=: (String value) -> String
|
|
31
|
+
def op_version: () -> Integer
|
|
32
|
+
def op_version=: (Integer value) -> Integer
|
|
33
|
+
def scope: () -> String?
|
|
34
|
+
def scope=: (String? value) -> String?
|
|
35
|
+
|
|
36
|
+
def execute: (String command) -> untyped
|
|
37
|
+
def initialize: (String filename, *untyped args) -> void
|
|
38
|
+
def name: () -> String
|
|
39
|
+
def disable_ddl_transaction: () -> false
|
|
40
|
+
def migrate: (:up | :down direction) -> untyped
|
|
41
|
+
def up: () -> untyped
|
|
42
|
+
def down: () -> untyped
|
|
43
|
+
def drop: () -> untyped
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def drop_function: () -> untyped
|
|
48
|
+
def drop_type: () -> untyped
|
|
49
|
+
def drop_trigger: () -> untyped
|
|
50
|
+
def drop_view: () -> untyped
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Torque
|
|
2
|
+
module PostgreSQL
|
|
3
|
+
module VersionedCommands
|
|
4
|
+
module Generator
|
|
5
|
+
TEMPLATES_PATH: String
|
|
6
|
+
|
|
7
|
+
attr_reader file_name: String?
|
|
8
|
+
|
|
9
|
+
def self.included: (singleton(Rails::Generators::Base) base) -> untyped
|
|
10
|
+
def type: () -> String
|
|
11
|
+
def create_migration_file: () -> untyped
|
|
12
|
+
def count_object_entries: () -> Integer
|
|
13
|
+
def validate_file_name!: () -> nil
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Torque
|
|
2
|
+
module PostgreSQL
|
|
3
|
+
class IllegalCommandTypeError < ActiveRecord::MigrationError
|
|
4
|
+
def initialize: (String file) -> void
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
module VersionedCommands
|
|
8
|
+
module MigrationContext
|
|
9
|
+
type status = [String, String, String]
|
|
10
|
+
|
|
11
|
+
InvalidMigrationTimestampError: untyped
|
|
12
|
+
PGAdapter: singleton(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
|
|
13
|
+
|
|
14
|
+
def migrations: () -> Array[untyped]
|
|
15
|
+
def migrations_status: () -> Array[status]
|
|
16
|
+
def migration_commands: () -> Array[CommandMigration]
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def running_for_pg?: () -> bool
|
|
21
|
+
def command_files: () -> Array[String]
|
|
22
|
+
def parse_command_filename: (String filename) -> Array[String?]?
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
class ActiveRecord::MigrationContext
|
|
29
|
+
prepend Torque::PostgreSQL::VersionedCommands::MigrationContext
|
|
30
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Torque
|
|
2
|
+
module PostgreSQL
|
|
3
|
+
module VersionedCommands
|
|
4
|
+
module Migrator
|
|
5
|
+
@versioned_command: CommandMigration | false
|
|
6
|
+
@versioned_table: SchemaTable
|
|
7
|
+
@versioned_counter: Integer
|
|
8
|
+
|
|
9
|
+
def execute_migration_in_transaction: (untyped migration) -> untyped
|
|
10
|
+
def record_version_state_after_migrating: (Integer version) -> untyped
|
|
11
|
+
def versioned_command?: (untyped migration) -> bool
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
class ActiveRecord::Migrator
|
|
18
|
+
prepend Torque::PostgreSQL::VersionedCommands::Migrator
|
|
19
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Torque
|
|
2
|
+
module PostgreSQL
|
|
3
|
+
module VersionedCommands
|
|
4
|
+
class SchemaTable
|
|
5
|
+
attr_reader arel_table: arel_table
|
|
6
|
+
|
|
7
|
+
@pool: pool
|
|
8
|
+
|
|
9
|
+
def initialize: (pool pool) -> void
|
|
10
|
+
def create_version: (CommandMigration command) -> untyped
|
|
11
|
+
def delete_version: (CommandMigration command) -> Integer
|
|
12
|
+
def primary_key: () -> String
|
|
13
|
+
def name: () -> String
|
|
14
|
+
def table_name: () -> String
|
|
15
|
+
def create_table: () -> untyped
|
|
16
|
+
def drop_table: () -> untyped
|
|
17
|
+
def count: () -> Integer
|
|
18
|
+
def table_exists?: () -> bool
|
|
19
|
+
def versions_of: (Symbol | String type) -> Array[[String, Integer]]
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Torque
|
|
2
|
+
module PostgreSQL
|
|
3
|
+
module VersionedCommands
|
|
4
|
+
type command_type = :function | :type | :view | :trigger
|
|
5
|
+
type dirs = String | Array[String]
|
|
6
|
+
|
|
7
|
+
RAILS_APP: untyped
|
|
8
|
+
NAME_MATCH: String
|
|
9
|
+
|
|
10
|
+
@filename_regexp: Regexp
|
|
11
|
+
|
|
12
|
+
def self.valid_type?: (Symbol | String type) -> bool
|
|
13
|
+
def self.validate!: (Symbol | String type, String content, String name) -> nil
|
|
14
|
+
def self.fetch_command: (dirs dirs, Symbol | String type, String name, Integer | String version) -> String
|
|
15
|
+
def self.filename_regexp: () -> Regexp
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def self.validate_function!: (String content, String name) -> nil
|
|
20
|
+
def self.validate_type!: (String content, String name) -> nil
|
|
21
|
+
def self.validate_trigger!: (String content, String name) -> nil
|
|
22
|
+
def self.validate_view!: (String content, String name) -> nil
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Torque
|
|
2
|
+
module PostgreSQL
|
|
3
|
+
type model = singleton(ActiveRecord::Base)
|
|
4
|
+
type record = ActiveRecord::Base
|
|
5
|
+
type relation = ActiveRecord::Relation
|
|
6
|
+
type connection = ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
|
|
7
|
+
type pool = ActiveRecord::ConnectionAdapters::ConnectionPool
|
|
8
|
+
type reflection = ActiveRecord::Reflection::AssociationReflection
|
|
9
|
+
type any_reflection = ActiveRecord::Reflection::AbstractReflection
|
|
10
|
+
type column = ActiveRecord::ConnectionAdapters::PostgreSQL::Column
|
|
11
|
+
type type_caster = ActiveModel::Type::Value
|
|
12
|
+
type column_ref = String | Symbol
|
|
13
|
+
type table_ref = String | Symbol | ActiveRecord::ConnectionAdapters::PostgreSQL::Name
|
|
14
|
+
type arel_table = ::Arel::Table
|
|
15
|
+
type arel_attribute = ::Arel::Attributes::Attribute
|
|
16
|
+
type arel_node = ::Arel::Nodes::Node | ::Arel::Nodes::SqlLiteral | arel_attribute
|
|
17
|
+
type collector = ::Arel::Collectors::SQLString | ::Arel::Collectors::Composite | ::Arel::Collectors::Bind | ::Arel::Collectors::SubstituteBinds
|
|
18
|
+
type stream = IO | StringIO
|
|
19
|
+
type table_node = arel_table | ::Arel::Nodes::TableAlias
|
|
20
|
+
type path_key = column_ref | Integer
|
|
21
|
+
|
|
22
|
+
interface _Callable
|
|
23
|
+
def call: (*untyped) -> untyped
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: torque-postgresql
|
|
3
|
+
description: PostgreSQL features in Rails through the torque-postgresql gem. Use when writing models, migrations, or queries in an app whose Gemfile has torque-postgresql, or when a task needs a PostgreSQL type (enum, enum set, jsonb document, composite, ltree, range, interval, geometry) or query feature (CTE, DISTINCT ON, FILTER aggregates, width_bucket, generate_series, full-text search, array associations, table inheritance).
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# torque-postgresql
|
|
7
|
+
|
|
8
|
+
The gem exposes PostgreSQL features through the regular Rails DSL: migration methods that dump
|
|
9
|
+
to `schema.rb`, model macros, and relation methods. Reach for it before raw SQL.
|
|
10
|
+
|
|
11
|
+
## Steps
|
|
12
|
+
|
|
13
|
+
1. Locate the installed gem with `bundle info torque-postgresql`. Done when you know its version
|
|
14
|
+
and path.
|
|
15
|
+
2. Read the app's `Torque::PostgreSQL.configure` block (search `config/` for it). Done when you
|
|
16
|
+
know which features are off and which macros are renamed: every `base_method` key renames a
|
|
17
|
+
macro, and `versioned_commands` and `cross_join` stay off unless enabled there.
|
|
18
|
+
3. Pick the feature from the table below and read its docs page before writing code. Done when
|
|
19
|
+
the migration, the model macro, and the query you plan all appear on that page.
|
|
20
|
+
4. Check exact signatures in `<gem path>/sig/`, when the installed release ships one. Methods
|
|
21
|
+
generated per attribute (`admin?`, period scopes, `full_text_search`) are named on the docs
|
|
22
|
+
page, never in `sig/`.
|
|
23
|
+
5. Write the migration with the gem's DSL, run it, and confirm `db/schema.rb` dumps it.
|
|
24
|
+
|
|
25
|
+
## Features
|
|
26
|
+
|
|
27
|
+
Docs live at `https://torque.dev/postgresql/<page>/`. The index is
|
|
28
|
+
`https://torque.dev/postgresql/llms.txt`, and every page in one file is
|
|
29
|
+
`https://torque.dev/postgresql/llms-full.txt`.
|
|
30
|
+
|
|
31
|
+
| Need | Migration | Model or query | Page |
|
|
32
|
+
|---|---|---|---|
|
|
33
|
+
| Fixed list of values | `create_enum`, `t.enum enum_type:` | `torque_enum :role`, `Enum::Roles` | `data-types/enum` |
|
|
34
|
+
| Several values of one enum | `t.enum enum_type:, array: true` | `torque_enum_set :perms` | `data-types/enum-set` |
|
|
35
|
+
| Typed jsonb document | `t.jsonb` | `struct_for :settings, Klass` | `data-types/struct` |
|
|
36
|
+
| Database composite type | `create_composite_type`, `t.composite composite_type:` | `Composite::Address` | `data-types/composite` |
|
|
37
|
+
| Tree paths | `enable_extension 'ltree'`, `t.ltree`, `t.lquery` | `where(path: ...)` | `data-types/ltree` |
|
|
38
|
+
| Time windows | `t.tsrange`, `t.daterange` | `period_for :period` | `data-types/date-time-range` |
|
|
39
|
+
| Durations | `t.interval` | `ActiveSupport::Duration` values | `data-types/interval` |
|
|
40
|
+
| Geometry | `t.box`, `t.circle`, `t.line`, `t.segment` | value objects | `data-types/box` and siblings |
|
|
41
|
+
| Array of foreign keys | `t.bigint :tag_ids, array: true` | `belongs_to_many :tags`, `has_many :videos, array: true` | `modeling/belongs-to-many`, `modeling/has-many` |
|
|
42
|
+
| Table inheritance | `create_table :child, inherits: :parent` | `expand_records` | `modeling/inherited-tables` |
|
|
43
|
+
| Value computed on demand | | `dynamic_attribute(:name) { }` | `modeling/dynamic-attributes` |
|
|
44
|
+
| Conditional upsert | | `upsert_all(rows, where: ...)` | `modeling/insert-all` |
|
|
45
|
+
| CTE | | `auxiliary_statement :name`, `.with(:name)` | `querying/auxiliary-statements` |
|
|
46
|
+
| First row per group | | `distinct_on(:col)` | `querying/distinct-on` |
|
|
47
|
+
| Histogram | | `buckets(:col, range_or_list)` | `querying/buckets` |
|
|
48
|
+
| Several filtered aggregates | | `segments(name: condition).count` | `querying/segments` |
|
|
49
|
+
| Report rows with no data | | `join_series(range, with: :col)` | `querying/join-series` |
|
|
50
|
+
| Full-text search | `t.search_vector columns:` | `torque_search_for :col`, `.full_text_search` | `querying/full-text-search` |
|
|
51
|
+
| Regexp and array conditions | | `where(title: /x/)` | `querying/predicate-builder` |
|
|
52
|
+
| SQL functions and operators | | `FN.*`, Arel infix methods | `querying/arel` |
|
|
53
|
+
| Several schemas | `create_schema` | `self.schema =` | `experimental/multiple-schemas` |
|
|
54
|
+
| Versioned views, functions, triggers, types | `rails g torque:view` and siblings | | `experimental/versioned-commands` |
|
|
55
|
+
| Join a function, subquery, or row list | | `cross_join(source, as:)` | `experimental/cross-join` |
|
|
56
|
+
|
|
57
|
+
## Rules
|
|
58
|
+
|
|
59
|
+
- **Enum types** come from Rails' own `create_enum`. Adding values with `add_enum_values` may
|
|
60
|
+
need `disable_ddl_transaction!` in that migration.
|
|
61
|
+
- **Struct classes** subclass `Torque::PostgreSQL::Struct` and are strict by default. Only `jsonb`
|
|
62
|
+
columns can be queried by property. Encrypt properties, never the whole column.
|
|
63
|
+
- **Inherited records** reached through an association come back partial and read-only. Load
|
|
64
|
+
them with `expand_records` before writing to them.
|
|
65
|
+
- **ltree labels** accept dashes only on PostgreSQL 16+. The `ltree.sanitize` setting rewrites
|
|
66
|
+
them, which matters for UUID labels.
|
|
67
|
+
- **`FN`** is `Torque::PostgreSQL::FN`. The app may expose it under a shorter name through
|
|
68
|
+
`arel.expose_function_helper_on`, which the docs write as `PG::Fn`.
|
|
69
|
+
- **Array conditions** use `ANY` and overlaps only when `predicate_builder.handle_array_attributes`
|
|
70
|
+
is on. It is off by default.
|
data/spec/initialize.rb
CHANGED
|
@@ -4,20 +4,32 @@ require_relative '../lib/torque/postgresql/adapter/schema_overrides'
|
|
|
4
4
|
|
|
5
5
|
require_relative '../lib/torque/postgresql/adapter/oid/box'
|
|
6
6
|
require_relative '../lib/torque/postgresql/adapter/oid/circle'
|
|
7
|
+
require_relative '../lib/torque/postgresql/adapter/oid/composite'
|
|
7
8
|
require_relative '../lib/torque/postgresql/adapter/oid/enum'
|
|
8
9
|
require_relative '../lib/torque/postgresql/adapter/oid/enum_set'
|
|
9
10
|
require_relative '../lib/torque/postgresql/adapter/oid/interval'
|
|
10
11
|
require_relative '../lib/torque/postgresql/adapter/oid/line'
|
|
12
|
+
require_relative '../lib/torque/postgresql/adapter/oid/lquery'
|
|
13
|
+
require_relative '../lib/torque/postgresql/adapter/oid/ltree'
|
|
11
14
|
require_relative '../lib/torque/postgresql/adapter/oid/segment'
|
|
15
|
+
require_relative '../lib/torque/postgresql/adapter/oid/struct'
|
|
16
|
+
require_relative '../lib/torque/postgresql/adapter/oid/struct_list'
|
|
17
|
+
require_relative '../lib/torque/postgresql/adapter/oid/struct_set'
|
|
12
18
|
|
|
19
|
+
require_relative '../lib/torque/postgresql/attributes/composite'
|
|
13
20
|
require_relative '../lib/torque/postgresql/attributes/enum'
|
|
14
21
|
require_relative '../lib/torque/postgresql/attributes/enum_set'
|
|
15
22
|
require_relative '../lib/torque/postgresql/attributes/period'
|
|
23
|
+
require_relative '../lib/torque/postgresql/attributes/struct'
|
|
16
24
|
require_relative '../lib/torque/postgresql/attributes/full_text_search'
|
|
25
|
+
require_relative '../lib/torque/postgresql/attributes/ltree'
|
|
26
|
+
require_relative '../lib/torque/postgresql/attributes/lquery'
|
|
17
27
|
|
|
18
28
|
require_relative '../lib/torque/postgresql/relation/auxiliary_statement'
|
|
19
29
|
require_relative '../lib/torque/postgresql/relation/join_series'
|
|
20
30
|
require_relative '../lib/torque/postgresql/relation/buckets'
|
|
31
|
+
require_relative '../lib/torque/postgresql/relation/segments'
|
|
32
|
+
require_relative '../lib/torque/postgresql/relation/cross_join'
|
|
21
33
|
|
|
22
34
|
require_relative '../lib/torque/postgresql/versioned_commands'
|
|
23
35
|
|
|
@@ -28,11 +40,17 @@ module Torque
|
|
|
28
40
|
Attributes::Enum.include_on(ActiveRecord::Base)
|
|
29
41
|
Attributes::EnumSet.include_on(ActiveRecord::Base)
|
|
30
42
|
Attributes::Period.include_on(ActiveRecord::Base)
|
|
43
|
+
Attributes::Struct.include_on(ActiveRecord::Base)
|
|
31
44
|
Attributes::FullTextSearch.include_on(ActiveRecord::Base)
|
|
32
45
|
|
|
33
46
|
Relation.include(Relation::AuxiliaryStatement)
|
|
34
47
|
Relation.include(Relation::JoinSeries)
|
|
35
48
|
Relation.include(Relation::Buckets)
|
|
49
|
+
Relation.include(Relation::Segments)
|
|
50
|
+
Relation.include(Relation::CrossJoin)
|
|
51
|
+
|
|
52
|
+
config.cross_join.enabled = true
|
|
53
|
+
ActiveRecord::Base.singleton_class.delegate(:cross_join, to: :all)
|
|
36
54
|
|
|
37
55
|
config.versioned_commands.enabled = true
|
|
38
56
|
ActiveRecord::Schema::Definition.include(Adapter::Definition)
|
|
@@ -40,6 +58,11 @@ module Torque
|
|
|
40
58
|
::Object.const_set('TorqueCTE', AuxiliaryStatement)
|
|
41
59
|
::Object.const_set('TorqueRecursiveCTE', AuxiliaryStatement::Recursive)
|
|
42
60
|
|
|
61
|
+
config.composite.namespace = ::Object.const_set('Composite', Module.new)
|
|
62
|
+
config.composite.namespace.define_singleton_method(:const_missing) do |name|
|
|
63
|
+
Attributes::Composite.lookup(name)
|
|
64
|
+
end
|
|
65
|
+
|
|
43
66
|
config.enum.namespace = ::Object.const_set('Enum', Module.new)
|
|
44
67
|
config.enum.namespace.define_singleton_method(:const_missing) do |name|
|
|
45
68
|
Attributes::Enum.lookup(name)
|
|
@@ -50,8 +73,9 @@ module Torque
|
|
|
50
73
|
end
|
|
51
74
|
|
|
52
75
|
ar_type = ActiveRecord::Type
|
|
53
|
-
ar_type.register(:enum,
|
|
54
|
-
ar_type.register(:enum_set,
|
|
76
|
+
ar_type.register(:enum, Adapter::OID::Enum, adapter: :postgresql)
|
|
77
|
+
ar_type.register(:enum_set, Adapter::OID::EnumSet, adapter: :postgresql)
|
|
78
|
+
ar_type.register(:composite, Adapter::OID::Composite, adapter: :postgresql)
|
|
55
79
|
|
|
56
80
|
ar_type.register(:box, Adapter::OID::Box, adapter: :postgresql)
|
|
57
81
|
ar_type.register(:circle, Adapter::OID::Circle, adapter: :postgresql)
|
|
@@ -60,6 +84,9 @@ module Torque
|
|
|
60
84
|
|
|
61
85
|
ar_type.register(:interval, Adapter::OID::Interval, adapter: :postgresql)
|
|
62
86
|
|
|
87
|
+
ar_type.register(:ltree, Adapter::OID::Ltree, adapter: :postgresql)
|
|
88
|
+
ar_type.register(:lquery, Adapter::OID::Lquery, adapter: :postgresql)
|
|
89
|
+
|
|
63
90
|
Arel.build_operations(config.arel.infix_operators)
|
|
64
91
|
|
|
65
92
|
ActiveRecord::Base.connection.torque_load_additional_types
|
data/spec/mocks/cache_query.rb
CHANGED
|
@@ -15,12 +15,24 @@ module Mocks
|
|
|
15
15
|
result
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
+
def capture_executed_queries
|
|
19
|
+
queries = []
|
|
20
|
+
subscriber = ActiveSupport::Notifications.subscribe('sql.active_record') do |*, payload|
|
|
21
|
+
queries << payload[:sql] unless payload[:name] == 'SCHEMA' || payload[:cached]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
yield
|
|
25
|
+
queries
|
|
26
|
+
ensure
|
|
27
|
+
ActiveSupport::Notifications.unsubscribe(subscriber)
|
|
28
|
+
end
|
|
29
|
+
|
|
18
30
|
def get_query_with_binds(&block)
|
|
19
31
|
result = nil
|
|
20
32
|
|
|
21
33
|
original_method = ActiveRecord::Base.connection.method(:raw_execute)
|
|
22
34
|
original_method.receiver.define_singleton_method(:raw_execute) do |*args, **xargs, &block|
|
|
23
|
-
result ||= [args.first, args.third]
|
|
35
|
+
result ||= [args.first, args.third] unless %w[SCHEMA TRANSACTION].include?(args.second)
|
|
24
36
|
super(*args, **xargs, &block)
|
|
25
37
|
end
|
|
26
38
|
|
data/spec/models/author.rb
CHANGED
data/spec/models/comment.rb
CHANGED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
class Profile < ActiveRecord::Base
|
|
2
|
+
class Settings < Torque::PostgreSQL::Attributes::Struct
|
|
3
|
+
attribute :theme, :string, default: 'light'
|
|
4
|
+
attribute :notifications, :boolean, default: true
|
|
5
|
+
attribute :tags
|
|
6
|
+
|
|
7
|
+
validates :theme, inclusion: { in: %w[light dark] }, allow_nil: true
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
class Bio < Torque::PostgreSQL::Attributes::Struct
|
|
11
|
+
attribute :headline, :string
|
|
12
|
+
attribute :website, :string
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class Preview < Torque::PostgreSQL::Attributes::Struct
|
|
16
|
+
attribute :label, :string
|
|
17
|
+
attribute :url, :string
|
|
18
|
+
|
|
19
|
+
validates :url, presence: true
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
class Snippet < Torque::PostgreSQL::Attributes::Struct
|
|
23
|
+
attribute :title, :string
|
|
24
|
+
attribute :body, :string
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
struct_for :settings, Settings, delegate: %i[theme]
|
|
28
|
+
struct_for :bio, Bio
|
|
29
|
+
struct_for :previews, Preview, array: true
|
|
30
|
+
struct_for :snippets, Snippet
|
|
31
|
+
end
|
data/spec/rbs_helper.rb
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
ENV['RBS_TEST_TARGET'] ||= 'Torque::PostgreSQL::*,Torque::Generators::*'
|
|
4
|
+
ENV['RBS_TEST_SKIP'] ||= '::Torque::PostgreSQL::Attributes::Lazy,::Torque::PostgreSQL::Adapter::OID::Range::Comparison'
|
|
5
|
+
ENV['RBS_TEST_OPT'] ||= '-I sig'
|
|
6
|
+
ENV['RBS_TEST_LOGLEVEL'] ||= 'warn'
|
|
7
|
+
|
|
8
|
+
require 'rbs/test/setup'
|
data/spec/schema.rb
CHANGED
|
@@ -10,13 +10,11 @@
|
|
|
10
10
|
#
|
|
11
11
|
# It's strongly recommended that you check this file into your version control system.
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
return if ActiveRecord::Migrator.current_version == version
|
|
16
|
-
ActiveRecord::Schema.define(version: version) do
|
|
13
|
+
ActiveRecord::Schema.define do
|
|
17
14
|
self.verbose = false
|
|
18
15
|
|
|
19
16
|
# These are extensions that must be enabled in order to support this database
|
|
17
|
+
enable_extension "ltree"
|
|
20
18
|
enable_extension "pgcrypto"
|
|
21
19
|
enable_extension "plpgsql"
|
|
22
20
|
|
|
@@ -31,6 +29,27 @@ ActiveRecord::Schema.define(version: version) do
|
|
|
31
29
|
create_enum "conflicts", ["valid", "invalid", "untrusted"]
|
|
32
30
|
create_enum "types", ["A", "B", "C", "D"]
|
|
33
31
|
|
|
32
|
+
create_composite_type "address", force: :cascade do |t|
|
|
33
|
+
t.string "street"
|
|
34
|
+
t.string "city"
|
|
35
|
+
t.integer "number"
|
|
36
|
+
t.enum "category", enum_type: :types
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
create_composite_type "full_address", force: :cascade do |t|
|
|
40
|
+
t.composite "base", composite_type: :address
|
|
41
|
+
t.string "country"
|
|
42
|
+
t.date "since"
|
|
43
|
+
t.decimal "rate", precision: 8, scale: 2
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
create_table "places", force: :cascade do |t|
|
|
47
|
+
t.string "name"
|
|
48
|
+
t.composite "home", composite_type: :address
|
|
49
|
+
t.composite "offices", composite_type: :address, array: true
|
|
50
|
+
t.composite "location", composite_type: :full_address
|
|
51
|
+
end
|
|
52
|
+
|
|
34
53
|
create_table "geometries", force: :cascade do |t|
|
|
35
54
|
t.point "point"
|
|
36
55
|
t.line "line"
|
|
@@ -65,6 +84,14 @@ ActiveRecord::Schema.define(version: version) do
|
|
|
65
84
|
t.datetime "updated_at", null: false
|
|
66
85
|
end
|
|
67
86
|
|
|
87
|
+
create_table "profiles", force: :cascade do |t|
|
|
88
|
+
t.string "name"
|
|
89
|
+
t.jsonb "settings"
|
|
90
|
+
t.json "bio"
|
|
91
|
+
t.jsonb "previews"
|
|
92
|
+
t.jsonb "snippets", array: true
|
|
93
|
+
end
|
|
94
|
+
|
|
68
95
|
create_table "authors", force: :cascade do |t|
|
|
69
96
|
t.string "name"
|
|
70
97
|
t.string "type"
|
|
@@ -74,6 +101,9 @@ ActiveRecord::Schema.define(version: version) do
|
|
|
74
101
|
create_table "categories", force: :cascade do |t|
|
|
75
102
|
t.integer "parent_id"
|
|
76
103
|
t.string "title"
|
|
104
|
+
t.ltree "path", index: { using: :gist }
|
|
105
|
+
t.lquery "pattern"
|
|
106
|
+
t.lquery "patterns", array: true
|
|
77
107
|
end
|
|
78
108
|
|
|
79
109
|
create_table "texts", force: :cascade do |t|
|
|
@@ -128,6 +158,7 @@ ActiveRecord::Schema.define(version: version) do
|
|
|
128
158
|
create_table "users", force: :cascade do |t|
|
|
129
159
|
t.string "name", null: false
|
|
130
160
|
t.enum "role", enum_type: :roles, default: :visitor
|
|
161
|
+
t.ltree "permissions", array: true
|
|
131
162
|
t.integer "age"
|
|
132
163
|
t.datetime "created_at", null: false
|
|
133
164
|
t.datetime "updated_at", null: false
|
data/spec/spec_helper.rb
CHANGED
data/spec/tests/arel_spec.rb
CHANGED
|
@@ -56,7 +56,7 @@ RSpec.describe 'Arel' do
|
|
|
56
56
|
it 'does not break the change column default value method' do
|
|
57
57
|
connection.add_column(:authors, :enabled, :boolean)
|
|
58
58
|
expect { connection.change_column_default(:authors, :enabled, { from: nil, to: true }) }.not_to raise_error
|
|
59
|
-
expect(Author.
|
|
59
|
+
expect(Author.new.enabled).to be(true)
|
|
60
60
|
end
|
|
61
61
|
|
|
62
62
|
it 'does not break jsonb' do
|
|
@@ -145,12 +145,12 @@ RSpec.describe 'Arel' do
|
|
|
145
145
|
condition = Video.arel_table[:tag_ids].contains([1,2]).cast(:bigint, :array)
|
|
146
146
|
query = Video.all.where(condition).to_sql
|
|
147
147
|
|
|
148
|
-
expect(query).to include(
|
|
148
|
+
expect(query).to include(%{WHERE "videos"."tag_ids" @> '{1,2}'::bigint[]})
|
|
149
149
|
|
|
150
150
|
condition = QuestionSelect.arel_table[:options].overlaps(%w[a b]).cast(:string, :array)
|
|
151
151
|
query = QuestionSelect.all.where(condition).to_sql
|
|
152
152
|
|
|
153
|
-
expect(query).to include(
|
|
153
|
+
expect(query).to include(%{"options" && '{a,b}'::string[]})
|
|
154
154
|
end
|
|
155
155
|
end
|
|
156
156
|
end
|
|
@@ -101,6 +101,18 @@ RSpec.describe 'AuxiliaryStatement' do
|
|
|
101
101
|
expect(query.send(:bound_attributes).map(&:value_before_type_cast)).to eql([1, 2])
|
|
102
102
|
end
|
|
103
103
|
|
|
104
|
+
it 'collects the bound attributes without a permanent connection' do
|
|
105
|
+
klass.send(:auxiliary_statement, :comments) do |cte|
|
|
106
|
+
cte.query Comment.where(id: 1)
|
|
107
|
+
cte.attributes content: :comment_content
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
expect(ActiveRecord::Base).not_to receive(:connection)
|
|
111
|
+
|
|
112
|
+
query = subject.where(id: 2).with(:comments)
|
|
113
|
+
expect(query.send(:bound_attributes).map(&:value_before_type_cast)).to eql([1, 2])
|
|
114
|
+
end
|
|
115
|
+
|
|
104
116
|
it 'accepts string as attributes' do
|
|
105
117
|
klass.send(:auxiliary_statement, :comments) do |cte|
|
|
106
118
|
cte.query Comment.all
|