activeentity 0.0.1.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +42 -0
  3. data/README.md +145 -0
  4. data/Rakefile +29 -0
  5. data/lib/active_entity.rb +73 -0
  6. data/lib/active_entity/aggregations.rb +276 -0
  7. data/lib/active_entity/associations.rb +146 -0
  8. data/lib/active_entity/associations/embedded/association.rb +134 -0
  9. data/lib/active_entity/associations/embedded/builder/association.rb +100 -0
  10. data/lib/active_entity/associations/embedded/builder/collection_association.rb +69 -0
  11. data/lib/active_entity/associations/embedded/builder/embedded_in.rb +38 -0
  12. data/lib/active_entity/associations/embedded/builder/embeds_many.rb +13 -0
  13. data/lib/active_entity/associations/embedded/builder/embeds_one.rb +16 -0
  14. data/lib/active_entity/associations/embedded/builder/singular_association.rb +28 -0
  15. data/lib/active_entity/associations/embedded/collection_association.rb +188 -0
  16. data/lib/active_entity/associations/embedded/collection_proxy.rb +310 -0
  17. data/lib/active_entity/associations/embedded/embedded_in_association.rb +31 -0
  18. data/lib/active_entity/associations/embedded/embeds_many_association.rb +15 -0
  19. data/lib/active_entity/associations/embedded/embeds_one_association.rb +19 -0
  20. data/lib/active_entity/associations/embedded/singular_association.rb +35 -0
  21. data/lib/active_entity/attribute_assignment.rb +85 -0
  22. data/lib/active_entity/attribute_decorators.rb +90 -0
  23. data/lib/active_entity/attribute_methods.rb +330 -0
  24. data/lib/active_entity/attribute_methods/before_type_cast.rb +78 -0
  25. data/lib/active_entity/attribute_methods/primary_key.rb +98 -0
  26. data/lib/active_entity/attribute_methods/query.rb +35 -0
  27. data/lib/active_entity/attribute_methods/read.rb +47 -0
  28. data/lib/active_entity/attribute_methods/serialization.rb +90 -0
  29. data/lib/active_entity/attribute_methods/time_zone_conversion.rb +91 -0
  30. data/lib/active_entity/attribute_methods/write.rb +63 -0
  31. data/lib/active_entity/attributes.rb +165 -0
  32. data/lib/active_entity/base.rb +303 -0
  33. data/lib/active_entity/coders/json.rb +15 -0
  34. data/lib/active_entity/coders/yaml_column.rb +50 -0
  35. data/lib/active_entity/core.rb +281 -0
  36. data/lib/active_entity/define_callbacks.rb +17 -0
  37. data/lib/active_entity/enum.rb +234 -0
  38. data/lib/active_entity/errors.rb +80 -0
  39. data/lib/active_entity/gem_version.rb +17 -0
  40. data/lib/active_entity/inheritance.rb +278 -0
  41. data/lib/active_entity/integration.rb +78 -0
  42. data/lib/active_entity/locale/en.yml +45 -0
  43. data/lib/active_entity/model_schema.rb +115 -0
  44. data/lib/active_entity/nested_attributes.rb +592 -0
  45. data/lib/active_entity/readonly_attributes.rb +47 -0
  46. data/lib/active_entity/reflection.rb +441 -0
  47. data/lib/active_entity/serialization.rb +25 -0
  48. data/lib/active_entity/store.rb +242 -0
  49. data/lib/active_entity/translation.rb +24 -0
  50. data/lib/active_entity/type.rb +73 -0
  51. data/lib/active_entity/type/date.rb +9 -0
  52. data/lib/active_entity/type/date_time.rb +9 -0
  53. data/lib/active_entity/type/decimal_without_scale.rb +15 -0
  54. data/lib/active_entity/type/hash_lookup_type_map.rb +25 -0
  55. data/lib/active_entity/type/internal/timezone.rb +17 -0
  56. data/lib/active_entity/type/json.rb +30 -0
  57. data/lib/active_entity/type/modifiers/array.rb +72 -0
  58. data/lib/active_entity/type/registry.rb +92 -0
  59. data/lib/active_entity/type/serialized.rb +71 -0
  60. data/lib/active_entity/type/text.rb +11 -0
  61. data/lib/active_entity/type/time.rb +21 -0
  62. data/lib/active_entity/type/type_map.rb +62 -0
  63. data/lib/active_entity/type/unsigned_integer.rb +17 -0
  64. data/lib/active_entity/validate_embedded_association.rb +305 -0
  65. data/lib/active_entity/validations.rb +50 -0
  66. data/lib/active_entity/validations/absence.rb +25 -0
  67. data/lib/active_entity/validations/associated.rb +60 -0
  68. data/lib/active_entity/validations/length.rb +26 -0
  69. data/lib/active_entity/validations/presence.rb +68 -0
  70. data/lib/active_entity/validations/subset.rb +76 -0
  71. data/lib/active_entity/validations/uniqueness_in_embedding.rb +99 -0
  72. data/lib/active_entity/version.rb +10 -0
  73. data/lib/tasks/active_entity_tasks.rake +6 -0
  74. metadata +155 -0
@@ -0,0 +1,165 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_model/attribute/user_provided_default"
4
+
5
+ module ActiveEntity
6
+ # See ActiveEntity::Attributes::ClassMethods for documentation
7
+ module Attributes
8
+ extend ActiveSupport::Concern
9
+
10
+ included do
11
+ class_attribute :attributes_to_define_after_schema_loads, instance_accessor: false, default: {} # :internal:
12
+ end
13
+
14
+ module ClassMethods
15
+ # Defines an attribute with a type on this model.
16
+ #
17
+ # +name+ The name of the methods to define attribute methods for, and the
18
+ # column which this will persist to.
19
+ #
20
+ # +cast_type+ A symbol such as +:string+ or +:integer+, or a type object
21
+ # to be used for this attribute. See the examples below for more
22
+ # information about providing custom type objects.
23
+ #
24
+ # ==== Options
25
+ #
26
+ # The following options are accepted:
27
+ #
28
+ # +default+ The default value to use when no value is provided. If this option
29
+ # is not passed, the previous default value (if any) will be used.
30
+ # Otherwise, the default will be +nil+.
31
+ #
32
+ # +array+ Specifies that the type should be an array (see the
33
+ # examples below).
34
+ #
35
+ # ==== Examples
36
+ #
37
+ # # app/models/my_model.rb
38
+ # class MyModel < ActiveEntity::Base
39
+ # attribute :my_string, :string
40
+ # attribute :my_int_array, :integer, array: true
41
+ # attribute :my_float_range, :float, range: true
42
+ # end
43
+ #
44
+ # model = MyModel.new(
45
+ # my_string: "string",
46
+ # my_int_array: ["1", "2", "3"],
47
+ # my_float_range: "[1,3.5]",
48
+ # )
49
+ # model.attributes
50
+ # # =>
51
+ # {
52
+ # my_string: "string",
53
+ # my_int_array: [1, 2, 3],
54
+ # my_float_range: 1.0..3.5
55
+ # }
56
+ #
57
+ # ==== Creating Custom Types
58
+ #
59
+ # Users may also define their own custom types, as long as they respond
60
+ # to the methods defined on the value type. The method +deserialize+ or
61
+ # +cast+ will be called on your type object, with raw input from the
62
+ # database or from your controllers. See ActiveModel::Type::Value for the
63
+ # expected API. It is recommended that your type objects inherit from an
64
+ # existing type, or from ActiveEntity::Type::Value
65
+ #
66
+ # class MoneyType < ActiveEntity::Type::Integer
67
+ # def cast(value)
68
+ # if !value.kind_of?(Numeric) && value.include?('$')
69
+ # price_in_dollars = value.gsub(/\$/, '').to_f
70
+ # super(price_in_dollars * 100)
71
+ # else
72
+ # super
73
+ # end
74
+ # end
75
+ # end
76
+ #
77
+ # # config/initializers/types.rb
78
+ # ActiveEntity::Type.register(:money, MoneyType)
79
+ #
80
+ # # app/models/store_listing.rb
81
+ # class StoreListing < ActiveEntity::Base
82
+ # attribute :price_in_cents, :money
83
+ # end
84
+ #
85
+ # store_listing = StoreListing.new(price_in_cents: '$10.00')
86
+ # store_listing.price_in_cents # => 1000
87
+ #
88
+ # For more details on creating custom types, see the documentation for
89
+ # ActiveModel::Type::Value. For more details on registering your types
90
+ # to be referenced by a symbol, see ActiveEntity::Type.register. You can
91
+ # also pass a type object directly, in place of a symbol.
92
+ #
93
+ # ==== Dirty Tracking
94
+ #
95
+ # The type of an attribute is given the opportunity to change how dirty
96
+ # tracking is performed. The methods +changed?+ and +changed_in_place?+
97
+ # will be called from ActiveModel::Dirty. See the documentation for those
98
+ # methods in ActiveModel::Type::Value for more details.
99
+ def attribute(name, cast_type = Type::Value.new, **options)
100
+ name = name.to_s
101
+ reload_schema_from_cache
102
+
103
+ self.attributes_to_define_after_schema_loads =
104
+ attributes_to_define_after_schema_loads.merge(
105
+ name => [cast_type, options]
106
+ )
107
+ end
108
+
109
+ # This is the low level API which sits beneath +attribute+. It only
110
+ # accepts type objects, and will do its work immediately instead of
111
+ # waiting for the schema to load. Automatic schema detection and
112
+ # ClassMethods#attribute both call this under the hood. While this method
113
+ # is provided so it can be used by plugin authors, application code
114
+ # should probably use ClassMethods#attribute.
115
+ #
116
+ # +name+ The name of the attribute being defined. Expected to be a +String+.
117
+ #
118
+ # +cast_type+ The type object to use for this attribute.
119
+ #
120
+ # +default+ The default value to use when no value is provided. If this option
121
+ # is not passed, the previous default value (if any) will be used.
122
+ # Otherwise, the default will be +nil+. A proc can also be passed, and
123
+ # will be called once each time a new value is needed.
124
+ def define_attribute(
125
+ name,
126
+ cast_type,
127
+ default: NO_DEFAULT_PROVIDED
128
+ )
129
+ attribute_types[name] = cast_type
130
+ define_default_attribute(name, default, cast_type)
131
+ end
132
+
133
+ def load_schema! # :nodoc:
134
+ super
135
+ attributes_to_define_after_schema_loads.each do |name, (type, options)|
136
+ if type.is_a?(Symbol)
137
+ type = ActiveEntity::Type.lookup(type, **options.except(:default))
138
+ end
139
+
140
+ define_attribute(name, type, **options.slice(:default))
141
+ end
142
+ end
143
+
144
+ private
145
+
146
+ NO_DEFAULT_PROVIDED = Object.new # :nodoc:
147
+ private_constant :NO_DEFAULT_PROVIDED
148
+
149
+ def define_default_attribute(name, value, type)
150
+ default_attribute =
151
+ if value == NO_DEFAULT_PROVIDED
152
+ _default_attributes[name].with_type(type)
153
+ else
154
+ ActiveModel::Attribute::UserProvidedDefault.new(
155
+ name,
156
+ value,
157
+ type,
158
+ _default_attributes.fetch(name.to_s) { nil },
159
+ )
160
+ end
161
+ _default_attributes[name] = default_attribute
162
+ end
163
+ end
164
+ end
165
+ end
@@ -0,0 +1,303 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+ require "active_support/benchmarkable"
5
+ require "active_support/dependencies"
6
+ require "active_support/descendants_tracker"
7
+ require "active_support/time"
8
+ require "active_support/core_ext/module/attribute_accessors"
9
+ require "active_support/core_ext/array/extract_options"
10
+ require "active_support/core_ext/hash/deep_merge"
11
+ require "active_support/core_ext/hash/slice"
12
+ require "active_support/core_ext/string/behavior"
13
+ require "active_support/core_ext/kernel/singleton_class"
14
+ require "active_support/core_ext/module/introspection"
15
+ require "active_support/core_ext/object/duplicable"
16
+ require "active_support/core_ext/class/subclasses"
17
+ require "active_entity/attribute_decorators"
18
+ require "active_entity/define_callbacks"
19
+ require "active_entity/errors"
20
+ require "active_entity/attributes"
21
+
22
+ module ActiveEntity #:nodoc:
23
+ # = Active Entity
24
+ #
25
+ # Active Entity objects don't specify their attributes directly, but rather infer them from
26
+ # the table definition with which they're linked. Adding, removing, and changing attributes
27
+ # and their type is done directly in the database. Any change is instantly reflected in the
28
+ # Active Entity objects. The mapping that binds a given Active Entity class to a certain
29
+ # database table will happen automatically in most common cases, but can be overwritten for the uncommon ones.
30
+ #
31
+ # See the mapping rules in table_name and the full example in link:files/activerecord/README_rdoc.html for more insight.
32
+ #
33
+ # == Creation
34
+ #
35
+ # Active Entitys accept constructor parameters either in a hash or as a block. The hash
36
+ # method is especially useful when you're receiving the data from somewhere else, like an
37
+ # HTTP request. It works like this:
38
+ #
39
+ # user = User.new(name: "David", occupation: "Code Artist")
40
+ # user.name # => "David"
41
+ #
42
+ # You can also use block initialization:
43
+ #
44
+ # user = User.new do |u|
45
+ # u.name = "David"
46
+ # u.occupation = "Code Artist"
47
+ # end
48
+ #
49
+ # And of course you can just create a bare object and specify the attributes after the fact:
50
+ #
51
+ # user = User.new
52
+ # user.name = "David"
53
+ # user.occupation = "Code Artist"
54
+ #
55
+ # == Conditions
56
+ #
57
+ # Conditions can either be specified as a string, array, or hash representing the WHERE-part of an SQL statement.
58
+ # The array form is to be used when the condition input is tainted and requires sanitization. The string form can
59
+ # be used for statements that don't involve tainted data. The hash form works much like the array form, except
60
+ # only equality and range is possible. Examples:
61
+ #
62
+ # class User < ActiveEntity::Base
63
+ # def self.authenticate_unsafely(user_name, password)
64
+ # where("user_name = '#{user_name}' AND password = '#{password}'").first
65
+ # end
66
+ #
67
+ # def self.authenticate_safely(user_name, password)
68
+ # where("user_name = ? AND password = ?", user_name, password).first
69
+ # end
70
+ #
71
+ # def self.authenticate_safely_simply(user_name, password)
72
+ # where(user_name: user_name, password: password).first
73
+ # end
74
+ # end
75
+ #
76
+ # The <tt>authenticate_unsafely</tt> method inserts the parameters directly into the query
77
+ # and is thus susceptible to SQL-injection attacks if the <tt>user_name</tt> and +password+
78
+ # parameters come directly from an HTTP request. The <tt>authenticate_safely</tt> and
79
+ # <tt>authenticate_safely_simply</tt> both will sanitize the <tt>user_name</tt> and +password+
80
+ # before inserting them in the query, which will ensure that an attacker can't escape the
81
+ # query and fake the login (or worse).
82
+ #
83
+ # When using multiple parameters in the conditions, it can easily become hard to read exactly
84
+ # what the fourth or fifth question mark is supposed to represent. In those cases, you can
85
+ # resort to named bind variables instead. That's done by replacing the question marks with
86
+ # symbols and supplying a hash with values for the matching symbol keys:
87
+ #
88
+ # Company.where(
89
+ # "id = :id AND name = :name AND division = :division AND created_at > :accounting_date",
90
+ # { id: 3, name: "37signals", division: "First", accounting_date: '2005-01-01' }
91
+ # ).first
92
+ #
93
+ # Similarly, a simple hash without a statement will generate conditions based on equality with the SQL AND
94
+ # operator. For instance:
95
+ #
96
+ # Student.where(first_name: "Harvey", status: 1)
97
+ # Student.where(params[:student])
98
+ #
99
+ # A range may be used in the hash to use the SQL BETWEEN operator:
100
+ #
101
+ # Student.where(grade: 9..12)
102
+ #
103
+ # An array may be used in the hash to use the SQL IN operator:
104
+ #
105
+ # Student.where(grade: [9,11,12])
106
+ #
107
+ # When joining tables, nested hashes or keys written in the form 'table_name.column_name'
108
+ # can be used to qualify the table name of a particular condition. For instance:
109
+ #
110
+ # Student.joins(:schools).where(schools: { category: 'public' })
111
+ # Student.joins(:schools).where('schools.category' => 'public' )
112
+ #
113
+ # == Overwriting default accessors
114
+ #
115
+ # All column values are automatically available through basic accessors on the Active Entity
116
+ # object, but sometimes you want to specialize this behavior. This can be done by overwriting
117
+ # the default accessors (using the same name as the attribute) and calling
118
+ # +super+ to actually change things.
119
+ #
120
+ # class Song < ActiveEntity::Base
121
+ # # Uses an integer of seconds to hold the length of the song
122
+ #
123
+ # def length=(minutes)
124
+ # super(minutes.to_i * 60)
125
+ # end
126
+ #
127
+ # def length
128
+ # super / 60
129
+ # end
130
+ # end
131
+ #
132
+ # == Attribute query methods
133
+ #
134
+ # In addition to the basic accessors, query methods are also automatically available on the Active Entity object.
135
+ # Query methods allow you to test whether an attribute value is present.
136
+ # Additionally, when dealing with numeric values, a query method will return false if the value is zero.
137
+ #
138
+ # For example, an Active Entity User with the <tt>name</tt> attribute has a <tt>name?</tt> method that you can call
139
+ # to determine whether the user has a name:
140
+ #
141
+ # user = User.new(name: "David")
142
+ # user.name? # => true
143
+ #
144
+ # anonymous = User.new(name: "")
145
+ # anonymous.name? # => false
146
+ #
147
+ # == Accessing attributes before they have been typecasted
148
+ #
149
+ # Sometimes you want to be able to read the raw attribute data without having the column-determined
150
+ # typecast run its course first. That can be done by using the <tt><attribute>_before_type_cast</tt>
151
+ # accessors that all attributes have. For example, if your Account model has a <tt>balance</tt> attribute,
152
+ # you can call <tt>account.balance_before_type_cast</tt> or <tt>account.id_before_type_cast</tt>.
153
+ #
154
+ # This is especially useful in validation situations where the user might supply a string for an
155
+ # integer field and you want to display the original string back in an error message. Accessing the
156
+ # attribute normally would typecast the string to 0, which isn't what you want.
157
+ #
158
+ # == Dynamic attribute-based finders
159
+ #
160
+ # Dynamic attribute-based finders are a mildly deprecated way of getting (and/or creating) objects
161
+ # by simple queries without turning to SQL. They work by appending the name of an attribute
162
+ # to <tt>find_by_</tt> like <tt>Person.find_by_user_name</tt>.
163
+ # Instead of writing <tt>Person.find_by(user_name: user_name)</tt>, you can use
164
+ # <tt>Person.find_by_user_name(user_name)</tt>.
165
+ #
166
+ # It's possible to add an exclamation point (!) on the end of the dynamic finders to get them to raise an
167
+ # ActiveEntity::RecordNotFound error if they do not return any records,
168
+ # like <tt>Person.find_by_last_name!</tt>.
169
+ #
170
+ # It's also possible to use multiple attributes in the same <tt>find_by_</tt> by separating them with
171
+ # "_and_".
172
+ #
173
+ # Person.find_by(user_name: user_name, password: password)
174
+ # Person.find_by_user_name_and_password(user_name, password) # with dynamic finder
175
+ #
176
+ # It's even possible to call these dynamic finder methods on relations and named scopes.
177
+ #
178
+ # Payment.order("created_on").find_by_amount(50)
179
+ #
180
+ # == Saving arrays, hashes, and other non-mappable objects in text columns
181
+ #
182
+ # Active Entity can serialize any object in text columns using YAML. To do so, you must
183
+ # specify this with a call to the class method
184
+ # {serialize}[rdoc-ref:AttributeMethods::Serialization::ClassMethods#serialize].
185
+ # This makes it possible to store arrays, hashes, and other non-mappable objects without doing
186
+ # any additional work.
187
+ #
188
+ # class User < ActiveEntity::Base
189
+ # serialize :preferences
190
+ # end
191
+ #
192
+ # user = User.create(preferences: { "background" => "black", "display" => large })
193
+ # User.find(user.id).preferences # => { "background" => "black", "display" => large }
194
+ #
195
+ # You can also specify a class option as the second parameter that'll raise an exception
196
+ # if a serialized object is retrieved as a descendant of a class not in the hierarchy.
197
+ #
198
+ # class User < ActiveEntity::Base
199
+ # serialize :preferences, Hash
200
+ # end
201
+ #
202
+ # user = User.create(preferences: %w( one two three ))
203
+ # User.find(user.id).preferences # raises SerializationTypeMismatch
204
+ #
205
+ # When you specify a class option, the default value for that attribute will be a new
206
+ # instance of that class.
207
+ #
208
+ # class User < ActiveEntity::Base
209
+ # serialize :preferences, OpenStruct
210
+ # end
211
+ #
212
+ # user = User.new
213
+ # user.preferences.theme_color = "red"
214
+ #
215
+ #
216
+ # == Single table inheritance
217
+ #
218
+ # Active Entity allows inheritance by storing the name of the class in a
219
+ # column that is named "type" by default. See ActiveEntity::Inheritance for
220
+ # more details.
221
+ #
222
+ # == Connection to multiple databases in different models
223
+ #
224
+ # Connections are usually created through
225
+ # {ActiveEntity::Base.establish_connection}[rdoc-ref:ConnectionHandling#establish_connection] and retrieved
226
+ # by ActiveEntity::Base.connection. All classes inheriting from ActiveEntity::Base will use this
227
+ # connection. But you can also set a class-specific connection. For example, if Course is an
228
+ # ActiveEntity::Base, but resides in a different database, you can just say <tt>Course.establish_connection</tt>
229
+ # and Course and all of its subclasses will use this connection instead.
230
+ #
231
+ # This feature is implemented by keeping a connection pool in ActiveEntity::Base that is
232
+ # a hash indexed by the class. If a connection is requested, the
233
+ # {ActiveEntity::Base.retrieve_connection}[rdoc-ref:ConnectionHandling#retrieve_connection] method
234
+ # will go up the class-hierarchy until a connection is found in the connection pool.
235
+ #
236
+ # == Exceptions
237
+ #
238
+ # * ActiveEntityError - Generic error class and superclass of all other errors raised by Active Entity.
239
+ # * AdapterNotSpecified - The configuration hash used in
240
+ # {ActiveEntity::Base.establish_connection}[rdoc-ref:ConnectionHandling#establish_connection]
241
+ # didn't include an <tt>:adapter</tt> key.
242
+ # * AdapterNotFound - The <tt>:adapter</tt> key used in
243
+ # {ActiveEntity::Base.establish_connection}[rdoc-ref:ConnectionHandling#establish_connection]
244
+ # specified a non-existent adapter
245
+ # (or a bad spelling of an existing one).
246
+ # * AssociationTypeMismatch - The object assigned to the association wasn't of the type
247
+ # specified in the association definition.
248
+ # * AttributeAssignmentError - An error occurred while doing a mass assignment through the
249
+ # {ActiveEntity::Base#attributes=}[rdoc-ref:AttributeAssignment#attributes=] method.
250
+ # You can inspect the +attribute+ property of the exception object to determine which attribute
251
+ # triggered the error.
252
+ # * ConnectionNotEstablished - No connection has been established.
253
+ # Use {ActiveEntity::Base.establish_connection}[rdoc-ref:ConnectionHandling#establish_connection] before querying.
254
+ # * MultiparameterAssignmentErrors - Collection of errors that occurred during a mass assignment using the
255
+ # {ActiveEntity::Base#attributes=}[rdoc-ref:AttributeAssignment#attributes=] method.
256
+ # The +errors+ property of this exception contains an array of
257
+ # AttributeAssignmentError
258
+ # objects that should be inspected to determine which attributes triggered the errors.
259
+ # * RecordInvalid - raised by {ActiveEntity::Base#save!}[rdoc-ref:Persistence#save!] and
260
+ # {ActiveEntity::Base.create!}[rdoc-ref:Persistence::ClassMethods#create!]
261
+ # when the record is invalid.
262
+ # * RecordNotFound - No record responded to the {ActiveEntity::Base.find}[rdoc-ref:FinderMethods#find] method.
263
+ # Either the row with the given ID doesn't exist or the row didn't meet the additional restrictions.
264
+ # Some {ActiveEntity::Base.find}[rdoc-ref:FinderMethods#find] calls do not raise this exception to signal
265
+ # nothing was found, please check its documentation for further details.
266
+ # * SerializationTypeMismatch - The serialized object wasn't of the class specified as the second parameter.
267
+ # * StatementInvalid - The database server rejected the SQL statement. The precise error is added in the message.
268
+ #
269
+ # *Note*: The attributes listed are class-level attributes (accessible from both the class and instance level).
270
+ # So it's possible to assign a logger to the class through <tt>Base.logger=</tt> which will then be used by all
271
+ # instances in the current object space.
272
+ class Base
273
+ extend ActiveModel::Naming
274
+
275
+ extend ActiveSupport::Benchmarkable
276
+ extend ActiveSupport::DescendantsTracker
277
+
278
+ extend Translation
279
+ extend Enum
280
+ extend Aggregations::ClassMethods
281
+
282
+ include Core
283
+ include ReadonlyAttributes
284
+ include ModelSchema
285
+ include Inheritance
286
+ include AttributeAssignment
287
+ include ActiveModel::Conversion
288
+ include Integration
289
+ include Validations
290
+ include Attributes
291
+ include AttributeDecorators
292
+ include DefineCallbacks
293
+ include AttributeMethods
294
+ include Associations
295
+ include ValidateEmbeddedAssociation
296
+ include NestedAttributes
297
+ include Reflection
298
+ include Serialization
299
+ include Store
300
+ end
301
+
302
+ ActiveSupport.run_load_hooks(:active_entity, Base)
303
+ end