rom 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +1 -1
  3. data/.travis.yml +5 -3
  4. data/CHANGELOG.md +38 -0
  5. data/Gemfile +2 -14
  6. data/README.md +11 -17
  7. data/lib/rom.rb +2 -0
  8. data/lib/rom/association_set.rb +26 -0
  9. data/lib/rom/command.rb +50 -45
  10. data/lib/rom/command_registry.rb +26 -3
  11. data/lib/rom/commands/class_interface.rb +52 -19
  12. data/lib/rom/commands/composite.rb +5 -0
  13. data/lib/rom/commands/delete.rb +1 -5
  14. data/lib/rom/commands/graph.rb +11 -0
  15. data/lib/rom/commands/lazy.rb +2 -0
  16. data/lib/rom/commands/update.rb +1 -5
  17. data/lib/rom/configuration.rb +2 -0
  18. data/lib/rom/container.rb +3 -3
  19. data/lib/rom/global.rb +1 -23
  20. data/lib/rom/memory/commands.rb +2 -0
  21. data/lib/rom/memory/relation.rb +3 -0
  22. data/lib/rom/memory/storage.rb +4 -7
  23. data/lib/rom/memory/types.rb +9 -0
  24. data/lib/rom/pipeline.rb +26 -12
  25. data/lib/rom/plugin_registry.rb +2 -2
  26. data/lib/rom/plugins/command/schema.rb +26 -0
  27. data/lib/rom/plugins/configuration/configuration_dsl.rb +2 -1
  28. data/lib/rom/plugins/relation/key_inference.rb +18 -3
  29. data/lib/rom/plugins/relation/registry_reader.rb +3 -1
  30. data/lib/rom/plugins/relation/view.rb +11 -6
  31. data/lib/rom/relation.rb +76 -16
  32. data/lib/rom/relation/class_interface.rb +44 -3
  33. data/lib/rom/relation/curried.rb +13 -4
  34. data/lib/rom/relation/graph.rb +15 -5
  35. data/lib/rom/relation/loaded.rb +42 -6
  36. data/lib/rom/relation/name.rb +102 -0
  37. data/lib/rom/relation_registry.rb +5 -0
  38. data/lib/rom/schema.rb +87 -0
  39. data/lib/rom/schema/dsl.rb +58 -0
  40. data/lib/rom/setup/auto_registration.rb +2 -2
  41. data/lib/rom/setup/finalize.rb +5 -5
  42. data/lib/rom/setup/finalize/{commands.rb → finalize_commands.rb} +2 -22
  43. data/lib/rom/setup/finalize/{mappers.rb → finalize_mappers.rb} +0 -0
  44. data/lib/rom/setup/finalize/finalize_relations.rb +60 -0
  45. data/lib/rom/types.rb +18 -0
  46. data/lib/rom/version.rb +1 -1
  47. data/log/.gitkeep +0 -0
  48. data/rom.gemspec +4 -2
  49. data/spec/integration/command_registry_spec.rb +13 -0
  50. data/spec/integration/commands/delete_spec.rb +0 -17
  51. data/spec/integration/commands/graph_builder_spec.rb +1 -1
  52. data/spec/integration/commands/graph_spec.rb +1 -1
  53. data/spec/integration/commands/update_spec.rb +0 -19
  54. data/spec/integration/commands_spec.rb +10 -3
  55. data/spec/integration/multi_repo_spec.rb +1 -1
  56. data/spec/integration/relations/default_dataset_spec.rb +27 -4
  57. data/spec/integration/setup_spec.rb +1 -4
  58. data/spec/shared/command_behavior.rb +17 -7
  59. data/spec/shared/container.rb +2 -2
  60. data/spec/shared/gateway_only.rb +1 -1
  61. data/spec/spec_helper.rb +5 -6
  62. data/spec/unit/rom/association_set_spec.rb +23 -0
  63. data/spec/unit/rom/auto_registration_spec.rb +1 -1
  64. data/spec/unit/rom/commands/lazy_spec.rb +8 -0
  65. data/spec/unit/rom/commands_spec.rb +45 -7
  66. data/spec/unit/rom/configurable_spec.rb +1 -1
  67. data/spec/unit/rom/container_spec.rb +6 -0
  68. data/spec/unit/rom/create_container_spec.rb +1 -1
  69. data/spec/unit/rom/environment_spec.rb +1 -1
  70. data/spec/unit/rom/memory/commands_spec.rb +43 -0
  71. data/spec/unit/rom/plugins/relation/key_inference_spec.rb +70 -12
  72. data/spec/unit/rom/plugins/relation/view_spec.rb +4 -0
  73. data/spec/unit/rom/relation/graph_spec.rb +10 -0
  74. data/spec/unit/rom/relation/lazy_spec.rb +3 -3
  75. data/spec/unit/rom/relation/loaded_spec.rb +15 -0
  76. data/spec/unit/rom/relation/name_spec.rb +51 -0
  77. data/spec/unit/rom/relation/schema_spec.rb +117 -0
  78. data/spec/unit/rom/relation_spec.rb +37 -7
  79. data/spec/unit/rom/schema_spec.rb +10 -0
  80. metadata +51 -12
  81. data/lib/rom/setup/finalize/relations.rb +0 -53
  82. data/spec/unit/rom/global_spec.rb +0 -18
  83. data/spec/unit/rom/registry_spec.rb +0 -38
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 25732b8177fd64f45b5e98ee76444dfd87fcbd87
4
- data.tar.gz: 1bb6afd01547c8c4455c0ba1f56ea3b939b45ea4
3
+ metadata.gz: a49d8efc969391ec0d48db3e9f41d29299537e44
4
+ data.tar.gz: 5c4ba339c27f15887468a364bd89de0c7c722572
5
5
  SHA512:
6
- metadata.gz: 51358af05cf918b0b8271758e7a56a01830bfd5c1252819f949cc4e8eeabde918568f5980faba63038cf2239b0fa0df83ac40ac69a902402fd4325a45144a36b
7
- data.tar.gz: bccc3cea146a146045b76d8c949d8fb8983302379bcff680c00e357b24793d2ae897361a3f6570a9a129b776a49d6a6c75046e45001a81d92f914246d4076ddf
6
+ metadata.gz: b720586dcc0542d8ab45d22209d91898c695a8f509af73f3bb1f967f3952f39f83ed3c9bcb7aa7b4ec87087518e7f9f2f592c4d5a4ad5763a5a3c8f9829389de
7
+ data.tar.gz: 1b5f6a9ae2038ea0b539d4e6931a1be194aa13d2cc2b7fbc3a1af03455bc028956f96a4ba39ab4cf94fd551931b86ab425e2c61bef8b13e2c823cd3a0f4ff967
data/.rspec CHANGED
@@ -1,3 +1,3 @@
1
1
  --color
2
2
  --order random
3
- --warnings
3
+ --require ./spec/spec_helper.rb
@@ -9,11 +9,10 @@ rvm:
9
9
  - 2.0
10
10
  - 2.1
11
11
  - 2.2
12
- - 2.3.0
12
+ - 2.3.1
13
13
  - rbx-2
14
- - jruby-9000
14
+ - jruby-9.0.5.0
15
15
  - ruby-head
16
- - jruby-head
17
16
  env:
18
17
  global:
19
18
  - JRUBY_OPTS='--dev -J-Xmx1024M'
@@ -21,6 +20,9 @@ matrix:
21
20
  allow_failures:
22
21
  - rvm: ruby-head
23
22
  - rvm: jruby-head
23
+ include:
24
+ - rvm: jruby-head
25
+ before_install: gem install bundler --no-ri --no-rdoc
24
26
  notifications:
25
27
  webhooks:
26
28
  urls:
@@ -1,3 +1,41 @@
1
+ ## v2.0.0 2016-07-27
2
+
3
+ ### Added
4
+
5
+ - Extendible `schema` DSL for relations with attribute and type definitions (solnic)
6
+ - New command plugin `:schema` which will set up an input handler from schema definition (solnic)
7
+ - New command option `restrictible` for commands that can use a restricted relation (solnic)
8
+ - More meaningful exception is raised when trying to access a non-existant command (thiagoa)
9
+ - `Relation::Name` class that contains both relation and dataset names (flash-gordon)
10
+ - `Relation::Loaded#pluck` returning values under specified key (solnic)
11
+ - `Relation::Loaded#primary_keys` returning a list of primary keys from a materialized relation (solnic)
12
+
13
+ #### New low-level APIs
14
+
15
+ - `Command.create_class` for building a command class dynamically (solnic)
16
+ - `Command.extend_for_relation` for extending a command with relation view interface (solnic)
17
+
18
+ ### Fixed
19
+
20
+ - [BREAKING] command graphs return materialized results (a hash or an array) (solnic)
21
+ - `Container#disconnect` properly delegates to gateways (endash)
22
+ - `Relation#with` properly carries original options (solnic)
23
+ - Command pipeline will stop processing if result was `nil` or an empty array (solnic)
24
+
25
+ ### Changed
26
+
27
+ - [BREAKING] `ROM.env` **is gone** (solnic)
28
+ - [BREAKING] `Update` and `Delete` no longer calls `assert_tuple_count` [more info](https://github.com/rom-rb/rom/commit/bec2c4c1dce370670c90f529feb1b4db0e6e4bd9) (solnic)
29
+ - [BREAKING] `Relation#name` and `Command#name` now returns `Relation::Name` instance (flash-gordon)
30
+ - `Command.validator` is now deprecated [more info](https://github.com/rom-rb/rom/commit/80bb8411bd411f05d9c51106ae026ad412a2f25f) (solnic)
31
+ - `Relation.dataset` yields a relation class when block was passed (solnic)
32
+ - `Relation#attributes` can return attributes explicitly passed via options (solnic)
33
+ - Relation `:key_inference` plugin supports schema information from other relations (solnic)
34
+ - `auto_registration` coerces its directory to a pathname now (adz)
35
+ - `macros` are now enabled by default in in-line setup block (endash)
36
+
37
+ [Compare v1.0.0...v2.0.0](https://github.com/rom-rb/rom/compare/v1.0.0...v2.0.0)
38
+
1
39
  ## v1.0.0 2016-01-06
2
40
 
3
41
  ### Added
data/Gemfile CHANGED
@@ -11,8 +11,6 @@ group :test do
11
11
  gem 'virtus'
12
12
  gem 'anima', '~> 0.2.0'
13
13
  gem 'minitest'
14
- gem 'thread_safe'
15
- gem 'activesupport'
16
14
  gem 'inflecto', '~> 0.0', '>= 0.0.2'
17
15
 
18
16
  platforms :rbx do
@@ -29,21 +27,11 @@ group :sql do
29
27
  end
30
28
 
31
29
  group :benchmarks do
32
- gem 'activerecord', '4.2.0'
30
+ gem 'activerecord', '5.0.0.beta4'
33
31
  gem 'benchmark-ips', '~> 2.2.0'
32
+ gem 'rom-repository', github: 'rom-rb/rom-repository', branch: 'master'
34
33
  end
35
34
 
36
35
  group :tools do
37
- gem 'rubocop', '~> 0.31'
38
-
39
- gem 'guard'
40
- gem 'guard-rspec'
41
- gem 'guard-rubocop'
42
-
43
36
  gem 'byebug', platform: :mri
44
-
45
- platform :mri do
46
- gem 'mutant'
47
- gem 'mutant-rspec'
48
- end
49
37
  end
data/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  [coveralls]: https://coveralls.io/r/rom-rb/rom
6
6
  [inchpages]: http://inch-ci.org/github/rom-rb/rom/
7
7
 
8
- # Ruby Object Mapper [![Gitter chat](https://badges.gitter.im/rom-rb/chat.svg)](https://gitter.im/rom-rb/chat) [![Stories in Ready](https://badge.waffle.io/rom-rb/rom.png?label=ready&title=Ready)](https://waffle.io/rom-rb/rom)
8
+ # rom [![Gitter chat](https://badges.gitter.im/rom-rb/chat.svg)](https://gitter.im/rom-rb/chat)
9
9
 
10
10
  [![Gem Version](https://badge.fury.io/rb/rom.svg)][gem]
11
11
  [![Build Status](https://travis-ci.org/rom-rb/rom.svg?branch=master)][travis]
@@ -15,14 +15,13 @@
15
15
  [![Inline docs](http://inch-ci.org/github/rom-rb/rom.svg?branch=master&style=flat)][inchpages]
16
16
 
17
17
  Ruby Object Mapper (ROM) is a data mapping and persistence toolkit for Ruby
18
- with the goal to provide powerful object mapping capabilities without limiting the
19
- full power of your datastore.
18
+ with the goal to provide powerful object mapping capabilities without limiting
19
+ the full power of your datastore.
20
20
 
21
21
  Learn more:
22
22
 
23
- * [Introduction](http://rom-rb.org/introduction/)
24
- * [Guides](http://rom-rb.org/guides/)
25
- * [Tutorials](http://rom-rb.org/tutorials/)
23
+ * [Introduction](http://rom-rb.org/learn/introduction)
24
+ * [Quick Start](http://rom-rb.org/learn/repositories/quick-start)
26
25
 
27
26
  ## Support Campaign
28
27
 
@@ -33,43 +32,38 @@ You can support ROM's development via our [campaign on Bountysource](https://sal
33
32
  There are other gems within the rom ecosystem that you will find useful:
34
33
 
35
34
  * [rom-repository](https://github.com/rom-rb/rom-repository) a higher-level, convenient abstraction with auto-mapping
36
- * [rom-model](https://github.com/rom-rb/rom-model) extensions for coercion and validation
35
+ * (WIP) [rom-migrator](https://github.com/rom-rb/rom-migrator) common APIs for database migrations
37
36
 
38
37
  ## Adapters
39
38
 
39
+ * [rom-sql](https://github.com/rom-rb/rom-sql) (supported URI schemes: ado amalgalite cubrid db2 dbi do fdbsql firebird ibmdb informix jdbc mysql mysql2 odbc openbase oracle postgres sqlanywhere sqlite swift tinytds)
40
+ * [rom-yesql](https://github.com/rom-rb/rom-yesql)
41
+ * [rom-http](https://github.com/rom-rb/rom-http)
40
42
  * [rom-couchdb](https://github.com/rom-rb/rom-couchdb)
41
43
  * [rom-csv](https://github.com/rom-rb/rom-csv)
44
+ * [rom-yaml](https://github.com/rom-rb/rom-yaml)
42
45
  * [rom-cassandra](https://github.com/rom-rb/rom-cassandra)
43
46
  * [rom-event_store](https://github.com/rom-rb/rom-event_store)
44
47
  * [rom-git](https://github.com/rom-rb/rom-git)
45
- * [rom-http](https://github.com/rom-rb/rom-http)
46
48
  * [rom-influxdb](https://github.com/rom-rb/rom-influxdb)
47
49
  * [rom-json](https://github.com/rom-rb/rom-json)
48
50
  * [rom-kafka](https://github.com/rom-rb/rom-kafka)
49
51
  * [rom-mongo](https://github.com/rom-rb/rom-mongo)
50
52
  * [rom-neo4j](https://github.com/rom-rb/rom-neo4j)
51
53
  * [rom-rethinkdb](https://github.com/rom-rb/rom-rethinkdb)
52
- * [rom-sql](https://github.com/rom-rb/rom-sql)
53
- * [rom-yaml](https://github.com/rom-rb/rom-yaml)
54
- * [rom-yesql](https://github.com/rom-rb/rom-yesql)
55
54
 
56
55
  See [issues](https://github.com/rom-rb/rom/issues?q=is%3Aopen+is%3Aissue+label%3Aadapter+label%3Afeature)
57
56
  for a list of adapters that are planned to be added soon.
58
57
 
59
58
  ## Framework integrations
60
59
 
61
- * [rom-lotus](https://github.com/rom-rb/rom-lotus)
62
60
  * [rom-rails](https://github.com/rom-rb/rom-rails)
63
61
  * [rom-roda](https://github.com/rom-rb/rom-roda)
64
62
 
65
- ## ROADMAP
66
-
67
- ROM is on its way towards 1.0.0. You can see an overview of tasks scheduled for 1.0.0 on our [waffle board](https://waffle.io/rom-rb/rom?label=1.0.0). Please notice that most of the 1.0.0 features/changes will become part of minor (0.x) upgrades before 1.0.0 final gets released.
68
-
69
63
  ## Community
70
64
 
71
65
  * [Official Blog](http://rom-rb.org/blog/)
72
- * [Discussion Forum](http://discourse.rom-rb.org)
66
+ * [Discussion Forum](http://discuss.rom-rb.org)
73
67
  * [Gitter Channel](https://gitter.im/rom-rb/chat)
74
68
 
75
69
  ## Credits
data/lib/rom.rb CHANGED
@@ -34,6 +34,7 @@ require 'rom/create_container'
34
34
  # register core plugins
35
35
  require 'rom/plugins/configuration/configuration_dsl'
36
36
  require 'rom/plugins/relation/registry_reader'
37
+ require 'rom/plugins/command/schema'
37
38
 
38
39
  module ROM
39
40
  extend Global
@@ -41,5 +42,6 @@ module ROM
41
42
  plugins do
42
43
  register :macros, ROM::ConfigurationPlugins::ConfigurationDSL, type: :configuration
43
44
  register :registry_reader, ROM::Plugins::Relation::RegistryReader, type: :relation
45
+ register :schema, ROM::Plugins::Command::Schema, type: :command
44
46
  end
45
47
  end
@@ -0,0 +1,26 @@
1
+ require 'rom/support/registry'
2
+ require 'rom/support/inflector'
3
+
4
+ module ROM
5
+ class AssociationSet < ROM::Registry
6
+ # @api private
7
+ def try(name, &block)
8
+ if key?(name)
9
+ yield(self[name])
10
+ else
11
+ false
12
+ end
13
+ end
14
+
15
+ # @api private
16
+ def [](name)
17
+ key = name.to_sym
18
+
19
+ if key?(key)
20
+ super
21
+ else
22
+ super(Inflector.singularize(key))
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,4 +1,6 @@
1
+ require 'rom/support/deprecations'
1
2
  require 'rom/support/options'
3
+ require 'rom/pipeline'
2
4
 
3
5
  require 'rom/commands/class_interface'
4
6
  require 'rom/commands/composite'
@@ -18,15 +20,18 @@ module ROM
18
20
  #
19
21
  # @private
20
22
  class Command
23
+ DEFAULT_VALIDATOR = proc {}
24
+
25
+ include Dry::Equalizer(:relation, :options)
21
26
  include Commands
27
+ include Pipeline::Operator
22
28
 
23
29
  extend ClassMacros
24
30
  extend ClassInterface
25
31
 
26
32
  include Options
27
- include Dry::Equalizer(:relation, :options)
28
33
 
29
- defines :adapter, :relation, :result, :input, :validator, :register_as
34
+ defines :adapter, :relation, :result, :input, :validator, :register_as, :restrictable
30
35
 
31
36
  option :type, allow: [:create, :update, :delete]
32
37
  option :source, reader: true
@@ -36,9 +41,26 @@ module ROM
36
41
  option :curry_args, type: Array, reader: true, default: EMPTY_ARRAY
37
42
 
38
43
  input Hash
39
- validator proc {}
44
+ validator DEFAULT_VALIDATOR
40
45
  result :many
41
46
 
47
+ # @deprecated
48
+ #
49
+ # @api public
50
+ def self.validator(vp = nil)
51
+ if defined?(@validator) && vp.nil?
52
+ @validator
53
+ else
54
+ unless vp.equal?(DEFAULT_VALIDATOR)
55
+ Deprecations.announce(
56
+ "#{name}.validator",
57
+ 'Please handle validation before calling commands'
58
+ )
59
+ end
60
+ super
61
+ end
62
+ end
63
+
42
64
  # @attr_reader [Relation] relation The command's relation
43
65
  attr_reader :relation
44
66
 
@@ -49,6 +71,24 @@ module ROM
49
71
  @source = options[:source] || relation
50
72
  end
51
73
 
74
+ # Return name of this command's relation
75
+ #
76
+ # @return [ROM::Relation::Name]
77
+ #
78
+ # @api public
79
+ def name
80
+ relation.name
81
+ end
82
+
83
+ # Return gateway of this command's relation
84
+ #
85
+ # @return [Symbol]
86
+ #
87
+ # @api public
88
+ def gateway
89
+ relation.gateway
90
+ end
91
+
52
92
  # Execute the command
53
93
  #
54
94
  # @abstract
@@ -66,8 +106,8 @@ module ROM
66
106
  # Call the command and return one or many tuples
67
107
  #
68
108
  # @api public
69
- def call(*args)
70
- tuples = execute(*(curry_args + args))
109
+ def call(*args, &block)
110
+ tuples = execute(*(curry_args + args), &block)
71
111
 
72
112
  if one?
73
113
  tuples.first
@@ -93,24 +133,6 @@ module ROM
93
133
  end
94
134
  alias_method :with, :curry
95
135
 
96
- # Compose a command with another one
97
- #
98
- # The other one will be called with the result from the first one
99
- #
100
- # @example
101
- #
102
- # command = users.create.curry(name: 'Jane')
103
- # command >>= tasks.create.curry(title: 'Task One')
104
- #
105
- # command.call # creates user, passes it to tasks and creates task
106
- #
107
- # @return [Composite]
108
- #
109
- # @api public
110
- def >>(other)
111
- Composite.new(self, other)
112
- end
113
-
114
136
  # @api public
115
137
  def combine(*others)
116
138
  Graph.new(self, others)
@@ -136,33 +158,16 @@ module ROM
136
158
  result.equal?(:many)
137
159
  end
138
160
 
139
- # Assert that tuple count in the relation corresponds to :result
140
- # setting
141
- #
142
- # @raise TupleCountMismatchError
143
- #
144
161
  # @api private
145
- def assert_tuple_count
146
- if one? && tuple_count > 1
147
- raise TupleCountMismatchError, "#{inspect} expects one tuple"
148
- end
162
+ def new(new_relation)
163
+ self.class.build(new_relation, options.merge(source: relation))
149
164
  end
150
165
 
151
- # Return number of tuples in the relation relation
152
- #
153
- # This should be overridden by gateways when `#count` is not available
154
- # in the relation objects
155
- #
156
- # @return [Fixnum]
157
- #
158
- # @api private
159
- def tuple_count
160
- relation.count
161
- end
166
+ private
162
167
 
163
168
  # @api private
164
- def new(new_relation)
165
- self.class.build(new_relation, options.merge(source: relation))
169
+ def composite_class
170
+ Command::Composite
166
171
  end
167
172
  end
168
173
  end
@@ -8,6 +8,15 @@ module ROM
8
8
  include Commands
9
9
  include Options
10
10
 
11
+ CommandNotFoundError = Class.new(KeyError)
12
+
13
+ # Name of the relation from which commands are under
14
+ #
15
+ # @return [String]
16
+ #
17
+ # @api private
18
+ attr_reader :relation_name
19
+
11
20
  # Internal command registry
12
21
  #
13
22
  # @return [Registry]
@@ -19,8 +28,10 @@ module ROM
19
28
  option :mapper, reader: true
20
29
 
21
30
  # @api private
22
- def initialize(elements, options = EMPTY_HASH)
31
+ def initialize(relation_name, elements, options = EMPTY_HASH)
23
32
  super
33
+
34
+ @relation_name = relation_name
24
35
  @registry =
25
36
  if elements.is_a?(Registry)
26
37
  elements
@@ -73,7 +84,7 @@ module ROM
73
84
  #
74
85
  # @api public
75
86
  def [](name)
76
- command = registry[name]
87
+ command = fetch_command(name)
77
88
  mapper = options[:mapper]
78
89
 
79
90
  if mapper
@@ -104,11 +115,23 @@ module ROM
104
115
  #
105
116
  # @api private
106
117
  def with(new_options)
107
- self.class.new(registry, options.merge(new_options))
118
+ self.class.new(relation_name, registry, options.merge(new_options))
108
119
  end
109
120
 
110
121
  private
111
122
 
123
+ # Fetch a command from the registry and raise a specialized error
124
+ # in case the command is not found
125
+ #
126
+ # @api private
127
+ def fetch_command(name)
128
+ registry.fetch(name) do
129
+ raise CommandNotFoundError.new(
130
+ "There is no :#{name} command for :#{relation_name} relation"
131
+ )
132
+ end
133
+ end
134
+
112
135
  # Allow checking if a certain command is available using dot-notation
113
136
  #
114
137
  # @api private