rom-sql 0.6.1 → 0.7.0.beta1

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 (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