hanami-model 0.6.1 → 0.7.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 (67) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +44 -0
  3. data/README.md +54 -420
  4. data/hanami-model.gemspec +9 -6
  5. data/lib/hanami/entity.rb +107 -191
  6. data/lib/hanami/entity/schema.rb +236 -0
  7. data/lib/hanami/model.rb +52 -138
  8. data/lib/hanami/model/association.rb +37 -0
  9. data/lib/hanami/model/associations/belongs_to.rb +19 -0
  10. data/lib/hanami/model/associations/dsl.rb +29 -0
  11. data/lib/hanami/model/associations/has_many.rb +200 -0
  12. data/lib/hanami/model/configuration.rb +52 -224
  13. data/lib/hanami/model/configurator.rb +62 -0
  14. data/lib/hanami/model/entity_name.rb +35 -0
  15. data/lib/hanami/model/error.rb +37 -24
  16. data/lib/hanami/model/mapping.rb +29 -35
  17. data/lib/hanami/model/migration.rb +31 -0
  18. data/lib/hanami/model/migrator.rb +111 -88
  19. data/lib/hanami/model/migrator/adapter.rb +39 -16
  20. data/lib/hanami/model/migrator/connection.rb +23 -11
  21. data/lib/hanami/model/migrator/mysql_adapter.rb +38 -17
  22. data/lib/hanami/model/migrator/postgres_adapter.rb +20 -19
  23. data/lib/hanami/model/migrator/sqlite_adapter.rb +9 -8
  24. data/lib/hanami/model/plugins.rb +25 -0
  25. data/lib/hanami/model/plugins/mapping.rb +55 -0
  26. data/lib/hanami/model/plugins/schema.rb +55 -0
  27. data/lib/hanami/model/plugins/timestamps.rb +118 -0
  28. data/lib/hanami/model/relation_name.rb +24 -0
  29. data/lib/hanami/model/sql.rb +161 -0
  30. data/lib/hanami/model/sql/console.rb +41 -0
  31. data/lib/hanami/model/sql/consoles/abstract.rb +33 -0
  32. data/lib/hanami/model/sql/consoles/mysql.rb +63 -0
  33. data/lib/hanami/model/sql/consoles/postgresql.rb +68 -0
  34. data/lib/hanami/model/sql/consoles/sqlite.rb +46 -0
  35. data/lib/hanami/model/sql/entity/schema.rb +125 -0
  36. data/lib/hanami/model/sql/types.rb +95 -0
  37. data/lib/hanami/model/sql/types/schema/coercions.rb +198 -0
  38. data/lib/hanami/model/types.rb +99 -0
  39. data/lib/hanami/model/version.rb +1 -1
  40. data/lib/hanami/repository.rb +287 -723
  41. metadata +77 -40
  42. data/EXAMPLE.md +0 -213
  43. data/lib/hanami/entity/dirty_tracking.rb +0 -74
  44. data/lib/hanami/model/adapters/abstract.rb +0 -281
  45. data/lib/hanami/model/adapters/file_system_adapter.rb +0 -288
  46. data/lib/hanami/model/adapters/implementation.rb +0 -111
  47. data/lib/hanami/model/adapters/memory/collection.rb +0 -132
  48. data/lib/hanami/model/adapters/memory/command.rb +0 -113
  49. data/lib/hanami/model/adapters/memory/query.rb +0 -653
  50. data/lib/hanami/model/adapters/memory_adapter.rb +0 -179
  51. data/lib/hanami/model/adapters/null_adapter.rb +0 -24
  52. data/lib/hanami/model/adapters/sql/collection.rb +0 -287
  53. data/lib/hanami/model/adapters/sql/command.rb +0 -88
  54. data/lib/hanami/model/adapters/sql/console.rb +0 -33
  55. data/lib/hanami/model/adapters/sql/consoles/mysql.rb +0 -49
  56. data/lib/hanami/model/adapters/sql/consoles/postgresql.rb +0 -48
  57. data/lib/hanami/model/adapters/sql/consoles/sqlite.rb +0 -26
  58. data/lib/hanami/model/adapters/sql/query.rb +0 -788
  59. data/lib/hanami/model/adapters/sql_adapter.rb +0 -296
  60. data/lib/hanami/model/coercer.rb +0 -74
  61. data/lib/hanami/model/config/adapter.rb +0 -116
  62. data/lib/hanami/model/config/mapper.rb +0 -45
  63. data/lib/hanami/model/mapper.rb +0 -124
  64. data/lib/hanami/model/mapping/attribute.rb +0 -85
  65. data/lib/hanami/model/mapping/coercers.rb +0 -314
  66. data/lib/hanami/model/mapping/collection.rb +0 -490
  67. data/lib/hanami/model/mapping/collection_coercer.rb +0 -79
@@ -1,45 +0,0 @@
1
- require 'hanami/utils/kernel'
2
-
3
- module Hanami
4
- module Model
5
- module Config
6
- # Read mapping file for mapping DSL
7
- #
8
- # @since 0.2.0
9
- # @api private
10
- class Mapper
11
- EXTNAME = '.rb'
12
-
13
- def initialize(path=nil, &blk)
14
- if block_given?
15
- @blk = blk
16
- elsif path
17
- @path = root.join(path)
18
- else
19
- raise Hanami::Model::InvalidMappingError.new('You must specify a block or a file.')
20
- end
21
- end
22
-
23
- def to_proc
24
- unless @blk
25
- code = realpath.read
26
- @blk = Proc.new { eval(code) }
27
- end
28
-
29
- @blk
30
- end
31
-
32
- private
33
- def realpath
34
- Utils::Kernel.Pathname("#{ @path }#{ EXTNAME }").realpath
35
- rescue Errno::ENOENT
36
- raise ArgumentError, 'You must specify a valid filepath.'
37
- end
38
-
39
- def root
40
- Utils::Kernel.Pathname(Dir.pwd).realpath
41
- end
42
- end
43
- end
44
- end
45
- end
@@ -1,124 +0,0 @@
1
- require 'hanami/model/mapping'
2
-
3
- module Hanami
4
- module Model
5
- # Error for missing mapper
6
- # It's raised when loading model without mapper
7
- #
8
- # @since 0.2.0
9
- #
10
- # @see Hanami::Model::Configuration#mapping
11
- class NoMappingError < Hanami::Model::Error
12
- def initialize
13
- super("Mapping is missing. Please check your framework configuration.")
14
- end
15
- end
16
-
17
- # @since 0.2.0
18
- # @api private
19
- class NullMapper
20
- def method_missing(m, *args)
21
- raise NoMappingError.new
22
- end
23
- end
24
-
25
- # A persistence mapper that keeps entities independent from database details.
26
- #
27
- # This is database independent. It can work with SQL, document, and even
28
- # with key/value stores.
29
- #
30
- # @since 0.1.0
31
- #
32
- # @see http://martinfowler.com/eaaCatalog/dataMapper.html
33
- #
34
- # @example
35
- # require 'hanami/model'
36
- #
37
- # mapper = Hanami::Model::Mapper.new do
38
- # collection :users do
39
- # entity User
40
- #
41
- # attribute :id, Integer
42
- # attribute :name, String
43
- # end
44
- # end
45
- #
46
- # # This guarantees thread-safety and should happen as last thing before
47
- # # to start the app code.
48
- # mapper.load!
49
- class Mapper
50
- # @attr_reader collections [Hash] all the mapped collections
51
- #
52
- # @since 0.1.0
53
- # @api private
54
- attr_reader :collections
55
-
56
- # Instantiate a mapper.
57
- #
58
- # It accepts an optional argument (`coercer`) a class that defines the
59
- # policies for entities translations from/to the database.
60
- #
61
- # If provided, this class must implement the following interface:
62
- #
63
- # * #initialize(collection) # Hanami::Model::Mapping::Collection
64
- # * #to_record(entity) # translates an entity to the database type
65
- # * #from_record(record) # translates a record into an entity
66
- # * #deserialize_*(value) # a set of methods, one for each database column.
67
- #
68
- # If not given, it uses `Hanami::Model::Mapping::CollectionCoercer`, by default.
69
- #
70
- #
71
- #
72
- # @param coercer [Class] an optional class that defines the policies for
73
- # entity translations from/to the database.
74
- #
75
- # @param blk [Proc] an optional block of code that gets evaluated in the
76
- # context of the current instance
77
- #
78
- # @return [Hanami::Model::Mapper]
79
- #
80
- # @since 0.1.0
81
- def initialize(coercer = nil, &blk)
82
- @coercer = coercer || Mapping::CollectionCoercer
83
- @collections = {}
84
-
85
- instance_eval(&blk) if block_given?
86
- end
87
-
88
- # Maps a collection.
89
- #
90
- # A collection is a set of homogeneous records. Think of a table of a SQL
91
- # database or about collection of MongoDB.
92
- #
93
- # @param name [Symbol] the name of the mapped collection. If used with a
94
- # SQL database it's the table name.
95
- #
96
- # @param blk [Proc] the block that maps the attributes of that collection.
97
- #
98
- # @since 0.1.0
99
- #
100
- # @see Hanami::Model::Mapping::Collection
101
- def collection(name, &blk)
102
- if block_given?
103
- @collections[name] = Mapping::Collection.new(name, @coercer, &blk)
104
- else
105
- @collections[name] or raise Mapping::UnmappedCollectionError.new(name)
106
- end
107
- end
108
-
109
- # Loads the internals of the mapper, in order to guarantee thread safety.
110
- #
111
- # This method MUST be invoked as the last thing before of start using the
112
- # application.
113
- #
114
- # @since 0.1.0
115
- def load!(adapter = nil)
116
- @collections.each_value do |collection|
117
- collection.adapter = adapter
118
- collection.load!
119
- end
120
- self
121
- end
122
- end
123
- end
124
- end
@@ -1,85 +0,0 @@
1
- require 'hanami/utils/class'
2
-
3
- module Hanami
4
- module Model
5
- module Mapping
6
- # Mapping attribute
7
- #
8
- # @api private
9
- # @since 0.5.0
10
- class Attribute
11
- # @api private
12
- # @since 0.5.0
13
- COERCERS_NAMESPACE = "Hanami::Model::Mapping::Coercers".freeze
14
-
15
- # Initialize a new attribute
16
- #
17
- # @param name [#to_sym] attribute name
18
- # @param coercer [.load, .dump] a coercer
19
- # @param options [Hash] a set of options
20
- #
21
- # @option options [#to_sym] :as Resolve mismatch between database column
22
- # name and entity attribute name
23
- #
24
- # @return [Hanami::Model::Mapping::Attribute]
25
- #
26
- # @api private
27
- # @since 0.5.0
28
- #
29
- # @see Hanami::Model::Coercer
30
- # @see Hanami::Model::Mapping::Coercers
31
- # @see Hanami::Model::Mapping::Collection#attribute
32
- def initialize(name, coercer, options)
33
- @name = name.to_sym
34
- @coercer = coercer
35
- @options = options
36
- end
37
-
38
- # Returns the mapped name
39
- #
40
- # @return [Symbol] the mapped name
41
- #
42
- # @api private
43
- # @since 0.5.0
44
- #
45
- # @see Hanami::Model::Mapping::Collection#attribute
46
- def mapped
47
- (@options.fetch(:as) { name }).to_sym
48
- end
49
-
50
- # @api private
51
- # @since 0.5.0
52
- def load_coercer
53
- "#{ coercer }.load"
54
- end
55
-
56
- # @api private
57
- # @since 0.5.0
58
- def dump_coercer
59
- "#{ coercer }.dump"
60
- end
61
-
62
- # @api private
63
- # @since 0.5.0
64
- def ==(other)
65
- self.class == other.class &&
66
- self.name == other.name &&
67
- self.mapped == other.mapped &&
68
- self.coercer == other.coercer
69
- end
70
-
71
- protected
72
-
73
- # @api private
74
- # @since 0.5.0
75
- attr_reader :name
76
-
77
- # @api private
78
- # @since 0.5.0
79
- def coercer
80
- Utils::Class.load_from_pattern!("(#{ COERCERS_NAMESPACE }::#{ @coercer }|#{ @coercer })")
81
- end
82
- end
83
- end
84
- end
85
- end
@@ -1,314 +0,0 @@
1
- require 'hanami/model/coercer'
2
- require 'hanami/utils/kernel'
3
-
4
- module Hanami
5
- module Model
6
- module Mapping
7
- # Default coercers
8
- #
9
- # @since 0.5.0
10
- # @api private
11
- module Coercers
12
- # Array coercer
13
- #
14
- # @since 0.5.0
15
- # @api private
16
- #
17
- # @see Hanami::Model::Coercer
18
- class Array < Coercer
19
- # Transform a value from the database into a Ruby Array, unless nil
20
- #
21
- # @param value [Object] the object to coerce
22
- #
23
- # @return [Array] the result of the coercion
24
- #
25
- # @raise [TypeError] if the value can't be coerced
26
- #
27
- # @since 0.5.0
28
- # @api private
29
- #
30
- # @see Hanami::Model::Coercer.load
31
- # @see http://ruby-doc.org/core/Kernel.html#method-i-Array
32
- def self.load(value)
33
- ::Kernel.Array(value) unless value.nil?
34
- end
35
- end
36
-
37
- # Boolean coercer
38
- #
39
- # @since 0.5.0
40
- # @api private
41
- #
42
- # @see Hanami::Model::Coercer
43
- class Boolean < Coercer
44
- # Transform a value from the database into a Boolean, unless nil
45
- #
46
- # @param value [Object] the object to coerce
47
- #
48
- # @return [Boolean] the result of the coercion
49
- #
50
- # @raise [TypeError] if the value can't be coerced
51
- #
52
- # @since 0.5.0
53
- # @api private
54
- #
55
- # @see Hanami::Model::Coercer.load
56
- # @see http://rdoc.info/gems/hanami-utils/Hanami/Utils/Kernel#Boolean-class_method
57
- def self.load(value)
58
- Utils::Kernel.Boolean(value) unless value.nil?
59
- end
60
- end
61
-
62
- # Date coercer
63
- #
64
- # @since 0.5.0
65
- # @api private
66
- #
67
- # @see Hanami::Model::Coercer
68
- class Date < Coercer
69
- # Transform a value from the database into a Date, unless nil
70
- #
71
- # @param value [Object] the object to coerce
72
- #
73
- # @return [Date] the result of the coercion
74
- #
75
- # @raise [TypeError] if the value can't be coerced
76
- #
77
- # @since 0.5.0
78
- # @api private
79
- #
80
- # @see Hanami::Model::Coercer.load
81
- # @see http://rdoc.info/gems/hanami-utils/Hanami/Utils/Kernel#Date-class_method
82
- def self.load(value)
83
- Utils::Kernel.Date(value) unless value.nil?
84
- end
85
- end
86
-
87
- # DateTime coercer
88
- #
89
- # @since 0.5.0
90
- # @api private
91
- #
92
- # @see Hanami::Model::Coercer
93
- class DateTime < Coercer
94
- # Transform a value from the database into a DateTime, unless nil
95
- #
96
- # @param value [Object] the object to coerce
97
- #
98
- # @return [DateTime] the result of the coercion
99
- #
100
- # @raise [TypeError] if the value can't be coerced
101
- #
102
- # @since 0.5.0
103
- # @api private
104
- #
105
- # @see Hanami::Model::Coercer.load
106
- # @see http://rdoc.info/gems/hanami-utils/Hanami/Utils/Kernel#DateTime-class_method
107
- def self.load(value)
108
- Utils::Kernel.DateTime(value) unless value.nil?
109
- end
110
- end
111
-
112
- # Float coercer
113
- #
114
- # @since 0.5.0
115
- # @api private
116
- #
117
- # @see Hanami::Model::Coercer
118
- class Float < Coercer
119
- # Transform a value from the database into a Float, unless nil
120
- #
121
- # @param value [Object] the object to coerce
122
- #
123
- # @return [Float] the result of the coercion
124
- #
125
- # @raise [TypeError] if the value can't be coerced
126
- #
127
- # @since 0.5.0
128
- # @api private
129
- #
130
- # @see Hanami::Model::Coercer.load
131
- # @see http://rdoc.info/gems/hanami-utils/Hanami/Utils/Kernel#Float-class_method
132
- def self.load(value)
133
- Utils::Kernel.Float(value) unless value.nil?
134
- end
135
- end
136
-
137
- # Hash coercer
138
- #
139
- # @since 0.5.0
140
- # @api private
141
- #
142
- # @see Hanami::Model::Coercer
143
- class Hash < Coercer
144
- # Transform a value from the database into a Hash, unless nil
145
- #
146
- # @param value [Object] the object to coerce
147
- #
148
- # @return [Hash] the result of the coercion
149
- #
150
- # @raise [TypeError] if the value can't be coerced
151
- #
152
- # @since 0.5.0
153
- # @api private
154
- #
155
- # @see Hanami::Model::Coercer.load
156
- # @see http://rdoc.info/gems/hanami-utils/Hanami/Utils/Kernel#Hash-class_method
157
- def self.load(value)
158
- Utils::Kernel.Hash(value) unless value.nil?
159
- end
160
- end
161
-
162
- # Integer coercer
163
- #
164
- # @since 0.5.0
165
- # @api private
166
- #
167
- # @see Hanami::Model::Coercer
168
- class Integer < Coercer
169
- # Transform a value from the database into a Integer, unless nil
170
- #
171
- # @param value [Object] the object to coerce
172
- #
173
- # @return [Integer] the result of the coercion
174
- #
175
- # @raise [TypeError] if the value can't be coerced
176
- #
177
- # @since 0.5.0
178
- # @api private
179
- #
180
- # @see Hanami::Model::Coercer.load
181
- # @see http://rdoc.info/gems/hanami-utils/Hanami/Utils/Kernel#Integer-class_method
182
- def self.load(value)
183
- Utils::Kernel.Integer(value) unless value.nil?
184
- end
185
- end
186
-
187
- # BigDecimal coercer
188
- #
189
- # @since 0.5.0
190
- # @api private
191
- #
192
- # @see Hanami::Model::Coercer
193
- class BigDecimal < Coercer
194
- # Transform a value from the database into a BigDecimal, unless nil
195
- #
196
- # @param value [Object] the object to coerce
197
- #
198
- # @return [BigDecimal] the result of the coercion
199
- #
200
- # @raise [TypeError] if the value can't be coerced
201
- #
202
- # @since 0.5.0
203
- # @api private
204
- #
205
- # @see Hanami::Model::Coercer.load
206
- # @see http://rdoc.info/gems/hanami-utils/Hanami/Utils/Kernel#BigDecimal-class_method
207
- def self.load(value)
208
- Utils::Kernel.BigDecimal(value) unless value.nil?
209
- end
210
- end
211
-
212
- # Set coercer
213
- #
214
- # @since 0.5.0
215
- # @api private
216
- #
217
- # @see Hanami::Model::Coercer
218
- class Set < Coercer
219
- # Transform a value from the database into a Set, unless nil
220
- #
221
- # @param value [Object] the object to coerce
222
- #
223
- # @return [Set] the result of the coercion
224
- #
225
- # @raise [TypeError] if the value can't be coerced
226
- #
227
- # @since 0.5.0
228
- # @api private
229
- #
230
- # @see Hanami::Model::Coercer.load
231
- # @see http://rdoc.info/gems/hanami-utils/Hanami/Utils/Kernel#Set-class_method
232
- def self.load(value)
233
- Utils::Kernel.Set(value) unless value.nil?
234
- end
235
- end
236
-
237
- # String coercer
238
- #
239
- # @since 0.5.0
240
- # @api private
241
- #
242
- # @see Hanami::Model::Coercer
243
- class String < Coercer
244
- # Transform a value from the database into a String, unless nil
245
- #
246
- # @param value [Object] the object to coerce
247
- #
248
- # @return [String] the result of the coercion
249
- #
250
- # @raise [TypeError] if the value can't be coerced
251
- #
252
- # @since 0.5.0
253
- # @api private
254
- #
255
- # @see Hanami::Model::Coercer.load
256
- # @see http://rdoc.info/gems/hanami-utils/Hanami/Utils/Kernel#String-class_method
257
- def self.load(value)
258
- Utils::Kernel.String(value) unless value.nil?
259
- end
260
- end
261
-
262
- # Symbol coercer
263
- #
264
- # @since 0.5.0
265
- # @api private
266
- #
267
- # @see Hanami::Model::Coercer
268
- class Symbol < Coercer
269
- # Transform a value from the database into a Symbol, unless nil
270
- #
271
- # @param value [Object] the object to coerce
272
- #
273
- # @return [Symbol] the result of the coercion
274
- #
275
- # @raise [TypeError] if the value can't be coerced
276
- #
277
- # @since 0.5.0
278
- # @api private
279
- #
280
- # @see Hanami::Model::Coercer.load
281
- # @see http://rdoc.info/gems/hanami-utils/Hanami/Utils/Kernel#Symbol-class_method
282
- def self.load(value)
283
- Utils::Kernel.Symbol(value) unless value.nil?
284
- end
285
- end
286
-
287
- # Time coercer
288
- #
289
- # @since 0.5.0
290
- # @api private
291
- #
292
- # @see Hanami::Model::Coercer
293
- class Time < Coercer
294
- # Transform a value from the database into a Time, unless nil
295
- #
296
- # @param value [Object] the object to coerce
297
- #
298
- # @return [Time] the result of the coercion
299
- #
300
- # @raise [TypeError] if the value can't be coerced
301
- #
302
- # @since 0.5.0
303
- # @api private
304
- #
305
- # @see Hanami::Model::Coercer.load
306
- # @see http://rdoc.info/gems/hanami-utils/Hanami/Utils/Kernel#Time-class_method
307
- def self.load(value)
308
- Utils::Kernel.Time(value) unless value.nil?
309
- end
310
- end
311
- end
312
- end
313
- end
314
- end