rom 0.4.2 → 0.5.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.
Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +81 -0
  3. data/.travis.yml +2 -1
  4. data/CHANGELOG.md +41 -0
  5. data/Gemfile +12 -8
  6. data/Guardfile +17 -11
  7. data/README.md +7 -7
  8. data/Rakefile +29 -0
  9. data/lib/rom.rb +9 -66
  10. data/lib/rom/adapter.rb +45 -12
  11. data/lib/rom/adapter/memory.rb +0 -4
  12. data/lib/rom/adapter/memory/commands.rb +0 -10
  13. data/lib/rom/adapter/memory/dataset.rb +18 -6
  14. data/lib/rom/adapter/memory/storage.rb +0 -3
  15. data/lib/rom/command_registry.rb +24 -43
  16. data/lib/rom/commands.rb +5 -6
  17. data/lib/rom/commands/create.rb +5 -5
  18. data/lib/rom/commands/delete.rb +8 -6
  19. data/lib/rom/commands/result.rb +82 -0
  20. data/lib/rom/commands/update.rb +5 -4
  21. data/lib/rom/commands/with_options.rb +1 -4
  22. data/lib/rom/config.rb +70 -0
  23. data/lib/rom/env.rb +11 -3
  24. data/lib/rom/global.rb +107 -0
  25. data/lib/rom/header.rb +122 -89
  26. data/lib/rom/header/attribute.rb +148 -0
  27. data/lib/rom/mapper.rb +46 -67
  28. data/lib/rom/mapper_builder.rb +20 -73
  29. data/lib/rom/mapper_builder/mapper_dsl.rb +114 -0
  30. data/lib/rom/mapper_builder/model_dsl.rb +29 -0
  31. data/lib/rom/mapper_registry.rb +21 -0
  32. data/lib/rom/model_builder.rb +11 -17
  33. data/lib/rom/processor.rb +28 -0
  34. data/lib/rom/processor/transproc.rb +105 -0
  35. data/lib/rom/reader.rb +81 -21
  36. data/lib/rom/reader_builder.rb +14 -4
  37. data/lib/rom/relation.rb +19 -5
  38. data/lib/rom/relation_builder.rb +20 -6
  39. data/lib/rom/repository.rb +0 -2
  40. data/lib/rom/setup.rb +156 -0
  41. data/lib/rom/{boot → setup}/base_relation_dsl.rb +4 -8
  42. data/lib/rom/setup/command_dsl.rb +46 -0
  43. data/lib/rom/setup/finalize.rb +125 -0
  44. data/lib/rom/setup/mapper_dsl.rb +19 -0
  45. data/lib/rom/{boot → setup}/relation_dsl.rb +1 -4
  46. data/lib/rom/setup/schema_dsl.rb +33 -0
  47. data/lib/rom/support/registry.rb +10 -6
  48. data/lib/rom/version.rb +1 -1
  49. data/rom.gemspec +3 -1
  50. data/spec/integration/adapters/extending_relations_spec.rb +0 -2
  51. data/spec/integration/commands/create_spec.rb +2 -9
  52. data/spec/integration/commands/delete_spec.rb +4 -5
  53. data/spec/integration/commands/error_handling_spec.rb +4 -3
  54. data/spec/integration/commands/update_spec.rb +3 -8
  55. data/spec/integration/mappers/deep_embedded_spec.rb +52 -0
  56. data/spec/integration/mappers/definition_dsl_spec.rb +0 -118
  57. data/spec/integration/mappers/embedded_spec.rb +82 -0
  58. data/spec/integration/mappers/group_spec.rb +170 -0
  59. data/spec/integration/mappers/prefixing_attributes_spec.rb +2 -2
  60. data/spec/integration/mappers/renaming_attributes_spec.rb +8 -6
  61. data/spec/integration/mappers/symbolizing_attributes_spec.rb +80 -0
  62. data/spec/integration/mappers/wrap_spec.rb +162 -0
  63. data/spec/integration/multi_repo_spec.rb +64 -0
  64. data/spec/integration/relations/reading_spec.rb +12 -8
  65. data/spec/integration/relations/registry_dsl_spec.rb +1 -3
  66. data/spec/integration/schema_spec.rb +10 -0
  67. data/spec/integration/setup_spec.rb +57 -6
  68. data/spec/spec_helper.rb +2 -1
  69. data/spec/unit/config_spec.rb +60 -0
  70. data/spec/unit/rom/adapter/memory/dataset_spec.rb +52 -0
  71. data/spec/unit/rom/adapter_spec.rb +31 -11
  72. data/spec/unit/rom/header_spec.rb +60 -16
  73. data/spec/unit/rom/mapper_builder_spec.rb +311 -0
  74. data/spec/unit/rom/mapper_registry_spec.rb +25 -0
  75. data/spec/unit/rom/mapper_spec.rb +4 -5
  76. data/spec/unit/rom/model_builder_spec.rb +15 -13
  77. data/spec/unit/rom/processor/transproc_spec.rb +331 -0
  78. data/spec/unit/rom/reader_spec.rb +73 -0
  79. data/spec/unit/rom/registry_spec.rb +38 -0
  80. data/spec/unit/rom/relation_spec.rb +0 -1
  81. data/spec/unit/rom/setup_spec.rb +55 -0
  82. data/spec/unit/rom_spec.rb +14 -0
  83. metadata +62 -22
  84. data/Gemfile.devtools +0 -71
  85. data/lib/rom/boot.rb +0 -197
  86. data/lib/rom/boot/command_dsl.rb +0 -48
  87. data/lib/rom/boot/dsl.rb +0 -37
  88. data/lib/rom/boot/mapper_dsl.rb +0 -23
  89. data/lib/rom/boot/schema_dsl.rb +0 -27
  90. data/lib/rom/ra.rb +0 -172
  91. data/lib/rom/ra/operation/group.rb +0 -47
  92. data/lib/rom/ra/operation/join.rb +0 -39
  93. data/lib/rom/ra/operation/wrap.rb +0 -45
  94. data/lib/rom/transformer.rb +0 -77
  95. data/spec/integration/ra/group_spec.rb +0 -46
  96. data/spec/integration/ra/join_spec.rb +0 -50
  97. data/spec/integration/ra/wrap_spec.rb +0 -37
  98. data/spec/unit/rom/ra/operation/group_spec.rb +0 -55
  99. data/spec/unit/rom/ra/operation/wrap_spec.rb +0 -29
  100. data/spec/unit/rom/transformer_spec.rb +0 -41
@@ -1,77 +0,0 @@
1
- module ROM
2
-
3
- class Transformer
4
- attr_reader :operations
5
-
6
- class Operation
7
- attr_reader :attribute, :key, :names
8
-
9
- def initialize(attribute)
10
- @attribute = attribute
11
- @key = attribute.key
12
- @names = attribute.header.map(&:key)
13
- end
14
- end
15
-
16
- class Wrap < Operation
17
- def call(tuples)
18
- keys = nil
19
-
20
- tuples.map { |tuple|
21
- keys ||= tuple.keys - names
22
-
23
- root = Hash[keys.zip(tuple.values_at(*keys))]
24
- child = Hash[names.zip(tuple.values_at(*names))]
25
-
26
- root.merge(key => child)
27
- }
28
- end
29
- end
30
-
31
- class Group < Operation
32
- def call(tuples)
33
- keys = nil
34
-
35
- tuples.
36
- group_by { |tuple|
37
- keys ||= tuple.keys - names
38
- Hash[keys.zip(tuple.values_at(*keys))]
39
- }.map { |root, children|
40
- root.merge(
41
- key => children.map { |child| Hash[names.zip(child.values_at(*names))] }
42
- )
43
- }
44
- end
45
- end
46
-
47
- def self.build(header)
48
- operations = header.map do |attribute|
49
- type = attribute.type
50
-
51
- if type == Hash
52
- Wrap.new(attribute)
53
- elsif type == Array
54
- Group.new(attribute)
55
- end
56
- end.compact
57
-
58
- sorted_ops =
59
- operations.select { |op| Group === op } +
60
- operations.select { |op| Wrap === op }
61
-
62
- new(sorted_ops.flatten)
63
- end
64
-
65
- def initialize(operations)
66
- @operations = operations
67
- end
68
-
69
- def call(input)
70
- output = input
71
- operations.each { |op| output = op.call(output) }
72
- output
73
- end
74
-
75
- end
76
-
77
- end
@@ -1,46 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe 'Group operation' do
4
- include_context 'users and tasks'
5
-
6
- specify 'defining a grouped relation' do
7
- setup.relation(:users) do
8
- include ROM::RA
9
-
10
- def with_tasks
11
- group(join(tasks), tasks: [:title, :priority])
12
- end
13
-
14
- def by_name(name)
15
- restrict(name: name)
16
- end
17
-
18
- end
19
-
20
- users = rom.relations.users
21
-
22
- expect(users.with_tasks.to_a).to eql(
23
- [
24
- {
25
- name: "Joe", email: "joe@doe.org", tasks: [
26
- { title: "be nice", priority: 1 },
27
- { title: "sleep well", priority: 2 }
28
- ]
29
- },
30
- { name: "Jane", email: "jane@doe.org", tasks: [{ title: "be cool", priority: 2 }] }
31
- ]
32
- )
33
-
34
- expect(users.with_tasks.by_name("Jane").to_a).to eql(
35
- [
36
- { name: "Jane", email: "jane@doe.org", tasks: [{ title: "be cool", priority: 2 }] }
37
- ]
38
- )
39
-
40
- expect(users.by_name("Jane").with_tasks.to_a).to eql(
41
- [
42
- { name: "Jane", email: "jane@doe.org", tasks: [{ title: "be cool", priority: 2 }] }
43
- ]
44
- )
45
- end
46
- end
@@ -1,50 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe 'Join operation' do
4
- include_context 'users and tasks'
5
-
6
- specify 'defining a joined one-to-many relation' do
7
- setup.relation(:users) do
8
- include ROM::RA
9
-
10
- def with_tasks
11
- join(tasks)
12
- end
13
- end
14
-
15
- setup.relation(:tasks)
16
-
17
- users = rom.relations.users
18
-
19
- expect(users.with_tasks.to_a).to eql(
20
- [
21
- { name: 'Joe', email: 'joe@doe.org', title: 'be nice', priority: 1 },
22
- { name: 'Joe', email: 'joe@doe.org', title: 'sleep well', priority: 2 },
23
- { name: 'Jane', email: 'jane@doe.org', title: 'be cool', priority: 2 }
24
- ]
25
- )
26
- end
27
-
28
- specify 'defining a joined many-to-one relation' do
29
- setup.relation(:users)
30
-
31
- setup.relation(:tasks) do
32
- include ROM::RA
33
-
34
- def with_user
35
- join(users)
36
- end
37
- end
38
-
39
- tasks = rom.relations.tasks
40
-
41
- expect(tasks.with_user.to_a).to eql(
42
- [
43
- { title: 'be nice', priority: 1, name: 'Joe', email: 'joe@doe.org' },
44
- { title: 'sleep well', priority: 2, name: 'Joe', email: 'joe@doe.org' },
45
- { title: 'be cool', priority: 2, name: 'Jane', email: 'jane@doe.org' }
46
- ]
47
- )
48
- end
49
-
50
- end
@@ -1,37 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe 'Wrap operation' do
4
- include_context 'users and tasks'
5
-
6
- specify 'defining a wrapped relation' do
7
- setup.relation(:users) do
8
- include ROM::RA
9
-
10
- def with_task
11
- wrap(join(tasks), task: [:title, :priority])
12
- end
13
- end
14
-
15
- users = rom.relations.users
16
-
17
- expect(users.with_task.to_a).to eql(
18
- [
19
- {
20
- name: "Joe",
21
- email: "joe@doe.org",
22
- task: { title: "be nice", priority: 1 }
23
- },
24
- {
25
- name: "Joe",
26
- email: "joe@doe.org",
27
- task: { title: "sleep well", priority: 2 }
28
- },
29
- {
30
- name: "Jane",
31
- email: "jane@doe.org",
32
- task: { title: "be cool", priority: 2 }
33
- }
34
- ]
35
- )
36
- end
37
- end
@@ -1,55 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe 'Group operation' do
4
- subject(:group) { relation.group(options) }
5
-
6
- let(:relation) do
7
- ROM::Relation.new(dataset, header).extend(ROM::RA)
8
- end
9
-
10
- let(:header) do
11
- [:name, :email, :street, :zipcode, :city]
12
- end
13
-
14
- let(:options) do
15
- { addresses: [:street, :zipcode, :city] }
16
- end
17
-
18
- context 'when group values are present' do
19
- let(:dataset) do
20
- [{ name: 'Jane',
21
- email: 'jane@doe.org',
22
- street: 'Street 1',
23
- zipcode: '1234',
24
- city: 'Cracow' }]
25
- end
26
-
27
- it 'groups given attributes under specified key' do
28
- expect(group.to_a).to eql(
29
- [{ name: 'Jane',
30
- email: 'jane@doe.org',
31
- addresses: [{ street: 'Street 1', zipcode: '1234', city: 'Cracow' }] }]
32
- )
33
- end
34
-
35
- it 'exposes the header' do
36
- expect(group.header).to eql([:name, :email, :addresses])
37
- end
38
- end
39
-
40
- context 'when group values are not present' do
41
- let(:dataset) do
42
- [{ name: 'Jane',
43
- email: 'jane@doe.org',
44
- street: nil,
45
- zipcode: nil,
46
- city: nil }]
47
- end
48
-
49
- it 'sets empty array for grouped attributes' do
50
- expect(group.to_a).to eql(
51
- [{ name: 'Jane', email: 'jane@doe.org', addresses: [] }]
52
- )
53
- end
54
- end
55
- end
@@ -1,29 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe 'Wrap operation' do
4
- subject(:wrap) { relation.wrap(address: [:street, :zipcode, :city]) }
5
-
6
- let(:relation) do
7
- ROM::Relation.new([{ name: 'Jane',
8
- email: 'jane@doe.org',
9
- street: 'Street 1',
10
- zipcode: '1234',
11
- city: 'Cracow' }], header).extend(ROM::RA)
12
- end
13
-
14
- let(:header) do
15
- [:name, :email, :street, :zipcode, :city]
16
- end
17
-
18
- it 'wraps given attributes under specified key' do
19
- expect(wrap.to_a).to eql(
20
- [{ name: 'Jane',
21
- email: 'jane@doe.org',
22
- address: { street: 'Street 1', zipcode: '1234', city: 'Cracow' } }]
23
- )
24
- end
25
-
26
- it 'exposes the header' do
27
- expect(wrap.header).to eql([:name, :email, :address])
28
- end
29
- end
@@ -1,41 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe ROM::Transformer do
4
- subject(:transformer) { ROM::Transformer.build(header) }
5
-
6
- let(:header) do
7
- ROM::Header.coerce([
8
- [:name],
9
- [:address, type: Hash, header: [[:street], [:zipcode]]],
10
- [:tasks, type: Array, header: [[:title], [:priority]]]
11
- ])
12
- end
13
-
14
- let(:relation) do
15
- [{ name: 'Jane',
16
- street: 'Street 1',
17
- zipcode: '123',
18
- title: 'Sing a song',
19
- priority: 'high' },
20
- { name: 'Jane',
21
- street: 'Street 1',
22
- zipcode: '123',
23
- title: 'Relax',
24
- priority: 'very-high' }]
25
- end
26
-
27
- it 'transforms a tuple' do
28
- expect(transformer.call(relation)).to eql([
29
- name: 'Jane',
30
- address: { street: 'Street 1', zipcode: '123' },
31
- tasks: [
32
- { title: 'Sing a song', priority: 'high' },
33
- { title: 'Relax', priority: 'very-high' }
34
- ]
35
- ])
36
- end
37
-
38
- it 'skip transforming if tuple is empty' do
39
- expect(transformer.call([])).to eql([])
40
- end
41
- end