rom-sql 0.7.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +1 -0
- data/.travis.yml +12 -7
- data/CHANGELOG.md +28 -0
- data/Gemfile +6 -9
- data/README.md +5 -4
- data/circle.yml +10 -0
- data/lib/rom/plugins/relation/sql/auto_combine.rb +16 -3
- data/lib/rom/plugins/relation/sql/auto_wrap.rb +3 -2
- data/lib/rom/sql/association.rb +75 -0
- data/lib/rom/sql/association/many_to_many.rb +86 -0
- data/lib/rom/sql/association/many_to_one.rb +60 -0
- data/lib/rom/sql/association/name.rb +70 -0
- data/lib/rom/sql/association/one_to_many.rb +9 -0
- data/lib/rom/sql/association/one_to_one.rb +46 -0
- data/lib/rom/sql/association/one_to_one_through.rb +9 -0
- data/lib/rom/sql/commands.rb +2 -0
- data/lib/rom/sql/commands/create.rb +2 -2
- data/lib/rom/sql/commands/delete.rb +0 -1
- data/lib/rom/sql/commands/postgres.rb +76 -0
- data/lib/rom/sql/commands/update.rb +6 -3
- data/lib/rom/sql/commands_ext/postgres.rb +17 -0
- data/lib/rom/sql/gateway.rb +23 -15
- data/lib/rom/sql/header.rb +7 -1
- data/lib/rom/sql/plugin/assoc_macros.rb +3 -3
- data/lib/rom/sql/plugin/associates.rb +50 -9
- data/lib/rom/sql/qualified_attribute.rb +53 -0
- data/lib/rom/sql/relation.rb +76 -25
- data/lib/rom/sql/relation/reading.rb +138 -35
- data/lib/rom/sql/relation/writing.rb +21 -0
- data/lib/rom/sql/schema.rb +35 -0
- data/lib/rom/sql/schema/associations_dsl.rb +68 -0
- data/lib/rom/sql/schema/dsl.rb +27 -0
- data/lib/rom/sql/schema/inferrer.rb +80 -0
- data/lib/rom/sql/support/active_support_notifications.rb +27 -17
- data/lib/rom/sql/types.rb +11 -0
- data/lib/rom/sql/types/pg.rb +26 -0
- data/lib/rom/sql/version.rb +1 -1
- data/rom-sql.gemspec +4 -2
- data/spec/integration/association/many_to_many_spec.rb +137 -0
- data/spec/integration/association/many_to_one_spec.rb +110 -0
- data/spec/integration/association/one_to_many_spec.rb +58 -0
- data/spec/integration/association/one_to_one_spec.rb +57 -0
- data/spec/integration/association/one_to_one_through_spec.rb +90 -0
- data/spec/integration/combine_spec.rb +24 -24
- data/spec/integration/commands/create_spec.rb +215 -168
- data/spec/integration/commands/delete_spec.rb +88 -46
- data/spec/integration/commands/update_spec.rb +141 -60
- data/spec/integration/commands/upsert_spec.rb +83 -0
- data/spec/integration/gateway_spec.rb +9 -17
- data/spec/integration/migration_spec.rb +3 -5
- data/spec/integration/plugins/associates_spec.rb +168 -0
- data/spec/integration/plugins/auto_wrap_spec.rb +46 -0
- data/spec/integration/read_spec.rb +80 -77
- data/spec/integration/relation_schema_spec.rb +180 -0
- data/spec/integration/schema_inference_spec.rb +67 -0
- data/spec/integration/setup_spec.rb +22 -0
- data/spec/{support → integration/support}/active_support_notifications_spec.rb +0 -0
- data/spec/{support → integration/support}/rails_log_subscriber_spec.rb +0 -0
- data/spec/shared/database_setup.rb +46 -8
- data/spec/shared/relations.rb +8 -0
- data/spec/shared/users_and_accounts.rb +10 -0
- data/spec/shared/users_and_tasks.rb +20 -2
- data/spec/spec_helper.rb +64 -11
- data/spec/support/helpers.rb +9 -0
- data/spec/unit/association/many_to_many_spec.rb +89 -0
- data/spec/unit/association/many_to_one_spec.rb +81 -0
- data/spec/unit/association/name_spec.rb +68 -0
- data/spec/unit/association/one_to_many_spec.rb +62 -0
- data/spec/unit/association/one_to_one_spec.rb +62 -0
- data/spec/unit/association/one_to_one_through_spec.rb +69 -0
- data/spec/unit/association_errors_spec.rb +2 -4
- data/spec/unit/gateway_spec.rb +12 -3
- data/spec/unit/migration_tasks_spec.rb +3 -3
- data/spec/unit/migrator_spec.rb +2 -4
- data/spec/unit/{combined_associations_spec.rb → plugin/assoc_macros/combined_associations_spec.rb} +13 -19
- data/spec/unit/{many_to_many_spec.rb → plugin/assoc_macros/many_to_many_spec.rb} +9 -15
- data/spec/unit/{many_to_one_spec.rb → plugin/assoc_macros/many_to_one_spec.rb} +9 -14
- data/spec/unit/plugin/assoc_macros/one_to_many_spec.rb +78 -0
- data/spec/unit/plugin/base_view_spec.rb +11 -11
- data/spec/unit/plugin/pagination_spec.rb +62 -62
- data/spec/unit/relation_spec.rb +218 -146
- data/spec/unit/schema_spec.rb +15 -14
- data/spec/unit/types_spec.rb +40 -0
- metadata +105 -21
- data/.rubocop.yml +0 -74
- data/.rubocop_todo.yml +0 -21
- data/spec/unit/one_to_many_spec.rb +0 -83
@@ -2,6 +2,27 @@ module ROM
|
|
2
2
|
module SQL
|
3
3
|
class Relation < ROM::Relation
|
4
4
|
module Writing
|
5
|
+
# Add upsert option (only PostgreSQL >= 9.5)
|
6
|
+
# Uses internal Sequel implementation
|
7
|
+
# Default - ON CONFLICT DO NOTHING
|
8
|
+
# more options: http://sequel.jeremyevans.net/rdoc-adapters/classes/Sequel/Postgres/DatasetMethods.html#method-i-insert_conflict
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# users.upsert({ name: 'Jane', email: 'jane@foo.com' },
|
12
|
+
# { target: :email, update: { name: :excluded__name } }
|
13
|
+
#
|
14
|
+
# @api public
|
15
|
+
def upsert(*args, &block)
|
16
|
+
if args.size > 1 && args[-1].is_a?(Hash)
|
17
|
+
*values, opts = args
|
18
|
+
else
|
19
|
+
values = args
|
20
|
+
opts = EMPTY_HASH
|
21
|
+
end
|
22
|
+
|
23
|
+
dataset.insert_conflict(opts).insert(*values, &block)
|
24
|
+
end
|
25
|
+
|
5
26
|
# Insert tuple into relation
|
6
27
|
#
|
7
28
|
# @example
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'rom/schema'
|
2
|
+
require 'rom/support/constants'
|
3
|
+
|
4
|
+
module ROM
|
5
|
+
module SQL
|
6
|
+
class Schema < ROM::Schema
|
7
|
+
# @!attribute [r] primary_key_name
|
8
|
+
# @return [Symbol] The name of the primary key. This is set because in
|
9
|
+
# most of the cases relations don't have composite pks
|
10
|
+
attr_reader :primary_key_name
|
11
|
+
|
12
|
+
# @!attribute [r] primary_key_names
|
13
|
+
# @return [Array<Symbol>] A list of all pk names
|
14
|
+
attr_reader :primary_key_names
|
15
|
+
|
16
|
+
def initialize(*)
|
17
|
+
super
|
18
|
+
@primary_key_name = nil
|
19
|
+
@primary_key_names = EMPTY_ARRAY
|
20
|
+
end
|
21
|
+
|
22
|
+
# @api private
|
23
|
+
def finalize!(*)
|
24
|
+
super do
|
25
|
+
if primary_key.size > 0
|
26
|
+
@primary_key_name = primary_key[0].meta[:name]
|
27
|
+
@primary_key_names = primary_key.map { |type| type.meta[:name] }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
require 'rom/sql/schema/dsl'
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'rom/sql/association'
|
2
|
+
|
3
|
+
module ROM
|
4
|
+
module SQL
|
5
|
+
class Schema < ROM::Schema
|
6
|
+
class AssociationsDSL < BasicObject
|
7
|
+
attr_reader :source, :registry
|
8
|
+
|
9
|
+
def initialize(source, &block)
|
10
|
+
@source = source
|
11
|
+
@registry = {}
|
12
|
+
instance_exec(&block)
|
13
|
+
end
|
14
|
+
|
15
|
+
def one_to_many(target, options = {})
|
16
|
+
if options[:through]
|
17
|
+
many_to_many(target, options)
|
18
|
+
else
|
19
|
+
add(Association::OneToMany.new(source, target, options))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
alias_method :has_many, :one_to_many
|
23
|
+
|
24
|
+
def one_to_one(target, options = {})
|
25
|
+
if options[:through]
|
26
|
+
one_to_one_through(target, options)
|
27
|
+
else
|
28
|
+
add(Association::OneToOne.new(source, target, options))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def one_to_one_through(target, options = {})
|
33
|
+
add(Association::OneToOneThrough.new(source, target, options))
|
34
|
+
end
|
35
|
+
|
36
|
+
def many_to_many(target, options = {})
|
37
|
+
add(Association::ManyToMany.new(source, target, options))
|
38
|
+
end
|
39
|
+
|
40
|
+
def many_to_one(target, options = {})
|
41
|
+
add(Association::ManyToOne.new(source, target, options))
|
42
|
+
end
|
43
|
+
|
44
|
+
def belongs_to(name, options = {})
|
45
|
+
many_to_one(dataset_name(name), options.merge(as: options[:as] || name))
|
46
|
+
end
|
47
|
+
|
48
|
+
def has_one(name, options = {})
|
49
|
+
one_to_one(dataset_name(name), options.merge(as: options[:as] || name))
|
50
|
+
end
|
51
|
+
|
52
|
+
def call
|
53
|
+
AssociationSet.new(registry)
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def add(association)
|
59
|
+
registry[association.name] = association
|
60
|
+
end
|
61
|
+
|
62
|
+
def dataset_name(name)
|
63
|
+
Inflector.pluralize(name).to_sym
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rom/sql/schema/inferrer'
|
2
|
+
require 'rom/sql/schema/associations_dsl'
|
3
|
+
|
4
|
+
module ROM
|
5
|
+
module SQL
|
6
|
+
class Schema < ROM::Schema
|
7
|
+
class DSL < ROM::Schema::DSL
|
8
|
+
attr_reader :associations_dsl
|
9
|
+
|
10
|
+
def associations(&block)
|
11
|
+
@associations_dsl = AssociationsDSL.new(name, &block)
|
12
|
+
end
|
13
|
+
|
14
|
+
def call
|
15
|
+
SQL::Schema.new(name, attributes, opts)
|
16
|
+
end
|
17
|
+
|
18
|
+
def opts
|
19
|
+
opts = {}
|
20
|
+
opts[:associations] = associations_dsl.call if associations_dsl
|
21
|
+
opts[:inferrer] = inferrer.new(self) if inferrer
|
22
|
+
opts
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module ROM
|
2
|
+
module SQL
|
3
|
+
class Schema < ROM::Schema
|
4
|
+
class Inferrer
|
5
|
+
extend ClassMacros
|
6
|
+
|
7
|
+
defines :type_mapping, :pk_type
|
8
|
+
|
9
|
+
type_mapping(
|
10
|
+
integer: Types::Strict::Int,
|
11
|
+
string: Types::Strict::String,
|
12
|
+
date: Types::Strict::Date,
|
13
|
+
datetime: Types::Strict::Time,
|
14
|
+
boolean: Types::Strict::Bool,
|
15
|
+
decimal: Types::Strict::Decimal,
|
16
|
+
blob: Types::Strict::String
|
17
|
+
).freeze
|
18
|
+
|
19
|
+
pk_type Types::Serial
|
20
|
+
|
21
|
+
attr_reader :dsl
|
22
|
+
|
23
|
+
def initialize(dsl)
|
24
|
+
@dsl = dsl
|
25
|
+
end
|
26
|
+
|
27
|
+
# @api private
|
28
|
+
def call(dataset, gateway)
|
29
|
+
columns = gateway.connection.schema(dataset)
|
30
|
+
fks = fks_for(gateway, dataset)
|
31
|
+
|
32
|
+
columns.each do |(name, definition)|
|
33
|
+
dsl.attribute name, build_type(definition.merge(foreign_key: fks[name]))
|
34
|
+
end
|
35
|
+
|
36
|
+
pks = columns
|
37
|
+
.map { |(name, definition)| name if definition.fetch(:primary_key) }
|
38
|
+
.compact
|
39
|
+
|
40
|
+
dsl.primary_key(*pks) if pks.any?
|
41
|
+
|
42
|
+
dsl.attributes
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
# @api private
|
48
|
+
def build_type(primary_key: , type: , allow_null: , foreign_key: , **rest)
|
49
|
+
if primary_key
|
50
|
+
self.class.pk_type
|
51
|
+
else
|
52
|
+
type = self.class.type_mapping.fetch(type)
|
53
|
+
type = type.optional if allow_null
|
54
|
+
type = type.meta(foreign_key: true, relation: foreign_key) if foreign_key
|
55
|
+
type
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# @api private
|
60
|
+
def fks_for(gateway, dataset)
|
61
|
+
gateway.connection.foreign_key_list(dataset).each_with_object({}) do |definition, fks|
|
62
|
+
column, fk = build_fk(definition)
|
63
|
+
|
64
|
+
fks[column] = fk if fk
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# @api private
|
69
|
+
def build_fk(columns: , table: , **rest)
|
70
|
+
if columns.size == 1
|
71
|
+
[columns[0], table]
|
72
|
+
else
|
73
|
+
# We don't have support for multicolumn foreign keys
|
74
|
+
columns[0]
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -1,26 +1,36 @@
|
|
1
1
|
require 'sequel/database/logging'
|
2
2
|
require 'active_support/notifications'
|
3
3
|
|
4
|
-
module
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
4
|
+
module ROM
|
5
|
+
module SQL
|
6
|
+
module ActiveSupportInstrumentation
|
7
|
+
if Sequel::MAJOR == 4 && Sequel::MINOR < 35
|
8
|
+
def log_yield(sql, args = nil)
|
9
|
+
ActiveSupport::Notifications.instrument(
|
10
|
+
'sql.rom',
|
11
|
+
sql: sql,
|
12
|
+
name: instrumentation_name,
|
13
|
+
binds: args
|
14
|
+
) { super }
|
15
|
+
end
|
16
|
+
else
|
17
|
+
def log_connection_yield(sql, _conn, args = nil)
|
18
|
+
ActiveSupport::Notifications.instrument(
|
19
|
+
'sql.rom',
|
20
|
+
sql: sql,
|
21
|
+
name: instrumentation_name,
|
22
|
+
binds: args
|
23
|
+
) { super }
|
24
|
+
end
|
14
25
|
end
|
15
|
-
end
|
16
|
-
|
17
|
-
alias_method :log_yield_without_instrumentation, :log_yield
|
18
|
-
alias_method :log_yield, :log_yield_with_instrumentation
|
19
26
|
|
20
|
-
|
27
|
+
private
|
21
28
|
|
22
|
-
|
23
|
-
|
29
|
+
def instrumentation_name
|
30
|
+
"ROM[#{database_type}]"
|
31
|
+
end
|
24
32
|
end
|
25
33
|
end
|
26
34
|
end
|
35
|
+
|
36
|
+
Sequel::Database.send(:prepend, ROM::SQL::ActiveSupportInstrumentation)
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'dry-types'
|
2
|
+
require 'sequel'
|
3
|
+
|
4
|
+
module ROM
|
5
|
+
module SQL
|
6
|
+
module Types
|
7
|
+
module PG
|
8
|
+
Sequel.extension(:pg_json)
|
9
|
+
|
10
|
+
Array = Dry::Types::Definition
|
11
|
+
.new(Sequel::Postgres::JSONArray)
|
12
|
+
.constructor(Sequel.method(:pg_json))
|
13
|
+
|
14
|
+
Hash = Dry::Types::Definition
|
15
|
+
.new(Sequel::Postgres::JSONHash)
|
16
|
+
.constructor(Sequel.method(:pg_json))
|
17
|
+
|
18
|
+
JSON = Array | Hash
|
19
|
+
|
20
|
+
Bytea = Dry::Types::Definition
|
21
|
+
.new(Sequel::SQL::Blob)
|
22
|
+
.constructor(Sequel::SQL::Blob.method(:new))
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/rom/sql/version.rb
CHANGED
data/rom-sql.gemspec
CHANGED
@@ -18,9 +18,11 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.add_runtime_dependency "sequel", "~> 4.
|
21
|
+
spec.add_runtime_dependency "sequel", "~> 4.25"
|
22
22
|
spec.add_runtime_dependency "dry-equalizer", "~> 0.2"
|
23
|
-
spec.add_runtime_dependency "
|
23
|
+
spec.add_runtime_dependency "dry-types", "~> 0.8"
|
24
|
+
spec.add_runtime_dependency "rom", "~> 2.0"
|
25
|
+
spec.add_runtime_dependency "rom-support", "~> 2.0"
|
24
26
|
|
25
27
|
spec.add_development_dependency "bundler"
|
26
28
|
spec.add_development_dependency "rake", "~> 10.0"
|
@@ -0,0 +1,137 @@
|
|
1
|
+
RSpec.describe ROM::SQL::Association::ManyToMany do
|
2
|
+
include_context 'users and tasks'
|
3
|
+
|
4
|
+
with_adapters :sqlite do
|
5
|
+
context 'with two associations pointing to the same target relation' do
|
6
|
+
let(:container) do
|
7
|
+
ROM.container(:sql, uri) do |conf|
|
8
|
+
conf.default.create_table(:users_tasks) do
|
9
|
+
foreign_key :user_id, :users
|
10
|
+
foreign_key :task_id, :tasks
|
11
|
+
primary_key [:user_id, :task_id]
|
12
|
+
end
|
13
|
+
|
14
|
+
conf.relation(:users) do
|
15
|
+
schema(infer: true) do
|
16
|
+
associations do
|
17
|
+
has_many :users_tasks
|
18
|
+
has_many :tasks, through: :users_tasks
|
19
|
+
has_many :tasks, as: :priv_tasks
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
conf.relation(:users_tasks) do
|
25
|
+
schema(infer: true) do
|
26
|
+
associations do
|
27
|
+
belongs_to :user
|
28
|
+
belongs_to :task
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
conf.relation(:tasks) do
|
34
|
+
schema(infer: true) do
|
35
|
+
associations do
|
36
|
+
has_many :users_tasks
|
37
|
+
has_many :users, through: :users_tasks
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'does not conflict with two FKs' do
|
45
|
+
users = container.relations[:users]
|
46
|
+
tasks = container.relations[:tasks]
|
47
|
+
assoc = users.associations[:tasks]
|
48
|
+
|
49
|
+
relation = tasks.for_combine(assoc).call(users.call)
|
50
|
+
|
51
|
+
expect(relation.to_a).to be_empty
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'preloads using FK' do
|
55
|
+
users = container.relations[:users]
|
56
|
+
tasks = container.relations[:tasks]
|
57
|
+
assoc = users.associations[:priv_tasks]
|
58
|
+
|
59
|
+
relation = tasks.for_combine(assoc).call(users.where(id: 2).call)
|
60
|
+
|
61
|
+
expect(relation.to_a).to eql([id: 1, user_id: 2, title: "Joe's task"])
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
with_adapters do
|
67
|
+
subject(:assoc) {
|
68
|
+
ROM::SQL::Association::ManyToMany.new(:tasks, :tags, through: :task_tags)
|
69
|
+
}
|
70
|
+
|
71
|
+
let(:tasks) { container.relations[:tasks] }
|
72
|
+
let(:tags) { container.relations[:tags] }
|
73
|
+
|
74
|
+
before do
|
75
|
+
conf.relation(:task_tags) do
|
76
|
+
schema do
|
77
|
+
attribute :task_id, ROM::SQL::Types::ForeignKey(:tasks)
|
78
|
+
attribute :tag_id, ROM::SQL::Types::ForeignKey(:tags)
|
79
|
+
|
80
|
+
primary_key :task_id, :tag_id
|
81
|
+
|
82
|
+
associations do
|
83
|
+
many_to_one :tasks
|
84
|
+
many_to_one :tags
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
conf.relation(:tasks) do
|
90
|
+
schema do
|
91
|
+
attribute :id, ROM::SQL::Types::Serial
|
92
|
+
attribute :user_id, ROM::SQL::Types::ForeignKey(:users)
|
93
|
+
attribute :title, ROM::SQL::Types::String
|
94
|
+
|
95
|
+
associations do
|
96
|
+
one_to_many :task_tags
|
97
|
+
one_to_many :tags, through: :task_tags
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe '#result' do
|
104
|
+
specify { expect(ROM::SQL::Association::ManyToMany.result).to be(:many) }
|
105
|
+
end
|
106
|
+
|
107
|
+
describe '#call' do
|
108
|
+
it 'prepares joined relations' do
|
109
|
+
relation = assoc.call(container.relations)
|
110
|
+
|
111
|
+
expect(relation.attributes).to eql(%i[id name task_id])
|
112
|
+
expect(relation.to_a).to eql([id: 1, name: 'important', task_id: 1])
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe ':through another assoc' do
|
117
|
+
subject(:assoc) do
|
118
|
+
ROM::SQL::Association::ManyToMany.new(:users, :tags, through: :tasks)
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'prepares joined relations through other association' do
|
122
|
+
relation = assoc.call(container.relations)
|
123
|
+
|
124
|
+
expect(relation.attributes).to eql(%i[id name user_id])
|
125
|
+
expect(relation.to_a).to eql([id: 1, name: 'important', user_id: 2])
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
describe ROM::Plugins::Relation::SQL::AutoCombine, '#for_combine' do
|
130
|
+
it 'preloads relation based on association' do
|
131
|
+
relation = tags.for_combine(assoc).call(tasks.call)
|
132
|
+
|
133
|
+
expect(relation.to_a).to eql([id: 1, name: 'important', task_id: 1])
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|