activerecord 3.2.19 → 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/CHANGELOG.md +1715 -604
- data/MIT-LICENSE +2 -2
- data/README.rdoc +40 -45
- data/examples/performance.rb +33 -22
- data/examples/simple.rb +3 -4
- data/lib/active_record/aggregations.rb +76 -51
- data/lib/active_record/association_relation.rb +35 -0
- data/lib/active_record/associations/alias_tracker.rb +54 -40
- data/lib/active_record/associations/association.rb +76 -56
- data/lib/active_record/associations/association_scope.rb +125 -93
- data/lib/active_record/associations/belongs_to_association.rb +57 -28
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -2
- data/lib/active_record/associations/builder/association.rb +120 -32
- data/lib/active_record/associations/builder/belongs_to.rb +115 -62
- data/lib/active_record/associations/builder/collection_association.rb +61 -53
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +117 -43
- data/lib/active_record/associations/builder/has_many.rb +9 -65
- data/lib/active_record/associations/builder/has_one.rb +18 -52
- data/lib/active_record/associations/builder/singular_association.rb +18 -19
- data/lib/active_record/associations/collection_association.rb +268 -186
- data/lib/active_record/associations/collection_proxy.rb +1003 -63
- data/lib/active_record/associations/foreign_association.rb +11 -0
- data/lib/active_record/associations/has_many_association.rb +81 -41
- data/lib/active_record/associations/has_many_through_association.rb +76 -55
- data/lib/active_record/associations/has_one_association.rb +51 -21
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +83 -108
- data/lib/active_record/associations/join_dependency/join_base.rb +7 -9
- data/lib/active_record/associations/join_dependency/join_part.rb +30 -37
- data/lib/active_record/associations/join_dependency.rb +239 -155
- data/lib/active_record/associations/preloader/association.rb +97 -62
- data/lib/active_record/associations/preloader/collection_association.rb +2 -8
- data/lib/active_record/associations/preloader/has_many_through.rb +7 -3
- data/lib/active_record/associations/preloader/has_one.rb +0 -8
- data/lib/active_record/associations/preloader/singular_association.rb +3 -3
- data/lib/active_record/associations/preloader/through_association.rb +75 -33
- data/lib/active_record/associations/preloader.rb +111 -79
- data/lib/active_record/associations/singular_association.rb +35 -13
- data/lib/active_record/associations/through_association.rb +41 -19
- data/lib/active_record/associations.rb +727 -501
- data/lib/active_record/attribute/user_provided_default.rb +28 -0
- data/lib/active_record/attribute.rb +213 -0
- data/lib/active_record/attribute_assignment.rb +32 -162
- data/lib/active_record/attribute_decorators.rb +67 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +52 -7
- data/lib/active_record/attribute_methods/dirty.rb +101 -61
- data/lib/active_record/attribute_methods/primary_key.rb +50 -36
- data/lib/active_record/attribute_methods/query.rb +7 -6
- data/lib/active_record/attribute_methods/read.rb +56 -117
- data/lib/active_record/attribute_methods/serialization.rb +43 -96
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +93 -42
- data/lib/active_record/attribute_methods/write.rb +34 -45
- data/lib/active_record/attribute_methods.rb +333 -144
- data/lib/active_record/attribute_mutation_tracker.rb +70 -0
- data/lib/active_record/attribute_set/builder.rb +108 -0
- data/lib/active_record/attribute_set.rb +108 -0
- data/lib/active_record/attributes.rb +265 -0
- data/lib/active_record/autosave_association.rb +285 -223
- data/lib/active_record/base.rb +95 -490
- data/lib/active_record/callbacks.rb +95 -61
- data/lib/active_record/coders/json.rb +13 -0
- data/lib/active_record/coders/yaml_column.rb +28 -19
- data/lib/active_record/collection_cache_key.rb +40 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +724 -277
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +199 -192
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +31 -26
- data/lib/active_record/connection_adapters/abstract/quoting.rb +140 -57
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +147 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +419 -276
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +105 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +963 -276
- data/lib/active_record/connection_adapters/abstract/transaction.rb +232 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +397 -106
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +643 -342
- data/lib/active_record/connection_adapters/column.rb +30 -259
- data/lib/active_record/connection_adapters/connection_specification.rb +263 -0
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +125 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +47 -196
- data/lib/active_record/connection_adapters/postgresql/column.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +170 -0
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +70 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +48 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +10 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +39 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +93 -0
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +31 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +116 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +180 -0
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +682 -0
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +558 -1039
- data/lib/active_record/connection_adapters/schema_cache.rb +74 -36
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +538 -24
- data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
- data/lib/active_record/connection_handling.rb +155 -0
- data/lib/active_record/core.rb +561 -0
- data/lib/active_record/counter_cache.rb +146 -105
- data/lib/active_record/dynamic_matchers.rb +101 -64
- data/lib/active_record/enum.rb +234 -0
- data/lib/active_record/errors.rb +153 -56
- data/lib/active_record/explain.rb +15 -63
- data/lib/active_record/explain_registry.rb +30 -0
- data/lib/active_record/explain_subscriber.rb +10 -6
- data/lib/active_record/fixture_set/file.rb +77 -0
- data/lib/active_record/fixtures.rb +355 -232
- data/lib/active_record/gem_version.rb +15 -0
- data/lib/active_record/inheritance.rb +144 -79
- data/lib/active_record/integration.rb +66 -13
- data/lib/active_record/internal_metadata.rb +56 -0
- data/lib/active_record/legacy_yaml_adapter.rb +46 -0
- data/lib/active_record/locale/en.yml +9 -1
- data/lib/active_record/locking/optimistic.rb +77 -56
- data/lib/active_record/locking/pessimistic.rb +6 -6
- data/lib/active_record/log_subscriber.rb +53 -28
- data/lib/active_record/migration/command_recorder.rb +166 -33
- data/lib/active_record/migration/compatibility.rb +126 -0
- data/lib/active_record/migration/join_table.rb +15 -0
- data/lib/active_record/migration.rb +792 -264
- data/lib/active_record/model_schema.rb +192 -130
- data/lib/active_record/nested_attributes.rb +238 -145
- data/lib/active_record/no_touching.rb +52 -0
- data/lib/active_record/null_relation.rb +89 -0
- data/lib/active_record/persistence.rb +357 -157
- data/lib/active_record/query_cache.rb +22 -43
- data/lib/active_record/querying.rb +34 -23
- data/lib/active_record/railtie.rb +88 -48
- data/lib/active_record/railties/console_sandbox.rb +3 -4
- data/lib/active_record/railties/controller_runtime.rb +5 -4
- data/lib/active_record/railties/databases.rake +170 -422
- data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
- data/lib/active_record/readonly_attributes.rb +2 -5
- data/lib/active_record/reflection.rb +715 -189
- data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
- data/lib/active_record/relation/batches.rb +203 -50
- data/lib/active_record/relation/calculations.rb +203 -194
- data/lib/active_record/relation/delegation.rb +103 -25
- data/lib/active_record/relation/finder_methods.rb +457 -261
- data/lib/active_record/relation/from_clause.rb +32 -0
- data/lib/active_record/relation/merger.rb +167 -0
- data/lib/active_record/relation/predicate_builder/array_handler.rb +43 -0
- data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
- data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
- data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
- data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
- data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
- data/lib/active_record/relation/predicate_builder.rb +153 -48
- data/lib/active_record/relation/query_attribute.rb +19 -0
- data/lib/active_record/relation/query_methods.rb +1019 -194
- data/lib/active_record/relation/record_fetch_warning.rb +49 -0
- data/lib/active_record/relation/spawn_methods.rb +46 -150
- data/lib/active_record/relation/where_clause.rb +174 -0
- data/lib/active_record/relation/where_clause_factory.rb +38 -0
- data/lib/active_record/relation.rb +450 -245
- data/lib/active_record/result.rb +104 -12
- data/lib/active_record/runtime_registry.rb +22 -0
- data/lib/active_record/sanitization.rb +120 -94
- data/lib/active_record/schema.rb +28 -18
- data/lib/active_record/schema_dumper.rb +141 -74
- data/lib/active_record/schema_migration.rb +50 -0
- data/lib/active_record/scoping/default.rb +64 -57
- data/lib/active_record/scoping/named.rb +93 -108
- data/lib/active_record/scoping.rb +73 -121
- data/lib/active_record/secure_token.rb +38 -0
- data/lib/active_record/serialization.rb +7 -5
- data/lib/active_record/statement_cache.rb +113 -0
- data/lib/active_record/store.rb +173 -15
- data/lib/active_record/suppressor.rb +58 -0
- data/lib/active_record/table_metadata.rb +68 -0
- data/lib/active_record/tasks/database_tasks.rb +313 -0
- data/lib/active_record/tasks/mysql_database_tasks.rb +151 -0
- data/lib/active_record/tasks/postgresql_database_tasks.rb +110 -0
- data/lib/active_record/tasks/sqlite_database_tasks.rb +59 -0
- data/lib/active_record/timestamp.rb +42 -24
- data/lib/active_record/touch_later.rb +58 -0
- data/lib/active_record/transactions.rb +233 -105
- data/lib/active_record/type/adapter_specific_registry.rb +130 -0
- data/lib/active_record/type/date.rb +7 -0
- data/lib/active_record/type/date_time.rb +7 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
- data/lib/active_record/type/internal/abstract_json.rb +29 -0
- data/lib/active_record/type/internal/timezone.rb +15 -0
- data/lib/active_record/type/serialized.rb +63 -0
- data/lib/active_record/type/time.rb +20 -0
- data/lib/active_record/type/type_map.rb +64 -0
- data/lib/active_record/type.rb +72 -0
- data/lib/active_record/type_caster/connection.rb +29 -0
- data/lib/active_record/type_caster/map.rb +19 -0
- data/lib/active_record/type_caster.rb +7 -0
- data/lib/active_record/validations/absence.rb +23 -0
- data/lib/active_record/validations/associated.rb +33 -18
- data/lib/active_record/validations/length.rb +24 -0
- data/lib/active_record/validations/presence.rb +66 -0
- data/lib/active_record/validations/uniqueness.rb +128 -68
- data/lib/active_record/validations.rb +48 -40
- data/lib/active_record/version.rb +5 -7
- data/lib/active_record.rb +71 -47
- data/lib/rails/generators/active_record/migration/migration_generator.rb +56 -8
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +24 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb +28 -16
- data/lib/rails/generators/active_record/migration.rb +18 -8
- data/lib/rails/generators/active_record/model/model_generator.rb +38 -16
- data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
- data/lib/rails/generators/active_record/model/templates/model.rb +7 -6
- data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
- data/lib/rails/generators/active_record.rb +3 -11
- metadata +188 -134
- data/examples/associations.png +0 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -63
- data/lib/active_record/associations/join_helper.rb +0 -55
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
- data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
- data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -441
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
- data/lib/active_record/dynamic_finder_match.rb +0 -68
- data/lib/active_record/dynamic_scope_match.rb +0 -23
- data/lib/active_record/fixtures/file.rb +0 -65
- data/lib/active_record/identity_map.rb +0 -162
- data/lib/active_record/observer.rb +0 -121
- data/lib/active_record/serializers/xml_serializer.rb +0 -203
- data/lib/active_record/session_store.rb +0 -360
- data/lib/active_record/test_case.rb +0 -73
- data/lib/rails/generators/active_record/model/templates/migration.rb +0 -15
- data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
- data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
- data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
- data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'ipaddr'
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module ConnectionAdapters
|
5
|
+
module PostgreSQL
|
6
|
+
module OID # :nodoc:
|
7
|
+
class Cidr < Type::Value # :nodoc:
|
8
|
+
def type
|
9
|
+
:cidr
|
10
|
+
end
|
11
|
+
|
12
|
+
def type_cast_for_schema(value)
|
13
|
+
subnet_mask = value.instance_variable_get(:@mask_addr)
|
14
|
+
|
15
|
+
# If the subnet mask is equal to /32, don't output it
|
16
|
+
if subnet_mask == (2**32 - 1)
|
17
|
+
"\"#{value}\""
|
18
|
+
else
|
19
|
+
"\"#{value}/#{subnet_mask.to_s(2).count('1')}\""
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def serialize(value)
|
24
|
+
if IPAddr === value
|
25
|
+
"#{value}/#{value.instance_variable_get(:@mask_addr).to_s(2).count('1')}"
|
26
|
+
else
|
27
|
+
value
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def cast_value(value)
|
32
|
+
if value.nil?
|
33
|
+
nil
|
34
|
+
elsif String === value
|
35
|
+
begin
|
36
|
+
IPAddr.new(value)
|
37
|
+
rescue ArgumentError
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
else
|
41
|
+
value
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module PostgreSQL
|
4
|
+
module OID # :nodoc:
|
5
|
+
class DateTime < Type::DateTime # :nodoc:
|
6
|
+
def cast_value(value)
|
7
|
+
case value
|
8
|
+
when 'infinity' then ::Float::INFINITY
|
9
|
+
when '-infinity' then -::Float::INFINITY
|
10
|
+
when / BC$/
|
11
|
+
astronomical_year = format("%04d", -value[/^\d+/].to_i + 1)
|
12
|
+
super(value.sub(/ BC$/, "").sub(/^\d+/, astronomical_year))
|
13
|
+
else
|
14
|
+
super
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module PostgreSQL
|
4
|
+
module OID # :nodoc:
|
5
|
+
class Decimal < Type::Decimal # :nodoc:
|
6
|
+
def infinity(options = {})
|
7
|
+
BigDecimal.new("Infinity") * (options[:negative] ? -1 : 1)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module PostgreSQL
|
4
|
+
module OID # :nodoc:
|
5
|
+
class Enum < Type::Value # :nodoc:
|
6
|
+
def type
|
7
|
+
:enum
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def cast_value(value)
|
13
|
+
value.to_s
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module PostgreSQL
|
4
|
+
module OID # :nodoc:
|
5
|
+
class Hstore < Type::Value # :nodoc:
|
6
|
+
include Type::Helpers::Mutable
|
7
|
+
|
8
|
+
def type
|
9
|
+
:hstore
|
10
|
+
end
|
11
|
+
|
12
|
+
def deserialize(value)
|
13
|
+
if value.is_a?(::String)
|
14
|
+
::Hash[value.scan(HstorePair).map { |k, v|
|
15
|
+
v = v.upcase == 'NULL' ? nil : v.gsub(/\A"(.*)"\Z/m,'\1').gsub(/\\(.)/, '\1')
|
16
|
+
k = k.gsub(/\A"(.*)"\Z/m,'\1').gsub(/\\(.)/, '\1')
|
17
|
+
[k, v]
|
18
|
+
}]
|
19
|
+
else
|
20
|
+
value
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def serialize(value)
|
25
|
+
if value.is_a?(::Hash)
|
26
|
+
value.map { |k, v| "#{escape_hstore(k)}=>#{escape_hstore(v)}" }.join(', ')
|
27
|
+
else
|
28
|
+
value
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def accessor
|
33
|
+
ActiveRecord::Store::StringKeyedHashAccessor
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
HstorePair = begin
|
39
|
+
quoted_string = /"[^"\\]*(?:\\.[^"\\]*)*"/
|
40
|
+
unquoted_string = /(?:\\.|[^\s,])[^\s=,\\]*(?:\\.[^\s=,\\]*|=[^,>])*/
|
41
|
+
/(#{quoted_string}|#{unquoted_string})\s*=>\s*(#{quoted_string}|#{unquoted_string})/
|
42
|
+
end
|
43
|
+
|
44
|
+
def escape_hstore(value)
|
45
|
+
if value.nil?
|
46
|
+
'NULL'
|
47
|
+
else
|
48
|
+
if value == ""
|
49
|
+
'""'
|
50
|
+
else
|
51
|
+
'"%s"' % value.to_s.gsub(/(["\\])/, '\\\\\1')
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module PostgreSQL
|
4
|
+
module OID # :nodoc:
|
5
|
+
class Jsonb < Json # :nodoc:
|
6
|
+
def type
|
7
|
+
:jsonb
|
8
|
+
end
|
9
|
+
|
10
|
+
def changed_in_place?(raw_old_value, new_value)
|
11
|
+
# Postgres does not preserve insignificant whitespaces when
|
12
|
+
# round-tripping jsonb columns. This causes some false positives for
|
13
|
+
# the comparison here. Therefore, we need to parse and re-dump the
|
14
|
+
# raw value here to ensure the insignificant whitespaces are
|
15
|
+
# consistent with our encoder's output.
|
16
|
+
raw_old_value = serialize(deserialize(raw_old_value))
|
17
|
+
super(raw_old_value, new_value)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module PostgreSQL
|
4
|
+
module OID # :nodoc:
|
5
|
+
class Money < Type::Decimal # :nodoc:
|
6
|
+
def type
|
7
|
+
:money
|
8
|
+
end
|
9
|
+
|
10
|
+
def scale
|
11
|
+
2
|
12
|
+
end
|
13
|
+
|
14
|
+
def cast_value(value)
|
15
|
+
return value unless ::String === value
|
16
|
+
|
17
|
+
# Because money output is formatted according to the locale, there are two
|
18
|
+
# cases to consider (note the decimal separators):
|
19
|
+
# (1) $12,345,678.12
|
20
|
+
# (2) $12.345.678,12
|
21
|
+
# Negative values are represented as follows:
|
22
|
+
# (3) -$2.55
|
23
|
+
# (4) ($2.55)
|
24
|
+
|
25
|
+
value.sub!(/^\((.+)\)$/, '-\1') # (4)
|
26
|
+
case value
|
27
|
+
when /^-?\D+[\d,]+\.\d{2}$/ # (1)
|
28
|
+
value.gsub!(/[^-\d.]/, '')
|
29
|
+
when /^-?\D+[\d.]+,\d{2}$/ # (2)
|
30
|
+
value.gsub!(/[^-\d,]/, '').sub!(/,/, '.')
|
31
|
+
end
|
32
|
+
|
33
|
+
super(value)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module PostgreSQL
|
4
|
+
module OID # :nodoc:
|
5
|
+
class Point < Type::Value # :nodoc:
|
6
|
+
include Type::Helpers::Mutable
|
7
|
+
|
8
|
+
def type
|
9
|
+
:point
|
10
|
+
end
|
11
|
+
|
12
|
+
def cast(value)
|
13
|
+
case value
|
14
|
+
when ::String
|
15
|
+
if value[0] == '(' && value[-1] == ')'
|
16
|
+
value = value[1...-1]
|
17
|
+
end
|
18
|
+
cast(value.split(','))
|
19
|
+
when ::Array
|
20
|
+
value.map { |v| Float(v) }
|
21
|
+
else
|
22
|
+
value
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def serialize(value)
|
27
|
+
if value.is_a?(::Array)
|
28
|
+
"(#{number_for_point(value[0])},#{number_for_point(value[1])})"
|
29
|
+
else
|
30
|
+
super
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def number_for_point(number)
|
37
|
+
number.to_s.gsub(/\.0$/, '')
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
Point = Struct.new(:x, :y)
|
3
|
+
|
4
|
+
module ConnectionAdapters
|
5
|
+
module PostgreSQL
|
6
|
+
module OID # :nodoc:
|
7
|
+
class Rails51Point < Type::Value # :nodoc:
|
8
|
+
include Type::Helpers::Mutable
|
9
|
+
|
10
|
+
def type
|
11
|
+
:point
|
12
|
+
end
|
13
|
+
|
14
|
+
def cast(value)
|
15
|
+
case value
|
16
|
+
when ::String
|
17
|
+
if value[0] == '(' && value[-1] == ')'
|
18
|
+
value = value[1...-1]
|
19
|
+
end
|
20
|
+
x, y = value.split(",")
|
21
|
+
build_point(x, y)
|
22
|
+
when ::Array
|
23
|
+
build_point(*value)
|
24
|
+
else
|
25
|
+
value
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def serialize(value)
|
30
|
+
if value.is_a?(ActiveRecord::Point)
|
31
|
+
"(#{number_for_point(value.x)},#{number_for_point(value.y)})"
|
32
|
+
else
|
33
|
+
super
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def number_for_point(number)
|
40
|
+
number.to_s.gsub(/\.0$/, '')
|
41
|
+
end
|
42
|
+
|
43
|
+
def build_point(x, y)
|
44
|
+
ActiveRecord::Point.new(Float(x), Float(y))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'active_support/core_ext/string/filters'
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module ConnectionAdapters
|
5
|
+
module PostgreSQL
|
6
|
+
module OID # :nodoc:
|
7
|
+
class Range < Type::Value # :nodoc:
|
8
|
+
attr_reader :subtype, :type
|
9
|
+
delegate :user_input_in_time_zone, to: :subtype
|
10
|
+
|
11
|
+
def initialize(subtype, type = :range)
|
12
|
+
@subtype = subtype
|
13
|
+
@type = type
|
14
|
+
end
|
15
|
+
|
16
|
+
def type_cast_for_schema(value)
|
17
|
+
value.inspect.gsub('Infinity', '::Float::INFINITY')
|
18
|
+
end
|
19
|
+
|
20
|
+
def cast_value(value)
|
21
|
+
return if value == 'empty'
|
22
|
+
return value unless value.is_a?(::String)
|
23
|
+
|
24
|
+
extracted = extract_bounds(value)
|
25
|
+
from = type_cast_single extracted[:from]
|
26
|
+
to = type_cast_single extracted[:to]
|
27
|
+
|
28
|
+
if !infinity?(from) && extracted[:exclude_start]
|
29
|
+
raise ArgumentError, "The Ruby Range object does not support excluding the beginning of a Range. (unsupported value: '#{value}')"
|
30
|
+
end
|
31
|
+
::Range.new(from, to, extracted[:exclude_end])
|
32
|
+
end
|
33
|
+
|
34
|
+
def serialize(value)
|
35
|
+
if value.is_a?(::Range)
|
36
|
+
from = type_cast_single_for_database(value.begin)
|
37
|
+
to = type_cast_single_for_database(value.end)
|
38
|
+
"[#{from},#{to}#{value.exclude_end? ? ')' : ']'}"
|
39
|
+
else
|
40
|
+
super
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def ==(other)
|
45
|
+
other.is_a?(Range) &&
|
46
|
+
other.subtype == subtype &&
|
47
|
+
other.type == type
|
48
|
+
end
|
49
|
+
|
50
|
+
def map(value) # :nodoc:
|
51
|
+
new_begin = yield(value.begin)
|
52
|
+
new_end = yield(value.end)
|
53
|
+
::Range.new(new_begin, new_end, value.exclude_end?)
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def type_cast_single(value)
|
59
|
+
infinity?(value) ? value : @subtype.deserialize(value)
|
60
|
+
end
|
61
|
+
|
62
|
+
def type_cast_single_for_database(value)
|
63
|
+
infinity?(value) ? '' : @subtype.serialize(value)
|
64
|
+
end
|
65
|
+
|
66
|
+
def extract_bounds(value)
|
67
|
+
from, to = value[1..-2].split(',')
|
68
|
+
{
|
69
|
+
from: (value[1] == ',' || from == '-infinity') ? infinity(negative: true) : from,
|
70
|
+
to: (value[-2] == ',' || to == 'infinity') ? infinity : to,
|
71
|
+
exclude_start: (value[0] == '('),
|
72
|
+
exclude_end: (value[-1] == ')')
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
76
|
+
def infinity(negative: false)
|
77
|
+
if subtype.respond_to?(:infinity)
|
78
|
+
subtype.infinity(negative: negative)
|
79
|
+
elsif negative
|
80
|
+
-::Float::INFINITY
|
81
|
+
else
|
82
|
+
::Float::INFINITY
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def infinity?(value)
|
87
|
+
value.respond_to?(:infinite?) && value.infinite?
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module PostgreSQL
|
4
|
+
module OID # :nodoc:
|
5
|
+
# This class uses the data from PostgreSQL pg_type table to build
|
6
|
+
# the OID -> Type mapping.
|
7
|
+
# - OID is an integer representing the type.
|
8
|
+
# - Type is an OID::Type object.
|
9
|
+
# This class has side effects on the +store+ passed during initialization.
|
10
|
+
class TypeMapInitializer # :nodoc:
|
11
|
+
def initialize(store)
|
12
|
+
@store = store
|
13
|
+
end
|
14
|
+
|
15
|
+
def run(records)
|
16
|
+
nodes = records.reject { |row| @store.key? row['oid'].to_i }
|
17
|
+
mapped, nodes = nodes.partition { |row| @store.key? row['typname'] }
|
18
|
+
ranges, nodes = nodes.partition { |row| row['typtype'] == 'r'.freeze }
|
19
|
+
enums, nodes = nodes.partition { |row| row['typtype'] == 'e'.freeze }
|
20
|
+
domains, nodes = nodes.partition { |row| row['typtype'] == 'd'.freeze }
|
21
|
+
arrays, nodes = nodes.partition { |row| row['typinput'] == 'array_in'.freeze }
|
22
|
+
composites, nodes = nodes.partition { |row| row['typelem'].to_i != 0 }
|
23
|
+
|
24
|
+
mapped.each { |row| register_mapped_type(row) }
|
25
|
+
enums.each { |row| register_enum_type(row) }
|
26
|
+
domains.each { |row| register_domain_type(row) }
|
27
|
+
arrays.each { |row| register_array_type(row) }
|
28
|
+
ranges.each { |row| register_range_type(row) }
|
29
|
+
composites.each { |row| register_composite_type(row) }
|
30
|
+
end
|
31
|
+
|
32
|
+
def query_conditions_for_initial_load(type_map)
|
33
|
+
known_type_names = type_map.keys.map { |n| "'#{n}'" }
|
34
|
+
known_type_types = %w('r' 'e' 'd')
|
35
|
+
<<-SQL % [known_type_names.join(", "), known_type_types.join(", ")]
|
36
|
+
WHERE
|
37
|
+
t.typname IN (%s)
|
38
|
+
OR t.typtype IN (%s)
|
39
|
+
OR t.typinput = 'array_in(cstring,oid,integer)'::regprocedure
|
40
|
+
OR t.typelem != 0
|
41
|
+
SQL
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
def register_mapped_type(row)
|
46
|
+
alias_type row['oid'], row['typname']
|
47
|
+
end
|
48
|
+
|
49
|
+
def register_enum_type(row)
|
50
|
+
register row['oid'], OID::Enum.new
|
51
|
+
end
|
52
|
+
|
53
|
+
def register_array_type(row)
|
54
|
+
register_with_subtype(row['oid'], row['typelem'].to_i) do |subtype|
|
55
|
+
OID::Array.new(subtype, row['typdelim'])
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def register_range_type(row)
|
60
|
+
register_with_subtype(row['oid'], row['rngsubtype'].to_i) do |subtype|
|
61
|
+
OID::Range.new(subtype, row['typname'].to_sym)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def register_domain_type(row)
|
66
|
+
if base_type = @store.lookup(row["typbasetype"].to_i)
|
67
|
+
register row['oid'], base_type
|
68
|
+
else
|
69
|
+
warn "unknown base type (OID: #{row["typbasetype"]}) for domain #{row["typname"]}."
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def register_composite_type(row)
|
74
|
+
if subtype = @store.lookup(row['typelem'].to_i)
|
75
|
+
register row['oid'], OID::Vector.new(row['typdelim'], subtype)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def register(oid, oid_type = nil, &block)
|
80
|
+
oid = assert_valid_registration(oid, oid_type || block)
|
81
|
+
if block_given?
|
82
|
+
@store.register_type(oid, &block)
|
83
|
+
else
|
84
|
+
@store.register_type(oid, oid_type)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def alias_type(oid, target)
|
89
|
+
oid = assert_valid_registration(oid, target)
|
90
|
+
@store.alias_type(oid, target)
|
91
|
+
end
|
92
|
+
|
93
|
+
def register_with_subtype(oid, target_oid)
|
94
|
+
if @store.key?(target_oid)
|
95
|
+
register(oid) do |_, *args|
|
96
|
+
yield @store.lookup(target_oid, *args)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def assert_valid_registration(oid, oid_type)
|
102
|
+
raise ArgumentError, "can't register nil type for OID #{oid}" if oid_type.nil?
|
103
|
+
oid.to_i
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module PostgreSQL
|
4
|
+
module OID # :nodoc:
|
5
|
+
class Uuid < Type::Value # :nodoc:
|
6
|
+
ACCEPTABLE_UUID = %r{\A\{?([a-fA-F0-9]{4}-?){8}\}?\z}x
|
7
|
+
|
8
|
+
alias_method :serialize, :deserialize
|
9
|
+
|
10
|
+
def type
|
11
|
+
:uuid
|
12
|
+
end
|
13
|
+
|
14
|
+
def cast(value)
|
15
|
+
value.to_s[ACCEPTABLE_UUID, 0]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module PostgreSQL
|
4
|
+
module OID # :nodoc:
|
5
|
+
class Vector < Type::Value # :nodoc:
|
6
|
+
attr_reader :delim, :subtype
|
7
|
+
|
8
|
+
# +delim+ corresponds to the `typdelim` column in the pg_types
|
9
|
+
# table. +subtype+ is derived from the `typelem` column in the
|
10
|
+
# pg_types table.
|
11
|
+
def initialize(delim, subtype)
|
12
|
+
@delim = delim
|
13
|
+
@subtype = subtype
|
14
|
+
end
|
15
|
+
|
16
|
+
# FIXME: this should probably split on +delim+ and use +subtype+
|
17
|
+
# to cast the values. Unfortunately, the current Rails behavior
|
18
|
+
# is to just return the string.
|
19
|
+
def cast(value)
|
20
|
+
value
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module PostgreSQL
|
4
|
+
module OID # :nodoc:
|
5
|
+
class Xml < Type::String # :nodoc:
|
6
|
+
def type
|
7
|
+
:xml
|
8
|
+
end
|
9
|
+
|
10
|
+
def serialize(value)
|
11
|
+
return unless value
|
12
|
+
Data.new(super)
|
13
|
+
end
|
14
|
+
|
15
|
+
class Data # :nodoc:
|
16
|
+
def initialize(value)
|
17
|
+
@value = value
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_s
|
21
|
+
@value
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'active_record/connection_adapters/postgresql/oid/array'
|
2
|
+
require 'active_record/connection_adapters/postgresql/oid/bit'
|
3
|
+
require 'active_record/connection_adapters/postgresql/oid/bit_varying'
|
4
|
+
require 'active_record/connection_adapters/postgresql/oid/bytea'
|
5
|
+
require 'active_record/connection_adapters/postgresql/oid/cidr'
|
6
|
+
require 'active_record/connection_adapters/postgresql/oid/date_time'
|
7
|
+
require 'active_record/connection_adapters/postgresql/oid/decimal'
|
8
|
+
require 'active_record/connection_adapters/postgresql/oid/enum'
|
9
|
+
require 'active_record/connection_adapters/postgresql/oid/hstore'
|
10
|
+
require 'active_record/connection_adapters/postgresql/oid/inet'
|
11
|
+
require 'active_record/connection_adapters/postgresql/oid/json'
|
12
|
+
require 'active_record/connection_adapters/postgresql/oid/jsonb'
|
13
|
+
require 'active_record/connection_adapters/postgresql/oid/money'
|
14
|
+
require 'active_record/connection_adapters/postgresql/oid/point'
|
15
|
+
require 'active_record/connection_adapters/postgresql/oid/rails_5_1_point'
|
16
|
+
require 'active_record/connection_adapters/postgresql/oid/range'
|
17
|
+
require 'active_record/connection_adapters/postgresql/oid/specialized_string'
|
18
|
+
require 'active_record/connection_adapters/postgresql/oid/uuid'
|
19
|
+
require 'active_record/connection_adapters/postgresql/oid/vector'
|
20
|
+
require 'active_record/connection_adapters/postgresql/oid/xml'
|
21
|
+
|
22
|
+
require 'active_record/connection_adapters/postgresql/oid/type_map_initializer'
|
23
|
+
|
24
|
+
module ActiveRecord
|
25
|
+
module ConnectionAdapters
|
26
|
+
module PostgreSQL
|
27
|
+
module OID # :nodoc:
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|