rom-repository 1.4.0 → 2.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -6
- data/{LICENSE.txt → LICENSE} +1 -1
- data/README.md +18 -1
- data/lib/rom-repository.rb +1 -2
- data/lib/rom/repository.rb +9 -216
- data/lib/rom/repository/class_interface.rb +16 -33
- data/lib/rom/repository/relation_reader.rb +46 -0
- data/lib/rom/repository/root.rb +3 -59
- data/lib/rom/repository/version.rb +1 -1
- metadata +9 -98
- data/.gitignore +0 -3
- data/.rspec +0 -3
- data/.travis.yml +0 -27
- data/.yardopts +0 -2
- data/Gemfile +0 -38
- data/Rakefile +0 -19
- data/lib/rom/open_struct.rb +0 -35
- data/lib/rom/repository/changeset.rb +0 -155
- data/lib/rom/repository/changeset/associated.rb +0 -100
- data/lib/rom/repository/changeset/create.rb +0 -16
- data/lib/rom/repository/changeset/delete.rb +0 -17
- data/lib/rom/repository/changeset/pipe.rb +0 -97
- data/lib/rom/repository/changeset/restricted.rb +0 -28
- data/lib/rom/repository/changeset/stateful.rb +0 -282
- data/lib/rom/repository/changeset/update.rb +0 -82
- data/lib/rom/repository/command_compiler.rb +0 -257
- data/lib/rom/repository/command_proxy.rb +0 -26
- data/lib/rom/repository/header_builder.rb +0 -65
- data/lib/rom/repository/mapper_builder.rb +0 -23
- data/lib/rom/repository/relation_proxy.rb +0 -337
- data/lib/rom/repository/relation_proxy/combine.rb +0 -320
- data/lib/rom/repository/relation_proxy/wrap.rb +0 -78
- data/lib/rom/repository/struct_builder.rb +0 -83
- data/lib/rom/struct.rb +0 -113
- data/log/.gitkeep +0 -0
- data/rom-repository.gemspec +0 -23
- data/spec/integration/changeset_spec.rb +0 -193
- data/spec/integration/command_macros_spec.rb +0 -191
- data/spec/integration/command_spec.rb +0 -228
- data/spec/integration/multi_adapter_spec.rb +0 -73
- data/spec/integration/repository/aggregate_spec.rb +0 -58
- data/spec/integration/repository_spec.rb +0 -406
- data/spec/integration/root_repository_spec.rb +0 -106
- data/spec/integration/typed_structs_spec.rb +0 -64
- data/spec/shared/database.rb +0 -79
- data/spec/shared/mappers.rb +0 -35
- data/spec/shared/models.rb +0 -41
- data/spec/shared/plugins.rb +0 -66
- data/spec/shared/relations.rb +0 -115
- data/spec/shared/repo.rb +0 -86
- data/spec/shared/seeds.rb +0 -30
- data/spec/shared/structs.rb +0 -140
- data/spec/spec_helper.rb +0 -83
- data/spec/support/mapper_registry.rb +0 -9
- data/spec/support/mutant.rb +0 -10
- data/spec/unit/changeset/associate_spec.rb +0 -120
- data/spec/unit/changeset/map_spec.rb +0 -111
- data/spec/unit/changeset_spec.rb +0 -186
- data/spec/unit/relation_proxy_spec.rb +0 -202
- data/spec/unit/repository/changeset_spec.rb +0 -197
- data/spec/unit/repository/inspect_spec.rb +0 -18
- data/spec/unit/repository/session_spec.rb +0 -251
- data/spec/unit/repository/transaction_spec.rb +0 -42
- data/spec/unit/session_spec.rb +0 -46
- data/spec/unit/struct_builder_spec.rb +0 -128
@@ -1,106 +0,0 @@
|
|
1
|
-
RSpec.describe ROM::Repository::Root do
|
2
|
-
subject(:repo) do
|
3
|
-
Class.new(ROM::Repository[:users]) do
|
4
|
-
relations :tasks, :posts, :labels
|
5
|
-
end.new(rom)
|
6
|
-
end
|
7
|
-
|
8
|
-
include_context 'database'
|
9
|
-
include_context 'relations'
|
10
|
-
|
11
|
-
describe '.[]' do
|
12
|
-
it 'creates a pre-configured root repo class' do
|
13
|
-
klass = ROM::Repository[:users]
|
14
|
-
|
15
|
-
expect(klass.relations).to eql([:users])
|
16
|
-
expect(klass.root).to be(:users)
|
17
|
-
|
18
|
-
child = klass[:users]
|
19
|
-
|
20
|
-
expect(child.relations).to eql([:users])
|
21
|
-
expect(child.root).to be(:users)
|
22
|
-
expect(child < klass).to be(true)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
describe 'inheritance' do
|
27
|
-
it 'inherits root and relations' do
|
28
|
-
klass = Class.new(repo.class)
|
29
|
-
|
30
|
-
expect(klass.relations).to eql([:users, :tasks, :posts, :labels])
|
31
|
-
expect(klass.root).to be(:users)
|
32
|
-
end
|
33
|
-
|
34
|
-
it 'creates base root class' do
|
35
|
-
klass = Class.new(ROM::Repository)[:users]
|
36
|
-
|
37
|
-
expect(klass.relations).to eql([:users])
|
38
|
-
expect(klass.root).to be(:users)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
describe '#root' do
|
43
|
-
it 'returns configured root relation' do
|
44
|
-
expect(repo.root.relation).to be(rom.relations[:users])
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
describe '#changeset' do
|
49
|
-
it 'returns a changeset automatically set for root relation' do
|
50
|
-
klass = Class.new(ROM::Changeset::Create)
|
51
|
-
|
52
|
-
changeset = repo.changeset(klass)
|
53
|
-
|
54
|
-
expect(changeset.relation).to be(repo.users)
|
55
|
-
expect(changeset).to be_kind_of(klass)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
describe '#aggregate' do
|
60
|
-
include_context 'seeds'
|
61
|
-
|
62
|
-
it 'builds an aggregate from the root relation and other relation(s)' do
|
63
|
-
user = repo.aggregate(many: repo.tasks).where(name: 'Jane').one
|
64
|
-
|
65
|
-
expect(user.name).to eql('Jane')
|
66
|
-
expect(user.tasks.size).to be(1)
|
67
|
-
expect(user.tasks[0].title).to eql('Jane Task')
|
68
|
-
end
|
69
|
-
|
70
|
-
context 'with associations' do
|
71
|
-
it 'builds an aggregate from a canonical association' do
|
72
|
-
user = repo.aggregate(:labels).where(name: 'Joe').one
|
73
|
-
|
74
|
-
expect(user.name).to eql('Joe')
|
75
|
-
expect(user.labels.size).to be(1)
|
76
|
-
expect(user.labels[0].name).to eql('green')
|
77
|
-
end
|
78
|
-
|
79
|
-
it 'builds an aggregate with nesting level = 2' do
|
80
|
-
user = repo.aggregate(posts: [:labels, :author]).where(name: 'Joe').one
|
81
|
-
|
82
|
-
expect(user.name).to eql('Joe')
|
83
|
-
expect(user.posts.size).to be(1)
|
84
|
-
expect(user.posts[0].title).to eql('Hello From Joe')
|
85
|
-
expect(user.posts[0].labels.size).to be(1)
|
86
|
-
end
|
87
|
-
|
88
|
-
it 'builds a command from an aggregate' do
|
89
|
-
command = repo.command(:create, repo.aggregate(:posts))
|
90
|
-
|
91
|
-
result = command.call(name: 'Jade', posts: [{ title: 'Jade post' }])
|
92
|
-
|
93
|
-
expect(result.name).to eql('Jade')
|
94
|
-
expect(result.posts.size).to be(1)
|
95
|
-
expect(result.posts[0].title).to eql('Jade post')
|
96
|
-
end
|
97
|
-
|
98
|
-
it 'builds same relation as manual combine' do
|
99
|
-
left = repo.aggregate(:posts)
|
100
|
-
right = repo.users.combine_children(many: repo.posts)
|
101
|
-
|
102
|
-
expect(left.to_ast).to eql(right.to_ast)
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
@@ -1,64 +0,0 @@
|
|
1
|
-
RSpec.describe 'ROM repository with typed structs' do
|
2
|
-
subject(:repo) do
|
3
|
-
Class.new(ROM::Repository[:books]) { commands :create }.new(rom)
|
4
|
-
end
|
5
|
-
|
6
|
-
include_context 'database'
|
7
|
-
include_context 'seeds'
|
8
|
-
|
9
|
-
context 'typed projections' do
|
10
|
-
before do
|
11
|
-
configuration.relation(:books) do
|
12
|
-
schema(infer: true)
|
13
|
-
|
14
|
-
view(:index) do
|
15
|
-
schema { project(:id, :title, :created_at) }
|
16
|
-
relation { order(:title) }
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
rom.relations[:books].insert(title: 'Hello World', created_at: Time.now)
|
21
|
-
end
|
22
|
-
|
23
|
-
it 'loads typed structs' do
|
24
|
-
book = repo.books.index.first
|
25
|
-
|
26
|
-
expect(book).to be_kind_of(Dry::Struct)
|
27
|
-
|
28
|
-
expect(book.id).to be_kind_of(Integer)
|
29
|
-
expect(book.title).to eql('Hello World')
|
30
|
-
expect(book.created_at).to be_kind_of(Time)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
context 'read-write type coercions' do
|
35
|
-
before do
|
36
|
-
configuration.relation(:books) do
|
37
|
-
schema(infer: true) do
|
38
|
-
attribute :title,
|
39
|
-
ROM::Types::Coercible::String.meta(
|
40
|
-
read: ROM::Types::Symbol.constructor(&:to_sym)
|
41
|
-
)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
configuration.commands(:books) do
|
46
|
-
define(:create) { result(:one) }
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
it 'loads typed structs' do
|
51
|
-
created_book = repo.create(title: :'Hello World', created_at: Time.now)
|
52
|
-
|
53
|
-
expect(created_book).to be_kind_of(Dry::Struct)
|
54
|
-
|
55
|
-
expect(created_book.id).to be_kind_of(Integer)
|
56
|
-
expect(created_book.title).to eql(:'Hello World')
|
57
|
-
expect(created_book.created_at).to be_kind_of(Time)
|
58
|
-
|
59
|
-
book = repo.books.to_a.first
|
60
|
-
|
61
|
-
expect(book).to eql(created_book)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
data/spec/shared/database.rb
DELETED
@@ -1,79 +0,0 @@
|
|
1
|
-
RSpec.shared_context 'database setup' do
|
2
|
-
let(:configuration) { ROM::Configuration.new(:sql, DB_URI) }
|
3
|
-
|
4
|
-
let(:conn) { configuration.gateways[:default].connection }
|
5
|
-
|
6
|
-
let(:rom) { ROM.container(configuration) }
|
7
|
-
|
8
|
-
before do
|
9
|
-
conn.loggers << LOGGER
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
RSpec.shared_context 'database' do
|
14
|
-
include_context 'database setup'
|
15
|
-
|
16
|
-
before do
|
17
|
-
[:tags, :tasks, :posts, :books, :users, :posts_labels, :labels,
|
18
|
-
:reactions, :messages].each { |table| conn.drop_table?(table) }
|
19
|
-
|
20
|
-
conn.create_table :users do
|
21
|
-
primary_key :id
|
22
|
-
column :name, String
|
23
|
-
end
|
24
|
-
|
25
|
-
conn.create_table :books do
|
26
|
-
primary_key :id
|
27
|
-
foreign_key :author_id, :users, on_delete: :cascade
|
28
|
-
column :title, String
|
29
|
-
column :created_at, Time
|
30
|
-
column :updated_at, Time
|
31
|
-
end
|
32
|
-
|
33
|
-
conn.create_table :tasks do
|
34
|
-
primary_key :id
|
35
|
-
foreign_key :user_id, :users, null: false, on_delete: :cascade
|
36
|
-
column :title, String
|
37
|
-
end
|
38
|
-
|
39
|
-
conn.create_table :tags do
|
40
|
-
primary_key :id
|
41
|
-
foreign_key :task_id, :tasks, null: false, on_delete: :cascade
|
42
|
-
column :name, String
|
43
|
-
end
|
44
|
-
|
45
|
-
conn.create_table :labels do
|
46
|
-
primary_key :id
|
47
|
-
column :name, String
|
48
|
-
end
|
49
|
-
|
50
|
-
conn.create_table :posts do
|
51
|
-
primary_key :id
|
52
|
-
foreign_key :author_id, :users, null: false, on_delete: :cascade
|
53
|
-
column :title, String, null: false
|
54
|
-
column :body, String
|
55
|
-
end
|
56
|
-
|
57
|
-
conn.create_table :posts_labels do
|
58
|
-
foreign_key :post_id, :labels, null: false, on_delete: :cascade
|
59
|
-
foreign_key :label_id, :labels, null: false, on_delete: :cascade
|
60
|
-
primary_key [:post_id, :label_id]
|
61
|
-
end
|
62
|
-
|
63
|
-
conn.create_table :messages do
|
64
|
-
primary_key :message_id
|
65
|
-
column :author, String
|
66
|
-
column :body, String
|
67
|
-
end
|
68
|
-
|
69
|
-
conn.create_table :reactions do
|
70
|
-
primary_key :reaction_id
|
71
|
-
foreign_key :message_id, :messages, null: false
|
72
|
-
column :author, String
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
after do
|
77
|
-
rom.disconnect
|
78
|
-
end
|
79
|
-
end
|
data/spec/shared/mappers.rb
DELETED
@@ -1,35 +0,0 @@
|
|
1
|
-
RSpec.shared_context 'mappers' do
|
2
|
-
let(:user_mappers) { users.mappers[:user] }
|
3
|
-
let(:task_mappers) { tasks.mappers[:task] }
|
4
|
-
let(:tag_mappers) { tags.mappers[:tag] }
|
5
|
-
|
6
|
-
before do
|
7
|
-
configuration.mappers do
|
8
|
-
define(:users) do
|
9
|
-
model Test::Models::User
|
10
|
-
register_as :user
|
11
|
-
|
12
|
-
attribute :id
|
13
|
-
attribute :name
|
14
|
-
end
|
15
|
-
|
16
|
-
define(:tasks) do
|
17
|
-
model Test::Models::Task
|
18
|
-
register_as :task
|
19
|
-
|
20
|
-
attribute :id
|
21
|
-
attribute :user_id
|
22
|
-
attribute :title
|
23
|
-
end
|
24
|
-
|
25
|
-
define(:tags) do
|
26
|
-
model Test::Models::Tag
|
27
|
-
register_as :tag
|
28
|
-
|
29
|
-
attribute :id
|
30
|
-
attribute :task_id
|
31
|
-
attribute :name
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
data/spec/shared/models.rb
DELETED
@@ -1,41 +0,0 @@
|
|
1
|
-
RSpec.shared_context 'models' do
|
2
|
-
let(:user_model) { Test::Models::User }
|
3
|
-
let(:task_model) { Test::Models::Task }
|
4
|
-
let(:tag_model) { Test::Models::Tag }
|
5
|
-
|
6
|
-
before do
|
7
|
-
module Test
|
8
|
-
module Models
|
9
|
-
class User
|
10
|
-
include Dry::Equalizer(:id, :name)
|
11
|
-
|
12
|
-
attr_reader :id, :name
|
13
|
-
|
14
|
-
def initialize(attrs)
|
15
|
-
@id, @name = attrs[:id], attrs[:name]
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
class Task
|
20
|
-
include Dry::Equalizer(:id, :user_id, :title)
|
21
|
-
|
22
|
-
attr_reader :id, :user_id, :title
|
23
|
-
|
24
|
-
def initialize(attrs)
|
25
|
-
@id, @name, @title = attrs[:id], attrs[:name], attrs[:title]
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
class Tag
|
30
|
-
include Dry::Equalizer(:id, :task_id, :name)
|
31
|
-
|
32
|
-
attr_reader :id, :task_id, :name
|
33
|
-
|
34
|
-
def initialize(attrs)
|
35
|
-
@id, @task_id, @name = attrs[:id], attrs[:task_id], attrs[:name]
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
data/spec/shared/plugins.rb
DELETED
@@ -1,66 +0,0 @@
|
|
1
|
-
RSpec.shared_context 'plugins' do
|
2
|
-
before do
|
3
|
-
module Test
|
4
|
-
class WrappingInput
|
5
|
-
def initialize(input)
|
6
|
-
@input = input || Hash
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
module Timestamps
|
11
|
-
class InputWithTimestamp < WrappingInput
|
12
|
-
def [](value)
|
13
|
-
v = @input[value]
|
14
|
-
now = Time.now
|
15
|
-
|
16
|
-
if v[:created_at]
|
17
|
-
v.merge(updated_at: now)
|
18
|
-
else
|
19
|
-
v.merge(created_at: now, updated_at: now)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
module ClassInterface
|
25
|
-
def build(relation, options = {})
|
26
|
-
super(relation, options.merge(input: InputWithTimestamp.new(input)))
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def self.included(klass)
|
31
|
-
super
|
32
|
-
|
33
|
-
klass.extend ClassInterface
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
module UpcaseName
|
38
|
-
class UpcaseNameInput < WrappingInput
|
39
|
-
def [](value)
|
40
|
-
v = @input[value]
|
41
|
-
v.merge(name: value.fetch(:name).upcase)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
module ClassInterface
|
46
|
-
def build(relation, options = {})
|
47
|
-
super(relation, options.merge(input: UpcaseNameInput.new(options.fetch(:input))))
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def self.included(klass)
|
52
|
-
super
|
53
|
-
|
54
|
-
klass.extend ClassInterface
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
ROM.plugins do
|
60
|
-
adapter :sql do
|
61
|
-
register :timestamps, Test::Timestamps, type: :command
|
62
|
-
register :upcase_name, Test::UpcaseName, type: :command
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
data/spec/shared/relations.rb
DELETED
@@ -1,115 +0,0 @@
|
|
1
|
-
RSpec.shared_context 'relations' do
|
2
|
-
let(:users) { rom.relations[:users] }
|
3
|
-
let(:tasks) { rom.relations[:tasks] }
|
4
|
-
let(:tags) { rom.relations[:tags] }
|
5
|
-
let(:posts) { rom.relations[:posts] }
|
6
|
-
let(:books) { rom.relations[:books] }
|
7
|
-
|
8
|
-
before do
|
9
|
-
configuration.relation(:books) do
|
10
|
-
schema(:books) do
|
11
|
-
attribute :id, ROM::SQL::Types::Serial
|
12
|
-
attribute :author_id, ROM::SQL::Types.ForeignKey(:users)
|
13
|
-
attribute :title, ROM::SQL::Types::String
|
14
|
-
attribute :created_at, ROM::SQL::Types::Time
|
15
|
-
attribute :updated_at, ROM::SQL::Types::Time
|
16
|
-
|
17
|
-
associations do
|
18
|
-
belongs_to :users, as: :author, relation: :authors, foreign_key: :author_id
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
configuration.relation(:users) do
|
24
|
-
schema(infer: true) do
|
25
|
-
associations do
|
26
|
-
has_many :posts
|
27
|
-
has_many :posts, as: :aliased_posts
|
28
|
-
has_many :labels, through: :posts
|
29
|
-
has_many :books, foreign_key: :author_id
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def by_name(name)
|
34
|
-
where(name: name)
|
35
|
-
end
|
36
|
-
|
37
|
-
def all
|
38
|
-
select(:id, :name).order(:name, :id)
|
39
|
-
end
|
40
|
-
|
41
|
-
def find(criteria)
|
42
|
-
where(criteria)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
configuration.relation(:authors) do
|
47
|
-
schema(:users, infer: true)
|
48
|
-
end
|
49
|
-
|
50
|
-
configuration.relation(:tasks) do
|
51
|
-
schema(infer: true) do
|
52
|
-
associations do
|
53
|
-
belongs_to :user
|
54
|
-
belongs_to :users, as: :assignee
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def find(criteria)
|
59
|
-
where(criteria)
|
60
|
-
end
|
61
|
-
|
62
|
-
def for_users(users)
|
63
|
-
where(user_id: users.map { |u| u[:id] })
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
configuration.relation(:tags) do
|
68
|
-
schema(infer: true)
|
69
|
-
end
|
70
|
-
|
71
|
-
configuration.relation(:labels) do
|
72
|
-
schema(infer: true) do
|
73
|
-
associations do
|
74
|
-
has_many :posts_labels
|
75
|
-
has_many :posts, through: :posts_labels
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
configuration.relation(:posts) do
|
81
|
-
schema(:posts, infer: true) do
|
82
|
-
associations do
|
83
|
-
has_many :labels, through: :posts_labels
|
84
|
-
belongs_to :user, as: :author
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
configuration.relation(:posts_labels) do
|
90
|
-
schema(infer: true) do
|
91
|
-
associations do
|
92
|
-
belongs_to :post
|
93
|
-
belongs_to :label
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
configuration.relation(:comments) do
|
99
|
-
schema(:messages, as: :comments, infer: true) do
|
100
|
-
associations do
|
101
|
-
has_many :reactions, relation: :likes
|
102
|
-
has_many :reactions, relation: :likes, as: :emotions
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
configuration.relation(:likes) do
|
108
|
-
schema(:reactions, as: :likes, infer: true) do
|
109
|
-
associations do
|
110
|
-
belongs_to :message, relation: :comments
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|