hanami-model 1.0.0 → 1.0.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 70775a4002119bba8febe56e6a61619320d1a832
4
- data.tar.gz: d1890cf53c762541f9821eaa4fe7d8ef50aac0dc
3
+ metadata.gz: bb1fca18a6f84f606883ffab656334c1b8e619f6
4
+ data.tar.gz: 8d2884fbd3bfda01dc6390b4271280cfffe1abc2
5
5
  SHA512:
6
- metadata.gz: c49a0c0249cb4e9083bdf0874d654e7cface01ede618be1cecb15a646abb34edab19b4597cdc5532dcf6657a0ec9b9dafba24559d9268dcd3558cb61204211cd
7
- data.tar.gz: 661788bbaf06b16872f40c25091c68aa0e67137265df3ba807f458b9118cfe0487890d4f3f268d909920ac10f1e337ec8a37fab496994ea04f220cabcc89654f
6
+ metadata.gz: 4af0a977d17c5cab779ba6b7fefc91b5e94ffa927324439ed99d45fd468000289f564f151c48e1926e2e603052967077517e055735dbe719152a021ccb2c7282
7
+ data.tar.gz: f4c30f92ab810dde2c9678d8352bec0787e2c446235e70a078e7a419913bf2fc59d8d0fdcd30727be296085b74f7dc89f300bb57cca463437cf94805ce2b2800
data/CHANGELOG.md CHANGED
@@ -1,6 +1,12 @@
1
1
  # Hanami::Model
2
2
  A persistence layer for Hanami
3
3
 
4
+ ## v1.0.1 - 2017-06-23
5
+ ### Fixed
6
+ - [Kai Kuchenbecker & Marcello Rocha & Luca Guidi] Ensure `Hanami::Entity#initialize` to not serialize (into `Hash`) other entities passed as an argument
7
+ - [Luca Guidi] Let `Hanami::Repository.relation=` to accept strings as an argument
8
+ - [Nikita Shilnikov] Prevent stack-overflow when `Hanami::Repository#update` is called thousand times
9
+
4
10
  ## v1.0.0 - 2017-04-06
5
11
 
6
12
  ## v1.0.0.rc1 - 2017-03-31
data/hanami-model.gemspec CHANGED
@@ -21,12 +21,12 @@ Gem::Specification.new do |spec|
21
21
  spec.required_ruby_version = '>= 2.3.0'
22
22
 
23
23
  spec.add_runtime_dependency 'hanami-utils', '~> 1.0'
24
- spec.add_runtime_dependency 'rom-sql', '~> 1.2'
24
+ spec.add_runtime_dependency 'rom-sql', '~> 1.3'
25
25
  spec.add_runtime_dependency 'rom-repository', '~> 1.3'
26
- spec.add_runtime_dependency 'dry-types', '~> 0.9'
26
+ spec.add_runtime_dependency 'dry-types', '~> 0.10'
27
27
  spec.add_runtime_dependency 'concurrent-ruby', '~> 1.0'
28
28
 
29
- spec.add_development_dependency 'bundler', '~> 1.6'
30
- spec.add_development_dependency 'minitest', '~> 5'
31
- spec.add_development_dependency 'rake', '~> 11'
29
+ spec.add_development_dependency 'bundler', '~> 1.6'
30
+ spec.add_development_dependency 'rake', '~> 11'
31
+ spec.add_development_dependency 'rspec', '~> 3.5'
32
32
  end
data/lib/hanami/entity.rb CHANGED
@@ -19,8 +19,7 @@ module Hanami
19
19
  # @example With Hanami::Entity
20
20
  # require 'hanami/model'
21
21
  #
22
- # class Person
23
- # include Hanami::Entity
22
+ # class Person < Hanami::Entity
24
23
  # end
25
24
  #
26
25
  # If we expand the code above in **pure Ruby**, it would be:
@@ -183,7 +182,7 @@ module Hanami
183
182
  #
184
183
  # @since 0.1.0
185
184
  def to_h
186
- attributes.deep_dup.to_h
185
+ Utils::Hash.deep_dup(attributes)
187
186
  end
188
187
 
189
188
  # @since 0.7.0
@@ -73,7 +73,7 @@ module Hanami
73
73
  if attributes.nil?
74
74
  {}
75
75
  else
76
- attributes.dup
76
+ Utils::Hash.deep_symbolize(attributes.to_hash.dup)
77
77
  end
78
78
  end
79
79
 
@@ -221,9 +221,9 @@ module Hanami
221
221
  # @since 0.7.0
222
222
  # @api private
223
223
  def call(attributes)
224
- Utils::Hash.new(
224
+ Utils::Hash.deep_symbolize(
225
225
  schema.call(attributes)
226
- ).deep_symbolize!
226
+ )
227
227
  end
228
228
 
229
229
  # @since 0.7.0
data/lib/hanami/model.rb CHANGED
@@ -85,7 +85,7 @@ module Hanami
85
85
  # This is useful for reboot applications in production and to ensure that
86
86
  # the framework prunes stale connections.
87
87
  #
88
- # @since x.x.x
88
+ # @since 1.0.0
89
89
  #
90
90
  # @example With Full Stack Hanami Project
91
91
  # # config/puma.rb
@@ -37,8 +37,8 @@ module Hanami
37
37
  # @since 0.7.0
38
38
  # @api private
39
39
  def build(relation, options = {})
40
- input(InputWithMapping.new(relation, input))
41
- super(relation, options.merge(input: input))
40
+ wrapped_input = InputWithMapping.new(relation, options.fetch(:input) { input })
41
+ super(relation, options.merge(input: wrapped_input))
42
42
  end
43
43
  end
44
44
 
@@ -37,8 +37,8 @@ module Hanami
37
37
  # @since 0.7.0
38
38
  # @api private
39
39
  def build(relation, options = {})
40
- input(InputWithSchema.new(relation, input))
41
- super(relation, options.merge(input: input))
40
+ wrapped_input = InputWithSchema.new(relation, options.fetch(:input) { input })
41
+ super(relation, options.merge(input: wrapped_input))
42
42
  end
43
43
  end
44
44
 
@@ -100,8 +100,8 @@ module Hanami
100
100
  InputWithUpdateTimestamp
101
101
  end
102
102
 
103
- input(plugin.new(relation, input))
104
- super(relation, options.merge(input: input))
103
+ wrapped_input = plugin.new(relation, options.fetch(:input) { input })
104
+ super(relation, options.merge(input: wrapped_input))
105
105
  end
106
106
  end
107
107
 
@@ -12,12 +12,12 @@ module Hanami
12
12
  # @api private
13
13
  class RelationName < EntityName
14
14
  # @param name [Class,String] the class or its name
15
- # @return [Symbol] the relation name
15
+ # @return [String] the relation name
16
16
  #
17
17
  # @since 0.7.0
18
18
  # @api private
19
19
  def self.new(name)
20
- Utils::String.new(super).underscore.pluralize.to_sym
20
+ Utils::String.new(super).underscore.pluralize
21
21
  end
22
22
  end
23
23
  end
@@ -38,6 +38,22 @@ module Hanami
38
38
  freeze
39
39
  end
40
40
 
41
+ # Process attributes
42
+ #
43
+ # @param attributes [#to_hash] the attributes hash
44
+ #
45
+ # @raise [TypeError] if the process fails
46
+ #
47
+ # @since 1.0.1
48
+ # @api private
49
+ def call(attributes)
50
+ schema.call(attributes)
51
+ end
52
+
53
+ # @since 1.0.1
54
+ # @api private
55
+ alias [] call
56
+
41
57
  # Check if the attribute is known
42
58
  #
43
59
  # @param name [Symbol] the attribute name
@@ -29,31 +29,31 @@ module Hanami
29
29
  Time = Types::Strict::Nil | Types::Time.constructor(Coercions.method(:time))
30
30
 
31
31
  Array = Types::Strict::Nil | Types::Array.constructor(Coercions.method(:array))
32
- Hash = Types::Strict::Nil | Types::Array.constructor(Coercions.method(:hash))
32
+ Hash = Types::Strict::Nil | Types::Hash.constructor(Coercions.method(:hash))
33
33
 
34
34
  # @since 0.7.0
35
35
  # @api private
36
36
  MAPPING = {
37
- Types::String.with(meta: {}) => Schema::String,
38
- Types::Int.with(meta: {}) => Schema::Int,
39
- Types::Float.with(meta: {}) => Schema::Float,
40
- Types::Decimal.with(meta: {}) => Schema::Decimal,
41
- Types::Bool.with(meta: {}) => Schema::Bool,
42
- Types::Date.with(meta: {}) => Schema::Date,
43
- Types::DateTime.with(meta: {}) => Schema::DateTime,
44
- Types::Time.with(meta: {}) => Schema::Time,
45
- Types::Array.with(meta: {}) => Schema::Array,
46
- Types::Hash.with(meta: {}) => Schema::Hash,
47
- Types::String.optional.with(meta: {}) => Schema::String,
48
- Types::Int.optional.with(meta: {}) => Schema::Int,
49
- Types::Float.optional.with(meta: {}) => Schema::Float,
50
- Types::Decimal.optional.with(meta: {}) => Schema::Decimal,
51
- Types::Bool.optional.with(meta: {}) => Schema::Bool,
52
- Types::Date.optional.with(meta: {}) => Schema::Date,
53
- Types::DateTime.optional.with(meta: {}) => Schema::DateTime,
54
- Types::Time.optional.with(meta: {}) => Schema::Time,
55
- Types::Array.optional.with(meta: {}) => Schema::Array,
56
- Types::Hash.optional.with(meta: {}) => Schema::Hash
37
+ Types::String.pristine => Schema::String,
38
+ Types::Int.pristine => Schema::Int,
39
+ Types::Float.pristine => Schema::Float,
40
+ Types::Decimal.pristine => Schema::Decimal,
41
+ Types::Bool.pristine => Schema::Bool,
42
+ Types::Date.pristine => Schema::Date,
43
+ Types::DateTime.pristine => Schema::DateTime,
44
+ Types::Time.pristine => Schema::Time,
45
+ Types::Array.pristine => Schema::Array,
46
+ Types::Hash.pristine => Schema::Hash,
47
+ Types::String.optional.pristine => Schema::String,
48
+ Types::Int.optional.pristine => Schema::Int,
49
+ Types::Float.optional.pristine => Schema::Float,
50
+ Types::Decimal.optional.pristine => Schema::Decimal,
51
+ Types::Bool.optional.pristine => Schema::Bool,
52
+ Types::Date.optional.pristine => Schema::Date,
53
+ Types::DateTime.optional.pristine => Schema::DateTime,
54
+ Types::Time.optional.pristine => Schema::Time,
55
+ Types::Array.optional.pristine => Schema::Array,
56
+ Types::Hash.optional.pristine => Schema::Hash
57
57
  }.freeze
58
58
 
59
59
  # Convert given type into coercible
@@ -62,8 +62,22 @@ module Hanami
62
62
  # @api private
63
63
  def self.coercible(attribute)
64
64
  return attribute if attribute.constrained?
65
- # TODO: figure out a better way of inferring coercions from schema types
66
- MAPPING.fetch(attribute.type.with(meta: {}), attribute)
65
+
66
+ type = attribute.type
67
+ unwrapped = type.optional? ? type.right : type
68
+
69
+ # NOTE: In the future rom-sql should be able to always return Ruby
70
+ # types instead of Sequel types. When that will happen we can get
71
+ # rid of this logic in the block and to fallback to:
72
+ #
73
+ # MAPPING.fetch(unwrapped.pristine, attribute)
74
+ MAPPING.fetch(unwrapped.pristine) do
75
+ if defined?(ROM::SQL::Types::PG::JSONB) && unwrapped.pristine == ROM::SQL::Types::PG::JSONB
76
+ Schema::Hash
77
+ else
78
+ attribute
79
+ end
80
+ end
67
81
  end
68
82
 
69
83
  # Coercer for SQL associations target
@@ -1,4 +1,5 @@
1
1
  require 'hanami/utils/string'
2
+ require 'hanami/utils/hash'
2
3
 
3
4
  module Hanami
4
5
  module Model
@@ -184,7 +185,9 @@ module Hanami
184
185
  when ::Hash
185
186
  arg
186
187
  when ->(a) { a.respond_to?(:to_hash) }
187
- ::Kernel.Hash(arg)
188
+ Utils::Hash.deep_symbolize(
189
+ ::Kernel.Hash(arg)
190
+ )
188
191
  else
189
192
  raise ArgumentError.new("invalid value for Hash(): #{arg.inspect}")
190
193
  end
@@ -3,6 +3,6 @@ module Hanami
3
3
  # Defines the version
4
4
  #
5
5
  # @since 0.1.0
6
- VERSION = '1.0.0'.freeze
6
+ VERSION = '1.0.1'.freeze
7
7
  end
8
8
  end
@@ -6,6 +6,7 @@ require 'hanami/model/associations/dsl'
6
6
  require 'hanami/model/association'
7
7
  require 'hanami/utils/class'
8
8
  require 'hanami/utils/class_attribute'
9
+ require 'hanami/utils/io'
9
10
 
10
11
  module Hanami
11
12
  # Mediates between the entities and the persistence layer, by offering an API
@@ -19,8 +20,7 @@ module Hanami
19
20
  # @example
20
21
  # require 'hanami/model'
21
22
  #
22
- # class Article
23
- # include Hanami::Entity
23
+ # class Article < Hanami::Entity
24
24
  # end
25
25
  #
26
26
  # # valid
@@ -107,7 +107,7 @@ module Hanami
107
107
  # @see Hanami::Entity
108
108
  # @see http://martinfowler.com/eaaCatalog/repository.html
109
109
  # @see http://en.wikipedia.org/wiki/Dependency_inversion_principle
110
- class Repository < ROM::Repository::Root
110
+ class Repository < ROM::Repository::Root # rubocop:disable Metrics/ClassLength
111
111
  # Plugins for database commands
112
112
  #
113
113
  # @since 0.7.0
@@ -282,13 +282,22 @@ module Hanami
282
282
  include Utils::ClassAttribute
283
283
  auto_struct true
284
284
 
285
- class_attribute :entity
285
+ @associations = nil
286
+ @mapping = nil
287
+ @schema = nil
286
288
 
289
+ class_attribute :entity
287
290
  class_attribute :entity_name
288
- self.entity_name = Model::EntityName.new(name)
289
-
290
291
  class_attribute :relation
291
- self.relation = Model::RelationName.new(name)
292
+
293
+ Hanami::Utils::IO.silence_warnings do
294
+ def self.relation=(name)
295
+ @relation = name.to_sym
296
+ end
297
+ end
298
+
299
+ self.entity_name = Model::EntityName.new(name)
300
+ self.relation = Model::RelationName.new(name)
292
301
 
293
302
  commands :create, update: :by_pk, delete: :by_pk, mapper: Model::MappedRelation.mapper_name, use: COMMAND_PLUGINS
294
303
  prepend Commands
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hanami-model
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luca Guidi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-04-06 00:00:00.000000000 Z
11
+ date: 2017-06-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: hanami-utils
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '1.2'
33
+ version: '1.3'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '1.2'
40
+ version: '1.3'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rom-repository
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -58,14 +58,14 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '0.9'
61
+ version: '0.10'
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '0.9'
68
+ version: '0.10'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: concurrent-ruby
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -95,33 +95,33 @@ dependencies:
95
95
  - !ruby/object:Gem::Version
96
96
  version: '1.6'
97
97
  - !ruby/object:Gem::Dependency
98
- name: minitest
98
+ name: rake
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '5'
103
+ version: '11'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '5'
110
+ version: '11'
111
111
  - !ruby/object:Gem::Dependency
112
- name: rake
112
+ name: rspec
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: '11'
117
+ version: '3.5'
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
- version: '11'
124
+ version: '3.5'
125
125
  description: A persistence framework with entities and repositories
126
126
  email:
127
127
  - me@lucaguidi.com
@@ -192,7 +192,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
192
192
  version: '0'
193
193
  requirements: []
194
194
  rubyforge_project:
195
- rubygems_version: 2.6.11
195
+ rubygems_version: 2.6.12
196
196
  signing_key:
197
197
  specification_version: 4
198
198
  summary: A persistence layer for Hanami