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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -5
  3. data/.rubocop_todo.yml +12 -6
  4. data/.travis.yml +3 -2
  5. data/CHANGELOG.md +27 -0
  6. data/Gemfile +1 -0
  7. data/lib/rom/plugins/relation/sql/auto_combine.rb +45 -0
  8. data/lib/rom/plugins/relation/sql/auto_wrap.rb +48 -0
  9. data/lib/rom/plugins/relation/sql/base_view.rb +31 -0
  10. data/lib/rom/sql.rb +17 -10
  11. data/lib/rom/sql/commands/error_wrapper.rb +1 -1
  12. data/lib/rom/sql/commands/update.rb +1 -1
  13. data/lib/rom/sql/gateway.rb +8 -2
  14. data/lib/rom/sql/header.rb +1 -1
  15. data/lib/rom/sql/migration.rb +11 -20
  16. data/lib/rom/sql/migration/migrator.rb +4 -0
  17. data/lib/rom/sql/{relation/associations.rb → plugin/assoc_macros.rb} +17 -2
  18. data/lib/rom/sql/plugin/assoc_macros/class_interface.rb +128 -0
  19. data/lib/rom/sql/plugin/associates.rb +2 -4
  20. data/lib/rom/sql/plugin/pagination.rb +1 -1
  21. data/lib/rom/sql/plugins.rb +4 -2
  22. data/lib/rom/sql/relation.rb +46 -6
  23. data/lib/rom/sql/relation/reading.rb +63 -0
  24. data/lib/rom/sql/tasks/migration_tasks.rake +37 -16
  25. data/lib/rom/sql/version.rb +1 -1
  26. data/rom-sql.gemspec +2 -2
  27. data/spec/fixtures/migrations/20150403090603_create_carrots.rb +1 -1
  28. data/spec/integration/combine_spec.rb +6 -6
  29. data/spec/integration/commands/create_spec.rb +25 -25
  30. data/spec/integration/commands/delete_spec.rb +6 -6
  31. data/spec/integration/commands/update_spec.rb +5 -5
  32. data/spec/integration/{repository_spec.rb → gateway_spec.rb} +34 -21
  33. data/spec/integration/migration_spec.rb +3 -3
  34. data/spec/integration/read_spec.rb +13 -7
  35. data/spec/shared/database_setup.rb +3 -5
  36. data/spec/spec_helper.rb +3 -6
  37. data/spec/support/active_support_notifications_spec.rb +1 -1
  38. data/spec/support/rails_log_subscriber_spec.rb +1 -1
  39. data/spec/unit/association_errors_spec.rb +4 -3
  40. data/spec/unit/combined_associations_spec.rb +7 -5
  41. data/spec/unit/gateway_spec.rb +2 -2
  42. data/spec/unit/logger_spec.rb +1 -1
  43. data/spec/unit/many_to_many_spec.rb +7 -4
  44. data/spec/unit/many_to_one_spec.rb +14 -8
  45. data/spec/unit/migration_tasks_spec.rb +7 -6
  46. data/spec/unit/one_to_many_spec.rb +16 -10
  47. data/spec/unit/plugin/base_view_spec.rb +18 -0
  48. data/spec/unit/plugin/pagination_spec.rb +10 -10
  49. data/spec/unit/relation_spec.rb +69 -3
  50. data/spec/unit/schema_spec.rb +5 -3
  51. metadata +19 -26
  52. data/lib/rom/sql/relation/class_methods.rb +0 -116
  53. 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) { rom.commands.users }
6
+ subject(:users) { container.commands.users }
7
7
 
8
8
  before do
9
- setup.relation(:users) do
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
- setup.commands(:users) do
15
+ configuration.commands(:users) do
16
16
  define(:delete) do
17
17
  result :one
18
18
  end
19
19
  end
20
20
 
21
- rom.relations.users.insert(id: 2, name: 'Jane')
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 { rom.relations.users.count }.by(-1)
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 { rom.relations.users.count }
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) { rom.command(:users) }
7
+ subject(:users) { container.command(:users) }
8
8
 
9
- let(:relation) { rom.relations.users }
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
- setup.relation(:users) do
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
- setup.commands(:users) do
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
- setup.mappers do
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) { ROM.env.gateways[:default] }
8
+ subject(:gateway) { container.gateways[:default] }
9
9
 
10
- before do
11
- ROM.setup(:sql, conn)
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 = ROM::SQL.migration do
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
- before do
53
- ROM.setup(:sql, [conn, migrator: migrator])
54
- ROM.finalize
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
- ROM.env.gateways[:default].run_migrations
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.setup(:sql, uri)
73
+ configuration = ROM::Configuration.new(:sql, uri) do |config|
74
+ config.use(:macros)
68
75
 
69
- ROM.relation(:foos) do
70
- one_to_many :bars, key: :foo_id
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.setup(:sql, uri)
78
-
79
- class Foos < ROM::Relation[:sql]
80
- dataset :foos
81
- one_to_many :bars, key: :foo_id
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.finalize }.not_to raise_error
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
- ROM.setup(:sql, DB_URI)
8
+ configuration
8
9
  connection.drop_table?(:dragons)
9
10
  end
10
11
 
11
- it 'creates a migration for a specific gateway' do
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
- setup.relation(:goals) do
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
- setup.relation(:users) do
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
- setup.relation(:user_goal_counts) do
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
- setup.mappers do
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 = rom.relation(:users).as(:users).with_goals.by_name('Piotr').to_a.first
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
- rom.relations[:goals].insert(id: 2, user_id: 1, title: 'Get Milk')
108
+ container.relations[:goals].insert(id: 2, user_id: 1, title: 'Get Milk')
103
109
 
104
- users_with_goal_count = rom.relation(:user_goal_counts).as(:user_goal_counts).all
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(:setup) { ROM.setup(:sql, conn) }
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
@@ -4,7 +4,7 @@ require 'bundler'
4
4
  Bundler.setup
5
5
 
6
6
  if RUBY_ENGINE == 'rbx'
7
- require "codeclimate-test-reporter"
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/rom'
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
@@ -7,7 +7,7 @@ describe 'ActiveSupport::Notifications support' do
7
7
  include_context 'database setup'
8
8
 
9
9
  it 'works' do
10
- rom.gateways[:default].use_logger(LOGGER)
10
+ container.gateways[:default].use_logger(LOGGER)
11
11
 
12
12
  sql = nil
13
13
 
@@ -18,7 +18,7 @@ describe 'Rails log subscriber' do
18
18
 
19
19
  before do
20
20
  set_logger(logger)
21
- rom.gateways[:default].use_logger(logger)
21
+ container.gateways[:default].use_logger(logger)
22
22
  end
23
23
 
24
24
  it 'works' do
@@ -5,16 +5,17 @@ describe 'Association errors' do
5
5
 
6
6
  describe 'accessing an undefined association' do
7
7
  specify do
8
- setup.relation(:users) do
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
- rom.relations.users.with_undefined
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
- setup.relation(:users)
11
+ configuration.relation(:users) { use :assoc_macros }
12
12
 
13
- setup.relation(:tags)
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 = rom.relations.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(
@@ -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) { rom.gateways[:default] }
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) { 'postgres://localhost/rom' }
13
+ let(:uri) { DB_URI }
14
14
  end
15
15
 
16
16
  describe '#dataset?' do
@@ -4,7 +4,7 @@ describe 'Logger' do
4
4
  include_context 'database setup'
5
5
 
6
6
  it 'sets up a logger for sequel' do
7
- gateway = rom.gateways[:default]
7
+ gateway = container.gateways[:default]
8
8
 
9
9
  gateway.use_logger(LOGGER)
10
10
 
@@ -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
- setup.relation(:tasks) do
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
- setup.relation(:tags)
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
- setup.relation(:tasks) do
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
- setup.mappers do
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
- setup.relation(:users)
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(rom.relation(:tasks).map_with(:with_user).all.with_user.to_a).to eql(
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
- setup.relation(:task_tags) do
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
- expect(rom.relation(:task_tags).with_tags.to_a).to eq(
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