rom-sql 0.6.1 → 0.7.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -5
- data/.rubocop_todo.yml +12 -6
- data/.travis.yml +3 -2
- data/CHANGELOG.md +27 -0
- data/Gemfile +1 -0
- data/lib/rom/plugins/relation/sql/auto_combine.rb +45 -0
- data/lib/rom/plugins/relation/sql/auto_wrap.rb +48 -0
- data/lib/rom/plugins/relation/sql/base_view.rb +31 -0
- data/lib/rom/sql.rb +17 -10
- data/lib/rom/sql/commands/error_wrapper.rb +1 -1
- data/lib/rom/sql/commands/update.rb +1 -1
- data/lib/rom/sql/gateway.rb +8 -2
- data/lib/rom/sql/header.rb +1 -1
- data/lib/rom/sql/migration.rb +11 -20
- data/lib/rom/sql/migration/migrator.rb +4 -0
- data/lib/rom/sql/{relation/associations.rb → plugin/assoc_macros.rb} +17 -2
- data/lib/rom/sql/plugin/assoc_macros/class_interface.rb +128 -0
- data/lib/rom/sql/plugin/associates.rb +2 -4
- data/lib/rom/sql/plugin/pagination.rb +1 -1
- data/lib/rom/sql/plugins.rb +4 -2
- data/lib/rom/sql/relation.rb +46 -6
- data/lib/rom/sql/relation/reading.rb +63 -0
- data/lib/rom/sql/tasks/migration_tasks.rake +37 -16
- data/lib/rom/sql/version.rb +1 -1
- data/rom-sql.gemspec +2 -2
- data/spec/fixtures/migrations/20150403090603_create_carrots.rb +1 -1
- data/spec/integration/combine_spec.rb +6 -6
- data/spec/integration/commands/create_spec.rb +25 -25
- data/spec/integration/commands/delete_spec.rb +6 -6
- data/spec/integration/commands/update_spec.rb +5 -5
- data/spec/integration/{repository_spec.rb → gateway_spec.rb} +34 -21
- data/spec/integration/migration_spec.rb +3 -3
- data/spec/integration/read_spec.rb +13 -7
- data/spec/shared/database_setup.rb +3 -5
- data/spec/spec_helper.rb +3 -6
- data/spec/support/active_support_notifications_spec.rb +1 -1
- data/spec/support/rails_log_subscriber_spec.rb +1 -1
- data/spec/unit/association_errors_spec.rb +4 -3
- data/spec/unit/combined_associations_spec.rb +7 -5
- data/spec/unit/gateway_spec.rb +2 -2
- data/spec/unit/logger_spec.rb +1 -1
- data/spec/unit/many_to_many_spec.rb +7 -4
- data/spec/unit/many_to_one_spec.rb +14 -8
- data/spec/unit/migration_tasks_spec.rb +7 -6
- data/spec/unit/one_to_many_spec.rb +16 -10
- data/spec/unit/plugin/base_view_spec.rb +18 -0
- data/spec/unit/plugin/pagination_spec.rb +10 -10
- data/spec/unit/relation_spec.rb +69 -3
- data/spec/unit/schema_spec.rb +5 -3
- metadata +19 -26
- data/lib/rom/sql/relation/class_methods.rb +0 -116
- data/lib/rom/sql/relation/inspection.rb +0 -16
@@ -3,22 +3,22 @@ require 'spec_helper'
|
|
3
3
|
describe 'Commands / Delete' do
|
4
4
|
include_context 'users and tasks'
|
5
5
|
|
6
|
-
subject(:users) {
|
6
|
+
subject(:users) { container.commands.users }
|
7
7
|
|
8
8
|
before do
|
9
|
-
|
9
|
+
configuration.relation(:users) do
|
10
10
|
def by_name(name)
|
11
11
|
where(name: name)
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
-
|
15
|
+
configuration.commands(:users) do
|
16
16
|
define(:delete) do
|
17
17
|
result :one
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
-
|
21
|
+
container.relations.users.insert(id: 2, name: 'Jane')
|
22
22
|
end
|
23
23
|
|
24
24
|
context '#transaction' do
|
@@ -27,7 +27,7 @@ describe 'Commands / Delete' do
|
|
27
27
|
users.delete.transaction do
|
28
28
|
users.delete.by_name('Jane').call
|
29
29
|
end
|
30
|
-
}.to change {
|
30
|
+
}.to change { container.relations.users.count }.by(-1)
|
31
31
|
end
|
32
32
|
|
33
33
|
it 'delete nothing if error was raised' do
|
@@ -36,7 +36,7 @@ describe 'Commands / Delete' do
|
|
36
36
|
users.delete.by_name('Jane').call
|
37
37
|
raise ROM::SQL::Rollback
|
38
38
|
end
|
39
|
-
}.to_not change {
|
39
|
+
}.to_not change { container.relations.users.count }
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
@@ -4,14 +4,14 @@ require 'anima'
|
|
4
4
|
describe 'Commands / Update' do
|
5
5
|
include_context 'database setup'
|
6
6
|
|
7
|
-
subject(:users) {
|
7
|
+
subject(:users) { container.command(:users) }
|
8
8
|
|
9
|
-
let(:relation) {
|
9
|
+
let(:relation) { container.relations.users }
|
10
10
|
let(:piotr) { relation.by_name('Piotr').one }
|
11
11
|
let(:peter) { { name: 'Peter' } }
|
12
12
|
|
13
13
|
before do
|
14
|
-
|
14
|
+
configuration.relation(:users) do
|
15
15
|
def by_id(id)
|
16
16
|
where(id: id).limit(1)
|
17
17
|
end
|
@@ -21,13 +21,13 @@ describe 'Commands / Update' do
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
|
24
|
+
configuration.commands(:users) do
|
25
25
|
define(:update)
|
26
26
|
end
|
27
27
|
|
28
28
|
User = Class.new { include Anima.new(:id, :name) }
|
29
29
|
|
30
|
-
|
30
|
+
configuration.mappers do
|
31
31
|
register :users, entity: -> tuples { tuples.map { |tuple| User.new(tuple) } }
|
32
32
|
end
|
33
33
|
|
@@ -5,12 +5,10 @@ describe ROM::SQL::Gateway do
|
|
5
5
|
let(:conn) { Sequel.connect(DB_URI) }
|
6
6
|
|
7
7
|
context 'creating migrations inline' do
|
8
|
-
subject(:gateway) {
|
8
|
+
subject(:gateway) { container.gateways[:default] }
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
ROM.finalize
|
13
|
-
end
|
10
|
+
let(:configuration) { ROM::Configuration.new(:sql, conn) }
|
11
|
+
let!(:container) { ROM.container(configuration) }
|
14
12
|
|
15
13
|
after do
|
16
14
|
[:rabbits, :carrots].each do |name|
|
@@ -19,7 +17,7 @@ describe ROM::SQL::Gateway do
|
|
19
17
|
end
|
20
18
|
|
21
19
|
it 'allows creating and running migrations' do
|
22
|
-
migration =
|
20
|
+
migration = gateway.migration do
|
23
21
|
up do
|
24
22
|
create_table(:rabbits) do
|
25
23
|
primary_key :id
|
@@ -43,19 +41,27 @@ describe ROM::SQL::Gateway do
|
|
43
41
|
end
|
44
42
|
|
45
43
|
context 'running migrations from a file system' do
|
44
|
+
include_context 'database setup'
|
45
|
+
|
46
46
|
let(:migration_dir) do
|
47
47
|
Pathname(__FILE__).dirname.join('../fixtures/migrations').realpath
|
48
48
|
end
|
49
49
|
|
50
50
|
let(:migrator) { ROM::SQL::Migration::Migrator.new(conn, path: migration_dir) }
|
51
|
+
let(:configuration) { ROM::Configuration.new(:sql, [conn, migrator: migrator]) }
|
52
|
+
let!(:container) { ROM.container(configuration) }
|
53
|
+
|
54
|
+
it 'returns true for pending migrations' do
|
55
|
+
expect(container.gateways[:default].pending_migrations?).to be_truthy
|
56
|
+
end
|
51
57
|
|
52
|
-
|
53
|
-
|
54
|
-
|
58
|
+
it 'returns false for non pending migrations' do
|
59
|
+
container.gateways[:default].run_migrations
|
60
|
+
expect(container.gateways[:default].pending_migrations?).to be_falsy
|
55
61
|
end
|
56
62
|
|
57
63
|
it 'runs migrations from a specified directory' do
|
58
|
-
|
64
|
+
container.gateways[:default].run_migrations
|
59
65
|
end
|
60
66
|
end
|
61
67
|
end
|
@@ -64,24 +70,31 @@ describe ROM::SQL::Gateway do
|
|
64
70
|
include_context 'database setup'
|
65
71
|
|
66
72
|
it 'skips settings up associations when tables are missing' do
|
67
|
-
ROM.
|
73
|
+
configuration = ROM::Configuration.new(:sql, uri) do |config|
|
74
|
+
config.use(:macros)
|
68
75
|
|
69
|
-
|
70
|
-
|
76
|
+
config.relation(:foos) do
|
77
|
+
use :assoc_macros
|
78
|
+
primary_key :id
|
79
|
+
one_to_many :bars, key: :foo_id
|
80
|
+
end
|
71
81
|
end
|
72
|
-
|
73
|
-
expect { ROM.finalize }.not_to raise_error
|
82
|
+
expect { ROM.container(configuration) }.not_to raise_error
|
74
83
|
end
|
75
84
|
|
76
85
|
it 'skips finalization a relation when table is missing' do
|
77
|
-
ROM.
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
86
|
+
configuration = ROM::Configuration.new(:sql, uri) do |config|
|
87
|
+
config.use(:macros)
|
88
|
+
|
89
|
+
class Foos < ROM::Relation[:sql]
|
90
|
+
dataset :foos
|
91
|
+
use :assoc_macros
|
92
|
+
primary_key :id
|
93
|
+
one_to_many :bars, key: :foo_id
|
94
|
+
end
|
82
95
|
end
|
83
96
|
|
84
|
-
expect { ROM.
|
97
|
+
expect { ROM.container(configuration) }.not_to raise_error
|
85
98
|
expect { Foos.model.dataset }.to raise_error(Sequel::Error, /no dataset/i)
|
86
99
|
end
|
87
100
|
end
|
@@ -2,14 +2,14 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe ROM::SQL, '.migration' do
|
4
4
|
let(:connection) { ROM::SQL.gateway.connection }
|
5
|
+
let(:configuration) { ROM::Configuration.new(:sql, DB_URI) }
|
5
6
|
|
6
7
|
before do
|
7
|
-
|
8
|
+
configuration
|
8
9
|
connection.drop_table?(:dragons)
|
9
10
|
end
|
10
11
|
|
11
|
-
|
12
|
-
|
12
|
+
xit 'creates a migration for a specific gateway' do
|
13
13
|
migration = ROM::SQL.migration do
|
14
14
|
change do
|
15
15
|
create_table :dragons do
|
@@ -34,12 +34,16 @@ describe 'Reading relations' do
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
-
|
37
|
+
configuration.relation(:goals) do
|
38
|
+
use :assoc_macros
|
39
|
+
|
38
40
|
register_as :goals
|
39
41
|
dataset :tasks
|
40
42
|
end
|
41
43
|
|
42
|
-
|
44
|
+
configuration.relation(:users) do
|
45
|
+
use :assoc_macros
|
46
|
+
|
43
47
|
one_to_many :goals, key: :user_id
|
44
48
|
|
45
49
|
def by_name(name)
|
@@ -55,7 +59,9 @@ describe 'Reading relations' do
|
|
55
59
|
end
|
56
60
|
end
|
57
61
|
|
58
|
-
|
62
|
+
configuration.relation(:user_goal_counts) do
|
63
|
+
use :assoc_macros
|
64
|
+
|
59
65
|
dataset :users
|
60
66
|
register_as :user_goal_counts
|
61
67
|
one_to_many :goals, key: :user_id
|
@@ -71,7 +77,7 @@ describe 'Reading relations' do
|
|
71
77
|
end
|
72
78
|
end
|
73
79
|
|
74
|
-
|
80
|
+
configuration.mappers do
|
75
81
|
define(:users) do
|
76
82
|
model User
|
77
83
|
|
@@ -90,7 +96,7 @@ describe 'Reading relations' do
|
|
90
96
|
end
|
91
97
|
|
92
98
|
it 'loads domain objects' do
|
93
|
-
user =
|
99
|
+
user = container.relation(:users).as(:users).with_goals.by_name('Piotr').to_a.first
|
94
100
|
|
95
101
|
expect(user).to eql(
|
96
102
|
User.new(
|
@@ -99,9 +105,9 @@ describe 'Reading relations' do
|
|
99
105
|
end
|
100
106
|
|
101
107
|
it 'works with grouping and aggregates' do
|
102
|
-
|
108
|
+
container.relations[:goals].insert(id: 2, user_id: 1, title: 'Get Milk')
|
103
109
|
|
104
|
-
users_with_goal_count =
|
110
|
+
users_with_goal_count = container.relation(:user_goal_counts).as(:user_goal_counts).all
|
105
111
|
|
106
112
|
expect(users_with_goal_count.to_a).to eq([
|
107
113
|
UserGoalCount.new(id: 1, name: "Piotr", goal_count: 2)
|
@@ -1,10 +1,8 @@
|
|
1
1
|
shared_context 'database setup' do
|
2
|
-
subject(:rom) { setup.finalize }
|
3
|
-
|
4
2
|
let(:uri) { DB_URI }
|
5
3
|
let(:conn) { Sequel.connect(uri) }
|
6
|
-
|
7
|
-
let(:
|
4
|
+
let(:configuration) { ROM::Configuration.new(:sql, conn).use(:macros) }
|
5
|
+
let(:container) { ROM.container(configuration) }
|
8
6
|
|
9
7
|
def drop_tables
|
10
8
|
[:tasks, :users, :tags, :task_tags, :rabbits, :carrots, :schema_migrations].each do |name|
|
@@ -36,7 +34,7 @@ shared_context 'database setup' do
|
|
36
34
|
end
|
37
35
|
|
38
36
|
conn.create_table :task_tags do
|
39
|
-
primary_key :tag_id, :task_id
|
37
|
+
primary_key [:tag_id, :task_id]
|
40
38
|
Integer :tag_id
|
41
39
|
Integer :task_id
|
42
40
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -4,7 +4,7 @@ require 'bundler'
|
|
4
4
|
Bundler.setup
|
5
5
|
|
6
6
|
if RUBY_ENGINE == 'rbx'
|
7
|
-
require
|
7
|
+
require 'codeclimate-test-reporter'
|
8
8
|
CodeClimate::TestReporter.start
|
9
9
|
end
|
10
10
|
|
@@ -18,13 +18,11 @@ require 'active_support/inflector'
|
|
18
18
|
require 'logger'
|
19
19
|
begin
|
20
20
|
require 'byebug'
|
21
|
-
rescue LoadError
|
21
|
+
rescue LoadError # rubocop:disable Lint/HandleExceptions
|
22
22
|
end
|
23
23
|
|
24
|
-
ROM.use :auto_registration
|
25
|
-
|
26
24
|
LOGGER = Logger.new(File.open('./log/test.log', 'a'))
|
27
|
-
DB_URI = 'postgres://localhost/
|
25
|
+
DB_URI = 'postgres://localhost/rom_sql'
|
28
26
|
|
29
27
|
root = Pathname(__FILE__).dirname
|
30
28
|
TMP_PATH = root.join('../tmp')
|
@@ -45,6 +43,5 @@ RSpec.configure do |config|
|
|
45
43
|
config.after do
|
46
44
|
added_constants = Object.constants - @constants
|
47
45
|
added_constants.each { |name| Object.send(:remove_const, name) }
|
48
|
-
ROM.instance_variable_get('@environment').instance_variable_set('@gateways', {})
|
49
46
|
end
|
50
47
|
end
|
@@ -5,16 +5,17 @@ describe 'Association errors' do
|
|
5
5
|
|
6
6
|
describe 'accessing an undefined association' do
|
7
7
|
specify do
|
8
|
-
|
8
|
+
configuration.relation(:users) do
|
9
|
+
use :assoc_macros
|
10
|
+
|
9
11
|
def with_undefined
|
10
12
|
association_join(:undefined)
|
11
13
|
end
|
12
14
|
end
|
13
15
|
|
14
16
|
expect {
|
15
|
-
|
17
|
+
container.relations.users.with_undefined
|
16
18
|
}.to raise_error ROM::SQL::NoAssociationError, 'Association :undefined has not been defined for relation :users'
|
17
19
|
end
|
18
20
|
end
|
19
21
|
end
|
20
|
-
|
@@ -8,11 +8,13 @@ describe 'Defining multiple associations' do
|
|
8
8
|
end
|
9
9
|
|
10
10
|
it 'extends relation with association methods' do
|
11
|
-
|
11
|
+
configuration.relation(:users) { use :assoc_macros }
|
12
12
|
|
13
|
-
|
13
|
+
configuration.relation(:tags) { use :assoc_macros }
|
14
|
+
|
15
|
+
configuration.relation(:tasks) do
|
16
|
+
use :assoc_macros
|
14
17
|
|
15
|
-
setup.relation(:tasks) do
|
16
18
|
many_to_one :users, key: :user_id
|
17
19
|
|
18
20
|
many_to_many :tags,
|
@@ -49,7 +51,7 @@ describe 'Defining multiple associations' do
|
|
49
51
|
end
|
50
52
|
end
|
51
53
|
|
52
|
-
tasks =
|
54
|
+
tasks = container.relations.tasks
|
53
55
|
|
54
56
|
expect(tasks.with_user_and_tags.to_a).to eql([
|
55
57
|
{ id: 1, title: 'Finish ROM', name: 'Piotr', tags_name: 'important' },
|
@@ -67,7 +69,7 @@ describe 'Defining multiple associations' do
|
|
67
69
|
|
68
70
|
expect(tasks.all.with_user.to_a).to eql([
|
69
71
|
{ id: 1, title: 'Finish ROM', name: 'Piotr' },
|
70
|
-
{ id: 2, title: 'Go to sleep', name: 'Piotr'
|
72
|
+
{ id: 2, title: 'Go to sleep', name: 'Piotr' }
|
71
73
|
])
|
72
74
|
|
73
75
|
expect(tasks.by_title('Go to sleep').to_a).to eql(
|
data/spec/unit/gateway_spec.rb
CHANGED
@@ -5,12 +5,12 @@ require 'rom/lint/spec'
|
|
5
5
|
describe ROM::SQL::Gateway do
|
6
6
|
include_context 'users and tasks'
|
7
7
|
|
8
|
-
let(:gateway) {
|
8
|
+
let(:gateway) { container.gateways[:default] }
|
9
9
|
|
10
10
|
it_behaves_like 'a rom gateway' do
|
11
11
|
let(:identifier) { :sql }
|
12
12
|
let(:gateway) { ROM::SQL::Gateway }
|
13
|
-
let(:uri) {
|
13
|
+
let(:uri) { DB_URI }
|
14
14
|
end
|
15
15
|
|
16
16
|
describe '#dataset?' do
|
data/spec/unit/logger_spec.rb
CHANGED
@@ -8,7 +8,12 @@ describe 'Defining many-to-one association' do
|
|
8
8
|
end
|
9
9
|
|
10
10
|
it 'extends relation with association methods' do
|
11
|
-
|
11
|
+
configuration.relation(:tags) { use :assoc_macros }
|
12
|
+
configuration.relation(:task_tags) { use :assoc_macros }
|
13
|
+
|
14
|
+
configuration.relation(:tasks) do
|
15
|
+
use :assoc_macros
|
16
|
+
|
12
17
|
many_to_many :tags,
|
13
18
|
join_table: :task_tags,
|
14
19
|
left_key: :task_id,
|
@@ -33,9 +38,7 @@ describe 'Defining many-to-one association' do
|
|
33
38
|
end
|
34
39
|
end
|
35
40
|
|
36
|
-
|
37
|
-
|
38
|
-
tasks = rom.relations.tasks
|
41
|
+
tasks = container.relations.tasks
|
39
42
|
|
40
43
|
expect(tasks.all.with_tags.to_a).to eql([
|
41
44
|
{ id: 1, title: 'Finish ROM', name: 'important' },
|
@@ -6,10 +6,14 @@ describe 'Defining many-to-one association' do
|
|
6
6
|
before do
|
7
7
|
conn[:users].insert id: 2, name: 'Jane'
|
8
8
|
conn[:tasks].insert id: 2, user_id: 2, title: 'Task one'
|
9
|
+
|
10
|
+
configuration.relation(:users) { use :assoc_macros }
|
9
11
|
end
|
10
12
|
|
11
13
|
it 'extends relation with association methods' do
|
12
|
-
|
14
|
+
configuration.relation(:tasks) do
|
15
|
+
use :assoc_macros
|
16
|
+
|
13
17
|
many_to_one :users, key: :user_id, on: { name: 'Piotr' }
|
14
18
|
|
15
19
|
def all
|
@@ -21,7 +25,7 @@ describe 'Defining many-to-one association' do
|
|
21
25
|
end
|
22
26
|
end
|
23
27
|
|
24
|
-
|
28
|
+
configuration.mappers do
|
25
29
|
define(:tasks)
|
26
30
|
|
27
31
|
define(:with_user, parent: :tasks) do
|
@@ -31,21 +35,21 @@ describe 'Defining many-to-one association' do
|
|
31
35
|
end
|
32
36
|
end
|
33
37
|
|
34
|
-
|
35
|
-
|
36
|
-
tasks = rom.relations.tasks
|
38
|
+
tasks = container.relations.tasks
|
37
39
|
|
38
40
|
expect(tasks.all.with_user.to_a).to eql(
|
39
41
|
[{ id: 1, name: 'Piotr', title: 'Finish ROM' }]
|
40
42
|
)
|
41
43
|
|
42
|
-
expect(
|
44
|
+
expect(container.relation(:tasks).map_with(:with_user).all.with_user.to_a).to eql(
|
43
45
|
[{ id: 1, title: 'Finish ROM', user: { name: 'Piotr' } }]
|
44
46
|
)
|
45
47
|
end
|
46
48
|
|
47
49
|
it "joins on specified key" do
|
48
|
-
|
50
|
+
configuration.relation(:task_tags) do
|
51
|
+
use :assoc_macros
|
52
|
+
|
49
53
|
many_to_one :tags, key: :tag_id
|
50
54
|
|
51
55
|
def with_tags
|
@@ -53,7 +57,9 @@ describe 'Defining many-to-one association' do
|
|
53
57
|
end
|
54
58
|
end
|
55
59
|
|
56
|
-
|
60
|
+
configuration.relation(:tags) { use :assoc_macros }
|
61
|
+
|
62
|
+
expect(container.relation(:task_tags).with_tags.to_a).to eq(
|
57
63
|
[{ tag_id: 1, task_id: 1, id: 1, name: "important" }]
|
58
64
|
)
|
59
65
|
end
|