diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 146b1f4d..376f668a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,6 @@ jobs: fail-fast: false matrix: ruby: - - '3.5' - '3.4' - '3.3' - '3.2' diff --git a/.rubocop.yml b/.rubocop.yml index 9aed9fee..a9f07401 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -51,6 +51,10 @@ Lint/EmptyClass: Exclude: - "spec/**/*.rb" +Lint/NestedMethodDefinition: + Exclude: + - "spec/**/*.rb" + Lint/RaiseException: Enabled: false @@ -63,6 +67,8 @@ Lint/SuppressedException: Metrics/AbcSize: Max: 20 + Exclude: + - "spec/**/*.rb" Metrics/BlockLength: Enabled: false @@ -76,6 +82,8 @@ Metrics/CyclomaticComplexity: Metrics/MethodLength: Max: 22 + Exclude: + - "spec/**/*.rb" Naming/FileName: Exclude: diff --git a/lib/rom/sql/plugin/associates.rb b/lib/rom/sql/plugin/associates.rb index ad8fa96c..1e258290 100644 --- a/lib/rom/sql/plugin/associates.rb +++ b/lib/rom/sql/plugin/associates.rb @@ -162,7 +162,7 @@ def associate( def with_association(name, opts = EMPTY_HASH) self.class.build( relation, - **options, associations: associations.merge(name => opts) + **options, associations: { **associations, name => opts } ) end end diff --git a/lib/rom/sql/schema/inferrer.rb b/lib/rom/sql/schema/inferrer.rb index 3e276212..3e7dd7c9 100644 --- a/lib/rom/sql/schema/inferrer.rb +++ b/lib/rom/sql/schema/inferrer.rb @@ -36,7 +36,7 @@ def call(schema, gateway) else infer_from_attributes(gateway, schema, **super) end - rescue Sequel::Error => e + rescue ::Sequel::Error => e on_error(schema.name, e) { **FALLBACK_SCHEMA, indexes: schema.indexes } end diff --git a/spec/extensions/postgres/attribute/array_spec.rb b/spec/extensions/postgres/attribute/array_spec.rb index 3f15237c..d169b8af 100644 --- a/spec/extensions/postgres/attribute/array_spec.rb +++ b/spec/extensions/postgres/attribute/array_spec.rb @@ -5,7 +5,7 @@ include_context 'database setup' - before do + setup_relations do conf.relation(:pg_arrays) do schema(infer: true) end @@ -16,7 +16,7 @@ end context 'with a primitive type' do - before do + setup_tables do conn.create_table :pg_arrays do column :numbers, 'int[]' end @@ -34,7 +34,7 @@ end context 'with a custom json type' do - before do + setup_tables do conn.create_table :pg_arrays do column :meta, 'json[]' end diff --git a/spec/extensions/postgres/attribute/range_spec.rb b/spec/extensions/postgres/attribute/range_spec.rb index 937532e9..25c49888 100644 --- a/spec/extensions/postgres/attribute/range_spec.rb +++ b/spec/extensions/postgres/attribute/range_spec.rb @@ -3,27 +3,6 @@ RSpec.describe 'ROM::SQL::Attribute', :postgres do include_context 'database setup' - def create_ranges_table(db_type, values) - conn.create_table :pg_ranges do - primary_key :id - text :name - - send(db_type, :range) - end - - conf.relation(:pg_ranges) do - schema(:pg_ranges, infer: true) - end - - conf.commands(:pg_ranges) do - define(:create) - end - - values.each do |key, value| - commands[:pg_ranges].create.(name: key.to_s, range: value) - end - end - shared_examples 'range type' do let(:rel) { pg_ranges.select { [name] } } @@ -106,10 +85,33 @@ def create_ranges_table(db_type, values) let(:pg_ranges) { relations[:pg_ranges] } let(:range_value) { ROM::SQL::Postgres::Values::Range } - before do + setup_tables do conn.extension(:pg_range) conn.drop_table?(:pg_ranges) - create_ranges_table(db_type, values) + + ctx = self + conn.create_table :pg_ranges do + primary_key :id + text :name + + send(ctx.db_type, :range) + end + end + + setup_relations do + conf.relation(:pg_ranges) do + schema(:pg_ranges, infer: true) + end + + conf.commands(:pg_ranges) do + define(:create) + end + end + + seed do + values.each do |key, value| + commands[:pg_ranges].create.(name: key.to_s, range: value) + end end describe 'numrange' do diff --git a/spec/extensions/postgres/attribute_spec.rb b/spec/extensions/postgres/attribute_spec.rb index 6f1f8f65..0ac81917 100644 --- a/spec/extensions/postgres/attribute_spec.rb +++ b/spec/extensions/postgres/attribute_spec.rb @@ -3,10 +3,12 @@ RSpec.describe 'ROM::SQL::Attribute', :postgres do include_context 'database setup' - before do + setup_tables do conn.drop_table?(:pg_people) conn.drop_table?(:people) + end + setup_relations do conf.relation(:people) do schema(:pg_people, infer: true) end @@ -17,18 +19,22 @@ %i[json jsonb].each do |type| describe "using arrays in #{type}" do - before do + setup_tables do conn.create_table :pg_people do primary_key :id String :name column :fields, type end + end + setup_relations do conf.commands(:people) do define(:create) define(:update) end + end + seed do create_person.( name: 'John Doe', fields: [ @@ -100,18 +106,22 @@ next unless type == :jsonb describe "using maps in #{type}" do - before do + setup_tables do conn.create_table :pg_people do primary_key :id String :name column :data, type end + end + setup_relations do conf.commands(:people) do define(:create) define(:update) end + end + seed do create_person.(name: 'John Doe', data: { age: 30, height: 180 }) create_person.(name: 'Jade Doe', data: { age: 25 }) end @@ -160,19 +170,23 @@ end describe 'using array types' do - before do + setup_tables do conn.create_table :pg_people do primary_key :id String :name column :emails, 'text[]' column :bigids, 'bigint[]' end + end + setup_relations do conf.commands(:people) do define(:create) define(:update) end + end + seed do create_person.(name: 'John Doe', emails: %w[john@doe.com john@example.com], bigids: [84]) create_person.(name: 'Jade Doe', emails: %w[jade@hotmail.com], bigids: [42]) end @@ -253,7 +267,7 @@ end describe 'using ltree types' do - before do + setup_tables do conn.execute('create extension if not exists ltree') conn.create_table :pg_people do @@ -262,12 +276,16 @@ column :ltree_tags, :ltree column :parents_tags, 'ltree[]', default: [] end + end + setup_relations do conf.commands(:people) do define(:create) define(:update) end + end + seed do create_person.(name: 'John Wilkson', ltree_tags: ltree('Bottom'), parents_tags: [ltree('Top'), ltree('Top.Building')]) create_person.(name: 'John Wayne', ltree_tags: ltree('Bottom.Countries'), parents_tags: [ltree('Left'), ltree('Left.Parks')]) create_person.(name: 'John Fake', ltree_tags: ltree('Bottom.Cities'), parents_tags: [ltree('Top.Building.EmpireState'), ltree('Top.Building.EmpireState.381')]) diff --git a/spec/extensions/postgres/integration_spec.rb b/spec/extensions/postgres/integration_spec.rb index 3e5fa259..cb348e87 100644 --- a/spec/extensions/postgres/integration_spec.rb +++ b/spec/extensions/postgres/integration_spec.rb @@ -3,20 +3,22 @@ RSpec.describe 'PostgreSQL extension', :postgres do include_context 'database setup' - before do + setup_tables do conn.drop_table?(:pg_people) conn.drop_table?(:people) end context 'with arrays' do - before do + setup_tables do conn.create_table :pg_people do primary_key :id String :name column :tags, 'text[]' column :allowed_subnets, 'cidr[]' end + end + setup_relations do conf.relation(:people) do schema(:pg_people, infer: true) end @@ -85,13 +87,15 @@ end context 'with jsonb' do - before do + setup_tables do conn.create_table :pg_people do primary_key :id String :name column :attributes, 'jsonb' end + end + setup_relations do conf.relation(:people) do schema(:pg_people, infer: true) end diff --git a/spec/integration/associations/many_to_many/custom_fks_spec.rb b/spec/integration/associations/many_to_many/custom_fks_spec.rb index d99bda0b..4e3a3ade 100644 --- a/spec/integration/associations/many_to_many/custom_fks_spec.rb +++ b/spec/integration/associations/many_to_many/custom_fks_spec.rb @@ -15,7 +15,7 @@ let(:puzzle_solvers) { relations[:puzzle_solvers] } with_adapters do - before do + setup_tables do conn.create_table(:puzzles) do primary_key :id column :text, String, null: false @@ -26,7 +26,9 @@ foreign_key :puzzle_id, :puzzles, null: false primary_key [:solver_id, :puzzle_id] end + end + setup_relations do conf.relation(:puzzles) { schema(infer: true) } conf.relation(:puzzle_solvers) do @@ -46,7 +48,9 @@ end end end + end + seed do p1_id = relations[:puzzles].insert(text: 'P1') p2_id = relations[:puzzles].insert(text: 'P2') p3_id = relations[:puzzles].insert(text: 'P3') diff --git a/spec/integration/associations/many_to_many/from_view_spec.rb b/spec/integration/associations/many_to_many/from_view_spec.rb index f334cd15..226a7838 100644 --- a/spec/integration/associations/many_to_many/from_view_spec.rb +++ b/spec/integration/associations/many_to_many/from_view_spec.rb @@ -15,7 +15,7 @@ let(:puzzle_solvers) { relations[:puzzle_solvers] } with_adapters do - before do + setup_tables do conn.create_table(:puzzles) do primary_key :id column :text, String, null: false @@ -27,7 +27,9 @@ foreign_key :puzzle_id, :puzzles, null: false primary_key [:user_id, :puzzle_id] end + end + setup_relations do conf.relation(:puzzles) do schema(infer: true) @@ -54,7 +56,9 @@ end end end + end + seed do p1_id = relations[:puzzles].insert(text: 'P1') p2_id = relations[:puzzles].insert(text: 'P2', solved: true) p3_id = relations[:puzzles].insert(text: 'P3') diff --git a/spec/integration/associations/many_to_many/self_ref_spec.rb b/spec/integration/associations/many_to_many/self_ref_spec.rb index 463be73e..3c560dd9 100644 --- a/spec/integration/associations/many_to_many/self_ref_spec.rb +++ b/spec/integration/associations/many_to_many/self_ref_spec.rb @@ -16,7 +16,7 @@ end with_adapters do - before do + setup_tables(hr: :db) do conn.create_table :employees do primary_key :id, Integer column :name, String @@ -27,7 +27,9 @@ foreign_key :manager_id, :employees foreign_key :participant_id, :employees end + end + setup_relations do conf.relation(:employees) do schema(:employees, infer: true) do associations do @@ -46,17 +48,19 @@ end end + seed do + jane = employees.insert(name: 'Jane') + fred = employees.insert(name: 'Fred') + + positions.insert(manager_id: jane, participant_id: fred) + end + after do conn.drop_table?(:positions) conn.drop_table?(:employees) end it 'preloads self-referenced tuples' do - jane = employees.insert(name: 'Jane') - fred = employees.insert(name: 'Fred') - - positions.insert(manager_id: jane, participant_id: fred) - expect(assoc.().to_a).to eql([{ id: 1, name: 'Jane', participant_id: 2 }]) end end diff --git a/spec/integration/associations/many_to_many_spec.rb b/spec/integration/associations/many_to_many_spec.rb index 3f41f98f..025edc4b 100644 --- a/spec/integration/associations/many_to_many_spec.rb +++ b/spec/integration/associations/many_to_many_spec.rb @@ -11,26 +11,6 @@ let(:tags) { relations[:tags] } - before do - conf.relation(:task_tags) do - schema(infer: true) do - associations do - belongs_to :task - belongs_to :tag - end - end - end - - conf.relation(:tasks) do - schema(infer: true) do - associations do - has_many :task_tags - has_many :tags, through: :task_tags - end - end - end - end - describe '#result' do specify { expect(assoc.result).to be(:many) } end @@ -105,13 +85,15 @@ inferrable_relations.push(:users_tasks) end - before do + setup_tables do conn.create_table(:users_tasks) do foreign_key :user_id, :users foreign_key :task_id, :tasks primary_key [:user_id, :task_id] end + end + setup_relations do conf.relation(:users) do schema(infer: true) do associations do diff --git a/spec/integration/associations/many_to_one/custom_fks_spec.rb b/spec/integration/associations/many_to_one/custom_fks_spec.rb index da7f2b62..02fb9310 100644 --- a/spec/integration/associations/many_to_one/custom_fks_spec.rb +++ b/spec/integration/associations/many_to_one/custom_fks_spec.rb @@ -13,7 +13,7 @@ let(:assoc_to) { relations[:flights].associations[:to] } with_adapters do - before do + setup_tables do conn.create_table(:destinations) do primary_key :id column :name, String, null: false @@ -25,7 +25,9 @@ foreign_key :to_id, :destinations, null: false column :code, String, null: false end + end + setup_relations do conf.relation(:destinations) { schema(infer: true) } conf.relation(:flights) do @@ -36,10 +38,11 @@ end end end + end + seed do from_id = relations[:destinations].insert(name: 'FROM') to_id = relations[:destinations].insert(name: 'TO') - relations[:flights].insert(code: 'F1', from_id: from_id, to_id: to_id) end diff --git a/spec/integration/associations/many_to_one/from_view_spec.rb b/spec/integration/associations/many_to_one/from_view_spec.rb index de7cf4eb..2e6da0eb 100644 --- a/spec/integration/associations/many_to_one/from_view_spec.rb +++ b/spec/integration/associations/many_to_one/from_view_spec.rb @@ -13,7 +13,7 @@ let(:assoc_final) { relations[:flights].associations[:final_destination] } with_adapters do - before do + setup_tables do conn.create_table(:destinations) do primary_key :id column :name, String, null: false @@ -25,7 +25,9 @@ foreign_key :destination_id, :destinations, null: false column :code, String, null: false end + end + setup_relations do conf.relation(:destinations) do schema(infer: true) @@ -46,7 +48,9 @@ end end end + end + seed do final_id = relations[:destinations].insert(name: 'Final') inter_id = relations[:destinations].insert(name: 'Intermediate', intermediate: true) @@ -55,8 +59,8 @@ end after do - conn.drop_table(:flights) - conn.drop_table(:destinations) + conn.drop_table?(:flights) + conn.drop_table?(:destinations) end it 'prepares joined relations using custom view in target relation' do diff --git a/spec/integration/associations/many_to_one/self_ref_spec.rb b/spec/integration/associations/many_to_one/self_ref_spec.rb index bc4f3b01..f768a982 100644 --- a/spec/integration/associations/many_to_one/self_ref_spec.rb +++ b/spec/integration/associations/many_to_one/self_ref_spec.rb @@ -10,13 +10,15 @@ include_context 'database setup' with_adapters do - before do + setup_tables do conn.create_table(:categories) do primary_key :id foreign_key :parent_id, :categories, null: true column :name, String, null: false end + end + setup_relations do conf.relation(:categories) do schema(infer: true) do associations do @@ -24,7 +26,9 @@ end end end + end + seed do p1_id = relations[:categories].insert(name: 'P1') p2_id = relations[:categories].insert(name: 'P2') relations[:categories].insert(name: 'C3', parent_id: p2_id) diff --git a/spec/integration/associations/many_to_one_spec.rb b/spec/integration/associations/many_to_one_spec.rb index a691bcbc..d3b635f0 100644 --- a/spec/integration/associations/many_to_one_spec.rb +++ b/spec/integration/associations/many_to_one_spec.rb @@ -10,7 +10,7 @@ build_assoc(:many_to_one, :tasks, :users) end - before do + setup_relations do conf.relation(:tasks) do schema(infer: true) end @@ -86,7 +86,7 @@ build_assoc(:many_to_one, articles_name, :users) end - before do + setup_relations do conf.relation(:articles) do schema(:posts, infer: true) end diff --git a/spec/integration/associations/one_to_many/custom_fks_spec.rb b/spec/integration/associations/one_to_many/custom_fks_spec.rb index ef14b8e0..becd9a5f 100644 --- a/spec/integration/associations/one_to_many/custom_fks_spec.rb +++ b/spec/integration/associations/one_to_many/custom_fks_spec.rb @@ -14,14 +14,16 @@ end with_adapters do - before do + setup_tables do conn.create_table(:puzzles) do primary_key :id foreign_key :author_id, :users, null: false foreign_key :solver_id, :users, null: true column :text, String, null: false end + end + setup_relations do conf.relation(:puzzles) { schema(infer: true) } conf.relation(:users) do @@ -32,7 +34,9 @@ end end end + end + seed do relations[:puzzles].insert(author_id: joe_id, text: 'P1') relations[:puzzles].insert(author_id: joe_id, solver_id: jane_id, text: 'P2') end diff --git a/spec/integration/associations/one_to_many/from_view_spec.rb b/spec/integration/associations/one_to_many/from_view_spec.rb index 459989bb..1e41b83c 100644 --- a/spec/integration/associations/one_to_many/from_view_spec.rb +++ b/spec/integration/associations/one_to_many/from_view_spec.rb @@ -14,14 +14,16 @@ end with_adapters do - before do + setup_tables do conn.create_table(:puzzles) do primary_key :id foreign_key :user_id, :users, null: false column :text, String, null: false column :solved, TrueClass, null: false, default: false end + end + setup_relations do conf.relation(:users) do schema(infer: true) do associations do @@ -38,7 +40,9 @@ where(solved: true) end end + end + seed do relations[:puzzles].insert(user_id: joe_id, text: 'P1') relations[:puzzles].insert(user_id: joe_id, solved: true, text: 'P2') end diff --git a/spec/integration/associations/one_to_many/self_ref_spec.rb b/spec/integration/associations/one_to_many/self_ref_spec.rb index b55e3d39..40451a2e 100644 --- a/spec/integration/associations/one_to_many/self_ref_spec.rb +++ b/spec/integration/associations/one_to_many/self_ref_spec.rb @@ -14,13 +14,15 @@ end with_adapters do - before do + setup_tables do conn.create_table(:categories) do primary_key :id foreign_key :parent_id, :categories, null: true column :name, String, null: false end + end + setup_relations do conf.relation(:categories) do schema(infer: true) do associations do @@ -29,7 +31,9 @@ end end end + end + seed do p1_id = relations[:categories].insert(name: 'P1') p2_id = relations[:categories].insert(name: 'P2') relations[:categories].insert(name: 'C3', parent_id: p2_id) diff --git a/spec/integration/associations/one_to_many_spec.rb b/spec/integration/associations/one_to_many_spec.rb index 12c447e0..450b7f2e 100644 --- a/spec/integration/associations/one_to_many_spec.rb +++ b/spec/integration/associations/one_to_many_spec.rb @@ -8,7 +8,7 @@ end with_adapters do - before do + setup_relations do conf.relation(:tasks) do schema do attribute :id, ROM::SQL::Types::Serial diff --git a/spec/integration/associations/one_to_one_spec.rb b/spec/integration/associations/one_to_one_spec.rb index d8bf750a..6d3b9bde 100644 --- a/spec/integration/associations/one_to_one_spec.rb +++ b/spec/integration/associations/one_to_one_spec.rb @@ -9,9 +9,7 @@ end with_adapters do - before do - conn[:accounts].insert user_id: 1, number: '43', balance: -273.15.to_d - + setup_relations do conf.relation(:accounts) do schema do attribute :id, ROM::SQL::Types::Serial @@ -22,6 +20,10 @@ end end + seed do + conn[:accounts].insert user_id: 1, number: '43', balance: -273.15.to_d + end + describe '#result' do specify { expect(assoc.result).to be(:one) } end diff --git a/spec/integration/associations/one_to_one_through_spec.rb b/spec/integration/associations/one_to_one_through_spec.rb index 36eba30a..63055f0e 100644 --- a/spec/integration/associations/one_to_one_through_spec.rb +++ b/spec/integration/associations/one_to_one_through_spec.rb @@ -9,7 +9,7 @@ end with_adapters do - before do + setup_relations do conf.relation(:accounts) do schema do attribute :id, ROM::SQL::Types::Serial diff --git a/spec/integration/auto_migrations/errors_spec.rb b/spec/integration/auto_migrations/errors_spec.rb index cd76071d..f067203d 100644 --- a/spec/integration/auto_migrations/errors_spec.rb +++ b/spec/integration/auto_migrations/errors_spec.rb @@ -5,12 +5,12 @@ subject(:gateway) { container.gateways[:default] } - before do + setup_tables do conn.drop_table?(:users) end describe 'unsupported conversions' do - before do + setup_relations do conf.relation(:users) do schema do attribute :id, ROM::SQL::Types::Serial @@ -19,12 +19,14 @@ end end - it 'raises an error' do + setup_tables do conn.create_table :users do primary_key :id column :name, Integer, null: false end + end + it 'raises an error' do expect { gateway.auto_migrate!(conf) }.to raise_error(ROM::SQL::UnsupportedConversion, /Don't know how to convert/) diff --git a/spec/integration/auto_migrations/file_based_migrations_spec.rb b/spec/integration/auto_migrations/file_based_migrations_spec.rb index 30a6833b..6aaa42e2 100644 --- a/spec/integration/auto_migrations/file_based_migrations_spec.rb +++ b/spec/integration/auto_migrations/file_based_migrations_spec.rb @@ -12,7 +12,7 @@ let(:options) { { path: path } } - before do + setup_tables do conn.drop_table?(:posts) conn.drop_table?(:users) conn.drop_table?(:schema_migrations) @@ -25,7 +25,7 @@ def migrations end context 'creating from scratch' do - before do + setup_relations do conf.relation(:users) do schema do attribute :id, ROM::SQL::Types::Serial @@ -61,13 +61,15 @@ def migrations context 'alter table' do context 'changing columns' do - before do + setup_tables do conn.create_table(:users) do primary_key :id column :name, String column :age, Integer end + end + setup_relations do conf.relation(:users) do schema do attribute :id, ROM::SQL::Types::Serial @@ -105,12 +107,14 @@ def migrations end context 'managing foreign keys' do - before do + setup_tables do conn.create_table(:users) do primary_key :id column :name, String, null: false end + end + setup_relations do conf.relation(:users) do schema do attribute :id, ROM::SQL::Types::Serial diff --git a/spec/integration/auto_migrations/foreign_keys_spec.rb b/spec/integration/auto_migrations/foreign_keys_spec.rb index e61ec0f2..5178c413 100644 --- a/spec/integration/auto_migrations/foreign_keys_spec.rb +++ b/spec/integration/auto_migrations/foreign_keys_spec.rb @@ -3,7 +3,7 @@ RSpec.describe ROM::SQL::Gateway, :postgres, :helpers do include_context 'database setup' - before do + setup_tables do conn.drop_table?(:posts) conn.drop_table?(:users) end @@ -24,13 +24,17 @@ let(:attributes) { migrated_schema.to_a } + before { container } + describe 'create table' do - before do + setup_tables do conn.create_table(:users) do primary_key :id column :name, String, null: false end + end + setup_relations do conf.relation(:posts) do schema do attribute :id, ROM::SQL::Types::Serial @@ -58,7 +62,7 @@ describe 'alter table' do context 'adding' do - before do + setup_tables do conn.create_table(:users) do primary_key :id column :name, String, null: false @@ -68,7 +72,9 @@ primary_key :id column :user_id, Integer, null: false end + end + setup_relations do conf.relation(:posts) do schema do attribute :id, ROM::SQL::Types::Serial @@ -96,7 +102,7 @@ end context 'removing' do - before do + setup_tables do conn.create_table(:users) do primary_key :id column :name, String, null: false @@ -106,7 +112,9 @@ primary_key :id foreign_key :user_id, :users end + end + setup_relations do conf.relation(:posts) do schema do attribute :id, ROM::SQL::Types::Serial diff --git a/spec/integration/auto_migrations/indexes_spec.rb b/spec/integration/auto_migrations/indexes_spec.rb index 9100d227..3367c70c 100644 --- a/spec/integration/auto_migrations/indexes_spec.rb +++ b/spec/integration/auto_migrations/indexes_spec.rb @@ -3,7 +3,7 @@ RSpec.describe ROM::SQL::Gateway, :postgres, :helpers do include_context 'database setup' - before do + setup_tables do conn.drop_table?(:users) end @@ -31,7 +31,7 @@ def indexdef(index) describe 'create table' do describe 'one-column indexes' do - before do + setup_relations do conf.relation(:users) do schema do attribute :id, ROM::SQL::Types::Serial @@ -50,11 +50,11 @@ def indexdef(index) expect(attributes.map(&:to_ast)).to eql([ [:attribute, [:id, - [:nominal, [Integer, {}]], + [:nominal, [Integer, {}, {}]], primary_key: true, source: :users, alias: nil]], [:attribute, [:name, - [:nominal, [String, {}]], + [:nominal, [String, {}, {}]], index: true, source: :users, alias: nil]] ]) @@ -73,170 +73,195 @@ def indexdef(index) describe 'alter table' do describe 'one-column indexes' do context 'adding' do - before do - end - - it 'adds indexed column' do - conn.create_table :users do - primary_key :id + context 'adding indexed column' do + setup_tables do + conn.create_table :users do + primary_key :id + end end - conf.relation(:users) do - schema do - attribute :id, ROM::SQL::Types::Serial - attribute :name, ROM::SQL::Types::String.meta(index: true) + setup_relations do + conf.relation(:users) do + schema do + attribute :id, ROM::SQL::Types::Serial + attribute :name, ROM::SQL::Types::String.meta(index: true) + end end end - gateway.auto_migrate!(conf, inline: true) + it 'adds indexed column' do + gateway.auto_migrate!(conf, inline: true) - name_index = migrated_schema.indexes.first + name_index = migrated_schema.indexes.first - expect(migrated_schema.attributes[1].name).to eql(:name) - expect(migrated_schema.indexes.size).to eql(1) - expect(name_index.name).to eql(:users_name_index) - expect(name_index.attributes.map(&:name)).to eql(%i[name]) + expect(migrated_schema.attributes[1].name).to eql(:name) + expect(migrated_schema.indexes.size).to eql(1) + expect(name_index.name).to eql(:users_name_index) + expect(name_index.attributes.map(&:name)).to eql(%i[name]) + end end - it 'supports custom names' do - conn.create_table :users do - primary_key :id + context 'adding index with custom name' do + setup_tables do + conn.create_table :users do + primary_key :id + end end - conf.relation(:users) do - schema do - attribute :id, ROM::SQL::Types::Serial - attribute :name, ROM::SQL::Types::String + setup_relations do + conf.relation(:users) do + schema do + attribute :id, ROM::SQL::Types::Serial + attribute :name, ROM::SQL::Types::String - indexes do - index :name, name: :custom_idx + indexes do + index :name, name: :custom_idx + end end end end - gateway.auto_migrate!(conf, inline: true) + it 'supports custom names' do + gateway.auto_migrate!(conf, inline: true) - name_index = migrated_schema.indexes.first + name_index = migrated_schema.indexes.first - expect(migrated_schema.attributes[1].name).to eql(:name) - expect(migrated_schema.indexes.size).to eql(1) - expect(name_index.name).to eql(:custom_idx) - expect(name_index.attributes.map(&:name)).to eql(%i[name]) + expect(migrated_schema.attributes[1].name).to eql(:name) + expect(migrated_schema.indexes.size).to eql(1) + expect(name_index.name).to eql(:custom_idx) + expect(name_index.attributes.map(&:name)).to eql(%i[name]) + end end - it 'adds index to existing column' do - conn.create_table :users do - primary_key :id - column :name, String + context 'adding index to existing column' do + setup_tables do + conn.create_table :users do + primary_key :id + column :name, String + end end - conf.relation(:users) do - schema do - attribute :id, ROM::SQL::Types::Serial - attribute :name, ROM::SQL::Types::String + setup_relations do + conf.relation(:users) do + schema do + attribute :id, ROM::SQL::Types::Serial + attribute :name, ROM::SQL::Types::String - indexes do - index :name + indexes do + index :name + end end end end - gateway.auto_migrate!(conf, inline: true) + it 'adds index to existing column' do + gateway.auto_migrate!(conf, inline: true) - name_index = migrated_schema.indexes.first + name_index = migrated_schema.indexes.first - expect(name_index.name).to eql(:users_name_index) - expect(name_index.attributes.map(&:name)).to eql(%i[name]) - expect(name_index).not_to be_unique + expect(name_index.name).to eql(:users_name_index) + expect(name_index.attributes.map(&:name)).to eql(%i[name]) + expect(name_index).not_to be_unique + end end - it 'supports unique indexes' do - conn.create_table :users do - primary_key :id - column :name, String + context 'adding unique index' do + setup_tables do + conn.create_table :users do + primary_key :id + column :name, String + end end - conf.relation(:users) do - schema do - attribute :id, ROM::SQL::Types::Serial - attribute :name, ROM::SQL::Types::String + setup_relations do + conf.relation(:users) do + schema do + attribute :id, ROM::SQL::Types::Serial + attribute :name, ROM::SQL::Types::String - indexes do - index :name, unique: true + indexes do + index :name, unique: true + end end end end - gateway.auto_migrate!(conf, inline: true) + it 'supports unique indexes' do + gateway.auto_migrate!(conf, inline: true) - name_index = migrated_schema.indexes.first + name_index = migrated_schema.indexes.first - expect(name_index.name).to eql(:users_name_index) - expect(name_index.attributes.map(&:name)).to eql(%i[name]) - expect(name_index).to be_unique + expect(name_index.name).to eql(:users_name_index) + expect(name_index.attributes.map(&:name)).to eql(%i[name]) + expect(name_index).to be_unique + end end if metadata[:postgres] - it 'uses index method' do - conn.create_table :users do - primary_key :id - column :props, :jsonb, null: false + context 'using index method' do + setup_tables do + conn.create_table :users do + primary_key :id + column :props, :jsonb, null: false + end end - conf.relation(:users) do - schema do - attribute :id, ROM::SQL::Types::Serial - attribute :props, ROM::SQL::Types::PG::JSONB + setup_relations do + conf.relation(:users) do + schema do + attribute :id, ROM::SQL::Types::Serial + attribute :props, ROM::SQL::Types::PG::JSONB - indexes do - index :props, type: :gin + indexes do + index :props, type: :gin + end end end end - gateway.auto_migrate!(conf, inline: true) + it 'uses index method' do + gateway.auto_migrate!(conf, inline: true) - expect(indexdef('users_props_index')).to eql( - 'CREATE INDEX users_props_index ON public.users USING gin (props)' - ) + expect(indexdef('users_props_index')).to eql( + 'CREATE INDEX users_props_index ON public.users USING gin (props)' + ) + end end - it 'supports partial indexes' do - conn.create_table :users do - primary_key :id - column :name, String + context 'supports partial indexes' do + setup_tables do + conn.create_table :users do + primary_key :id + column :name, String + end end - conf.relation(:users) do - schema do - attribute :id, ROM::SQL::Types::Serial - attribute :name, ROM::SQL::Types::String + setup_relations do + conf.relation(:users) do + schema do + attribute :id, ROM::SQL::Types::Serial + attribute :name, ROM::SQL::Types::String - indexes do - index :name, name: :long_names_only, predicate: 'length(name) > 10' + indexes do + index :name, name: :long_names_only, predicate: 'length(name) > 10' + end end end end - gateway.auto_migrate!(conf, inline: true) + it 'supports partial indexes' do + gateway.auto_migrate!(conf, inline: true) - expect(indexdef('long_names_only')).to eql( - 'CREATE INDEX long_names_only ON public.users USING btree (name) WHERE (length(name) > 10)' - ) + expect(indexdef('long_names_only')).to eql( + 'CREATE INDEX long_names_only ON public.users USING btree (name) WHERE (length(name) > 10)' + ) + end end end end context 'removing' do - before do - conf.relation(:users) do - schema do - attribute :id, ROM::SQL::Types::Serial - attribute :name, ROM::SQL::Types::String - attribute :email, ROM::SQL::Types::String - end - end - + setup_tables do conn.create_table :users do primary_key :id column :name, String @@ -247,6 +272,16 @@ def indexdef(index) end end + setup_relations do + conf.relation(:users) do + schema do + attribute :id, ROM::SQL::Types::Serial + attribute :name, ROM::SQL::Types::String + attribute :email, ROM::SQL::Types::String + end + end + end + it 'removes index' do gateway.auto_migrate!(conf, inline: true) diff --git a/spec/integration/auto_migrations/managing_columns_spec.rb b/spec/integration/auto_migrations/managing_columns_spec.rb index be92e53e..abfc195c 100644 --- a/spec/integration/auto_migrations/managing_columns_spec.rb +++ b/spec/integration/auto_migrations/managing_columns_spec.rb @@ -3,11 +3,11 @@ RSpec.describe ROM::SQL::Gateway, :postgres, :helpers do include_context 'database setup' - before do + setup_tables do conn.drop_table?(:users) end - before do + setup_relations do conf.relation(:users) do schema do attribute :id, ROM::SQL::Types::Serial @@ -37,16 +37,16 @@ expect(attributes.map(&:to_ast)).to eql([ [:attribute, [:id, - [:nominal, [Integer, {}]], + [:nominal, [Integer, {}, {}]], primary_key: true, source: :users, alias: nil]], - [:attribute, [:name, [:nominal, [String, {}]], source: :users, alias: nil]], + [:attribute, [:name, [:nominal, [String, {}, {}]], source: :users, alias: nil]], [:attribute, [:email, [:sum, [[:constrained, - [[:nominal, [NilClass, {}]], + [[:nominal, [NilClass, {}, {}]], [:predicate, [:type?, [[:type, NilClass], [:input, ROM::Undefined]]]]]], - [:nominal, [String, {}]], + [:nominal, [String, {}, {}]], {}]], source: :users, alias: nil]] ]) @@ -54,7 +54,7 @@ end describe 'adding columns' do - before do + setup_tables do conn.create_table :users do primary_key :id end @@ -64,16 +64,16 @@ gateway.auto_migrate!(conf, inline: true) expect(attributes[1].to_ast).to eql( - [:attribute, [:name, [:nominal, [String, {}]], source: :users, alias: nil]] + [:attribute, [:name, [:nominal, [String, {}, {}]], source: :users, alias: nil]] ) expect(attributes[2].to_ast).to eql( [:attribute, [:email, [:sum, [[:constrained, - [[:nominal, [NilClass, {}]], + [[:nominal, [NilClass, {}, {}]], [:predicate, [:type?, [[:type, NilClass], [:input, ROM::Undefined]]]]]], - [:nominal, [String, {}]], + [:nominal, [String, {}, {}]], {}]], source: :users, alias: nil]] ) @@ -81,7 +81,7 @@ end describe 'removing columns' do - before do + setup_tables do conn.create_table :users do primary_key :id column :name, String, null: false @@ -98,7 +98,7 @@ end describe 'empty diff' do - before do + setup_tables do conn.create_table :users do primary_key :id column :name, String, null: false @@ -117,7 +117,7 @@ describe 'changing NOTNULL' do describe 'adding' do - before do + setup_tables do conn.create_table :users do primary_key :id column :name, String @@ -134,7 +134,7 @@ end describe 'removing' do - before do + setup_tables do conn.create_table :users do primary_key :id column :name, String, null: false diff --git a/spec/integration/auto_migrations/postgres/column_types_spec.rb b/spec/integration/auto_migrations/postgres/column_types_spec.rb index c91e64d0..cdb729f7 100644 --- a/spec/integration/auto_migrations/postgres/column_types_spec.rb +++ b/spec/integration/auto_migrations/postgres/column_types_spec.rb @@ -3,7 +3,7 @@ RSpec.describe ROM::SQL::Gateway, :postgres, :helpers do include_context 'database setup' - before do + setup_tables do conn.drop_table?(:test_pg_types) conn.execute('create extension if not exists hstore') @@ -24,7 +24,7 @@ end describe 'common types' do - before do + setup_relations do conf.relation(:test_pg_types) do schema do attribute :id, ROM::SQL::Types::Serial diff --git a/spec/integration/combine_with_spec.rb b/spec/integration/combine_with_spec.rb index 75b90ac6..d59b3453 100644 --- a/spec/integration/combine_with_spec.rb +++ b/spec/integration/combine_with_spec.rb @@ -4,7 +4,7 @@ include_context 'users and tasks' with_adapters do - before do + setup_relations do conf.relation(:users) do auto_map false @@ -47,7 +47,7 @@ def for_tasks(tasks) include_context 'articles' with_adapters do - before do + setup_relations do conf.relation(:users) do schema infer: true do associations do diff --git a/spec/integration/commands/create_spec.rb b/spec/integration/commands/create_spec.rb index 0660f83f..e8bc45f5 100644 --- a/spec/integration/commands/create_spec.rb +++ b/spec/integration/commands/create_spec.rb @@ -12,7 +12,7 @@ let(:create_task) { task_commands.create } let(:create_profile) { profile_commands.create } - before do |ex| + setup_relations do module Test class Params < Dry::Struct attribute :name, Types::Strict::String.optional @@ -22,7 +22,9 @@ def self.[](input) end end end + end + setup_tables do |ex| conn.add_index :users, :name, unique: true if sqlite?(ex) @@ -30,7 +32,9 @@ def self.[](input) else conn.execute 'ALTER TABLE tasks add CONSTRAINT tasks_title_key UNIQUE (title)' end + end + setup_relations do conf.relation(:profiles) do schema(:users, infer: true) do attribute :name, Types::String, alias: :login @@ -146,25 +150,29 @@ def self.[](input) end end - it 'uses relation schema for the default input handler' do - conf.relation(:users_with_schema) do - schema(:users) do - attribute :id, ROM::SQL::Types::Serial - attribute :name, ROM::SQL::Types::String + context 'when using relation schema for the default input handler' do + setup_relations do + conf.relation(:users_with_schema) do + schema(:users) do + attribute :id, ROM::SQL::Types::Serial + attribute :name, ROM::SQL::Types::String + end end - end - conf.commands(:users_with_schema) do - define(:create) do - result :one + conf.commands(:users_with_schema) do + define(:create) do + result :one + end end end - create = container.commands[:users_with_schema][:create] + specify do + create = container.commands[:users_with_schema][:create] - expect(create.input[foo: 'bar', id: 1, name: 'Jane']).to eql( - id: 1, name: 'Jane' - ) + expect(create.input[foo: 'bar', id: 1, name: 'Jane']).to eql( + id: 1, name: 'Jane' + ) + end end it 'returns a single tuple when result is set to :one' do @@ -190,7 +198,7 @@ def self.[](input) context 'with json notes' do include_context 'json_notes' - before do + setup_relations do conf.commands(:json_notes) do define(:create) end @@ -208,7 +216,7 @@ def self.[](input) context 'with puppies' do include_context 'puppies' - before do + setup_relations do conf.relation(:puppies) do schema(infer: true) end @@ -277,13 +285,15 @@ def self.[](input) inferrable_relations.push(:user_group) end - before do + setup_tables do conn.create_table(:user_group) do primary_key [:user_id, :group_id] column :user_id, Integer, null: false column :group_id, Integer, null: false end + end + setup_relations do conf.relation(:user_group) do schema(infer: true) end @@ -322,7 +332,7 @@ def self.[](input) describe '#upsert' do let(:task) { { title: 'task 1' } } - before { create_task.call(task) } + seed { create_task.call(task) } it 'raises error without upsert marker' do expect { diff --git a/spec/integration/commands/delete_spec.rb b/spec/integration/commands/delete_spec.rb index 8b32a754..eb88b735 100644 --- a/spec/integration/commands/delete_spec.rb +++ b/spec/integration/commands/delete_spec.rb @@ -1,12 +1,25 @@ # frozen_string_literal: true RSpec.describe 'Commands / Delete' do - include_context 'users and tasks' + include_context 'database setup' let(:delete_user) { user_commands.delete } + let(:user_commands) { container.commands[:users] } + with_adapters do - before do + setup_tables do + conn.drop_table?(:users) + + conn.create_table(:users) do + primary_key :id + String :name, null: false + end + end + + let(:users) { container.relations[:users] } + + setup_relations do conf.relation(:users) do def by_name(name) where(name: name) @@ -18,7 +31,9 @@ def by_name(name) result :one end end + end + seed do users.insert(id: 3, name: 'Jade') users.insert(id: 4, name: 'John') end diff --git a/spec/integration/commands/update_spec.rb b/spec/integration/commands/update_spec.rb index 0905d963..7d1cca78 100644 --- a/spec/integration/commands/update_spec.rb +++ b/spec/integration/commands/update_spec.rb @@ -14,7 +14,7 @@ let(:peter) { { name: 'Peter' } } with_adapters do - before do + setup_relations do Test::User = Class.new(Dry::Struct) { attribute :id, Types::Strict::Integer attribute :name, Types::Strict::String @@ -53,7 +53,9 @@ def by_name(name) conf.mappers do register :users, entity: -> tuples { tuples.map { |tuple| Test::User.new(tuple) } } end + end + seed do users.insert(name: 'Piotr') users.insert(name: 'Jane') end @@ -114,7 +116,7 @@ def by_name(name) context 'with json notes' do include_context 'json_notes' - before do + setup_relations do conf.commands(:json_notes) do define(:update) end diff --git a/spec/integration/commands/upsert_spec.rb b/spec/integration/commands/upsert_spec.rb index a4a59ab2..71ab7c2c 100644 --- a/spec/integration/commands/upsert_spec.rb +++ b/spec/integration/commands/upsert_spec.rb @@ -5,9 +5,11 @@ include_context 'relations' - before do + setup_tables do conn.execute 'ALTER TABLE tasks add CONSTRAINT tasks_title_key UNIQUE (title)' + end + seed do conn[:users].insert id: 1, name: 'Jane' conn[:users].insert id: 2, name: 'Joe' conn[:users].insert id: 3, name: 'Jean' @@ -17,7 +19,7 @@ let(:task) { { title: 'task 1', user_id: 1 } } let(:excluded) { task.merge(user_id: 3) } - before do + setup_relations do command_config = self.command_config conf.commands(:tasks) do @@ -30,7 +32,7 @@ end end - before { command.relation.upsert(task) } + seed { command.relation.upsert(task) } context 'on conflict do nothing' do let(:command_config) { -> {} } @@ -54,9 +56,9 @@ end context 'with index predicate' do - before do + setup_tables do conn.execute <<~SQL - ALTER TABLE tasks DROP CONSTRAINT tasks_title_key; + ALTER TABLE tasks DROP CONSTRAINT IF EXISTS tasks_title_key; CREATE UNIQUE INDEX tasks_title_partial_index ON tasks (title) WHERE user_id = 1; @@ -74,7 +76,7 @@ context 'when predicate matches' do let(:excluded) { task } - it 'returns updated data', :aggregate_failures do + it 'returns updated data' do expect(command.call(excluded)).to eql(id: 1, user_id: 2, title: 'task 1') end end @@ -82,7 +84,7 @@ context 'when predicate does not match' do let(:excluded) { task.update(user_id: 2) } - it 'creates new task', :aggregate_failures do + it 'creates new task' do expect(command.call(excluded)).to eql(id: 2, user_id: 2, title: 'task 1') end end diff --git a/spec/integration/gateway_spec.rb b/spec/integration/gateway_spec.rb index ba505a3a..cc489f78 100644 --- a/spec/integration/gateway_spec.rb +++ b/spec/integration/gateway_spec.rb @@ -12,7 +12,6 @@ subject(:gateway) { container.gateways[:default] } let(:conf) { ROM::Configuration.new(:sql, conn) } - let(:container) { ROM.container(conf) } it 'allows creating and running migrations' do migration = gateway.migration do @@ -49,7 +48,6 @@ let(:migrator) { ROM::SQL::Migration::Migrator.new(conn, path: migration_dir) } let(:conf) { ROM::Configuration.new(:sql, [conn, migrator: migrator]) } - let(:container) { ROM.container(conf) } it 'returns true for pending migrations' do expect(container.gateways[:default].pending_migrations?).to be_truthy @@ -75,7 +73,6 @@ end let(:conf) { ROM::Configuration.new(:sql, [conn, migrator: { path: migration_dir }]) } - let(:container) { ROM.container(conf) } it 'runs migrations from a specified directory' do container.gateways[:default].run_migrations @@ -88,7 +85,7 @@ inferrable_relations.push(:names) end - before do + setup_tables do conn.create_table(:names) do String :name end diff --git a/spec/integration/migration_spec.rb b/spec/integration/migration_spec.rb index 0ce775aa..040be837 100644 --- a/spec/integration/migration_spec.rb +++ b/spec/integration/migration_spec.rb @@ -7,9 +7,13 @@ inferrable_relations.push(:dragons, :schema_migrations) end - with_adapters do - before { conf } + setup_tables do + %i[dragons turtles].each do |table| + conn.drop_table?(table) + end + end + with_adapters do it 'creates a migration for a specific gateway' do migration = ROM::SQL.migration(container) do change do @@ -37,6 +41,12 @@ let(:in_memory_connection) { container.gateways[:in_memory].connection } + before do + %i[dragons turtles].each do |table| + in_memory_connection.drop_table?(table) + end + end + it 'creates a migration for a specific gateway' do in_memory_migration = ROM::SQL.migration(container, :in_memory) do change do diff --git a/spec/integration/plugins/associates/many_to_many_spec.rb b/spec/integration/plugins/associates/many_to_many_spec.rb index 7928d393..05d9f983 100644 --- a/spec/integration/plugins/associates/many_to_many_spec.rb +++ b/spec/integration/plugins/associates/many_to_many_spec.rb @@ -14,32 +14,7 @@ users.by_pk(users.insert(name: 'John')).one end - before do - conf.relation(:tasks) do - schema(infer: true) do - associations do - has_many :tags, through: :task_tags - end - end - end - - conf.relation(:task_tags) do - schema(infer: true) do - associations do - belongs_to :tasks, as: :task - belongs_to :tags, as: :tag - end - end - end - - conf.relation(:tags) do - schema(infer: true) do - associations do - has_many :tasks, through: :task_tags - end - end - end - + setup_relations do conf.commands(:tags) do define(:create) do result :many diff --git a/spec/integration/plugins/associates_spec.rb b/spec/integration/plugins/associates_spec.rb index 46d48135..04baa8b5 100644 --- a/spec/integration/plugins/associates_spec.rb +++ b/spec/integration/plugins/associates_spec.rb @@ -9,7 +9,7 @@ let(:tasks) { container.commands[:tasks] } let(:tags) { container.commands[:tags] } - before do + setup_relations do conf.relation(:tasks) do schema(infer: true) do associations do @@ -35,7 +35,7 @@ { title: 'Task one' } end - before do + setup_relations do conf.commands(:users) do define(:create) { result :one } end @@ -61,12 +61,28 @@ ) end - it 'allows setting up multiple associations' do - command = tasks[:create] - .with_association(:user, key: %i[user_id id], parent: user) - .with_association(:other, key: %i[other_id id]) + context 'with multiple associations' do + setup_relations do + conf.relation(:users) do + schema(infer: true) + end + + conf.relation(:task_tags) do + schema(infer: true) + end + + conf.relation(:tags) do + schema(infer: true) + end + end + + it 'allows setting up multiple associations' do + command = tasks[:create] + .with_association(:user, key: %i[user_id id], parent: user) + .with_association(:other, key: %i[other_id id]) - expect(command.configured_associations).to eql(%i[user other]) + expect(command.configured_associations).to eql(%i[user other]) + end end end @@ -102,7 +118,7 @@ context 'with a schema' do include_context 'automatic FK setting' - before do + setup_relations do conf.relation(:tasks) do schema(infer: true) do associations do @@ -128,7 +144,9 @@ end context 'with many-to-many association' do - before do + setup_relations do + conf.relation(:users) { schema(infer: true) } + conf.relation(:tags) do schema(infer: true) do associations do @@ -221,15 +239,7 @@ container.commands[:tasks][:create].call(user_id: john[:id], title: 'John Task') end - before do - conf.relation(:tasks) do - schema(infer: true) do - associations do - belongs_to :user - end - end - end - + setup_relations do conf.commands(:users) do define(:create) do result :one diff --git a/spec/integration/plugins/auto_restrictions_spec.rb b/spec/integration/plugins/auto_restrictions_spec.rb index 2bfab97e..378030ba 100644 --- a/spec/integration/plugins/auto_restrictions_spec.rb +++ b/spec/integration/plugins/auto_restrictions_spec.rb @@ -1,10 +1,10 @@ # frozen_string_literal: true -RSpec.describe 'Plugins / :auto_restrictions', seeds: true do +RSpec.describe 'Plugins / :auto_restrictions' do include_context 'users and tasks' with_adapters do - before do + setup_tables(index: :tasks) do conn.add_index :tasks, :title, unique: true end @@ -19,7 +19,7 @@ end context 'with an inferred schema' do - before do + setup_tables(plguin: :index) do conf.plugin(:sql, relations: :auto_restrictions) end @@ -37,7 +37,7 @@ two: ROM.container(confs[:two]) } end - before do + setup_relations do class Test::Tasks < ROM::Relation[:sql] schema(:tasks, infer: true) end @@ -58,7 +58,7 @@ class Test::Tasks < ROM::Relation[:sql] end context 'with explicit schema' do - before do + setup_relations do conf.relation(:tasks) do schema do attribute :id, ROM::SQL::Types::Serial @@ -74,7 +74,7 @@ class Test::Tasks < ROM::Relation[:sql] end end - include_context 'auto-generated restriction view' + # include_context 'auto-generated restriction view' it 'generates restrictrions by a composite index' do expect(tasks.by_user_id_and_title(1, "Jane's task").first).to eql(id: 2, user_id: 1, title: "Jane's task") @@ -82,25 +82,29 @@ class Test::Tasks < ROM::Relation[:sql] end if metadata[:postgres] - # An auto-generated restriction should include the prediate from the index definition - # but it seems to be too much from my POV, better leave it to the user - # Note that this can be enabled later - it 'skips partial indexes' do - conf.relation(:tasks) do - schema do - attribute :id, ROM::SQL::Types::Serial - attribute :user_id, ROM::SQL::Types::Integer - attribute :title, ROM::SQL::Types::String - - indexes do - index :title, predicate: 'title is not null' + context 'with a partial index' do + setup_relations do + conf.relation(:tasks) do + schema do + attribute :id, ROM::SQL::Types::Serial + attribute :user_id, ROM::SQL::Types::Integer + attribute :title, ROM::SQL::Types::String + + indexes do + index :title, predicate: 'title is not null' + end end - end - use :auto_restrictions + use :auto_restrictions + end end - expect(tasks).not_to respond_to(:by_title) + # An auto-generated restriction should include the prediate from the index definition + # but it seems to be too much from my POV, better leave it to the user + # Note that this can be enabled later + it 'skips partial indexes' do + expect(tasks).not_to respond_to(:by_title) + end end end end diff --git a/spec/integration/plugins/explain_spec.rb b/spec/integration/plugins/explain_spec.rb index 155dc5b0..ac5a26df 100644 --- a/spec/integration/plugins/explain_spec.rb +++ b/spec/integration/plugins/explain_spec.rb @@ -5,7 +5,7 @@ RSpec.describe 'Plugins / :explain', :postgres do include_context 'users and tasks' - before do + setup_relations do conf.plugin(:sql, relations: :pg_explain) end diff --git a/spec/integration/plugins/full_text_search_spec.rb b/spec/integration/plugins/full_text_search_spec.rb index 0ee2d594..680fc4ba 100644 --- a/spec/integration/plugins/full_text_search_spec.rb +++ b/spec/integration/plugins/full_text_search_spec.rb @@ -5,7 +5,7 @@ RSpec.describe 'Plugins / :pg_full_text_search', :postgres do include_context 'users and tasks' - before do + setup_tables do conf.plugin(:sql, relations: :pg_full_text_search) end @@ -23,16 +23,12 @@ expect(result).to contain_exactly(task) end - it 'handles complex queries' do - conf.relation(:tasks) do - schema(infer: true) do - associations { belongs_to :user } - end - end - - searched_users = users.full_text_search([:name], 'Joe', language: 'simple') - result = tasks.exists(searched_users).pluck(:id) + context 'when handling complex queries' do + specify do + searched_users = users.full_text_search([:name], 'Joe', language: 'simple') + result = tasks.exists(searched_users).pluck(:id) - expect(result).to contain_exactly(1) + expect(result).to contain_exactly(1) + end end end diff --git a/spec/integration/plugins/pg_streaming_spec.rb b/spec/integration/plugins/pg_streaming_spec.rb index 1d999e9b..4e73a531 100644 --- a/spec/integration/plugins/pg_streaming_spec.rb +++ b/spec/integration/plugins/pg_streaming_spec.rb @@ -6,7 +6,7 @@ with_adapters(:postgres) do include_context 'users and tasks' - before do + setup_tables do skip 'it is not supported by jruby' if jruby? conf.plugin(:sql, relations: :pg_streaming) end @@ -25,10 +25,8 @@ tasks.with(auto_struct: true).stream_each { |task| result << task } - aggregate_failures do - tasks.dataset.to_a.each_with_index do |task_attrs, i| - expect(result[i]).to have_attributes(task_attrs) - end + tasks.dataset.to_a.each_with_index do |task_attrs, i| + expect(result[i]).to have_attributes(task_attrs) end end diff --git a/spec/integration/relation/default_views_spec.rb b/spec/integration/relation/default_views_spec.rb index 7aa533a9..8be38560 100644 --- a/spec/integration/relation/default_views_spec.rb +++ b/spec/integration/relation/default_views_spec.rb @@ -8,13 +8,15 @@ subject(:users) { relations[:users] } context 'when dataset is overridden' do - before do + setup_tables do conn.create_table(:users) do primary_key :id column :name, String column :email, String end + end + setup_relations do conf.relation(:users) do dataset { select(:name) } schema(infer: true) diff --git a/spec/integration/relation_schema_spec.rb b/spec/integration/relation_schema_spec.rb index 51a8c901..e88862e7 100644 --- a/spec/integration/relation_schema_spec.rb +++ b/spec/integration/relation_schema_spec.rb @@ -1,14 +1,12 @@ # frozen_string_literal: true -RSpec.describe 'Inferring schema from database' do +RSpec.describe 'Inferring schema from database', relations: false do include_context 'users' include_context 'posts' with_adapters do - context 'when database schema exists' do + context 'when database schema exists', relations: true do it 'infers the schema from the database relations' do - conf.relation(:users) - expect(container.relations.users.to_a) .to eql(container.gateways[:default][:users].to_a) end @@ -20,283 +18,363 @@ end end - context 'defining associations', seeds: false do - let(:config) { TestConfiguration.new(:sql, conn) } - let(:container) { ROM.container(config) } + context 'defining associations' do + let(:conf) { TestConfiguration.new(:sql, conn) } + + setup_relations do + conf.relation(:accounts) { schema(infer: true) } + conf.relation(:cards) { schema(infer: true) } + conf.relation(:posts_tags) { schema(infer: true) } + end let(:user_associations) do - config.relation(:accounts) { schema(infer: true) } - config.relation(:cards) { schema(infer: true) } - config.register_relation(Test::Users) container.relations[:users].associations end let(:post_associations) do - config.relation(:tags) { schema(infer: true) } - config.relation(:posts_tags) { schema(infer: true) } - config.register_relation(Test::Posts) container.relations[:posts].associations end let(:tag_associations) do - config.relation(:posts) { schema(infer: true) } - config.relation(:users) { schema(infer: true) } - config.relation(:posts_tags) { schema(infer: true) } - config.register_relation(Test::Tags) container.relations[:tags].associations end - it 'allows defining a one-to-many' do - class Test::Posts < ROM::Relation[:sql] - schema(:posts) do - associations do - one_to_many :tags + context 'with posts relation' do + context 'allows defining a one-to-many' do + setup_relations do + conf.relation(:tags) { schema(infer: true) } + + class Test::Posts < ROM::Relation[:sql] + schema(:posts) do + associations do + one_to_many :tags + end + end end + + conf.register_relation(Test::Posts) end - end - assoc = ROM::Associations::Definitions::OneToMany.new(:posts, :tags) + specify do + assoc = ROM::Associations::Definitions::OneToMany.new(:posts, :tags) - expect(post_associations[:tags].definition).to eql(assoc) - end + expect(post_associations[:tags].definition).to eql(assoc) + end + end - it 'allows defining a one-to-many using has_many shortcut' do - class Test::Posts < ROM::Relation[:sql] - schema(:posts) do - associations do - has_many :tags + context 'allows defining a one-to-many using has_many shortcut' do + setup_relations do + conf.relation(:tags) { schema(infer: true) } + + class Test::Posts < ROM::Relation[:sql] + schema(:posts) do + associations do + has_many :tags + end + end end + conf.register_relation(Test::Posts) end - end - assoc = ROM::Associations::Definitions::OneToMany.new(:posts, :tags) + specify do + assoc = ROM::Associations::Definitions::OneToMany.new(:posts, :tags) - expect(post_associations[:tags].definition).to eql(assoc) + expect(post_associations[:tags].definition).to eql(assoc) + end + end end - it 'allows defining a one-to-one' do - class Test::Users < ROM::Relation[:sql] - schema(:users) do - associations do - one_to_one :accounts + context 'allows defining a one-to-one' do + setup_relations do + class Test::Users < ROM::Relation[:sql] + schema(:users) do + associations do + one_to_one :accounts + end end end + conf.register_relation(Test::Users) end - assoc = ROM::Associations::Definitions::OneToOne.new(:users, :accounts) + specify do + assoc = ROM::Associations::Definitions::OneToOne.new(:users, :accounts) - expect(user_associations[:accounts].definition).to eql(assoc) + expect(user_associations[:accounts].definition).to eql(assoc) + end end - it 'allows defining a one-to-one using has_one shortcut' do - class Test::Users < ROM::Relation[:sql] - schema(:users) do - associations do - has_one :account + context 'allows defining a one-to-one using has_one shortcut' do + setup_relations do + class Test::Users < ROM::Relation[:sql] + schema(:users) do + associations do + has_one :account + end end end + conf.register_relation(Test::Users) end - assoc = ROM::Associations::Definitions::OneToOne.new(:users, :accounts, as: :account) + specify do + assoc = ROM::Associations::Definitions::OneToOne.new(:users, :accounts, as: :account) - expect(user_associations[:account].definition).to eql(assoc) - expect(user_associations[:account].definition.target).to be_aliased + expect(user_associations[:account].definition).to eql(assoc) + expect(user_associations[:account].definition.target).to be_aliased + end end - it 'allows defining a one-to-one using has_one shortcut with an alias' do - class Test::Users < ROM::Relation[:sql] - schema(:users) do - associations do - has_one :account, as: :user_account + context 'allows defining a one-to-one using has_one shortcut with an alias' do + setup_relations do + class Test::Users < ROM::Relation[:sql] + schema(:users) do + associations do + has_one :account, as: :user_account + end end end + conf.register_relation(Test::Users) end - assoc = ROM::Associations::Definitions::OneToOne.new(:users, :accounts, as: :user_account) + specify do + assoc = ROM::Associations::Definitions::OneToOne.new(:users, :accounts, as: :user_account) - expect(user_associations[:user_account].definition).to eql(assoc) - expect(user_associations[:user_account].definition.target).to be_aliased + expect(user_associations[:user_account].definition).to eql(assoc) + expect(user_associations[:user_account].definition.target).to be_aliased + end end - it 'allows defining a one-to-one-through' do - class Test::Users < ROM::Relation[:sql] - schema(:users) do - associations do - one_to_one :cards, through: :accounts + context 'allows defining a one-to-one-through' do + setup_relations do + class Test::Users < ROM::Relation[:sql] + schema(:users) do + associations do + one_to_one :cards, through: :accounts + end end end + conf.register_relation(Test::Users) end - assoc = ROM::Associations::Definitions::OneToOneThrough.new(:users, :cards, through: :accounts) + specify do + assoc = ROM::Associations::Definitions::OneToOneThrough.new(:users, :cards, through: :accounts) - expect(user_associations[:cards].definition).to eql(assoc) + expect(user_associations[:cards].definition).to eql(assoc) + end end - it 'allows defining a many-to-one' do - class Test::Tags < ROM::Relation[:sql] - schema(:tags) do - attribute :post_id, Types::Integer + context 'allows defining a many-to-one' do + setup_relations do + conf.relation(:posts) { schema(infer: true) } + + class Test::Tags < ROM::Relation[:sql] + schema(:tags) do + attribute :post_id, Types::Integer - associations do - many_to_one :posts + associations do + many_to_one :posts + end end end + conf.register_relation(Test::Tags) end - assoc = ROM::Associations::Definitions::ManyToOne.new(:tags, :posts) + specify do + assoc = ROM::Associations::Definitions::ManyToOne.new(:tags, :posts) - expect(tag_associations[:posts].definition).to eql(assoc) + expect(tag_associations[:posts].definition).to eql(assoc) + end end - it 'allows defining a many-to-one using belongs_to shortcut' do - class Test::Tags < ROM::Relation[:sql] - schema(:tags) do - attribute :post_id, Types::Integer + context 'allows defining a many-to-one using belongs_to shortcut' do + setup_relations do + conf.relation(:posts) { schema(infer: true) } + + class Test::Tags < ROM::Relation[:sql] + schema(:tags) do + attribute :post_id, Types::Integer - associations do - belongs_to :post + associations do + belongs_to :post + end end end + conf.register_relation(Test::Tags) end - assoc = ROM::Associations::Definitions::ManyToOne.new(:tags, :posts, as: :post) + specify do + assoc = ROM::Associations::Definitions::ManyToOne.new(:tags, :posts, as: :post) - expect(tag_associations[:post].definition).to eql(assoc) + expect(tag_associations[:post].definition).to eql(assoc) + end end - it 'allows defining a many-to-one using belongs_to shortcut' do - class Test::Tags < ROM::Relation[:sql] - schema(:tags) do - attribute :post_id, Types::Integer + context 'allows defining a many-to-one using belongs_to shortcut' do + setup_relations do + conf.relation(:posts) { schema(infer: true) } - associations do - belongs_to :post, as: :post_tag + class Test::Tags < ROM::Relation[:sql] + schema(:tags) do + attribute :post_id, Types::Integer + + associations do + belongs_to :post, as: :post_tag + end end end + conf.register_relation(Test::Tags) end - assoc = ROM::Associations::Definitions::ManyToOne.new(:tags, :posts, as: :post_tag) + specify do + assoc = ROM::Associations::Definitions::ManyToOne.new(:tags, :posts, as: :post_tag) - expect(tag_associations[:post_tag].definition).to eql(assoc) + expect(tag_associations[:post_tag].definition).to eql(assoc) + end end - it 'allows defining a many-to-many' do - class Test::Posts < ROM::Relation[:sql] - schema(:posts) do - associations do - one_to_many :tags, through: :posts_tags + context 'allows defining a many-to-many' do + setup_relations do + conf.relation(:tags) { schema(infer: true) } + + class Test::Posts < ROM::Relation[:sql] + schema(:posts) do + associations do + one_to_many :tags, through: :posts_tags + end end end + conf.register_relation(Test::Posts) end - assoc = ROM::Associations::Definitions::ManyToMany.new(:posts, :tags, through: :posts_tags) + specify do + assoc = ROM::Associations::Definitions::ManyToMany.new(:posts, :tags, through: :posts_tags) - expect(post_associations[:tags].definition).to eql(assoc) + expect(post_associations[:tags].definition).to eql(assoc) + end end - it 'allows defining a many-to-one with a custom name' do - class Test::Tags < ROM::Relation[:sql] - schema(:tags) do - attribute :post_id, Types::Integer + context 'allows defining a many-to-one with a custom name' do + setup_relations do + conf.relation(:posts) { schema(infer: true) } + + class Test::Tags < ROM::Relation[:sql] + schema(:tags) do + attribute :post_id, Types::Integer - associations do - many_to_one :posts, as: :published_posts + associations do + many_to_one :posts, as: :published_posts + end end end + conf.register_relation(Test::Tags) end - assoc = ROM::Associations::Definitions::ManyToOne.new(:tags, :posts, as: :published_posts) + specify do + assoc = ROM::Associations::Definitions::ManyToOne.new(:tags, :posts, as: :published_posts) - expect(tag_associations[:published_posts].definition).to eql(assoc) + expect(tag_associations[:published_posts].definition).to eql(assoc) + end end - it 'adds foreign keys to the schema' do - class Test::Tags < ROM::Relation[:sql] - schema(:tags) do - attribute :id, Types::Serial - attribute :post_id, Types::ForeignKey(:posts) + context 'adds foreign keys to the schema' do + setup_relations do + class Test::Tags < ROM::Relation[:sql] + schema(:tags) do + attribute :id, Types::Serial + attribute :post_id, Types::ForeignKey(:posts) + end end - end - config.relation(:posts) { schema(infer: true) } - config.relation(:users) { schema(infer: true) } - config.register_relation(Test::Tags) + conf.relation(:posts) { schema(infer: true) } + conf.relation(:users) { schema(infer: true) } + conf.register_relation(Test::Tags) + end - tags = container.relations[:tags].schema + specify do + tags = container.relations[:tags].schema - expect(tags.foreign_keys.size).to eql(1) + expect(tags.foreign_keys.size).to eql(1) - fk = tags.foreign_keys.first + fk = tags.foreign_keys.first - expect(fk.parent_table).to be(:posts) - expect(fk.attributes[0].name).to be(:post_id) + expect(fk.parent_table).to be(:posts) + expect(fk.attributes[0].name).to be(:post_id) + end end end context 'defining indexes', :helpers do |_ctx| - it 'allows defining indexes' do - class Test::Tags < ROM::Relation[:sql] - schema(:tags) do - attribute :id, Types::Serial - attribute :name, Types::String - attribute :created_at, Types::Time - attribute :updated_at, Types::Time - - indexes do - index :name - index :created_at, :name - index :updated_at, name: :recently_idx - index :created_at, name: :unique_date, unique: true - end - end - end - - conf.register_relation(Test::Tags) - schema = container.relations[:tags].schema - - expect(schema.indexes.to_a).to contain_exactly( - ROM::SQL::Index.new([define_attribute(:name, :String, source: schema.name)]), - ROM::SQL::Index.new( - [define_attribute(:created_at, :Time, source: schema.name), - define_attribute(:name, :String, source: schema.name)] - ), - ROM::SQL::Index.new( - [define_attribute(:updated_at, :Time, source: schema.name)], - name: :recently_idx - ), - ROM::SQL::Index.new( - [define_attribute(:created_at, :Time, source: schema.name)], - name: :unique_date, - unique: true - ) - ) - end - - if metadata[:postgres] - it 'can provide index type' do + context 'allows defining indexes' do + setup_relations do class Test::Tags < ROM::Relation[:sql] schema(:tags) do - attribute :id, Types::Serial - attribute :name, Types::String + attribute :id, Types::Serial + attribute :name, Types::String + attribute :created_at, Types::Time + attribute :updated_at, Types::Time indexes do - index :name, type: :gist + index :name + index :created_at, :name + index :updated_at, name: :recently_idx + index :created_at, name: :unique_date, unique: true end end end conf.register_relation(Test::Tags) + end + + specify do schema = container.relations[:tags].schema - index = schema.indexes.first - expect(index).to eql( + expect(schema.indexes.to_a).to contain_exactly( + ROM::SQL::Index.new([define_attribute(:name, :String, source: schema.name)]), + ROM::SQL::Index.new( + [define_attribute(:created_at, :Time, source: schema.name), + define_attribute(:name, :String, source: schema.name)] + ), ROM::SQL::Index.new( - [define_attribute(:name, :String, source: schema.name)], - type: :gist + [define_attribute(:updated_at, :Time, source: schema.name)], + name: :recently_idx + ), + ROM::SQL::Index.new( + [define_attribute(:created_at, :Time, source: schema.name)], + name: :unique_date, + unique: true ) ) + end + end + + if metadata[:postgres] + context 'can provide index type' do + setup_relations do + class Test::Tags < ROM::Relation[:sql] + schema(:tags) do + attribute :id, Types::Serial + attribute :name, Types::String + + indexes do + index :name, type: :gist + end + end + end + conf.register_relation(Test::Tags) + end + + specify do + schema = container.relations[:tags].schema + index = schema.indexes.first - expect(index.type).to eql(:gist) + expect(index).to eql( + ROM::SQL::Index.new( + [define_attribute(:name, :String, source: schema.name)], + type: :gist + ) + ) + + expect(index.type).to eql(:gist) + end end end end diff --git a/spec/integration/schema/call_spec.rb b/spec/integration/schema/call_spec.rb index 44f7b2a4..11aae489 100644 --- a/spec/integration/schema/call_spec.rb +++ b/spec/integration/schema/call_spec.rb @@ -6,12 +6,6 @@ include_context 'users' with_adapters :postgres do - before do - conf.relation(:users) do - schema(infer: true) - end - end - let(:schema) { relations[:users].schema } it 'auto-projects a relation' do diff --git a/spec/integration/schema/inferrer/mysql_spec.rb b/spec/integration/schema/inferrer/mysql_spec.rb index d669f873..a2b5adaa 100644 --- a/spec/integration/schema/inferrer/mysql_spec.rb +++ b/spec/integration/schema/inferrer/mysql_spec.rb @@ -7,7 +7,7 @@ inferrable_relations.push(:test_inferrence) end - before do + setup_tables do conn.create_table :test_inferrence do tinyint :tiny mediumint :medium @@ -26,7 +26,7 @@ end end - before do + setup_relations do conf.relation(:test_inferrence) do schema(infer: true) end diff --git a/spec/integration/schema/inferrer/postgres_spec.rb b/spec/integration/schema/inferrer/postgres_spec.rb index 8a6fbe14..c3c25113 100644 --- a/spec/integration/schema/inferrer/postgres_spec.rb +++ b/spec/integration/schema/inferrer/postgres_spec.rb @@ -9,7 +9,7 @@ colors = %w[red orange yellow green blue purple] - before do + setup_tables do conn.execute('create extension if not exists hstore') conn.execute('create extension if not exists ltree') @@ -68,7 +68,7 @@ end context 'when pg_enum in primary key' do - before do + setup_tables do conn.drop_table?(:test_inferrence) conn.create_table(:test_inferrence) do column :colours, :rainbow @@ -77,9 +77,11 @@ end it 'can infer primary key on enum column' do - expect(schema.to_h).to eql(attributes( - colours: ROM::SQL::Types::String.enum(*colors).meta(primary_key: true) - )) + expect(schema.to_h).to eql( + attributes( + colours: ROM::SQL::Types::String.enum(*colors).meta(primary_key: true) + ) + ) end end @@ -129,8 +131,11 @@ end context 'with a table without columns' do - before do + setup_tables do conn.create_table(:dummy) unless conn.table_exists?(:dummy) + end + + setup_relations do conf.relation(:dummy) { schema(infer: true) } end @@ -140,7 +145,7 @@ end context 'with a column with bi-directional mapping' do - before do + setup_tables do conn.execute('create extension if not exists hstore') conn.execute('create extension if not exists ltree') @@ -164,7 +169,9 @@ daterange :daterange ltree :ltree_path end + end + setup_relations do conf.relation(:test_bidirectional) { schema(infer: true) } conf.commands(:test_bidirectional) do diff --git a/spec/integration/schema/inferrer/sqlite_spec.rb b/spec/integration/schema/inferrer/sqlite_spec.rb index 5f0f9c42..76c22d56 100644 --- a/spec/integration/schema/inferrer/sqlite_spec.rb +++ b/spec/integration/schema/inferrer/sqlite_spec.rb @@ -7,7 +7,7 @@ inferrable_relations.push(:test_inferrence) end - before do + setup_tables do conn.create_table :test_inferrence do tinyint :tiny int8 :big @@ -17,7 +17,7 @@ end end - before do + setup_relations do conf.relation(:test_inferrence) do schema(infer: true) end diff --git a/spec/integration/schema/inferrer_spec.rb b/spec/integration/schema/inferrer_spec.rb index 06b2e612..02065f39 100644 --- a/spec/integration/schema/inferrer_spec.rb +++ b/spec/integration/schema/inferrer_spec.rb @@ -20,7 +20,7 @@ def index_by_name(indexes, name) with_adapters do |_adapter| describe 'inferring attributes' do - before do + setup_relations do dataset = self.dataset conf.relation(dataset) do schema(dataset, infer: true) @@ -63,7 +63,7 @@ def index_by_name(indexes, name) end context 'for complex table' do - before do |example| + setup_tables do |example| ctx = self conn.create_table :test_inferrence do @@ -118,7 +118,7 @@ def index_by_name(indexes, name) end context 'character datatypes' do - before do + setup_tables do conn.create_table :test_characters do String :text1, text: false, null: false String :text2, size: 100, null: false @@ -163,7 +163,7 @@ def index_by_name(indexes, name) end context 'numeric datatypes' do - before do + setup_tables do conn.create_table :test_numeric do primary_key :id decimal :dec, null: false @@ -221,7 +221,7 @@ def index_by_name(indexes, name) let(:relation) { container.relations[:people] } - before do + setup_relations do conf.relation(:people) do schema(infer: true) end @@ -237,7 +237,7 @@ def index_by_name(indexes, name) let(:create) { commands[:people].create } context "Sequel's types" do - before do + setup_tables do conn.create_table :people do primary_key :id String :name, null: false @@ -252,7 +252,7 @@ def index_by_name(indexes, name) end context 'nullable columns' do - before do + setup_tables do conn.create_table :people do primary_key :id String :name, null: false @@ -274,7 +274,7 @@ def index_by_name(indexes, name) end context 'columns with default value' do - before do + setup_tables do conn.create_table :people do primary_key :id String :name, null: false @@ -295,7 +295,7 @@ def index_by_name(indexes, name) context 'coercions' do context 'date' do - before do + setup_tables do conn.create_table :people do primary_key :id String :name, null: false @@ -315,7 +315,7 @@ def index_by_name(indexes, name) unless metadata[:sqlite] && defined? JRUBY_VERSION context 'timestamp' do - before do |ex| + setup_tables do |ex| ctx = self conn.create_table :people do @@ -375,48 +375,63 @@ def index_by_name(indexes, name) let(:dataset) { :test_inferrence } let(:source) { ROM::Relation::Name[dataset] } - it 'infers types with indices' do - conn.create_table :test_inferrence do - primary_key :id - Integer :foo - Integer :bar, null: false - Integer :baz, null: false + context 'inferring types with indices' do + setup_tables do + conn.create_table :test_inferrence do + primary_key :id + Integer :foo + Integer :bar, null: false + Integer :baz, null: false - index :foo, name: :foo_idx - index :bar, name: :bar_idx - index :baz, name: :baz1_idx - index :baz, name: :baz2_idx + index :foo, name: :foo_idx + index :bar, name: :bar_idx + index :baz, name: :baz1_idx + index :baz, name: :baz2_idx - index %i[bar baz], name: :composite_idx - index %i[foo bar], name: :unique_idx, unique: true + index %i[bar baz], name: :composite_idx + index %i[foo bar], name: :unique_idx, unique: true + end end - conf.relation(:test_inferrence) { schema(infer: true) } + setup_relations do + conf.relation(:test_inferrence) { schema(infer: true) } + end - expect(schema.indexes.map(&:name)).to match_array( - %i[foo_idx bar_idx baz1_idx baz2_idx composite_idx unique_idx] - ) + it 'infers types with indices' do + expect(schema.indexes.map(&:name)).to match_array( + %i[foo_idx bar_idx baz1_idx baz2_idx composite_idx unique_idx] + ) - unique_idx = index_by_name(schema.indexes, :unique_idx) + unique_idx = index_by_name(schema.indexes, :unique_idx) - expect(unique_idx).to be_unique + expect(unique_idx).to be_unique + end end if metadata[:postgres] - it 'infers cutsom index types' do - pending 'Sequel not returning index type' - conn.create_table :test_inferrence do - primary_key :id - Integer :foo - index :foo, name: :foo_idx, type: :gist + context 'infers cutsom index types' do + setup_tables do + conn.execute('create extension if not exists btree_gist') + + conn.create_table :test_inferrence do + primary_key :id + Integer :foo + index :foo, name: :foo_idx, type: :gist + end end - conf.relation(:test_inferrence) { schema(infer: true) } + setup_relations do + conf.relation(:test_inferrence) { schema(infer: true) } + end - index = schema.indexes.first + it 'infers cutsom index types' do + pending 'Sequel not returning index type' - expect(index.name).to eql(:foo_idx) - expect(index.type).to eql(:gist) + index = schema.indexes.first + + expect(index.name).to eql(:foo_idx) + expect(index.type).to eql(:gist) + end end end end diff --git a/spec/integration/schema/prefix_spec.rb b/spec/integration/schema/prefix_spec.rb index 401cef50..afeb962b 100644 --- a/spec/integration/schema/prefix_spec.rb +++ b/spec/integration/schema/prefix_spec.rb @@ -2,15 +2,9 @@ require 'spec_helper' -RSpec.describe ROM::SQL::Schema, '#prefix', :postgres, seeds: false do +RSpec.describe ROM::SQL::Schema, '#prefix', :postgres do include_context 'users' - before do - conf.relation(:users) do - schema(infer: true) - end - end - it 'auto-projects a relation with renamed columns using provided prefix' do expect(relations[:users].schema.prefix(:user).(relations[:users]).dataset.sql) .to eql('SELECT "users"."id" AS "user_id", "users"."name" AS "user_name" FROM "users" ORDER BY "users"."id"') diff --git a/spec/integration/schema/qualified_spec.rb b/spec/integration/schema/qualified_spec.rb index 505c967b..771b668b 100644 --- a/spec/integration/schema/qualified_spec.rb +++ b/spec/integration/schema/qualified_spec.rb @@ -2,15 +2,9 @@ require 'spec_helper' -RSpec.describe ROM::SQL::Schema, '#qualified', :postgres, seeds: false do +RSpec.describe ROM::SQL::Schema, '#qualified', :postgres do include_context 'users' - before do - conf.relation(:users) do - schema(infer: true) - end - end - it 'qualifies column names' do expect(relations[:users].schema.qualified.(relations[:users]).dataset.sql) .to eql('SELECT "users"."id", "users"."name" FROM "users" ORDER BY "users"."id"') diff --git a/spec/integration/schema/rename_spec.rb b/spec/integration/schema/rename_spec.rb index b455ee64..b52ca5fa 100644 --- a/spec/integration/schema/rename_spec.rb +++ b/spec/integration/schema/rename_spec.rb @@ -2,15 +2,9 @@ require 'spec_helper' -RSpec.describe ROM::SQL::Schema, '#rename', :postgres, seeds: false do +RSpec.describe ROM::SQL::Schema, '#rename', :postgres do include_context 'users' - before do - conf.relation(:users) do - schema(infer: true) - end - end - it 'auto-projects a relation with renamed' do expect(relations[:users].schema.qualified.rename(id: :user_id, name: :user_name).(relations[:users]).dataset.sql) .to eql('SELECT "users"."id" AS "user_id", "users"."name" AS "user_name" FROM "users" ORDER BY "users"."id"') diff --git a/spec/integration/schema/view_spec.rb b/spec/integration/schema/view_spec.rb index 4dedad16..de762305 100644 --- a/spec/integration/schema/view_spec.rb +++ b/spec/integration/schema/view_spec.rb @@ -7,7 +7,7 @@ with_adapters do describe 'defining a projected view' do - before do + setup_relations do conf.relation(:users) do schema(infer: true) @@ -16,7 +16,9 @@ relation { order(:name, :id) } end end + end + seed do container.relations[:users].insert(name: 'Joe') container.relations[:users].insert(name: 'Jane') container.relations[:users].insert(name: 'Jade') diff --git a/spec/integration/support/active_support_notifications_spec.rb b/spec/integration/support/active_support_notifications_spec.rb index cf07d5cf..f15dd0f8 100644 --- a/spec/integration/support/active_support_notifications_spec.rb +++ b/spec/integration/support/active_support_notifications_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'ActiveSupport::Notifications support', :postgres, seeds: false do +RSpec.describe 'ActiveSupport::Notifications support', :postgres do before do ROM::SQL.load_extensions(:active_support_notifications, :rails_log_subscriber) end diff --git a/spec/integration/support/rails_log_subscriber_spec.rb b/spec/integration/support/rails_log_subscriber_spec.rb index 91ae763b..33cf2f4a 100644 --- a/spec/integration/support/rails_log_subscriber_spec.rb +++ b/spec/integration/support/rails_log_subscriber_spec.rb @@ -4,7 +4,7 @@ require 'active_support/log_subscriber/test_helper' -RSpec.describe 'Rails log subscriber', :postgres, seeds: false do +RSpec.describe 'Rails log subscriber', :postgres do before do ROM::SQL.load_extensions(:active_support_notifications, :rails_log_subscriber) end diff --git a/spec/integration/wrap_spec.rb b/spec/integration/wrap_spec.rb index fa07e616..16eb512c 100644 --- a/spec/integration/wrap_spec.rb +++ b/spec/integration/wrap_spec.rb @@ -30,7 +30,7 @@ end context 'using association with inferred relation name' do - before do + setup_relations do conf.relation(:tasks) do auto_map false @@ -48,7 +48,7 @@ end context 'using association with an alias' do - before do + setup_relations do conf.relation(:tasks) do auto_map false @@ -66,7 +66,7 @@ end context 'using association with an aliased relation' do - before do + setup_relations do conf.relation(:tasks) do auto_map false @@ -91,7 +91,7 @@ end context 'using association with a view' do - before do + setup_relations do conf.relation(:users) do auto_map false diff --git a/spec/shared/accounts.rb b/spec/shared/accounts.rb index fa61dfae..46f150c2 100644 --- a/spec/shared/accounts.rb +++ b/spec/shared/accounts.rb @@ -8,7 +8,7 @@ inferrable_relations.push(:accounts, :cards, :subscriptions) end - before do |example| + setup_tables do |example| ctx = self conn.create_table :accounts do @@ -34,15 +34,15 @@ Integer :card_id String :service end + end + setup_relations do conf.relation(:accounts) { schema(infer: true) } conf.relation(:cards) { schema(infer: true) } conf.relation(:subscriptions) { schema(infer: true) } end - before do |example| - next if example.metadata[:seeds] == false - + seed do conn[:accounts].insert user_id: 1, number: '42', balance: 10_000.to_d conn[:cards].insert id: 1, account_id: 1, pan: '*6789' conn[:subscriptions].insert id: 1, card_id: 1, service: 'aws' diff --git a/spec/shared/articles.rb b/spec/shared/articles.rb index c3fd54fc..44508487 100644 --- a/spec/shared/articles.rb +++ b/spec/shared/articles.rb @@ -5,7 +5,7 @@ inferrable_relations.push(:articles) end - before do + setup_tables do conn.create_table :articles do primary_key :article_id String :author_name @@ -16,13 +16,13 @@ index :author_name index :status end + end + setup_relations do conf.relation(:articles) { schema(infer: true) } end - before do |example| - next if example.metadata[:seeds] == false - + seed do conn[:users].insert(name: 'John') conn[:articles].insert( diff --git a/spec/shared/database_setup.rb b/spec/shared/database_setup.rb index 80dfa7de..7dda034c 100644 --- a/spec/shared/database_setup.rb +++ b/spec/shared/database_setup.rb @@ -5,11 +5,11 @@ accounts cards subscriptions notes destinations flights categories user_group test_inferrence test_bidirectional people dragons - rabbits carrots names schema_migrations] + rabbits carrots names schema_migrations puzzles] cleared_dbs = [] - before do + setup_tables(:db) do unless cleared_dbs.include?(conn.database_type) all_tables.reverse.each { |table| conn.drop_table?(table) } cleared_dbs << conn.database_type @@ -32,7 +32,6 @@ let(:database_type) { conn.database_type } let(:inferrable_relations) { [] } let(:conf) { TestConfiguration.new(:sql, conn) } - let(:container) { ROM.container(conf) } let(:relations) { container.relations } let(:commands) { container.commands } diff --git a/spec/shared/json_notes.rb b/spec/shared/json_notes.rb index 22e729a2..efc1ed85 100644 --- a/spec/shared/json_notes.rb +++ b/spec/shared/json_notes.rb @@ -5,12 +5,15 @@ inferrable_relations.push(:json_notes) end - before do |_example| + setup_tables do + conn.drop_table?(:json_notes) conn.create_table :json_notes do primary_key :id String :note end + end + setup_relations do write_type = Dry.Types.Constructor(String) { |value| JSON.dump({ content: value }) } read_type = Dry.Types.Constructor(String) { |value| JSON.parse(value)['content'] } diff --git a/spec/shared/notes.rb b/spec/shared/notes.rb index a66445a7..e5295cf5 100644 --- a/spec/shared/notes.rb +++ b/spec/shared/notes.rb @@ -5,7 +5,7 @@ inferrable_relations.push(:notes) end - before do |example| + setup_tables(notes: :users) do |example| ctx = self conn.create_table :notes do @@ -18,7 +18,11 @@ DateTime :completed_at Date :written end + end - conf.relation(:notes) { schema(infer: true) } + setup_relations do |example| + if example.metadata[:relations] != false + conf.relation(:notes) { schema(infer: true) } + end end end diff --git a/spec/shared/posts.rb b/spec/shared/posts.rb index 10d84bfa..a7e0c961 100644 --- a/spec/shared/posts.rb +++ b/spec/shared/posts.rb @@ -5,32 +5,36 @@ inferrable_relations.push(:posts) end - before do |_example| + setup_tables(posts: :users) do conn.create_table :posts do primary_key :post_id foreign_key :author_id, :users String :title String :body end - - conf.relation(:posts) { schema(infer: true) } end - before do |example| - next if example.metadata[:seeds] == false + setup_relations do |example| + if example.metadata[:relations] != false + conf.relation(:posts) { schema(infer: true) } + end + end - conn[:posts].insert( - post_id: 1, - author_id: 2, - title: "Joe's post", - body: 'Joe wrote sutin' - ) + seed(posts: :users) do |example| + if example.metadata[:seeds] != false + conn[:posts].insert( + post_id: 1, + author_id: 2, + title: "Joe's post", + body: 'Joe wrote sutin' + ) - conn[:posts].insert( - post_id: 2, - author_id: 1, - title: "Jane's post", - body: 'Jane wrote sutin' - ) + conn[:posts].insert( + post_id: 2, + author_id: 1, + title: "Jane's post", + body: 'Jane wrote sutin' + ) + end end end diff --git a/spec/shared/puppies.rb b/spec/shared/puppies.rb index 677833dd..5620e4c7 100644 --- a/spec/shared/puppies.rb +++ b/spec/shared/puppies.rb @@ -5,13 +5,15 @@ inferrable_relations.push(:puppies) end - before do + setup_tables do conn.create_table :puppies do primary_key :id String :name, null: false boolean :cute, null: false, default: true end + end + setup_relations do conf.relation(:puppies) { schema(infer: true) } end end diff --git a/spec/shared/relations.rb b/spec/shared/relations.rb index 5159e851..a027a9d6 100644 --- a/spec/shared/relations.rb +++ b/spec/shared/relations.rb @@ -2,9 +2,4 @@ RSpec.shared_context 'relations' do include_context 'users and tasks' - - before do - conf.relation(:users) { schema(infer: true) } - conf.relation(:tasks) { schema(infer: true) } - end end diff --git a/spec/shared/users.rb b/spec/shared/users.rb index 8244ca09..8ac77d94 100644 --- a/spec/shared/users.rb +++ b/spec/shared/users.rb @@ -13,7 +13,7 @@ let(:jane_id) { 1 } let(:joe_id) { 2 } - before do |example| + setup_tables(users: :db) do |example| ctx = self conn.create_table :users do @@ -21,16 +21,18 @@ String :name, text: false, null: false check { char_length(name) > 2 } if ctx.postgres?(example) end + end + setup_relations(:users) do |example| if example.metadata[:relations] != false conf.relation(:users) { schema(infer: true) } end end - before do |example| - next if example.metadata[:seeds] == false - - conn[:users].insert name: 'Jane' - conn[:users].insert name: 'Joe' + seed(:users) do |example| + if example.metadata[:seeds] != false + conn[:users].insert name: 'Jane' + conn[:users].insert name: 'Joe' + end end end diff --git a/spec/shared/users_and_tasks.rb b/spec/shared/users_and_tasks.rb index 2fb8c669..8557e417 100644 --- a/spec/shared/users_and_tasks.rb +++ b/spec/shared/users_and_tasks.rb @@ -13,7 +13,7 @@ inferrable_relations.push(:tasks, :tags, :task_tags) end - before do |example| + setup_tables(tasks: :users) do |example| ctx = self conn.create_table :tasks do @@ -35,21 +35,53 @@ Integer :tag_id Integer :task_id end + end + setup_relations(tasks: :users) do |example| if example.metadata[:relations] != false - conf.relation(:tasks) { schema(infer: true) } - conf.relation(:task_tags) { schema(infer: true) } - conf.relation(:tags) { schema(infer: true) } + conf.relation(:users) do + schema(infer: true) do + associations do + has_many :tasks + end + end + end + + conf.relation(:tasks) do + schema(infer: true) do + associations do + belongs_to :user + has_many :tags, through: :task_tags + end + end + end + + conf.relation(:task_tags) do + schema(infer: true) do + associations do + belongs_to :task + belongs_to :tag + end + end + end + + conf.relation(:tags) do + schema(infer: true) do + associations do + has_many :tasks, through: :task_tags + end + end + end end end - before do |example| - next if example.metadata[:seeds] == false - - conn[:tasks].insert id: 1, user_id: 2, title: "Joe's task" - conn[:tasks].insert id: 2, user_id: 1, title: "Jane's task" + seed(tasks: :users) do |example| + if example.metadata[:seeds] != false + conn[:tasks].insert id: 1, user_id: 2, title: "Joe's task" + conn[:tasks].insert id: 2, user_id: 1, title: "Jane's task" - conn[:tags].insert id: 1, name: 'important' - conn[:task_tags].insert(tag_id: 1, task_id: 1) + conn[:tags].insert id: 1, name: 'important' + conn[:task_tags].insert(tag_id: 1, task_id: 1) + end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 84d42a72..c8b6358f 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -151,4 +151,6 @@ module Test config.include(Helpers, helpers: true) config.include ENVHelper + + ContainerHelper.install(config) end diff --git a/spec/support/container_helper.rb b/spec/support/container_helper.rb new file mode 100644 index 00000000..b2419e34 --- /dev/null +++ b/spec/support/container_helper.rb @@ -0,0 +1,110 @@ +# frozen_string_literal: true + +module ContainerHelper + Entry = ::Struct.new(:block, :provides, :depends_on) + + def self.install(config) + config.extend(DSL) + config.include(InstanceMethods) + end + + def self.parse_dependency(arg) + case arg + when nil + [nil, []] + when ::Symbol + [arg, []] + when ::Hash + raise ::ArgumentError, "expected a single-key hash, got #{arg.inspect}" if arg.size != 1 + + key, value = arg.first + [key, Array(value)] + else + raise ::ArgumentError, "expected a Symbol or a single-key Hash, got #{arg.inspect}" + end + end + + def self.sort_entries(entries) + sorted, unsorted = entries.partition(&:provides) + by_name = sorted.to_h { |entry| [entry.provides, entry] } + state = {} + result = [] + + visit = lambda do |entry| + case state[entry] + when :done then return + when :visiting then raise "circular dependency detected at #{entry.provides.inspect}" + end + + state[entry] = :visiting + entry.depends_on.each do |dep_name| + dep_entry = by_name[dep_name] + visit.call(dep_entry) if dep_entry + end + state[entry] = :done + result << entry + end + + sorted.each(&visit) + result.concat(unsorted) + end + + module DSL + def container_blocks + @container_blocks ||= ::Hash.new do |hash, key| + hash[key] = [] + end + end + + def all_blocks(group) + entries = ancestors.select { |ancestor| + ancestor.is_a?(::Class) && ancestor.respond_to?(:container_blocks) + }.reverse.flat_map { |klass| klass.container_blocks[group] } + + ContainerHelper.sort_entries(entries).map(&:block) + end + + def setup_relations(dependency = nil, &block) + provides, depends_on = ContainerHelper.parse_dependency(dependency) + container_blocks[:relations] << Entry.new(block, provides, depends_on) + end + + def seed(dependency = nil, &block) + provides, depends_on = ContainerHelper.parse_dependency(dependency) + container_blocks[:seeds] << Entry.new(block, provides, depends_on) + end + + def setup_tables(dependency = nil, &block) + provides, depends_on = ContainerHelper.parse_dependency(dependency) + container_blocks[:tables] << Entry.new(block, provides, depends_on) + end + end + + module InstanceMethods + def self.included(base) + base.let(:container) do |example| + self.class.all_blocks(:tables).each do |block| + instance_exec(example, &block) + end + + self.class.all_blocks(:relations).each do |block| + instance_exec(example, &block) + end + + ::ROM.container(conf) + end + + base.before do |example| + seeds = self.class.all_blocks(:seeds) + + if seeds.any? + container + + seeds.each do |block| + instance_exec(example, &block) + end + end + end + end + end +end diff --git a/spec/unit/commands/create_spec.rb b/spec/unit/commands/create_spec.rb index 6d34879b..f6b168ed 100644 --- a/spec/unit/commands/create_spec.rb +++ b/spec/unit/commands/create_spec.rb @@ -15,13 +15,15 @@ end describe '#call' do - before do + setup_tables do conn.create_table :books do primary_key :id column :author, String column :title, String end + end + setup_relations do conf.relation(:books) do schema do attribute :id, ROM::SQL::Types::Serial diff --git a/spec/unit/plugin/nullify_spec.rb b/spec/unit/plugin/nullify_spec.rb index 7acc82bd..f019ed83 100644 --- a/spec/unit/plugin/nullify_spec.rb +++ b/spec/unit/plugin/nullify_spec.rb @@ -5,7 +5,7 @@ RSpec.describe ROM::Relation, '#nullify' do include_context 'users' - before do + setup_relations do conf.relation(:users) do use :nullify end diff --git a/spec/unit/plugin/pagination_spec.rb b/spec/unit/plugin/pagination_spec.rb index e7f92156..37e56afe 100644 --- a/spec/unit/plugin/pagination_spec.rb +++ b/spec/unit/plugin/pagination_spec.rb @@ -6,9 +6,11 @@ include_context 'users' with_adapters do - before do + seed do 9.times { |i| conn[:users].insert(name: "User #{i}") } + end + setup_relations do conf.relation(:users) do use :pagination diff --git a/spec/unit/plugin/timestamp_spec.rb b/spec/unit/plugin/timestamp_spec.rb index c9ba9ed1..09cf62d3 100644 --- a/spec/unit/plugin/timestamp_spec.rb +++ b/spec/unit/plugin/timestamp_spec.rb @@ -5,7 +5,7 @@ include_context 'notes' with_adapters do - before do + setup_relations do conf.commands(:notes) do define :create do result :one diff --git a/spec/unit/relation/as_hash_spec.rb b/spec/unit/relation/as_hash_spec.rb index 6ed164b0..d01b086d 100644 --- a/spec/unit/relation/as_hash_spec.rb +++ b/spec/unit/relation/as_hash_spec.rb @@ -3,13 +3,7 @@ RSpec.describe ROM::Relation, '#as_hash' do subject(:relation) { container.relations.users } - include_context 'users and tasks' - - before do - conf.relation(:users) do - schema(infer: true) - end - end + include_context 'users' with_adapters do it 'returns a hash with all tuples been the key the primary key' do diff --git a/spec/unit/relation/assoc_spec.rb b/spec/unit/relation/assoc_spec.rb index 508ae430..94bfaa7b 100644 --- a/spec/unit/relation/assoc_spec.rb +++ b/spec/unit/relation/assoc_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe ROM::SQL::Relation do +RSpec.describe ROM::SQL::Relation, 'associations' do include_context 'users and tasks' context 'with has_many' do @@ -10,16 +10,6 @@ let(:tasks) { relations[:tasks] } - before do - conf.relation(:users) do - schema(infer: true) do - associations do - has_many :tasks - end - end - end - end - with_adapters do it 'returns child tuples for a relation' do expect(users.assoc(:tasks).where(name: 'Jane').to_a).to eql([ @@ -32,24 +22,7 @@ context 'with has_many-through' do subject(:tasks) { relations[:tasks] } - before do - conf.relation(:task_tags) do - schema(infer: true) do - associations do - belongs_to :tasks - belongs_to :tags - end - end - end - - conf.relation(:tasks) do - schema(infer: true) do - associations do - has_many :tags, through: :task_tags - end - end - end - + seed do conn[:tags].insert id: 2, name: 'whatevah' conn[:task_tags].insert(tag_id: 2, task_id: 2) end @@ -73,16 +46,6 @@ context 'with belongs_to' do subject(:tasks) { relations[:tasks] } - before do - conf.relation(:tasks) do - schema(infer: true) do - associations do - belongs_to :users, as: :user - end - end - end - end - with_adapters do it 'returns parent tuples for a relation' do expect(tasks.assoc(:user).where(title: "Jane's task").to_a).to eql([ diff --git a/spec/unit/relation/associations_spec.rb b/spec/unit/relation/associations_spec.rb index 03f7c614..dad3d25e 100644 --- a/spec/unit/relation/associations_spec.rb +++ b/spec/unit/relation/associations_spec.rb @@ -7,7 +7,7 @@ with_adapters do context 'with schema' do - it 'returns configured primary key from the schema' do + setup_relations do conf.relation(:users) do schema(infer: true) do associations do @@ -15,12 +15,18 @@ end end end - + end + it 'returns configured primary key from the schema' do expect(relation.associations[:tasks]).to be(container.relations.users.schema.associations[:tasks]) end end context 'without schema' do + setup_relations do + conf.relation(:users) do + schema(infer: true) + end + end it 'returns an empty association set' do expect(relation.associations.elements).to be_empty end diff --git a/spec/unit/relation/batch_spec.rb b/spec/unit/relation/batch_spec.rb index b2a82d67..0ecd9989 100644 --- a/spec/unit/relation/batch_spec.rb +++ b/spec/unit/relation/batch_spec.rb @@ -6,7 +6,7 @@ context 'single-column PK' do subject(:relation) { relations[:users] } - before do + seed do 7.times do |i| conn[:users].insert name: "User #{i + 1}" end diff --git a/spec/unit/relation/by_pk_spec.rb b/spec/unit/relation/by_pk_spec.rb index 74e173c7..e373ac84 100644 --- a/spec/unit/relation/by_pk_spec.rb +++ b/spec/unit/relation/by_pk_spec.rb @@ -39,13 +39,15 @@ context 'without PK' do subject(:relation) { relations[:people] } - before do + setup_tables(people: :db) do conn.drop_table?(:people) conn.create_table(:people) do column :name, String end + end + setup_relations do conf.relation(:people) do schema do attribute :name, ROM::SQL::Types::String diff --git a/spec/unit/relation/dataset_spec.rb b/spec/unit/relation/dataset_spec.rb index ff380545..52b9099a 100644 --- a/spec/unit/relation/dataset_spec.rb +++ b/spec/unit/relation/dataset_spec.rb @@ -3,13 +3,13 @@ RSpec.describe ROM::Relation, '#dataset' do subject(:relation) { container.relations.users } - include_context 'users and tasks' + include_context 'users' let(:dataset) { container.gateways[:default].dataset(:users) } with_adapters do context 'with schema' do - before do + setup_relations do conf.relation(:users) do schema do attribute :id, ROM::SQL::Types::Serial @@ -26,7 +26,7 @@ end context 'with cherry-picked attributes in schema' do - before do + setup_relations do conf.relation(:users) do schema do attribute :id, ROM::SQL::Types::Serial @@ -42,10 +42,6 @@ end context 'with inferred schema' do - before do - conf.relation(:users) { schema(infer: true) } - end - it 'selects all qualified columns and sorts by pk' do expect(relation.dataset.sql).to eql(dataset.select(*relation.schema.qualified).order(Sequel.qualify(:users, :id)).sql) end diff --git a/spec/unit/relation/distinct_spec.rb b/spec/unit/relation/distinct_spec.rb index 6699d129..e9b87830 100644 --- a/spec/unit/relation/distinct_spec.rb +++ b/spec/unit/relation/distinct_spec.rb @@ -5,7 +5,7 @@ include_context 'users and tasks' - before do + seed do relation.insert id: 3, name: 'Jane' end diff --git a/spec/unit/relation/exists_spec.rb b/spec/unit/relation/exists_spec.rb index bad782c4..25829219 100644 --- a/spec/unit/relation/exists_spec.rb +++ b/spec/unit/relation/exists_spec.rb @@ -1,26 +1,10 @@ # frozen_string_literal: true -RSpec.describe ROM::Relation, '#exists', relations: false do +RSpec.describe ROM::Relation, '#exists' do include_context 'users and tasks' - before do + seed do conn[:users].insert name: 'Jack' - - conf.relation(:users) do - schema(infer: true) do - associations do - has_many :tasks - end - end - end - - conf.relation(:tasks) do - schema(infer: true) do - associations do - belongs_to :user - end - end - end end with_adapters do diff --git a/spec/unit/relation/having_spec.rb b/spec/unit/relation/having_spec.rb index a5b74960..0ee42ae0 100644 --- a/spec/unit/relation/having_spec.rb +++ b/spec/unit/relation/having_spec.rb @@ -12,7 +12,7 @@ include_context 'users and tasks' with_adapters :postgres do - before do + seed do conn[:tasks].insert(id: 3, user_id: 2, title: "Joe's another task") end diff --git a/spec/unit/relation/import_spec.rb b/spec/unit/relation/import_spec.rb index 79808912..714c0c95 100644 --- a/spec/unit/relation/import_spec.rb +++ b/spec/unit/relation/import_spec.rb @@ -9,22 +9,26 @@ with_adapters(:postgres) do context 'within a single gateway' do - before do + setup_tables(users_for_loading: :db) do conn.drop_table?(:users_for_loading) conn.create_table(:users_for_loading) do primary_key :id column :full_name, String, null: false end + end - conn[:users_for_loading].insert(full_name: 'Jack') - conn[:users_for_loading].insert(full_name: 'John') - + setup_relations do conf.relation(:users_for_loading) do schema(:users_for_loading, infer: true) end end + seed do + conn[:users_for_loading].insert(full_name: 'Jack') + conn[:users_for_loading].insert(full_name: 'John') + end + it 'inserts data from another relation' do relation.import(source.project { [(id + 10).as(:id), full_name.as(:name)] }) @@ -44,7 +48,7 @@ ROM::Memory::Dataset.new(data) end - before do + setup_relations do conf.relation(:users_for_loading, adapter: :memory) do gateway :other diff --git a/spec/unit/relation/inner_join_spec.rb b/spec/unit/relation/inner_join_spec.rb index 5895ca16..c463306e 100644 --- a/spec/unit/relation/inner_join_spec.rb +++ b/spec/unit/relation/inner_join_spec.rb @@ -60,13 +60,15 @@ inferrable_relations.push(:puzzles) end - before do + setup_tables(puzzles: :users) do conn.create_table(:puzzles) do primary_key :id foreign_key :author_id, :users, null: false column :text, String, null: false end + end + setup_relations do conf.relation(:users) do schema(infer: true) do associations do @@ -95,6 +97,14 @@ end end + conf.relation(:tags) do + schema(infer: true) do + associations do + has_many :task_tags + end + end + end + conf.relation(:puzzles) do schema(infer: true) do associations do @@ -102,7 +112,9 @@ end end end + end + seed do relation.insert id: 3, name: 'Jade' puzzles.insert id: 1, author_id: 1, text: 'solved by Jane' end @@ -142,7 +154,7 @@ def name end describe 'joined relation with join keys inferred for m:m-through' do - before do + seed do tags.insert(id: 2, name: 'postponed') tasks.task_tags.insert(tag_id: 2, task_id: 2) end diff --git a/spec/unit/relation/instrument_spec.rb b/spec/unit/relation/instrument_spec.rb index 83c5ba95..d0208777 100644 --- a/spec/unit/relation/instrument_spec.rb +++ b/spec/unit/relation/instrument_spec.rb @@ -22,7 +22,7 @@ def instrument(*args, &) end.new end - before do + setup_tables do conn.create_table :users do primary_key :id column :name, String @@ -31,7 +31,9 @@ def instrument(*args, &) conf.plugin(:sql, relations: :instrumentation) do |p| p.notifications = notifications end + end + setup_relations do conf.relation(:users) do schema(infer: true) end @@ -76,13 +78,15 @@ def instrument(*args, &) let(:container_alt) { ROM.container(conf_alt) } - before do + setup_relations do conf_alt.plugin(:sql, relations: :instrumentation) conf_alt.relation(:users) do schema(infer: true) end + end + before do container_alt end diff --git a/spec/unit/relation/join_dsl_spec.rb b/spec/unit/relation/join_dsl_spec.rb index 79d3e6ea..69deaa26 100644 --- a/spec/unit/relation/join_dsl_spec.rb +++ b/spec/unit/relation/join_dsl_spec.rb @@ -1,26 +1,8 @@ # frozen_string_literal: true -RSpec.describe ROM::Relation, '#join_dsl', relations: false do +RSpec.describe ROM::Relation, '#join_dsl' do subject(:relation) { relations[:tasks] } - before do - conf.relation(:users) do - schema(infer: true) do - associations do - has_many :tasks - end - end - end - - conf.relation(:tasks) do - schema(infer: true) do - associations do - belongs_to :user - end - end - end - end - include_context 'users and tasks' shared_context 'valid joined relation' do diff --git a/spec/unit/relation/left_join_spec.rb b/spec/unit/relation/left_join_spec.rb index 943af27f..59b537df 100644 --- a/spec/unit/relation/left_join_spec.rb +++ b/spec/unit/relation/left_join_spec.rb @@ -23,19 +23,7 @@ end context 'with associations' do - before do - conf.relation(:users) do - schema(infer: true) do - associations { has_many :tasks } - end - end - - conf.relation(:tasks) do - schema(infer: true) do - associations { belongs_to :user } - end - end - + seed do relation.insert id: 3, name: 'Jade' end diff --git a/spec/unit/relation/lock_spec.rb b/spec/unit/relation/lock_spec.rb index 621578a4..821e9e77 100644 --- a/spec/unit/relation/lock_spec.rb +++ b/spec/unit/relation/lock_spec.rb @@ -3,7 +3,7 @@ require 'concurrent/atomic/count_down_latch' RSpec.describe ROM::Relation, '#lock' do - include_context 'users and tasks' + include_context 'users' subject(:relation) { users } diff --git a/spec/unit/relation/map_spec.rb b/spec/unit/relation/map_spec.rb index 1bbbf238..1432c84d 100644 --- a/spec/unit/relation/map_spec.rb +++ b/spec/unit/relation/map_spec.rb @@ -3,7 +3,7 @@ RSpec.describe ROM::Relation, '#map' do subject(:relation) { container.relations.users } - include_context 'users and tasks' + include_context 'users' with_adapters do it 'yields tuples' do diff --git a/spec/unit/relation/order_spec.rb b/spec/unit/relation/order_spec.rb index 1437b9a2..0d240db7 100644 --- a/spec/unit/relation/order_spec.rb +++ b/spec/unit/relation/order_spec.rb @@ -5,7 +5,7 @@ include_context 'users and tasks' - before do + seed do relation.insert(id: 3, name: 'Jade') end diff --git a/spec/unit/relation/prefix_spec.rb b/spec/unit/relation/prefix_spec.rb index cfaf7b66..3f52210a 100644 --- a/spec/unit/relation/prefix_spec.rb +++ b/spec/unit/relation/prefix_spec.rb @@ -5,7 +5,7 @@ include_context 'users and tasks' - before do + setup_relations do conf.relation(:users) do schema(infer: true) diff --git a/spec/unit/relation/primary_key_spec.rb b/spec/unit/relation/primary_key_spec.rb index a6db79a2..6a1a2f04 100644 --- a/spec/unit/relation/primary_key_spec.rb +++ b/spec/unit/relation/primary_key_spec.rb @@ -3,25 +3,25 @@ RSpec.describe ROM::Relation, '#primary_key' do subject(:relation) { container.relations.users } - include_context 'users and tasks' + include_context 'users' with_adapters do context 'with schema' do - it 'returns configured primary key from the schema' do + setup_relations do conf.relation(:users) do schema do attribute :name, ROM::SQL::Types::String.meta(primary_key: true) end end + end + it 'returns configured primary key from the schema' do expect(relation.primary_key).to be(:name) end end context 'without schema' do it 'returns :id by default' do - conf.relation(:users) { schema(infer: true) } - expect(relation.primary_key).to be(:id) end end diff --git a/spec/unit/relation/project_spec.rb b/spec/unit/relation/project_spec.rb index a6ff7d19..076a5760 100644 --- a/spec/unit/relation/project_spec.rb +++ b/spec/unit/relation/project_spec.rb @@ -5,7 +5,7 @@ include_context 'users and tasks' - before do + setup_relations do conf.relation(:users) do schema(infer: true) diff --git a/spec/unit/relation/qualified_columns_spec.rb b/spec/unit/relation/qualified_columns_spec.rb index 899b729d..5a63a05d 100644 --- a/spec/unit/relation/qualified_columns_spec.rb +++ b/spec/unit/relation/qualified_columns_spec.rb @@ -5,7 +5,7 @@ include_context 'users and tasks' - before do + setup_relations do conf.relation(:users) do schema(infer: true) @@ -19,8 +19,10 @@ def sorted it 'returns qualified column names' do columns = relation.sorted.prefix(:user).qualified_columns - expect(columns).to eql([Sequel.qualify(:users, :id).as(:user_id), - Sequel.qualify(:users, :name).as(:user_name)]) + expect(columns).to eql([ + Sequel.qualify(:users, :id).as(:user_id), + Sequel.qualify(:users, :name).as(:user_name) + ]) end it 'returns projected qualified column names' do diff --git a/spec/unit/relation/rename_spec.rb b/spec/unit/relation/rename_spec.rb index 3e4015c0..9bdfb5a3 100644 --- a/spec/unit/relation/rename_spec.rb +++ b/spec/unit/relation/rename_spec.rb @@ -1,11 +1,11 @@ # frozen_string_literal: true -RSpec.describe ROM::Relation, '#rename' do +RSpec.describe ROM::Relation, '#rename', relations: false do subject(:relation) { container.relations.users } include_context 'users and tasks' - before do + setup_relations do conf.relation(:users) do schema(infer: true) diff --git a/spec/unit/relation/right_join_spec.rb b/spec/unit/relation/right_join_spec.rb index f408d442..dec19bd3 100644 --- a/spec/unit/relation/right_join_spec.rb +++ b/spec/unit/relation/right_join_spec.rb @@ -24,20 +24,6 @@ end context 'with associations' do - before do - conf.relation(:users) do - schema(infer: true) do - associations { has_many :tasks } - end - end - - conf.relation(:tasks) do - schema(infer: true) do - associations { belongs_to :user } - end - end - end - it 'joins relation with join keys inferred' do users.insert id: 3, name: 'Jade' relation.insert id: 3, title: 'Unassigned' diff --git a/spec/unit/relation/select_spec.rb b/spec/unit/relation/select_spec.rb index 94d2d4a7..d8326e8e 100644 --- a/spec/unit/relation/select_spec.rb +++ b/spec/unit/relation/select_spec.rb @@ -5,10 +5,6 @@ include_context 'users and tasks' - before do - conf.relation(:tasks) { schema(infer: true) } - end - with_adapters do it 'projects a relation using a list of symbols' do expect(relation.select(:id, :title).to_a).to eql( diff --git a/spec/unit/relation/union_spec.rb b/spec/unit/relation/union_spec.rb index 94ef3c5c..be3efbd8 100644 --- a/spec/unit/relation/union_spec.rb +++ b/spec/unit/relation/union_spec.rb @@ -5,7 +5,7 @@ include_context 'users and tasks' - before do + setup_relations do conf.relation(:tasks) do schema(infer: true) do associations do @@ -13,14 +13,6 @@ end end end - - conf.relation(:task_tags) do - schema(infer: true) do - associations do - belongs_to :task - end - end - end end with_adapters do diff --git a/spec/unit/relation/unique_predicate_spec.rb b/spec/unit/relation/unique_predicate_spec.rb index e0bcfdea..3a3697d9 100644 --- a/spec/unit/relation/unique_predicate_spec.rb +++ b/spec/unit/relation/unique_predicate_spec.rb @@ -6,7 +6,7 @@ include_context 'users and tasks' with_adapters do - before { relation.delete } + seed { relation.delete } it 'returns true when there is only one tuple matching criteria' do expect(relation.unique?(title: 'Task One')).to be(true) diff --git a/spec/unit/relation/where_spec.rb b/spec/unit/relation/where_spec.rb index a1c1b9ab..34206eca 100644 --- a/spec/unit/relation/where_spec.rb +++ b/spec/unit/relation/where_spec.rb @@ -121,7 +121,7 @@ end context 'with :read types' do - before do + setup_relations do conf.relation(:tasks) do schema(infer: true) do attribute :id, ROM::SQL::Types::Serial.constructor(&:to_i)