torque-postgresql 0.2.16 → 1.0.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.
- checksums.yaml +4 -4
- data/README.rdoc +76 -3
- data/lib/torque-postgresql.rb +1 -0
- data/lib/torque/postgresql.rb +6 -0
- data/lib/torque/postgresql/adapter.rb +2 -4
- data/lib/torque/postgresql/adapter/database_statements.rb +23 -9
- data/lib/torque/postgresql/adapter/oid.rb +12 -1
- data/lib/torque/postgresql/adapter/oid/box.rb +28 -0
- data/lib/torque/postgresql/adapter/oid/circle.rb +37 -0
- data/lib/torque/postgresql/adapter/oid/enum.rb +9 -5
- data/lib/torque/postgresql/adapter/oid/enum_set.rb +44 -0
- data/lib/torque/postgresql/adapter/oid/line.rb +59 -0
- data/lib/torque/postgresql/adapter/oid/range.rb +52 -0
- data/lib/torque/postgresql/adapter/oid/segment.rb +73 -0
- data/lib/torque/postgresql/adapter/quoting.rb +21 -0
- data/lib/torque/postgresql/adapter/schema_definitions.rb +7 -0
- data/lib/torque/postgresql/adapter/schema_dumper.rb +10 -1
- data/lib/torque/postgresql/arel.rb +3 -0
- data/lib/torque/postgresql/arel/infix_operation.rb +42 -0
- data/lib/torque/postgresql/arel/nodes.rb +32 -0
- data/lib/torque/postgresql/arel/operations.rb +18 -0
- data/lib/torque/postgresql/arel/visitors.rb +28 -2
- data/lib/torque/postgresql/associations.rb +8 -0
- data/lib/torque/postgresql/associations/association.rb +30 -0
- data/lib/torque/postgresql/associations/association_scope.rb +116 -0
- data/lib/torque/postgresql/associations/belongs_to_many_association.rb +117 -0
- data/lib/torque/postgresql/associations/builder.rb +2 -0
- data/lib/torque/postgresql/associations/builder/belongs_to_many.rb +121 -0
- data/lib/torque/postgresql/associations/builder/has_many.rb +15 -0
- data/lib/torque/postgresql/associations/join_dependency/join_association.rb +15 -0
- data/lib/torque/postgresql/associations/preloader.rb +25 -0
- data/lib/torque/postgresql/associations/preloader/association.rb +64 -0
- data/lib/torque/postgresql/attributes.rb +2 -0
- data/lib/torque/postgresql/attributes/builder.rb +1 -0
- data/lib/torque/postgresql/attributes/builder/enum.rb +23 -15
- data/lib/torque/postgresql/attributes/builder/period.rb +452 -0
- data/lib/torque/postgresql/attributes/enum.rb +11 -8
- data/lib/torque/postgresql/attributes/enum_set.rb +256 -0
- data/lib/torque/postgresql/attributes/lazy.rb +1 -1
- data/lib/torque/postgresql/attributes/period.rb +31 -0
- data/lib/torque/postgresql/attributes/type_map.rb +3 -5
- data/lib/torque/postgresql/autosave_association.rb +40 -0
- data/lib/torque/postgresql/auxiliary_statement.rb +201 -198
- data/lib/torque/postgresql/auxiliary_statement/settings.rb +20 -12
- data/lib/torque/postgresql/base.rb +161 -2
- data/lib/torque/postgresql/config.rb +91 -9
- data/lib/torque/postgresql/geometry_builder.rb +92 -0
- data/lib/torque/postgresql/i18n.rb +1 -1
- data/lib/torque/postgresql/railtie.rb +18 -5
- data/lib/torque/postgresql/reflection.rb +21 -0
- data/lib/torque/postgresql/reflection/abstract_reflection.rb +109 -0
- data/lib/torque/postgresql/reflection/association_reflection.rb +30 -0
- data/lib/torque/postgresql/reflection/belongs_to_many_reflection.rb +44 -0
- data/lib/torque/postgresql/reflection/has_many_reflection.rb +13 -0
- data/lib/torque/postgresql/reflection/runtime_reflection.rb +12 -0
- data/lib/torque/postgresql/reflection/through_reflection.rb +11 -0
- data/lib/torque/postgresql/relation.rb +11 -10
- data/lib/torque/postgresql/relation/auxiliary_statement.rb +11 -18
- data/lib/torque/postgresql/relation/inheritance.rb +2 -2
- data/lib/torque/postgresql/relation/merger.rb +11 -7
- data/lib/torque/postgresql/schema_cache.rb +1 -1
- data/lib/torque/postgresql/version.rb +1 -1
- data/lib/torque/range.rb +40 -0
- metadata +41 -9
@@ -2,18 +2,29 @@ module Torque
|
|
2
2
|
module PostgreSQL
|
3
3
|
class AuxiliaryStatement
|
4
4
|
class Settings < Collector.new(:attributes, :join, :join_type, :query, :requires,
|
5
|
-
|
5
|
+
:polymorphic, :through)
|
6
6
|
|
7
|
-
attr_reader :source
|
8
|
-
|
7
|
+
attr_reader :base, :source
|
8
|
+
alias_method :select, :attributes
|
9
|
+
alias_method :cte, :source
|
9
10
|
|
10
|
-
delegate :base, :base_name, :base_table, :table, :table_name, to: :@source
|
11
11
|
delegate :relation_query?, to: Torque::PostgreSQL::AuxiliaryStatement
|
12
|
+
delegate :table, :table_name, to: :@source
|
13
|
+
delegate :sql, to: ::Arel
|
12
14
|
|
13
|
-
def initialize(source)
|
15
|
+
def initialize(base, source)
|
16
|
+
@base = base
|
14
17
|
@source = source
|
15
18
|
end
|
16
19
|
|
20
|
+
def base_name
|
21
|
+
@base.name
|
22
|
+
end
|
23
|
+
|
24
|
+
def base_table
|
25
|
+
@base.arel_table
|
26
|
+
end
|
27
|
+
|
17
28
|
# Get the arel version of the table set on the query
|
18
29
|
def query_table
|
19
30
|
raise StandardError, 'The query is not defined yet' if query.nil?
|
@@ -28,11 +39,6 @@ module Torque
|
|
28
39
|
|
29
40
|
alias column col
|
30
41
|
|
31
|
-
# Grant an easy access to arel sql literal
|
32
|
-
def sql(string)
|
33
|
-
::Arel::Nodes::SqlLiteral.new(string)
|
34
|
-
end
|
35
|
-
|
36
42
|
# There are two ways of setting the query:
|
37
43
|
# - A simple relation based on a Model
|
38
44
|
# - A Arel-based select manager
|
@@ -48,11 +54,13 @@ module Torque
|
|
48
54
|
end
|
49
55
|
|
50
56
|
valid_type = command.respond_to?(:call) || command.is_a?(String)
|
51
|
-
|
57
|
+
|
58
|
+
raise ArgumentError, <<-MSG.squish if command.nil?
|
52
59
|
To use proc or string as query, you need to provide the table name
|
53
60
|
as the first argument
|
54
61
|
MSG
|
55
|
-
|
62
|
+
|
63
|
+
raise ArgumentError, <<-MSG.squish unless valid_type
|
56
64
|
Only relation, string and proc are valid object types for query,
|
57
65
|
#{command.inspect} given.
|
58
66
|
MSG
|
@@ -3,6 +3,10 @@ module Torque
|
|
3
3
|
module Base
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
|
+
included do
|
7
|
+
mattr_accessor :belongs_to_many_required_by_default, instance_accessor: false
|
8
|
+
end
|
9
|
+
|
6
10
|
module ClassMethods
|
7
11
|
delegate :distinct_on, :with, :itself_only, :cast_records, to: :all
|
8
12
|
|
@@ -12,7 +16,8 @@ module Torque
|
|
12
16
|
super
|
13
17
|
|
14
18
|
subclass.class_attribute(:auxiliary_statements_list)
|
15
|
-
subclass.auxiliary_statements_list =
|
19
|
+
subclass.auxiliary_statements_list = {}
|
20
|
+
|
16
21
|
record_class = ActiveRecord::Relation._record_class_attribute
|
17
22
|
|
18
23
|
# Define helper methods to return the class of the given records
|
@@ -44,6 +49,160 @@ module Torque
|
|
44
49
|
end
|
45
50
|
end
|
46
51
|
|
52
|
+
# Specifies a one-to-many association. The following methods for
|
53
|
+
# retrieval and query of collections of associated objects will be
|
54
|
+
# added:
|
55
|
+
#
|
56
|
+
# +collection+ is a placeholder for the symbol passed as the +name+
|
57
|
+
# argument, so <tt>belongs_to_many :tags</tt> would add among others
|
58
|
+
# <tt>tags.empty?</tt>.
|
59
|
+
#
|
60
|
+
# [collection]
|
61
|
+
# Returns a Relation of all the associated objects.
|
62
|
+
# An empty Relation is returned if none are found.
|
63
|
+
# [collection<<(object, ...)]
|
64
|
+
# Adds one or more objects to the collection by adding their ids to
|
65
|
+
# the array of ids on the parent object.
|
66
|
+
# Note that this operation instantly fires update SQL without waiting
|
67
|
+
# for the save or update call on the parent object, unless the parent
|
68
|
+
# object is a new record.
|
69
|
+
# This will also run validations and callbacks of associated
|
70
|
+
# object(s).
|
71
|
+
# [collection.delete(object, ...)]
|
72
|
+
# Removes one or more objects from the collection by removing their
|
73
|
+
# ids from the list on the parent object.
|
74
|
+
# Objects will be in addition destroyed if they're associated with
|
75
|
+
# <tt>dependent: :destroy</tt>, and deleted if they're associated
|
76
|
+
# with <tt>dependent: :delete_all</tt>.
|
77
|
+
# [collection.destroy(object, ...)]
|
78
|
+
# Removes one or more objects from the collection by running
|
79
|
+
# <tt>destroy</tt> on each record, regardless of any dependent option,
|
80
|
+
# ensuring callbacks are run. They will also be removed from the list
|
81
|
+
# on the parent object.
|
82
|
+
# [collection=objects]
|
83
|
+
# Replaces the collections content by deleting and adding objects as
|
84
|
+
# appropriate.
|
85
|
+
# [collection_singular_ids]
|
86
|
+
# Returns an array of the associated objects' ids
|
87
|
+
# [collection_singular_ids=ids]
|
88
|
+
# Replace the collection with the objects identified by the primary
|
89
|
+
# keys in +ids+. This method loads the models and calls
|
90
|
+
# <tt>collection=</tt>. See above.
|
91
|
+
# [collection.clear]
|
92
|
+
# Removes every object from the collection. This destroys the
|
93
|
+
# associated objects if they are associated with
|
94
|
+
# <tt>dependent: :destroy</tt>, deletes them directly from the
|
95
|
+
# database if <tt>dependent: :delete_all</tt>, otherwise just remove
|
96
|
+
# them from the list on the parent object.
|
97
|
+
# [collection.empty?]
|
98
|
+
# Returns +true+ if there are no associated objects.
|
99
|
+
# [collection.size]
|
100
|
+
# Returns the number of associated objects.
|
101
|
+
# [collection.find(...)]
|
102
|
+
# Finds an associated object according to the same rules as
|
103
|
+
# ActiveRecord::FinderMethods#find.
|
104
|
+
# [collection.exists?(...)]
|
105
|
+
# Checks whether an associated object with the given conditions exists.
|
106
|
+
# Uses the same rules as ActiveRecord::FinderMethods#exists?.
|
107
|
+
# [collection.build(attributes = {}, ...)]
|
108
|
+
# Returns one or more new objects of the collection type that have
|
109
|
+
# been instantiated with +attributes+ and linked to this object by
|
110
|
+
# adding its +id+ to the list after saving.
|
111
|
+
# [collection.create(attributes = {})]
|
112
|
+
# Returns a new object of the collection type that has been
|
113
|
+
# instantiated with +attributes+, linked to this object by adding its
|
114
|
+
# +id+ to the list after performing the save (if it passed the
|
115
|
+
# validation).
|
116
|
+
# [collection.create!(attributes = {})]
|
117
|
+
# Does the same as <tt>collection.create</tt>, but raises
|
118
|
+
# ActiveRecord::RecordInvalid if the record is invalid.
|
119
|
+
# [collection.reload]
|
120
|
+
# Returns a Relation of all of the associated objects, forcing a
|
121
|
+
# database read. An empty Relation is returned if none are found.
|
122
|
+
#
|
123
|
+
# === Example
|
124
|
+
#
|
125
|
+
# A <tt>Video</tt> class declares <tt>belongs_to_many :tags</tt>,
|
126
|
+
# which will add:
|
127
|
+
# * <tt>Video#tags</tt> (similar to <tt>Tag.where([id] && tag_ids)</tt>)
|
128
|
+
# * <tt>Video#tags<<</tt>
|
129
|
+
# * <tt>Video#tags.delete</tt>
|
130
|
+
# * <tt>Video#tags.destroy</tt>
|
131
|
+
# * <tt>Video#tags=</tt>
|
132
|
+
# * <tt>Video#tag_ids</tt>
|
133
|
+
# * <tt>Video#tag_ids=</tt>
|
134
|
+
# * <tt>Video#tags.clear</tt>
|
135
|
+
# * <tt>Video#tags.empty?</tt>
|
136
|
+
# * <tt>Video#tags.size</tt>
|
137
|
+
# * <tt>Video#tags.find</tt>
|
138
|
+
# * <tt>Video#tags.exists?(name: 'ACME')</tt>
|
139
|
+
# * <tt>Video#tags.build</tt>
|
140
|
+
# * <tt>Video#tags.create</tt>
|
141
|
+
# * <tt>Video#tags.create!</tt>
|
142
|
+
# * <tt>Video#tags.reload</tt>
|
143
|
+
# The declaration can also include an +options+ hash to specialize the
|
144
|
+
# behavior of the association.
|
145
|
+
#
|
146
|
+
# === Options
|
147
|
+
# [:class_name]
|
148
|
+
# Specify the class name of the association. Use it only if that name
|
149
|
+
# can't be inferred from the association name. So <tt>belongs_to_many
|
150
|
+
# :tags</tt> will by default be linked to the +Tag+ class, but if the
|
151
|
+
# real class name is +SpecialTag+, you'll have to specify it with this
|
152
|
+
# option.
|
153
|
+
# [:foreign_key]
|
154
|
+
# Specify the foreign key used for the association. By default this is
|
155
|
+
# guessed to be the name of this class in lower-case and "_ids"
|
156
|
+
# suffixed. So a Video class that makes a #belongs_to_many association
|
157
|
+
# with Tag will use "tag_ids" as the default <tt>:foreign_key</tt>.
|
158
|
+
#
|
159
|
+
# It is a good idea to set the <tt>:inverse_of</tt> option as well.
|
160
|
+
# [:primary_key]
|
161
|
+
# Specify the name of the column to use as the primary key for the
|
162
|
+
# association. By default this is +id+.
|
163
|
+
# [:dependent]
|
164
|
+
# Controls what happens to the associated objects when their owner is
|
165
|
+
# destroyed. Note that these are implemented as callbacks, and Rails
|
166
|
+
# executes callbacks in order. Therefore, other similar callbacks may
|
167
|
+
# affect the <tt>:dependent</tt> behavior, and the <tt>:dependent</tt>
|
168
|
+
# behavior may affect other callbacks.
|
169
|
+
# [:touch]
|
170
|
+
# If true, the associated objects will be touched (the updated_at/on
|
171
|
+
# attributes set to current time) when this record is either saved or
|
172
|
+
# destroyed. If you specify a symbol, that attribute will be updated
|
173
|
+
# with the current time in addition to the updated_at/on attribute.
|
174
|
+
# Please note that with touching no validation is performed and only
|
175
|
+
# the +after_touch+, +after_commit+ and +after_rollback+ callbacks are
|
176
|
+
# executed.
|
177
|
+
# [:optional]
|
178
|
+
# When set to +true+, the association will not have its presence
|
179
|
+
# validated.
|
180
|
+
# [:required]
|
181
|
+
# When set to +true+, the association will also have its presence
|
182
|
+
# validated. This will validate the association itself, not the id.
|
183
|
+
# You can use +:inverse_of+ to avoid an extra query during validation.
|
184
|
+
# NOTE: <tt>required</tt> is set to <tt>false</tt> by default and is
|
185
|
+
# deprecated. If you want to have association presence validated,
|
186
|
+
# use <tt>required: true</tt>.
|
187
|
+
# [:default]
|
188
|
+
# Provide a callable (i.e. proc or lambda) to specify that the
|
189
|
+
# association should be initialized with a particular record before
|
190
|
+
# validation.
|
191
|
+
# [:inverse_of]
|
192
|
+
# Specifies the name of the #has_many association on the associated
|
193
|
+
# object that is the inverse of this #belongs_to_many association.
|
194
|
+
# See ActiveRecord::Associations::ClassMethods's overview on
|
195
|
+
# Bi-directional associations for more detail.
|
196
|
+
#
|
197
|
+
# Option examples:
|
198
|
+
# belongs_to_many :tags, dependent: :nullify
|
199
|
+
# belongs_to_many :tags, required: true, touch: true
|
200
|
+
# belongs_to_many :tags, default: -> { Tag.default }
|
201
|
+
def belongs_to_many(name, scope = nil, **options)
|
202
|
+
reflection = Associations::Builder::BelongsToMany.build(self, name, scope, options)
|
203
|
+
::ActiveRecord::Reflection.add_reflection(self, name, reflection)
|
204
|
+
end
|
205
|
+
|
47
206
|
protected
|
48
207
|
|
49
208
|
# Allow optional select attributes to be loaded manually when they are
|
@@ -134,6 +293,6 @@ module Torque
|
|
134
293
|
end
|
135
294
|
end
|
136
295
|
|
137
|
-
ActiveRecord::Base.include
|
296
|
+
::ActiveRecord::Base.include(Base)
|
138
297
|
end
|
139
298
|
end
|
@@ -26,17 +26,39 @@ module Torque
|
|
26
26
|
end.to_h
|
27
27
|
end
|
28
28
|
|
29
|
+
# Configure associations features
|
30
|
+
config.nested(:associations) do |assoc|
|
31
|
+
|
32
|
+
# Define if +belongs_to_many+ associations are marked as required by
|
33
|
+
# default. False means that no validation will be performed
|
34
|
+
assoc.belongs_to_many_required_by_default = false
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
# Configure auxiliary statement features
|
39
|
+
config.nested(:auxiliary_statement) do |cte|
|
40
|
+
|
41
|
+
# Define the key that is used on auxiliary statements to send extra
|
42
|
+
# arguments to format string or send on a proc
|
43
|
+
cte.send_arguments_key = :args
|
44
|
+
|
45
|
+
# Estipulate a class name (which may contain namespace) that expose the
|
46
|
+
# auxiliary statement in order to perform detached CTEs
|
47
|
+
cte.exposed_class = 'TorqueCTE'
|
48
|
+
|
49
|
+
end
|
50
|
+
|
29
51
|
# Configure ENUM features
|
30
52
|
config.nested(:enum) do |enum|
|
31
53
|
|
32
|
-
# Indicates if the enum features on ActiveRecord::Base should be initiated
|
33
|
-
# automatically or not
|
34
|
-
enum.initializer = false
|
35
|
-
|
36
54
|
# The name of the method to be used on any ActiveRecord::Base to
|
37
55
|
# initialize model-based enum features
|
38
56
|
enum.base_method = :enum
|
39
57
|
|
58
|
+
# The name of the method to be used on any ActiveRecord::Base to
|
59
|
+
# initialize model-based enum set features
|
60
|
+
enum.set_method = :enum_set
|
61
|
+
|
40
62
|
# Indicates if bang methods like 'disabled!' should update the record on
|
41
63
|
# database or not
|
42
64
|
enum.save_on_bang = true
|
@@ -63,12 +85,28 @@ module Torque
|
|
63
85
|
|
64
86
|
end
|
65
87
|
|
66
|
-
# Configure
|
67
|
-
config.nested(:
|
88
|
+
# Configure geometry data types
|
89
|
+
config.nested(:geometry) do |geometry|
|
68
90
|
|
69
|
-
# Define the
|
70
|
-
#
|
71
|
-
|
91
|
+
# Define the class that will be handling Point data types after decoding
|
92
|
+
# it. Any class provided here must respond to 'x', and 'y'
|
93
|
+
geometry.point_class = ActiveRecord::Point
|
94
|
+
|
95
|
+
# Define the class that will be handling Box data types after decoding it.
|
96
|
+
# Any class provided here must respond to 'x1', 'y1', 'x2', and 'y2'
|
97
|
+
geometry.box_class = nil
|
98
|
+
|
99
|
+
# Define the class that will be handling Circle data types after decoding
|
100
|
+
# it. Any class provided here must respond to 'x', 'y', and 'r'
|
101
|
+
geometry.circle_class = nil
|
102
|
+
|
103
|
+
# Define the class that will be handling Line data types after decoding
|
104
|
+
# it. Any class provided here must respond to 'a', 'b', and 'c'
|
105
|
+
geometry.line_class = nil
|
106
|
+
|
107
|
+
# Define the class that will be handling Segment data types after decoding
|
108
|
+
# it. Any class provided here must respond to 'x1', 'y1', 'x2', and 'y2'
|
109
|
+
geometry.segment_class = nil
|
72
110
|
|
73
111
|
end
|
74
112
|
|
@@ -92,5 +130,49 @@ module Torque
|
|
92
130
|
|
93
131
|
end
|
94
132
|
|
133
|
+
# Configure period features
|
134
|
+
config.nested(:period) do |period|
|
135
|
+
|
136
|
+
# The name of the method to be used on any ActiveRecord::Base to
|
137
|
+
# initialize model-based period features
|
138
|
+
period.base_method = :period_for
|
139
|
+
|
140
|
+
# Define the list of methods that will be created by default while setting
|
141
|
+
# up a new period field
|
142
|
+
period.method_names = {
|
143
|
+
current_on: '%s_on', # 0
|
144
|
+
current: 'current_%s', # 1
|
145
|
+
not_current: 'not_current_%s', # 2
|
146
|
+
containing: '%s_containing', # 3
|
147
|
+
not_containing: '%s_not_containing', # 4
|
148
|
+
overlapping: '%s_overlapping', # 5
|
149
|
+
not_overlapping: '%s_not_overlapping', # 6
|
150
|
+
starting_after: '%s_starting_after', # 7
|
151
|
+
starting_before: '%s_starting_before', # 8
|
152
|
+
finishing_after: '%s_finishing_after', # 9
|
153
|
+
finishing_before: '%s_finishing_before', # 10
|
154
|
+
|
155
|
+
real_containing: '%s_real_containing', # 11
|
156
|
+
real_overlapping: '%s_real_overlapping', # 12
|
157
|
+
real_starting_after: '%s_real_starting_after', # 13
|
158
|
+
real_starting_before: '%s_real_starting_before', # 14
|
159
|
+
real_finishing_after: '%s_real_finishing_after', # 15
|
160
|
+
real_finishing_before: '%s_real_finishing_before', # 16
|
161
|
+
|
162
|
+
containing_date: '%s_containing_date', # 17
|
163
|
+
not_containing_date: '%s_not_containing_date', # 18
|
164
|
+
overlapping_date: '%s_overlapping_date', # 19
|
165
|
+
not_overlapping_date: '%s_not_overlapping_date', # 20
|
166
|
+
|
167
|
+
current?: 'current_%s?', # 21
|
168
|
+
current_on?: 'current_%s_on?', # 22
|
169
|
+
start: '%s_start', # 23
|
170
|
+
finish: '%s_finish', # 24
|
171
|
+
real: 'real_%s', # 25
|
172
|
+
real_start: '%s_real_start', # 26
|
173
|
+
real_finish: '%s_real_finish', # 27
|
174
|
+
}
|
175
|
+
|
176
|
+
end
|
95
177
|
end
|
96
178
|
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module Torque
|
2
|
+
module PostgreSQL
|
3
|
+
class GeometryBuilder < ActiveModel::Type::Value
|
4
|
+
|
5
|
+
DESTRUCTOR = /[<>{}()]/.freeze
|
6
|
+
NUMBER_SERIALIZER = ->(num) { num.to_s.gsub(/\.0$/, '') }
|
7
|
+
|
8
|
+
def type
|
9
|
+
return self.class.const_get('TYPE') if self.class.const_defined?('TYPE')
|
10
|
+
self.class.const_set('TYPE', self.class.name.demodulize.underscore)
|
11
|
+
end
|
12
|
+
|
13
|
+
def pieces
|
14
|
+
self.class.const_get('PIECES')
|
15
|
+
end
|
16
|
+
|
17
|
+
def formation
|
18
|
+
self.class.const_get('FORMATION')
|
19
|
+
end
|
20
|
+
|
21
|
+
def cast(value)
|
22
|
+
case value
|
23
|
+
when ::String
|
24
|
+
return if value.blank?
|
25
|
+
value.gsub!(DESTRUCTOR, '')
|
26
|
+
build_klass(*value.split(','))
|
27
|
+
when ::Hash
|
28
|
+
build_klass(*value.symbolize_keys.slice(*pieces).values)
|
29
|
+
when ::Array
|
30
|
+
build_klass(*(value.flatten))
|
31
|
+
else
|
32
|
+
value
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def serialize(value)
|
37
|
+
parts =
|
38
|
+
case value
|
39
|
+
when config_class
|
40
|
+
pieces.map { |piece| value.public_send(piece) }
|
41
|
+
when ::Hash
|
42
|
+
value.symbolize_keys.slice(*pieces).values
|
43
|
+
when ::Array
|
44
|
+
value.flatten
|
45
|
+
end
|
46
|
+
|
47
|
+
parts = parts&.compact&.flatten
|
48
|
+
return if parts.blank?
|
49
|
+
|
50
|
+
raise 'Invalid format' if parts.size < pieces.size
|
51
|
+
format(formation, *parts.first(pieces.size).map(&number_serializer))
|
52
|
+
end
|
53
|
+
|
54
|
+
def deserialize(value)
|
55
|
+
build_klass(*value.gsub(DESTRUCTOR, '').split(',')) unless value.nil?
|
56
|
+
end
|
57
|
+
|
58
|
+
def type_cast_for_schema(value)
|
59
|
+
if config_class === value
|
60
|
+
pieces.map { |piece| value.public_send(piece) }
|
61
|
+
else
|
62
|
+
super
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def changed_in_place?(raw_old_value, new_value)
|
67
|
+
raw_old_value != serialize(new_value)
|
68
|
+
end
|
69
|
+
|
70
|
+
protected
|
71
|
+
|
72
|
+
def number_serializer
|
73
|
+
self.class.const_get('NUMBER_SERIALIZER')
|
74
|
+
end
|
75
|
+
|
76
|
+
def config_class
|
77
|
+
Torque::PostgreSQL.config.geometry.public_send("#{type}_class")
|
78
|
+
end
|
79
|
+
|
80
|
+
def build_klass(*args)
|
81
|
+
return nil if args.empty?
|
82
|
+
check_invalid_format!(args)
|
83
|
+
|
84
|
+
config_class.new(*args.try(:first, pieces.size)&.map(&:to_f))
|
85
|
+
end
|
86
|
+
|
87
|
+
def check_invalid_format!(args)
|
88
|
+
raise 'Invalid format' if args.size < pieces.size
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|