rom 2.0.2 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|