hanami-model 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
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