cuprum-collections 0.2.0 → 0.3.0

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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +18 -0
  3. data/README.md +255 -8
  4. data/lib/cuprum/collections/basic/collection.rb +13 -0
  5. data/lib/cuprum/collections/basic/commands/destroy_one.rb +4 -3
  6. data/lib/cuprum/collections/basic/commands/find_many.rb +1 -1
  7. data/lib/cuprum/collections/basic/commands/insert_one.rb +4 -3
  8. data/lib/cuprum/collections/basic/commands/update_one.rb +4 -3
  9. data/lib/cuprum/collections/basic/query.rb +3 -3
  10. data/lib/cuprum/collections/commands/abstract_find_many.rb +33 -32
  11. data/lib/cuprum/collections/commands/abstract_find_one.rb +4 -3
  12. data/lib/cuprum/collections/commands/create.rb +60 -0
  13. data/lib/cuprum/collections/commands/find_one_matching.rb +134 -0
  14. data/lib/cuprum/collections/commands/update.rb +74 -0
  15. data/lib/cuprum/collections/commands/upsert.rb +162 -0
  16. data/lib/cuprum/collections/commands.rb +7 -2
  17. data/lib/cuprum/collections/errors/abstract_find_error.rb +210 -0
  18. data/lib/cuprum/collections/errors/already_exists.rb +4 -72
  19. data/lib/cuprum/collections/errors/extra_attributes.rb +8 -18
  20. data/lib/cuprum/collections/errors/failed_validation.rb +5 -18
  21. data/lib/cuprum/collections/errors/invalid_parameters.rb +7 -15
  22. data/lib/cuprum/collections/errors/invalid_query.rb +5 -15
  23. data/lib/cuprum/collections/errors/missing_default_contract.rb +5 -17
  24. data/lib/cuprum/collections/errors/not_found.rb +4 -67
  25. data/lib/cuprum/collections/errors/not_unique.rb +18 -0
  26. data/lib/cuprum/collections/errors/unknown_operator.rb +7 -17
  27. data/lib/cuprum/collections/errors.rb +13 -1
  28. data/lib/cuprum/collections/queries/ordering.rb +2 -2
  29. data/lib/cuprum/collections/repository.rb +23 -10
  30. data/lib/cuprum/collections/rspec/collection_contract.rb +140 -103
  31. data/lib/cuprum/collections/rspec/destroy_one_command_contract.rb +8 -6
  32. data/lib/cuprum/collections/rspec/find_many_command_contract.rb +114 -34
  33. data/lib/cuprum/collections/rspec/find_one_command_contract.rb +12 -9
  34. data/lib/cuprum/collections/rspec/insert_one_command_contract.rb +4 -3
  35. data/lib/cuprum/collections/rspec/query_contract.rb +3 -3
  36. data/lib/cuprum/collections/rspec/querying_contract.rb +2 -2
  37. data/lib/cuprum/collections/rspec/repository_contract.rb +167 -93
  38. data/lib/cuprum/collections/rspec/update_one_command_contract.rb +4 -3
  39. data/lib/cuprum/collections/version.rb +1 -1
  40. data/lib/cuprum/collections.rb +1 -0
  41. metadata +20 -89
@@ -38,29 +38,19 @@ module Cuprum::Collections::Errors
38
38
  # @return [Array<String>] The names of valid attributes for the entity.
39
39
  attr_reader :valid_attributes
40
40
 
41
- # @return [Hash] a serializable hash representation of the error.
42
- def as_json
41
+ private
42
+
43
+ def as_json_data
43
44
  {
44
- 'data' => {
45
- 'entity_class' => entity_class.name,
46
- 'extra_attributes' => extra_attributes,
47
- 'valid_attributes' => valid_attributes
48
- },
49
- 'message' => message,
50
- 'type' => type
45
+ 'entity_class' => entity_class.name,
46
+ 'extra_attributes' => extra_attributes,
47
+ 'valid_attributes' => valid_attributes
51
48
  }
52
49
  end
53
50
 
54
- # @return [String] short string used to identify the type of error.
55
- def type
56
- TYPE
57
- end
58
-
59
- private
60
-
61
51
  def default_message
62
- "invalid attributes for #{entity_class.name}:" \
63
- " #{extra_attributes.join(', ')}"
52
+ "invalid attributes for #{entity_class.name}: " \
53
+ "#{extra_attributes.join(', ')}"
64
54
  end
65
55
  end
66
56
  end
@@ -7,9 +7,6 @@ require 'cuprum/collections/errors'
7
7
  module Cuprum::Collections::Errors
8
8
  # Error returned when a collection item fails validation.
9
9
  class FailedValidation < Cuprum::Error
10
- COMPARABLE_PROPERTIES = %i[entity_class errors message].freeze
11
- private_constant :COMPARABLE_PROPERTIES
12
-
13
10
  # Short string used to identify the type of error.
14
11
  TYPE = 'cuprum.collections.errors.failed_validation'
15
12
 
@@ -33,25 +30,15 @@ module Cuprum::Collections::Errors
33
30
  # @return [Stannum::Errors] The errors generated when validating the entity.
34
31
  attr_reader :errors
35
32
 
36
- # @return [Hash] a serializable hash representation of the error.
37
- def as_json
33
+ private
34
+
35
+ def as_json_data
38
36
  {
39
- 'data' => {
40
- 'entity_class' => entity_class.name,
41
- 'errors' => format_errors
42
- },
43
- 'message' => message,
44
- 'type' => type
37
+ 'entity_class' => entity_class.name,
38
+ 'errors' => format_errors
45
39
  }
46
40
  end
47
41
 
48
- # @return [String] short string used to identify the type of error.
49
- def type
50
- TYPE
51
- end
52
-
53
- private
54
-
55
42
  def default_message
56
43
  "#{entity_class.name} failed validation"
57
44
  end
@@ -24,27 +24,19 @@ module Cuprum::Collections::Errors
24
24
  )
25
25
  end
26
26
 
27
- # @return [Hash] a serializable hash representation of the error.
28
- def as_json
29
- {
30
- 'data' => {
31
- 'command_class' => command.class.name,
32
- 'errors' => errors.to_a
33
- },
34
- 'message' => message,
35
- 'type' => type
36
- }
37
- end
38
-
39
27
  # @return [Cuprum::Command] the called command.
40
28
  attr_reader :command
41
29
 
42
30
  # @return [Stannum::Errors] the errors returned by the parameters contract.
43
31
  attr_reader :errors
44
32
 
45
- # @return [String] short string used to identify the type of error.
46
- def type
47
- TYPE
33
+ private
34
+
35
+ def as_json_data
36
+ {
37
+ 'command_class' => command.class.name,
38
+ 'errors' => errors.to_a
39
+ }
48
40
  end
49
41
  end
50
42
  end
@@ -29,25 +29,15 @@ module Cuprum::Collections::Errors
29
29
  # @return [Symbol] the strategy used to construct the query.
30
30
  attr_reader :strategy
31
31
 
32
- # @return [Hash] a serializable hash representation of the error.
33
- def as_json
32
+ private
33
+
34
+ def as_json_data
34
35
  {
35
- 'data' => {
36
- 'errors' => errors.to_a,
37
- 'strategy' => strategy
38
- },
39
- 'message' => message,
40
- 'type' => type
36
+ 'errors' => errors.to_a,
37
+ 'strategy' => strategy
41
38
  }
42
39
  end
43
40
 
44
- # @return [String] short string used to identify the type of error.
45
- def type
46
- TYPE
47
- end
48
-
49
- private
50
-
51
41
  def default_message
52
42
  "unable to parse query with strategy #{strategy.inspect}"
53
43
  end
@@ -23,27 +23,15 @@ module Cuprum::Collections::Errors
23
23
  # @return [Class] the class of the assigned entity.
24
24
  attr_reader :entity_class
25
25
 
26
- # @return [Hash] a serializable hash representation of the error.
27
- def as_json
28
- {
29
- 'data' => {
30
- 'entity_class' => entity_class.name
31
- },
32
- 'message' => message,
33
- 'type' => type
34
- }
35
- end
26
+ private
36
27
 
37
- # @return [String] short string used to identify the type of error.
38
- def type
39
- TYPE
28
+ def as_json_data
29
+ { 'entity_class' => entity_class.name }
40
30
  end
41
31
 
42
- private
43
-
44
32
  def default_message
45
- "attempted to validate a #{entity_class.name}, but #{entity_class.name}" \
46
- ' does not define a default contract'
33
+ "attempted to validate a #{entity_class.name}, but " \
34
+ "#{entity_class.name} does not define a default contract"
47
35
  end
48
36
  end
49
37
  end
@@ -1,81 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'cuprum/error'
4
- require 'sleeping_king_studios/tools/toolbelt'
5
-
6
3
  require 'cuprum/collections/errors'
4
+ require 'cuprum/collections/errors/abstract_find_error'
7
5
 
8
6
  module Cuprum::Collections::Errors
9
7
  # Returned when a find command does not find the requested items.
10
- class NotFound < Cuprum::Error
8
+ class NotFound < Cuprum::Collections::Errors::AbstractFindError
11
9
  # Short string used to identify the type of error.
12
10
  TYPE = 'cuprum.collections.errors.not_found'
13
11
 
14
- # @param collection_name [String, Symbol] The name of the collection.
15
- # @param primary_key_name [String, Symbol] The name of the primary key
16
- # attribute.
17
- # @param primary_key_values [Object, Array] The expected values of the
18
- # primary key attribute.
19
- def initialize(collection_name:, primary_key_name:, primary_key_values:)
20
- @collection_name = collection_name
21
- @primary_key_name = primary_key_name
22
- @primary_key_values = Array(primary_key_values)
23
-
24
- super(message: default_message)
25
- end
26
-
27
- # @return [String, Symbol] the name of the collection.
28
- attr_reader :collection_name
29
-
30
- # @return [String, Symbol] the name of the primary key attribute.
31
- attr_reader :primary_key_name
32
-
33
- # @return [Array] The expected values of the primary key attribute.
34
- attr_reader :primary_key_values
35
-
36
- # @return [Hash] a serializable hash representation of the error.
37
- def as_json
38
- {
39
- 'data' => {
40
- 'collection_name' => collection_name,
41
- 'primary_key_name' => primary_key_name,
42
- 'primary_key_values' => primary_key_values
43
- },
44
- 'message' => message,
45
- 'type' => type
46
- }
47
- end
48
-
49
- # @return [String] short string used to identify the type of error.
50
- def type
51
- TYPE
52
- end
53
-
54
12
  private
55
13
 
56
- def default_message
57
- primary_keys = primary_key_values.map(&:inspect).join(', ')
58
-
59
- "#{entity_name} not found with #{primary_key_name} #{primary_keys}"
60
- end
61
-
62
- def entity_name
63
- entity_name = collection_name
64
- entity_name = tools.str.singularize(entity_name) if singular?
65
-
66
- titleize(entity_name)
67
- end
68
-
69
- def singular?
70
- primary_key_values.size == 1
71
- end
72
-
73
- def titleize(string)
74
- tools.str.underscore(string).split('_').map(&:capitalize).join(' ')
75
- end
76
-
77
- def tools
78
- SleepingKingStudios::Tools::Toolbelt.instance
14
+ def message_fragment
15
+ 'not found'
79
16
  end
80
17
  end
81
18
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cuprum/collections/errors'
4
+ require 'cuprum/collections/errors/abstract_find_error'
5
+
6
+ module Cuprum::Collections::Errors
7
+ # Returned when a unique find command does finds multiple items.
8
+ class NotUnique < Cuprum::Collections::Errors::AbstractFindError
9
+ # Short string used to identify the type of error.
10
+ TYPE = 'cuprum.collections.errors.not_unique'
11
+
12
+ private
13
+
14
+ def message_fragment
15
+ 'not unique'
16
+ end
17
+ end
18
+ end
@@ -22,18 +22,6 @@ module Cuprum::Collections::Errors
22
22
  # @return [String, Symbol] the unknown operator.
23
23
  attr_reader :operator
24
24
 
25
- # @return [Hash] a serializable hash representation of the error.
26
- def as_json
27
- {
28
- 'data' => {
29
- 'corrections' => corrections,
30
- 'operator' => operator
31
- },
32
- 'message' => message,
33
- 'type' => type
34
- }
35
- end
36
-
37
25
  # @return [Array<String>] Suggested possible values for the operator.
38
26
  def corrections
39
27
  @corrections ||=
@@ -42,13 +30,15 @@ module Cuprum::Collections::Errors
42
30
  .correct(operator)
43
31
  end
44
32
 
45
- # @return [String] short string used to identify the type of error.
46
- def type
47
- TYPE
48
- end
49
-
50
33
  private
51
34
 
35
+ def as_json_data
36
+ {
37
+ 'corrections' => corrections,
38
+ 'operator' => operator
39
+ }
40
+ end
41
+
52
42
  def generate_message
53
43
  message = "unknown operator #{operator.inspect}"
54
44
 
@@ -4,5 +4,17 @@ require 'cuprum/collections'
4
4
 
5
5
  module Cuprum::Collections
6
6
  # Namespace for errors, which represent failure states of commands.
7
- module Errors; end
7
+ module Errors
8
+ autoload :AbstractFindError, 'cuprum/collections/errors/abstract_find_error'
9
+ autoload :AlreadyExists, 'cuprum/collections/errors/already_exists'
10
+ autoload :ExtraAttributes, 'cuprum/collections/errors/extra_attributes'
11
+ autoload :FailedValidation, 'cuprum/collections/errors/failed_validation'
12
+ autoload :InvalidParameters, 'cuprum/collections/errors/invalid_parameters'
13
+ autoload :InvalidQuery, 'cuprum/collections/errors/invalid_query'
14
+ autoload :MissingDefaultContract,
15
+ 'cuprum/collections/errors/missing_default_contract'
16
+ autoload :NotFound, 'cuprum/collections/errors/not_found'
17
+ autoload :NotUnique, 'cuprum/collections/errors/not_unique'
18
+ autoload :UnknownOperator, 'cuprum/collections/errors/unknown_operator'
19
+ end
8
20
  end
@@ -68,8 +68,8 @@ module Cuprum::Collections::Queries
68
68
  return if ordering_constraint.matches?(attributes)
69
69
 
70
70
  raise InvalidOrderError,
71
- 'order must be a list of attribute names and/or a hash of attribute' \
72
- ' names with values :asc or :desc'
71
+ 'order must be a list of attribute names and/or a hash of ' \
72
+ 'attribute names with values :asc or :desc'
73
73
  end
74
74
  end
75
75
  end
@@ -16,6 +16,9 @@ module Cuprum::Collections
16
16
  class Repository
17
17
  extend Forwardable
18
18
 
19
+ # Error raised when trying to add an existing collection to the repository.
20
+ class DuplicateCollectionError < StandardError; end
21
+
19
22
  # Error raised when trying to add an invalid collection to the repository.
20
23
  class InvalidCollectionError < StandardError; end
21
24
 
@@ -35,17 +38,17 @@ module Cuprum::Collections
35
38
 
36
39
  # Finds and returns the collection with the given name.
37
40
  #
38
- # @param collection_name [String, Symbol] The name of the collection to
39
- # return.
41
+ # @param qualified_name [String, Symbol] The qualified name of the
42
+ # collection to return.
40
43
  #
41
44
  # @return [Object] the requested collection.
42
45
  #
43
46
  # @raise [Cuprum::Collection::Repository::UndefinedCOllectionError] if the
44
47
  # requested collection is not in the repository.
45
- def [](collection_name)
46
- @collections.fetch(collection_name.to_s) do
48
+ def [](qualified_name)
49
+ @collections.fetch(qualified_name.to_s) do
47
50
  raise UndefinedCollectionError,
48
- "repository does not define collection #{collection_name.inspect}"
51
+ "repository does not define collection #{qualified_name.inspect}"
49
52
  end
50
53
  end
51
54
 
@@ -56,12 +59,22 @@ module Cuprum::Collections
56
59
  #
57
60
  # @param collection [#collection_name] The collection to add to the
58
61
  # repository.
62
+ # @param force [true, false] If true, override an existing collection with
63
+ # the same name.
59
64
  #
60
65
  # @return [Cuprum::Rails::Repository] the repository.
61
- def add(collection)
66
+ #
67
+ # @raise [DuplicateCollectionError] if a collection with the same name
68
+ # already exists in the repository.
69
+ def add(collection, force: false)
62
70
  validate_collection!(collection)
63
71
 
64
- @collections[collection.collection_name.to_s] = collection
72
+ if !force && key?(collection.qualified_name.to_s)
73
+ raise DuplicateCollectionError,
74
+ "collection #{collection.qualified_name} already exists"
75
+ end
76
+
77
+ @collections[collection.qualified_name.to_s] = collection
65
78
 
66
79
  self
67
80
  end
@@ -69,11 +82,11 @@ module Cuprum::Collections
69
82
 
70
83
  # Checks if a collection with the given name exists in the repository.
71
84
  #
72
- # @param collection_name [String, Symbol] The name to check for.
85
+ # @param qualified_name [String, Symbol] The name to check for.
73
86
  #
74
87
  # @return [true, false] true if the key exists, otherwise false.
75
- def key?(collection_name)
76
- @collections.key?(collection_name.to_s)
88
+ def key?(qualified_name)
89
+ @collections.key?(qualified_name.to_s)
77
90
  end
78
91
 
79
92
  private