rom 2.0.2 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +4 -7
- data/.yardopts +2 -0
- data/CHANGELOG.md +35 -1
- data/Gemfile +17 -2
- data/Rakefile +7 -2
- data/lib/rom/array_dataset.rb +44 -0
- data/lib/rom/association_set.rb +11 -5
- data/lib/rom/auto_curry.rb +55 -0
- data/lib/rom/command.rb +331 -47
- data/lib/rom/command_registry.rb +7 -18
- data/lib/rom/commands/class_interface.rb +120 -6
- data/lib/rom/commands/composite.rb +0 -1
- data/lib/rom/commands/graph.rb +7 -15
- data/lib/rom/commands/lazy/update.rb +1 -1
- data/lib/rom/configuration.rb +2 -0
- data/lib/rom/configuration_dsl/command.rb +6 -8
- data/lib/rom/configuration_dsl/mapper.rb +2 -3
- data/lib/rom/configuration_dsl/mapper_dsl.rb +0 -1
- data/lib/rom/configuration_dsl/relation.rb +4 -4
- data/lib/rom/configuration_dsl.rb +0 -4
- data/lib/rom/constants.rb +7 -1
- data/lib/rom/container.rb +11 -17
- data/lib/rom/create_container.rb +0 -2
- data/lib/rom/data_proxy.rb +94 -0
- data/lib/rom/enumerable_dataset.rb +68 -0
- data/lib/rom/gateway.rb +74 -32
- data/lib/rom/global/plugin_dsl.rb +0 -2
- data/lib/rom/global.rb +0 -2
- data/lib/rom/initializer.rb +26 -0
- data/lib/rom/lint/gateway.rb +17 -0
- data/lib/rom/mapper_registry.rb +1 -1
- data/lib/rom/memory/commands.rb +0 -2
- data/lib/rom/memory/dataset.rb +1 -2
- data/lib/rom/memory/relation.rb +14 -1
- data/lib/rom/memory/schema.rb +13 -0
- data/lib/rom/plugin_registry.rb +1 -1
- data/lib/rom/plugins/command/schema.rb +2 -2
- data/lib/rom/plugins/configuration/configuration_dsl.rb +6 -2
- data/lib/rom/plugins/relation/key_inference.rb +4 -2
- data/lib/rom/plugins/relation/registry_reader.rb +5 -1
- data/lib/rom/registry.rb +50 -0
- data/lib/rom/relation/class_interface.rb +142 -30
- data/lib/rom/relation/curried.rb +15 -15
- data/lib/rom/relation/view_dsl.rb +31 -0
- data/lib/rom/relation.rb +101 -41
- data/lib/rom/schema/attribute.rb +367 -0
- data/lib/rom/schema/dsl.rb +14 -10
- data/lib/rom/schema.rb +337 -19
- data/lib/rom/setup/auto_registration.rb +20 -17
- data/lib/rom/setup/auto_registration_strategies/base.rb +8 -3
- data/lib/rom/setup/auto_registration_strategies/custom_namespace.rb +4 -3
- data/lib/rom/setup/auto_registration_strategies/no_namespace.rb +5 -4
- data/lib/rom/setup/auto_registration_strategies/with_namespace.rb +3 -3
- data/lib/rom/setup/finalize/finalize_commands.rb +1 -1
- data/lib/rom/setup/finalize/finalize_mappers.rb +1 -1
- data/lib/rom/setup/finalize/finalize_relations.rb +4 -2
- data/lib/rom/setup/finalize.rb +1 -1
- data/lib/rom/transaction.rb +24 -0
- data/lib/rom/types.rb +9 -1
- data/lib/rom/version.rb +1 -1
- data/lib/rom.rb +4 -8
- data/rom.gemspec +5 -4
- data/spec/integration/command_registry_spec.rb +1 -14
- data/spec/integration/commands/create_spec.rb +5 -25
- data/spec/integration/commands/delete_spec.rb +1 -1
- data/spec/integration/commands/error_handling_spec.rb +1 -1
- data/spec/integration/commands/graph_spec.rb +20 -14
- data/spec/integration/commands/update_spec.rb +4 -27
- data/spec/integration/commands_spec.rb +1 -1
- data/spec/integration/{repositories → gateways}/extending_relations_spec.rb +1 -1
- data/spec/integration/{repositories → gateways}/setting_logger_spec.rb +2 -2
- data/spec/integration/mappers/combine_spec.rb +1 -1
- data/spec/integration/mappers/deep_embedded_spec.rb +1 -1
- data/spec/integration/mappers/definition_dsl_spec.rb +1 -1
- data/spec/integration/mappers/embedded_spec.rb +1 -1
- data/spec/integration/mappers/exclude_spec.rb +1 -1
- data/spec/integration/mappers/fold_spec.rb +1 -1
- data/spec/integration/mappers/group_spec.rb +1 -1
- data/spec/integration/mappers/overwrite_attributes_value_spec.rb +1 -1
- data/spec/integration/mappers/prefix_separator_spec.rb +1 -1
- data/spec/integration/mappers/prefix_spec.rb +1 -1
- data/spec/integration/mappers/prefixing_attributes_spec.rb +1 -1
- data/spec/integration/mappers/registering_custom_mappers_spec.rb +1 -1
- data/spec/integration/mappers/renaming_attributes_spec.rb +1 -1
- data/spec/integration/mappers/reusing_mappers_spec.rb +1 -1
- data/spec/integration/mappers/step_spec.rb +1 -1
- data/spec/integration/mappers/symbolizing_attributes_spec.rb +1 -1
- data/spec/integration/mappers/unfold_spec.rb +1 -1
- data/spec/integration/mappers/ungroup_spec.rb +2 -2
- data/spec/integration/mappers/unwrap_spec.rb +2 -2
- data/spec/integration/mappers/wrap_spec.rb +1 -1
- data/spec/integration/memory/commands/create_spec.rb +1 -1
- data/spec/integration/memory/commands/delete_spec.rb +1 -1
- data/spec/integration/memory/commands/update_spec.rb +1 -1
- data/spec/integration/multi_env_spec.rb +1 -1
- data/spec/integration/multi_repo_spec.rb +1 -1
- data/spec/integration/relations/default_dataset_spec.rb +1 -1
- data/spec/integration/relations/reading_spec.rb +1 -1
- data/spec/integration/relations/registry_dsl_spec.rb +1 -1
- data/spec/integration/setup_spec.rb +10 -4
- data/spec/shared/command_graph.rb +8 -4
- data/spec/shared/enumerable_dataset.rb +1 -1
- data/spec/spec_helper.rb +7 -9
- data/spec/support/schema.rb +14 -0
- data/spec/unit/rom/array_dataset_spec.rb +59 -0
- data/spec/unit/rom/association_set_spec.rb +4 -0
- data/spec/unit/rom/auto_curry_spec.rb +63 -0
- data/spec/unit/rom/commands/graph_spec.rb +12 -11
- data/spec/unit/rom/commands/lazy_spec.rb +8 -5
- data/spec/unit/rom/commands/pre_and_post_processors_spec.rb +336 -0
- data/spec/unit/rom/commands/result_spec.rb +1 -1
- data/spec/unit/rom/commands_spec.rb +26 -3
- data/spec/unit/rom/configuration_spec.rb +1 -1
- data/spec/unit/rom/container_spec.rb +15 -5
- data/spec/unit/rom/create_container_spec.rb +1 -1
- data/spec/unit/rom/enumerable_dataset_spec.rb +15 -0
- data/spec/unit/rom/gateway_spec.rb +1 -1
- data/spec/unit/rom/mapper_registry_spec.rb +1 -1
- data/spec/unit/rom/memory/commands_spec.rb +1 -1
- data/spec/unit/rom/memory/dataset_spec.rb +1 -1
- data/spec/unit/rom/memory/{repository_spec.rb → gateway_spec.rb} +1 -1
- data/spec/unit/rom/memory/inheritance_spec.rb +32 -0
- data/spec/unit/rom/memory/relation_spec.rb +15 -3
- data/spec/unit/rom/memory/storage_spec.rb +1 -1
- data/spec/unit/rom/plugin_spec.rb +1 -1
- data/spec/unit/rom/plugins/command/schema_spec.rb +5 -5
- data/spec/unit/rom/plugins/relation/key_inference_spec.rb +1 -1
- data/spec/unit/rom/registry_spec.rb +86 -0
- data/spec/unit/rom/relation/attribute_reader_spec.rb +17 -0
- data/spec/unit/rom/relation/call_spec.rb +51 -0
- data/spec/unit/rom/relation/composite_spec.rb +1 -1
- data/spec/unit/rom/relation/graph_spec.rb +1 -1
- data/spec/unit/rom/relation/lazy/combine_spec.rb +1 -1
- data/spec/unit/rom/relation/lazy_spec.rb +1 -1
- data/spec/unit/rom/relation/loaded_spec.rb +1 -1
- data/spec/unit/rom/relation/schema_spec.rb +50 -6
- data/spec/unit/rom/relation/view_spec.rb +122 -0
- data/spec/unit/rom/relation_spec.rb +20 -5
- data/spec/unit/rom/schema/accessing_attributes_spec.rb +52 -0
- data/spec/unit/rom/schema/append_spec.rb +17 -0
- data/spec/unit/rom/schema/exclude_spec.rb +15 -0
- data/spec/unit/rom/schema/finalize_spec.rb +59 -0
- data/spec/unit/rom/schema/key_predicate_spec.rb +15 -0
- data/spec/unit/rom/schema/merge_spec.rb +17 -0
- data/spec/unit/rom/schema/prefix_spec.rb +16 -0
- data/spec/unit/rom/schema/project_spec.rb +15 -0
- data/spec/unit/rom/schema/rename_spec.rb +22 -0
- data/spec/unit/rom/schema/type_spec.rb +49 -0
- data/spec/unit/rom/schema/uniq_spec.rb +21 -0
- data/spec/unit/rom/schema/wrap_spec.rb +17 -0
- data/spec/unit/rom/schema_spec.rb +2 -2
- metadata +79 -17
- data/lib/rom/plugins/relation/view/dsl.rb +0 -32
- data/lib/rom/plugins/relation/view.rb +0 -95
- data/spec/unit/rom/plugins/relation/view_spec.rb +0 -51
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe ROM::Container do
|
3
|
+
RSpec.describe ROM::Container do
|
4
4
|
include_context 'container'
|
5
5
|
include_context 'users and tasks'
|
6
6
|
|
@@ -8,16 +8,22 @@ describe ROM::Container do
|
|
8
8
|
configuration
|
9
9
|
|
10
10
|
users = Class.new(ROM::Relation[:memory]) do
|
11
|
-
|
12
|
-
|
11
|
+
schema(:users) do
|
12
|
+
attribute :name, ROM::Types::String
|
13
|
+
attribute :email, ROM::Types::String
|
14
|
+
end
|
15
|
+
|
13
16
|
def by_name(name)
|
14
17
|
restrict(name: name).project(:name)
|
15
18
|
end
|
16
19
|
end
|
17
20
|
|
18
21
|
tasks = Class.new(ROM::Relation[:memory]) do
|
19
|
-
|
20
|
-
|
22
|
+
schema(:tasks) do
|
23
|
+
attribute :name, ROM::Types::String
|
24
|
+
attribute :title, ROM::Types::String
|
25
|
+
attribute :priority, ROM::Types::Int
|
26
|
+
end
|
21
27
|
end
|
22
28
|
|
23
29
|
create_user = Class.new(ROM::Commands::Create[:memory]) do
|
@@ -83,6 +89,10 @@ describe ROM::Container do
|
|
83
89
|
expect(container.relation(:tasks)).to be_kind_of(ROM::Relation)
|
84
90
|
expect(container.relation(:tasks).mappers.elements).to be_empty
|
85
91
|
end
|
92
|
+
|
93
|
+
it 'returns a relation with finalized schema' do
|
94
|
+
expect(container.relation(:tasks).schema.relations[:users]).to be(container.relations[:users])
|
95
|
+
end
|
86
96
|
end
|
87
97
|
|
88
98
|
describe '#mappers' do
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rom/enumerable_dataset'
|
2
|
+
|
3
|
+
RSpec.describe ROM::EnumerableDataset do
|
4
|
+
let(:klass) do
|
5
|
+
Class.new do
|
6
|
+
include ROM::EnumerableDataset
|
7
|
+
|
8
|
+
def self.row_proc
|
9
|
+
-> i { i.each_with_object({}) { |(k,v),h| h[k.to_sym] = v } }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
it_behaves_like 'an enumerable dataset'
|
15
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'rom/memory'
|
2
|
+
|
3
|
+
RSpec.describe ROM::Memory::Relation, '.inherited' do
|
4
|
+
subject(:relation) do
|
5
|
+
Class.new(ROM::Relation[:test]) do
|
6
|
+
schema(:users) do
|
7
|
+
attribute :name, ROM::Types::String
|
8
|
+
end
|
9
|
+
end.new([])
|
10
|
+
end
|
11
|
+
|
12
|
+
before do
|
13
|
+
module Test
|
14
|
+
module AnotherAdapter
|
15
|
+
class Relation < ROM::Memory::Relation
|
16
|
+
adapter :test
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
ROM.register_adapter(:test, Test::AnotherAdapter)
|
22
|
+
end
|
23
|
+
|
24
|
+
after do
|
25
|
+
ROM.adapters.delete(:test)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'extends subclass with core methods' do
|
29
|
+
expect(relation.name.to_sym).to be(:users)
|
30
|
+
expect(relation.schema.map(&:name)).to eql(%i[name])
|
31
|
+
end
|
32
|
+
end
|
@@ -4,8 +4,16 @@ require 'rom/lint/spec'
|
|
4
4
|
require 'rom/memory/dataset'
|
5
5
|
require 'rom/memory/relation'
|
6
6
|
|
7
|
-
describe ROM::Memory::Relation do
|
8
|
-
subject(:relation)
|
7
|
+
RSpec.describe ROM::Memory::Relation do
|
8
|
+
subject(:relation) do
|
9
|
+
Class.new(ROM::Memory::Relation) do
|
10
|
+
schema do
|
11
|
+
attribute :name, ROM::Types::String
|
12
|
+
attribute :email, ROM::Types::String
|
13
|
+
attribute :age, ROM::Types::Int
|
14
|
+
end
|
15
|
+
end.new(dataset)
|
16
|
+
end
|
9
17
|
|
10
18
|
let(:dataset) do
|
11
19
|
ROM::Memory::Dataset.new([
|
@@ -30,7 +38,11 @@ describe ROM::Memory::Relation do
|
|
30
38
|
|
31
39
|
describe '#project' do
|
32
40
|
it 'projects tuples with the provided keys' do
|
33
|
-
|
41
|
+
projected = relation.project(:name, :age)
|
42
|
+
|
43
|
+
expect(projected.schema).to eql(relation.schema.project(:name, :age))
|
44
|
+
|
45
|
+
expect(projected).to match_array([
|
34
46
|
{ name: 'Jane', age: 10 },
|
35
47
|
{ name: 'Jade', age: 11 },
|
36
48
|
{ name: 'Joe', age: 12 },
|
@@ -38,17 +38,17 @@ RSpec.describe ROM::Plugins::Command::Schema do
|
|
38
38
|
|
39
39
|
context 'when relation has a schema' do
|
40
40
|
let(:relation) do
|
41
|
-
instance_double(ROM::Relation, schema?: true,
|
41
|
+
instance_double(ROM::Relation, schema?: true, input_schema: input_schema)
|
42
42
|
end
|
43
43
|
|
44
|
-
let(:
|
45
|
-
double(:
|
44
|
+
let(:input_schema) do
|
45
|
+
double(:input_schema)
|
46
46
|
end
|
47
47
|
|
48
48
|
it 'sets schema hash as input handler' do
|
49
49
|
command = Class.new(command_class).build(relation)
|
50
50
|
|
51
|
-
expect(command.input).to be(
|
51
|
+
expect(command.input).to be(input_schema)
|
52
52
|
end
|
53
53
|
|
54
54
|
it 'sets a composed input handler with schema hash and a custom one' do
|
@@ -57,7 +57,7 @@ RSpec.describe ROM::Plugins::Command::Schema do
|
|
57
57
|
command = Class.new(command_class) { input my_handler }.build(relation)
|
58
58
|
|
59
59
|
expect(my_handler).to receive(:[]).with('some value').and_return('my handler')
|
60
|
-
expect(
|
60
|
+
expect(input_schema).to receive(:[]).with('my handler').and_return('a tuple')
|
61
61
|
|
62
62
|
expect(command.input['some value']).to eql('a tuple')
|
63
63
|
end
|
@@ -58,7 +58,7 @@ RSpec.describe ROM::Plugins::Relation::KeyInference do
|
|
58
58
|
use :key_inference
|
59
59
|
|
60
60
|
schema :posts do
|
61
|
-
attribute :author_id, ROM::Types::Int.meta(foreign_key: true,
|
61
|
+
attribute :author_id, ROM::Types::Int.meta(foreign_key: true, target: :users)
|
62
62
|
end
|
63
63
|
end
|
64
64
|
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'rom/registry'
|
2
|
+
|
3
|
+
RSpec.shared_examples_for 'registry fetch' do
|
4
|
+
it 'raises an ArgumentError when nil is used as a key' do
|
5
|
+
expect {
|
6
|
+
registry.public_send(fetch_method, nil)
|
7
|
+
}.to raise_error(ArgumentError, "key cannot be nil")
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'returns registered element identified by name' do
|
11
|
+
expect(registry.public_send(fetch_method, :mars)).to be(mars)
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'raises error when element is not found' do
|
15
|
+
expect { registry.public_send(fetch_method, :twix) }.to raise_error(
|
16
|
+
ROM::Registry::ElementNotFoundError,
|
17
|
+
":twix doesn't exist in Candy registry"
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'returns the value from an optional block when key is not found' do
|
22
|
+
value = registry.public_send(fetch_method, :candy) { :twix }
|
23
|
+
|
24
|
+
expect(value).to eq(:twix)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'calls #to_sym on a key before fetching' do
|
28
|
+
expect(registry.public_send(fetch_method, double(to_sym: :mars))).to be(mars)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
RSpec.describe ROM::Registry do
|
33
|
+
subject(:registry) { registry_class.new(mars: mars) }
|
34
|
+
|
35
|
+
let(:mars) { double('mars') }
|
36
|
+
|
37
|
+
let(:registry_class) do
|
38
|
+
Class.new(ROM::Registry) do
|
39
|
+
def self.name
|
40
|
+
'Candy'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '#fetch' do
|
46
|
+
let(:fetch_method) { :fetch }
|
47
|
+
|
48
|
+
it_behaves_like 'registry fetch'
|
49
|
+
end
|
50
|
+
|
51
|
+
describe '#[]' do
|
52
|
+
let(:fetch_method) { :[] }
|
53
|
+
|
54
|
+
it_behaves_like 'registry fetch'
|
55
|
+
end
|
56
|
+
|
57
|
+
describe '#method_missing' do
|
58
|
+
it 'returns registered element identified by name' do
|
59
|
+
expect(registry.mars).to be(mars)
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'raises no-method error when element is not there' do
|
63
|
+
expect { registry.twix }.to raise_error(NoMethodError)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe '#key?' do
|
68
|
+
let(:mars) { double(to_sym: :mars) }
|
69
|
+
|
70
|
+
it 'calls #to_sym on a key before checking if it exists' do
|
71
|
+
registry.key?(:mars)
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'returns true for an existing key' do
|
75
|
+
expect(registry.key?(:mars)).to be(true)
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'returns false for a non-existing key' do
|
79
|
+
expect(registry.key?(:twix)).to be(false)
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'returns false for a nil key' do
|
83
|
+
expect(registry.key?(nil)).to be(false)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rom/memory'
|
2
|
+
|
3
|
+
RSpec.describe ROM::Relation, '#[]' do
|
4
|
+
it 'defines a canonical schema for a relation' do
|
5
|
+
class Test::Users < ROM::Relation[:memory]
|
6
|
+
schema do
|
7
|
+
attribute :id, Types::Int
|
8
|
+
attribute :name, Types::String
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
relation = Test::Users.new([])
|
13
|
+
|
14
|
+
expect(relation[:id]).to be(Test::Users.schema[:id])
|
15
|
+
expect(relation[:name]).to be(Test::Users.schema[:name])
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'rom/relation'
|
2
|
+
|
3
|
+
RSpec.describe ROM::Relation, '#call' do
|
4
|
+
subject(:relation) do
|
5
|
+
relation_class.new(data)
|
6
|
+
end
|
7
|
+
|
8
|
+
context 'without read types in schema' do
|
9
|
+
let(:relation_class) do
|
10
|
+
Class.new(ROM::Relation[:memory]) do
|
11
|
+
schema do
|
12
|
+
attribute :id, ROM::Types::Int
|
13
|
+
attribute :name, ROM::Types::String
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
let(:data) do
|
19
|
+
[{ id: '1', name: 'Jane' }, { id: '2', name: 'John'} ]
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'has noop output_schema' do
|
23
|
+
expect(relation.output_schema).to be(ROM::Relation::NOOP_OUTPUT_SCHEMA)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'returns loaded relation with data' do
|
27
|
+
expect(relation.call.collection).
|
28
|
+
to eql(data)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'with read types in schema' do
|
33
|
+
let(:relation_class) do
|
34
|
+
Class.new(ROM::Relation[:memory]) do
|
35
|
+
schema do
|
36
|
+
attribute :id, ROM::Types::String, read: ROM::Types::Coercible::Int
|
37
|
+
attribute :name, ROM::Types::String
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
let(:data) do
|
43
|
+
[{ id: '1', name: 'Jane' }, { id: '2', name: 'John'} ]
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'returns loaded relation with coerced data' do
|
47
|
+
expect(relation.call.collection).
|
48
|
+
to eql([{ id: 1, name: 'Jane' }, { id: 2, name: 'John'} ])
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'rom/memory'
|
3
3
|
|
4
|
-
describe ROM::Relation, '.schema' do
|
4
|
+
RSpec.describe ROM::Relation, '.schema' do
|
5
5
|
it 'defines a canonical schema for a relation' do
|
6
6
|
class Test::Users < ROM::Relation[:memory]
|
7
7
|
schema do
|
@@ -13,16 +13,42 @@ describe ROM::Relation, '.schema' do
|
|
13
13
|
|
14
14
|
Test::Users.schema.finalize!
|
15
15
|
|
16
|
-
|
16
|
+
relation_name = ROM::Relation::Name[:test_users]
|
17
|
+
|
18
|
+
schema = ROM::Memory::Schema.define(
|
17
19
|
ROM::Relation::Name.new(:test_users),
|
18
|
-
|
19
|
-
|
20
|
-
|
20
|
+
attributes: [
|
21
|
+
ROM::Memory::Types::Int.meta(primary_key: true, name: :id, source: relation_name),
|
22
|
+
ROM::Memory::Types::String.meta(name: :name, source: relation_name),
|
23
|
+
ROM::Memory::Types::Bool.meta(name: :admin, source: relation_name)
|
24
|
+
]
|
21
25
|
).finalize!
|
22
26
|
|
23
27
|
expect(Test::Users.schema.primary_key).to eql([Test::Users.schema[:id]])
|
24
28
|
|
25
29
|
expect(Test::Users.schema).to eql(schema)
|
30
|
+
|
31
|
+
expect(Test::Users.schema.relations).to be_empty
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'allows defining types for reading tuples' do
|
35
|
+
module Test
|
36
|
+
module Types
|
37
|
+
CoercibleDate = ROM::Types::Date.constructor(Date.method(:parse))
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class Test::Users < ROM::Relation[:memory]
|
42
|
+
schema do
|
43
|
+
attribute :id, Types::Int
|
44
|
+
attribute :date, Types::Coercible::String, read: Test::Types::CoercibleDate
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
schema = Test::Users.schema
|
49
|
+
|
50
|
+
expect(schema.to_output_hash).
|
51
|
+
to eql(ROM::Types::Coercible::Hash.schema(id: schema[:id].type, date: schema[:date].meta[:read]))
|
26
52
|
end
|
27
53
|
|
28
54
|
it 'allows setting composite primary key' do
|
@@ -81,6 +107,24 @@ describe ROM::Relation, '.schema' do
|
|
81
107
|
expect(Test::Users.register_as).to be(:test_users)
|
82
108
|
end
|
83
109
|
|
110
|
+
it 'allows setting both dataset and relation alias' do
|
111
|
+
class Test::Users < ROM::Relation[:memory]
|
112
|
+
schema(:test_users, as: :users) { }
|
113
|
+
end
|
114
|
+
|
115
|
+
expect(Test::Users.register_as).to be(:users)
|
116
|
+
expect(Test::Users.dataset).to be(:test_users)
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'raises error when schema_class is missing' do
|
120
|
+
class Test::Users < ROM::Relation[:memory]
|
121
|
+
schema_class nil
|
122
|
+
end
|
123
|
+
|
124
|
+
expect { Test::Users.schema(:test) { } }.
|
125
|
+
to raise_error(ROM::MissingSchemaClassError, "Test::Users relation is missing schema_class")
|
126
|
+
end
|
127
|
+
|
84
128
|
describe '#schema' do
|
85
129
|
it 'returns defined schema' do
|
86
130
|
class Test::Users < ROM::Relation[:memory]
|
@@ -111,7 +155,7 @@ describe ROM::Relation, '.schema' do
|
|
111
155
|
end
|
112
156
|
end
|
113
157
|
|
114
|
-
expect(Test::Users.schema[:admin]).to eql(ROM::Types::Bool.meta(name: :admin))
|
158
|
+
expect(Test::Users.schema[:admin]).to eql(ROM::Types::Bool.meta(name: :admin, source: ROM::Relation::Name[:test_users]))
|
115
159
|
end
|
116
160
|
end
|
117
161
|
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'rom'
|
2
|
+
require 'rom/memory'
|
3
|
+
|
4
|
+
RSpec.describe ROM::Relation, '.view' do
|
5
|
+
subject(:relation) { relation_class.new(ROM::Memory::Dataset.new([])) }
|
6
|
+
|
7
|
+
it 'returns view method name' do
|
8
|
+
klass = Class.new(ROM::Relation[:memory]) {
|
9
|
+
schema { attribute :id, ROM::Types::Int }
|
10
|
+
}
|
11
|
+
|
12
|
+
name = klass.view(:by_id, klass.schema) { self }
|
13
|
+
|
14
|
+
expect(name).to be(:by_id)
|
15
|
+
end
|
16
|
+
|
17
|
+
shared_context 'relation with views' do
|
18
|
+
before do
|
19
|
+
relation << { id: 1, name: 'Joe' }
|
20
|
+
relation << { id: 2, name: 'Jane' }
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'uses projected schema for view schema' do
|
24
|
+
expect(relation.schemas[:names].map(&:name)).to eql(%i[name])
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'auto-projects the relation via schema' do
|
28
|
+
new_rel = relation_class.new([{ name: 'Jane' }, { name: 'Joe' }])
|
29
|
+
names_schema = relation_class.schemas[:names]
|
30
|
+
|
31
|
+
expect(names_schema).to receive(:call).with(relation).and_return(new_rel)
|
32
|
+
expect(relation.names).to eql(new_rel)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'auto-projects a restricted relation via schema' do
|
36
|
+
new_rel = relation_class.new([{ id: 2 }])
|
37
|
+
ids_schema = relation_class.schemas[:ids_for_names]
|
38
|
+
|
39
|
+
expect(ids_schema).to receive(:call).with(relation.restrict(name: ['Jane'])).and_return(new_rel)
|
40
|
+
expect(relation.ids_for_names(['Jane'])).to eql(new_rel)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'with an explicit schema' do
|
45
|
+
before do
|
46
|
+
# this is normally called automatically during setup
|
47
|
+
relation_class.finalize({}, relation)
|
48
|
+
end
|
49
|
+
|
50
|
+
include_context 'relation with views' do
|
51
|
+
let(:relation_class) do
|
52
|
+
Class.new(ROM::Memory::Relation) do
|
53
|
+
schema(:users) do
|
54
|
+
attribute :id, ROM::Types::Int
|
55
|
+
attribute :name, ROM::Types::String
|
56
|
+
end
|
57
|
+
|
58
|
+
view(:names) do
|
59
|
+
schema do
|
60
|
+
project(:name)
|
61
|
+
end
|
62
|
+
|
63
|
+
relation do
|
64
|
+
self
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
view(:ids_for_names) do
|
69
|
+
schema do
|
70
|
+
project(:id)
|
71
|
+
end
|
72
|
+
|
73
|
+
relation do |names|
|
74
|
+
restrict(name: names)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context 'with an inferred schema' do
|
83
|
+
before do
|
84
|
+
# this is normally called automatically during setup
|
85
|
+
relation_class.schema.finalize!
|
86
|
+
relation_class.finalize({}, relation)
|
87
|
+
end
|
88
|
+
|
89
|
+
include_context 'relation with views' do
|
90
|
+
let(:relation_class) do
|
91
|
+
Class.new(ROM::Memory::Relation) do
|
92
|
+
schema_inferrer -> dataset, gateway {
|
93
|
+
[[ROM::Types::Int.meta(name: :id, source: :users),
|
94
|
+
ROM::Types::String.meta(name: :name, source: :users)], []]
|
95
|
+
}
|
96
|
+
|
97
|
+
schema(:users, infer: true)
|
98
|
+
|
99
|
+
view(:names) do
|
100
|
+
schema do
|
101
|
+
project(:name)
|
102
|
+
end
|
103
|
+
|
104
|
+
relation do
|
105
|
+
self
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
view(:ids_for_names) do
|
110
|
+
schema do
|
111
|
+
project(:id)
|
112
|
+
end
|
113
|
+
|
114
|
+
relation do |names|
|
115
|
+
restrict(name: names)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|