Class: Torque::PostgreSQL::Attributes::Struct
- Defined in:
- lib/torque/postgresql/attributes/struct.rb
Defined Under Namespace
Classes: Uninitialized
Class Attribute Summary collapse
-
.strict ⇒ Object
writeonly
Sets the attribute strict.
Class Method Summary collapse
-
._default_attributes ⇒ Object
Declared properties without a default are uninitialized, so that they are absent from the document until they are written to.
-
.build_on(model, column, klass, default: nil, array: nil, delegate: nil, backfill: nil, strict: nil) ⇒ Object
Setup the struct column on the given model, adding the proper attribute type, default, validation, and delegations.
-
.include_on(klass, method_name = nil) ⇒ Object
Provide a method on the given class to setup which columns are backed by a struct class.
-
.strict? ⇒ Boolean
Whether properties that are not declared by the class are rejected.
Instance Method Summary collapse
-
#attribute_writer_missing(name, value) ⇒ Object
Properties that are not declared by the class are kept as they are, without any type, which is only allowed when the class is not strict.
Methods inherited from Base
#==, #[], #[]=, columns_hash, #empty?, encrypts, #hash, #inspect, #read_attribute_before_type_cast, #read_attribute_for_database, #to_h, #type_for_attribute
Class Attribute Details
.strict=(value) ⇒ Object (writeonly)
Sets the attribute strict
18 19 20 |
# File 'lib/torque/postgresql/attributes/struct.rb', line 18 def strict=(value) @strict = value end |
Class Method Details
._default_attributes ⇒ Object
Declared properties without a default are uninitialized, so that they are absent from the document until they are written to
30 31 32 33 34 35 |
# File 'lib/torque/postgresql/attributes/struct.rb', line 30 def _default_attributes @_struct_default_attributes ||= super.map do |attribute| next attribute if attribute.is_a?(ActiveModel::Attribute::UserProvidedDefault) Uninitialized.new(attribute.name, attribute.type) end end |
.build_on(model, column, klass, default: nil, array: nil, delegate: nil, backfill: nil, strict: nil) ⇒ Object
Setup the struct column on the given model, adding the proper attribute type, default, validation, and delegations
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/torque/postgresql/attributes/struct.rb', line 50 def build_on(model, column, klass, default: nil, array: nil, delegate: nil, backfill: nil, strict: nil) return unless model.table_exists? column = column.to_s has_encryption = model.respond_to?(:encrypted_attributes) && model.encrypted_attributes&.include?(column.to_sym) raise ArgumentError, <<~MSG.squish if has_encryption Unable to setup the struct column "#{column}" on #{model.name} because the column is encrypted. Encryption is supported on individual struct attributes instead. MSG info = model.columns_hash[column] return if info.nil? raise ArgumentError, <<~MSG.squish unless %i[json jsonb].include?(info.type) Unable to setup the struct column "#{column}" on #{model.name} because #{info.sql_type} columns cannot hold a document. MSG klass = klass.constantize if klass.is_a?(String) || klass.is_a?(Symbol) klass.strict = !!strict if !strict.nil? && klass.respond_to?(:strict=) type = if array Adapter::OID::StructList.new(klass, type: info.type, backfill: backfill) else Adapter::OID::Struct.new(klass, type: info.type, backfill: backfill) end type = Adapter::OID::StructSet.new(type) if info.array? # Defaults that can be composed from the record have to be resolved # on it, all the others are plain attribute defaults if default.is_a?(Proc) || default.is_a?(Symbol) model.attribute(column, type) resolve_default_on(model, column, default) else model.attribute(column, type, default: -> { default&.deep_dup || type.blank_document }) end Array.wrap(delegate).flat_map do |property| [property, "#{property}="] end.then do |delegations| model.delegate(*delegations, to: column) if delegations.any? end model.validates(column, nested: true, allow_blank: true) end |
.include_on(klass, method_name = nil) ⇒ Object
Provide a method on the given class to setup which columns are backed by a struct class
39 40 41 42 43 44 45 46 |
# File 'lib/torque/postgresql/attributes/struct.rb', line 39 def include_on(klass, method_name = nil) method_name ||= PostgreSQL.config.struct.base_method klass.define_singleton_method(method_name) do |column, struct_klass, **| Struct.build_on(self, column, struct_klass, **) rescue Interrupt # Not able to build the attribute, maybe pending migrations end end |
.strict? ⇒ Boolean
Whether properties that are not declared by the class are rejected
21 22 23 24 25 26 |
# File 'lib/torque/postgresql/attributes/struct.rb', line 21 def strict? return !!@strict if defined?(@strict) return !!superclass.strict? if superclass.respond_to?(:strict?) PostgreSQL.config.struct.default_strict end |
Instance Method Details
#attribute_writer_missing(name, value) ⇒ Object
Properties that are not declared by the class are kept as they are, without any type, which is only allowed when the class is not strict
124 125 126 127 128 129 130 131 |
# File 'lib/torque/postgresql/attributes/struct.rb', line 124 def attribute_writer_missing(name, value) return super if self.class.strict? name = name.to_s attribute = @attributes[name] if @attributes.key?(name) attribute ||= ActiveModel::Attribute.from_database(name, nil, ActiveModel::Type.default_value) @attributes[name] = attribute.with_value_from_user(value) end |