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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 092d7392edf6c7ee3ab5ae94c46642226cc9fe9c
4
- data.tar.gz: 53c8bcf25ba8f8855b06e8e9f17e26c06c2ec359
3
+ metadata.gz: 46efc98cee0cbb717be8ea7e8be52c08a488957c
4
+ data.tar.gz: 7b170fa8ac4f6c827c0feb6bd66e475322d28606
5
5
  SHA512:
6
- metadata.gz: 07fd1f32d6a6d81068434ed420be539ab0a6781b24cb1601dbffc9c3620d29b2b02201f90cb121f4d33afd03e91faa8f07c47e687af2ff45a9ef57e3d889a749
7
- data.tar.gz: 4176a62ba46b000a5248a76cb06e355440e46532c9050199533add0e9c4a3009d56c9e5a137edc70c402ea2a092c68fdc81de2f6f00f817194beb300289447df
6
+ metadata.gz: 3b2af71d8e33ab121d77365e7c743fa33817ea24daa67f2c87a3b4f1610a97c601482e0147ea77e3bb21fde6180c1e8c21c693f3e0ba9bc0eed0ad7d0221133a
7
+ data.tar.gz: 3eb3431b48c7739ffdbaf40cbc4a4ed33cef80ddcdfedfd0e3cc89928bb9dbdb4a194aef8626244aedaf7e56ceb952456cee3174660d2b36e48b8b75fccaad3c
@@ -29,7 +29,7 @@ Style/AsciiComments:
29
29
  Enabled: false
30
30
 
31
31
  # Allow using braces for value-returning blocks
32
- Style/Blocks:
32
+ Style/BlockDelimiters:
33
33
  Enabled: false
34
34
 
35
35
  # Documentation checked by Inch CI
@@ -53,10 +53,6 @@ Style/OpMethod:
53
53
  Exclude:
54
54
  - lib/rom/command_registry.rb
55
55
 
56
- # Even a single escaped slash can be confusing
57
- Style/RegexpLiteral:
58
- MaxSlashes: 0
59
-
60
56
  # Don’t introduce semantic fail/raise distinction
61
57
  Style/SignalException:
62
58
  EnforcedStyle: only_raise
@@ -1,15 +1,21 @@
1
- # This configuration was generated by `rubocop --auto-gen-config`
2
- # on 2015-01-25 22:37:25 +0100 using RuboCop version 0.28.0.
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2015-09-26 17:45:40 +0200 using RuboCop version 0.34.2.
3
4
  # The point is for the user to remove these configuration records
4
5
  # one by one as the offenses are removed from the code base.
5
6
  # Note that changes in the inspected code, or installation of new
6
7
  # versions of RuboCop, may require this file to be generated again.
7
8
 
8
- # Offense count: 3
9
+ # Offense count: 4
9
10
  Metrics/AbcSize:
10
- Max: 20
11
+ Max: 23
11
12
 
12
- # Offense count: 2
13
+ # Offense count: 17
14
+ # Configuration parameters: AllowURI, URISchemes.
15
+ Metrics/LineLength:
16
+ Max: 118
17
+
18
+ # Offense count: 5
13
19
  # Configuration parameters: CountComments.
14
20
  Metrics/MethodLength:
15
- Max: 14
21
+ Max: 17
@@ -3,14 +3,14 @@ sudo: false
3
3
  cache: bundler
4
4
  bundler_args: --without yard guard benchmarks tools
5
5
  before_script:
6
- - psql -c 'create database rom;' -U postgres
6
+ - psql -c 'create database rom_sql;' -U postgres
7
7
  script: "bundle exec rake ci"
8
8
  rvm:
9
9
  - 2.0
10
10
  - 2.1
11
11
  - 2.2
12
12
  - rbx-2
13
- - jruby
13
+ - jruby-9000
14
14
  - jruby-head
15
15
  - ruby-head
16
16
  env:
@@ -19,6 +19,7 @@ env:
19
19
  - JRUBY_OPTS='--dev -J-Xmx1024M'
20
20
  matrix:
21
21
  allow_failures:
22
+ - rvm: jruby-9000
22
23
  - rvm: ruby-head
23
24
  - rvm: jruby-head
24
25
  notifications:
@@ -1,3 +1,30 @@
1
+ ## v0.7.0 to-be-released
2
+
3
+ ### Added
4
+
5
+ * Repository plugins have been imported:
6
+ * `view` allows defining a relation view with an explicit header (solnic)
7
+ * `base_view` defines a base view with all column names as the header (solnic)
8
+ * `auto_combine` defines a generic `for_combine` method which eager-loads
9
+ parent/children relation (solnic)
10
+ * `auto-wrap` defines a generic `for_wrap` method which inner-joins
11
+ a parent/children relation (solnic)
12
+ * Possibility to check for pending migrations (gotar)
13
+ * `Relation#sum` interface (gotar)
14
+ * `Relation#avg` interface (gotar)
15
+ * `Relation#min` interface (gotar)
16
+ * `Relation#max` interface (gotar)
17
+ * `Relation#union` interface (spscream)
18
+ * `primary_key` macro which allows setting a custom primary key when it cannot be
19
+ inferred automatically (solnic)
20
+
21
+ ### Changed
22
+
23
+ * `ROM::SQL.gateway` renamed to `ROM::SQL::Gateway.instance` for migrations (endash)
24
+ * Association macros are now an optional plugin (solnic)
25
+
26
+ [Compare v0.6.1...HEAD](https://github.com/rom-rb/rom-sql/compare/v0.6.1...HEAD)
27
+
1
28
  ## v0.6.1 2015-09-23
2
29
 
3
30
  ### Added
data/Gemfile CHANGED
@@ -5,6 +5,7 @@ gemspec
5
5
  group :test do
6
6
  gem 'byebug', platforms: :mri
7
7
  gem 'anima', '~> 0.2.0'
8
+ gem 'transproc', github: 'solnic/transproc', branch: 'master'
8
9
  gem 'rom', github: 'rom-rb/rom', branch: 'master'
9
10
  gem 'rom-support', github: 'rom-rb/rom-support', branch: 'master'
10
11
  gem 'rom-mapper', github: 'rom-rb/rom-mapper', branch: 'master'
@@ -0,0 +1,45 @@
1
+ module ROM
2
+ module Plugins
3
+ module Relation
4
+ module SQL
5
+ module AutoCombine
6
+ # @api private
7
+ def self.included(klass)
8
+ super
9
+ klass.class_eval do
10
+ include(InstanceInterface)
11
+ extend(ClassInterface)
12
+ end
13
+ end
14
+
15
+ module ClassInterface
16
+ def inherited(klass)
17
+ super
18
+ klass.auto_curry :for_combine
19
+ end
20
+ end
21
+
22
+ module InstanceInterface
23
+ # Default methods for fetching combined relation
24
+ #
25
+ # This method is used by default by `combine`
26
+ #
27
+ # @return [SQL::Relation]
28
+ #
29
+ # @api private
30
+ def for_combine(keys, relation)
31
+ pk, fk = keys.to_a.flatten
32
+ where(fk => relation.map { |tuple| tuple[pk] })
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ ROM.plugins do
42
+ adapter :sql do
43
+ register :auto_combine, ROM::Plugins::Relation::SQL::AutoCombine, type: :relation
44
+ end
45
+ end
@@ -0,0 +1,48 @@
1
+ module ROM
2
+ module Plugins
3
+ module Relation
4
+ module SQL
5
+ module AutoWrap
6
+ # @api private
7
+ def self.included(klass)
8
+ super
9
+ klass.class_eval do
10
+ include(InstanceInterface)
11
+ extend(ClassInterface)
12
+ end
13
+ end
14
+
15
+ module ClassInterface
16
+ def inherited(klass)
17
+ super
18
+ klass.auto_curry :for_wrap
19
+ end
20
+ end
21
+
22
+ module InstanceInterface
23
+ # Default methods for fetching wrapped relation
24
+ #
25
+ # This method is used by default by `wrap` and `wrap_parents`
26
+ #
27
+ # @return [SQL::Relation]
28
+ #
29
+ # @api private
30
+ def for_wrap(keys, name)
31
+ other = __registry__[name]
32
+
33
+ inner_join(name, keys)
34
+ .select(*qualified.header.columns)
35
+ .select_append(*other.prefix(other.name).qualified.header)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ ROM.plugins do
45
+ adapter :sql do
46
+ register :auto_wrap, ROM::Plugins::Relation::SQL::AutoWrap, type: :relation
47
+ end
48
+ end
@@ -0,0 +1,31 @@
1
+ module ROM
2
+ module Plugins
3
+ module Relation
4
+ module SQL
5
+ module BaseView
6
+ # @api private
7
+ def self.included(klass)
8
+ super
9
+ klass.extend(ClassInterface)
10
+ end
11
+
12
+ module ClassInterface
13
+ def inherited(klass)
14
+ super
15
+ klass.view(:base) do
16
+ header { dataset.columns }
17
+ relation { select(*attributes(:base)).order(primary_key) }
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ ROM.plugins do
28
+ adapter :sql do
29
+ register :base_view, ROM::Plugins::Relation::SQL::BaseView, type: :relation
30
+ end
31
+ end
@@ -1,16 +1,23 @@
1
- require "sequel"
2
- require "rom"
1
+ require 'dry-equalizer'
2
+ require 'sequel'
3
+ require 'rom'
3
4
 
4
- require "rom/sql/version"
5
- require "rom/sql/errors"
6
- require "rom/sql/plugins"
7
- require "rom/sql/relation"
8
- require "rom/sql/gateway"
9
- require "rom/sql/migration"
5
+ module ROM
6
+ MissingConfigurationError = Class.new(StandardError)
7
+ end
8
+
9
+ require 'rom/configuration_dsl'
10
+
11
+ require 'rom/sql/version'
12
+ require 'rom/sql/errors'
13
+ require 'rom/sql/plugins'
14
+ require 'rom/sql/relation'
15
+ require 'rom/sql/gateway'
16
+ require 'rom/sql/migration'
10
17
 
11
18
  if defined?(Rails)
12
- require "rom/sql/support/active_support_notifications"
13
- require "rom/sql/support/rails_log_subscriber"
19
+ require 'rom/sql/support/active_support_notifications'
20
+ require 'rom/sql/support/rails_log_subscriber'
14
21
  end
15
22
 
16
23
  ROM.register_adapter(:sql, ROM::SQL)
@@ -14,7 +14,7 @@ module ROM
14
14
  raise ERROR_MAP[e.class], e
15
15
  end
16
16
 
17
- alias :[] :call
17
+ alias_method :[], :call
18
18
  end
19
19
  end
20
20
  end
@@ -13,7 +13,7 @@ module ROM
13
13
  class Update < ROM::Commands::Update
14
14
  adapter :sql
15
15
 
16
- include Deprecations
16
+ extend Deprecations
17
17
 
18
18
  include Transaction
19
19
  include ErrorWrapper
@@ -19,6 +19,10 @@ module ROM
19
19
  include Options
20
20
  include Migration
21
21
 
22
+ class << self
23
+ attr_accessor :instance
24
+ end
25
+
22
26
  # Return optionally configured logger
23
27
  #
24
28
  # @return [Object] logger
@@ -63,13 +67,15 @@ module ROM
63
67
  # @api public
64
68
  def initialize(uri, options = {})
65
69
  repo_options = self.class.option_definitions.names
66
- conn_options = options.reject { |k,_| repo_options.include?(k) }
70
+ conn_options = options.reject { |k, _| repo_options.include?(k) }
67
71
 
68
72
  @connection = connect(uri, conn_options)
69
73
  @schema = connection.tables
70
74
  add_extensions(Array(options[:extensions])) if options[:extensions]
71
75
 
72
- super(uri, options.reject { |k,_| conn_options.keys.include?(k) })
76
+ super(uri, options.reject { |k, _| conn_options.keys.include?(k) })
77
+
78
+ self.class.instance = self
73
79
  end
74
80
 
75
81
  # Disconnect from database
@@ -2,7 +2,7 @@ module ROM
2
2
  module SQL
3
3
  # @private
4
4
  class Header
5
- include Equalizer.new(:columns, :table)
5
+ include Dry::Equalizer(:columns, :table)
6
6
 
7
7
  attr_reader :columns, :table
8
8
 
@@ -2,7 +2,8 @@ require 'rom/sql/migration/migrator'
2
2
 
3
3
  module ROM
4
4
  module SQL
5
- # Create a database migration for a specific gateway
5
+ # Trap for the migration runner. To create a migration
6
+ # on a specific gateway, use ROM::SQL::Gateway#migration
6
7
  #
7
8
  # @example
8
9
  # ROM.setup(
@@ -21,26 +22,9 @@ module ROM
21
22
  # end
22
23
  # end
23
24
  #
24
- # # for a non-default gateway
25
- # ROM::SQL.migration(:other) do
26
- # # ...
27
- # end
28
- #
29
25
  # @api public
30
- def self.migration(gateway = :default, &block)
31
- gateways = ROM.boot ? ROM.boot.gateways : ROM.env.gateways
32
- gateways[gateway].migration(&block)
33
- end
34
-
35
- # Return first sql gateway for migrations
36
- #
37
- # This is used by migration tasks, they only support a single sql gateway
38
- #
39
- # @api private
40
- def self.gateway
41
- ROM.gateways
42
- .keys
43
- .detect { |gateway| gateway.instance_of?(Gateway) }
26
+ def self.migration(&block)
27
+ ROM::SQL::Gateway.instance.migration(&block)
44
28
  end
45
29
 
46
30
  module Migration
@@ -55,6 +39,13 @@ module ROM
55
39
  end
56
40
  end
57
41
 
42
+ # @see ROM::SQL::Migration.pending?
43
+ #
44
+ # @api public
45
+ def pending_migrations?
46
+ migrator.pending?
47
+ end
48
+
58
49
  # @see ROM::SQL.migration
59
50
  #
60
51
  # @api public
@@ -20,6 +20,10 @@ module ROM
20
20
  Sequel::Migrator.run(connection, path.to_s, options)
21
21
  end
22
22
 
23
+ def pending?
24
+ !Sequel::Migrator.is_current?(connection, path.to_s)
25
+ end
26
+
23
27
  def migration(&block)
24
28
  Sequel.migration(&block)
25
29
  end
@@ -1,7 +1,22 @@
1
+ require 'rom/sql/plugin/assoc_macros/class_interface'
2
+
1
3
  module ROM
2
4
  module SQL
3
- class Relation < ROM::Relation
4
- module Associations
5
+ module Plugin
6
+ module AssocMacros
7
+ # Extends a relation class with assoc-macros and instance-level methods
8
+ #
9
+ # @api private
10
+ def self.included(relation)
11
+ super
12
+ relation.extend(ClassInterface)
13
+ end
14
+
15
+ # @api private
16
+ def model
17
+ self.class.model
18
+ end
19
+
5
20
  # Join configured association.
6
21
  #
7
22
  # Uses INNER JOIN type.
@@ -0,0 +1,128 @@
1
+ module ROM
2
+ module SQL
3
+ module Plugin
4
+ module AssocMacros
5
+ # Class DSL for SQL relations
6
+ #
7
+ # @api private
8
+ module ClassInterface
9
+ # @api private
10
+ def self.prepare(klass)
11
+ klass.class_eval do
12
+ class << self
13
+ attr_reader :model, :associations
14
+ end
15
+ end
16
+ klass.instance_variable_set('@model', Class.new(Sequel::Model))
17
+ klass.instance_variable_set('@associations', [])
18
+ end
19
+
20
+ # @api private
21
+ def self.extended(klass)
22
+ prepare(klass)
23
+ end
24
+
25
+ # Set up model and association ivars for descendant class
26
+ #
27
+ # @api private
28
+ def inherited(klass)
29
+ super
30
+ ClassInterface.prepare(klass)
31
+ end
32
+
33
+ # Set up a one-to-many association
34
+ #
35
+ # @example
36
+ # class Users < ROM::Relation[:sql]
37
+ # one_to_many :tasks, key: :user_id
38
+ #
39
+ # def with_tasks
40
+ # association_join(:tasks)
41
+ # end
42
+ # end
43
+ #
44
+ # @param [Symbol] name The name of the association
45
+ # @param [Hash] options The options hash
46
+ # @option options [Symbol] :key Name of the key to join on
47
+ # @option options [Hash] :on Additional conditions for join
48
+ # @option options [Hash] :conditions Additional conditions for WHERE
49
+ #
50
+ # @api public
51
+ def one_to_many(name, options)
52
+ associations << [__method__, name, { relation: name }.merge(options)]
53
+ end
54
+
55
+ # Set up a many-to-many association
56
+ #
57
+ # @example
58
+ # class Tasks < ROM::Relation[:sql]
59
+ # many_to_many :tags,
60
+ # join_table: :task_tags,
61
+ # left_key: :task_id,
62
+ # right_key: :tag_id,
63
+ #
64
+ # def with_tags
65
+ # association_join(:tags)
66
+ # end
67
+ # end
68
+ #
69
+ # @param [Symbol] name The name of the association
70
+ # @param [Hash] options The options hash
71
+ # @option options [Symbol] :join_table Name of the join table
72
+ # @option options [Hash] :left_key Name of the left join key
73
+ # @option options [Hash] :right_key Name of the right join key
74
+ # @option options [Hash] :on Additional conditions for join
75
+ # @option options [Hash] :conditions Additional conditions for WHERE
76
+ #
77
+ # @api public
78
+ def many_to_many(name, options = {})
79
+ associations << [__method__, name, { relation: name }.merge(options)]
80
+ end
81
+
82
+ # Set up a many-to-one association
83
+ #
84
+ # @example
85
+ # class Tasks < ROM::Relation[:sql]
86
+ # many_to_one :users, key: :user_id
87
+ #
88
+ # def with_users
89
+ # association_join(:users)
90
+ # end
91
+ # end
92
+ #
93
+ # @param [Symbol] name The name of the association
94
+ # @param [Hash] options The options hash
95
+ # @option options [Symbol] :join_table Name of the join table
96
+ # @option options [Hash] :key Name of the join key
97
+ # @option options [Hash] :on Additional conditions for join
98
+ # @option options [Hash] :conditions Additional conditions for WHERE
99
+ #
100
+ # @api public
101
+ def many_to_one(name, options = {})
102
+ associations << [__method__, name, { relation: name }.merge(options)]
103
+ end
104
+
105
+ # Finalize the relation by setting up its associations (if any)
106
+ #
107
+ # @api private
108
+ def finalize(relations, relation)
109
+ return unless relation.dataset.db.table_exists?(dataset)
110
+
111
+ model.set_dataset(relation.dataset)
112
+ model.dataset.naked!
113
+
114
+ associations.each do |*args, assoc_opts|
115
+ options = Hash[assoc_opts]
116
+ other = relations[options.delete(:relation) || args[1]].model
117
+ model.public_send(*args, options.merge(class: other))
118
+ end
119
+
120
+ model.freeze
121
+
122
+ super
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end