hanami-model 0.6.1 → 0.7.0

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