activerecord 4.1.16 → 4.2.0.beta1

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.

Files changed (167) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +634 -2185
  3. data/README.rdoc +15 -10
  4. data/lib/active_record.rb +2 -1
  5. data/lib/active_record/aggregations.rb +12 -8
  6. data/lib/active_record/associations.rb +58 -33
  7. data/lib/active_record/associations/association.rb +1 -1
  8. data/lib/active_record/associations/association_scope.rb +53 -21
  9. data/lib/active_record/associations/belongs_to_association.rb +15 -5
  10. data/lib/active_record/associations/builder/association.rb +16 -5
  11. data/lib/active_record/associations/builder/belongs_to.rb +7 -29
  12. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -11
  13. data/lib/active_record/associations/builder/has_one.rb +2 -2
  14. data/lib/active_record/associations/builder/singular_association.rb +8 -1
  15. data/lib/active_record/associations/collection_association.rb +32 -44
  16. data/lib/active_record/associations/collection_proxy.rb +1 -10
  17. data/lib/active_record/associations/has_many_association.rb +60 -14
  18. data/lib/active_record/associations/has_many_through_association.rb +34 -23
  19. data/lib/active_record/associations/has_one_association.rb +0 -1
  20. data/lib/active_record/associations/join_dependency.rb +7 -9
  21. data/lib/active_record/associations/join_dependency/join_association.rb +18 -14
  22. data/lib/active_record/associations/preloader.rb +2 -2
  23. data/lib/active_record/associations/preloader/association.rb +9 -5
  24. data/lib/active_record/associations/preloader/through_association.rb +3 -3
  25. data/lib/active_record/associations/singular_association.rb +16 -1
  26. data/lib/active_record/associations/through_association.rb +6 -22
  27. data/lib/active_record/attribute.rb +131 -0
  28. data/lib/active_record/attribute_assignment.rb +19 -11
  29. data/lib/active_record/attribute_decorators.rb +66 -0
  30. data/lib/active_record/attribute_methods.rb +53 -90
  31. data/lib/active_record/attribute_methods/before_type_cast.rb +2 -2
  32. data/lib/active_record/attribute_methods/dirty.rb +85 -42
  33. data/lib/active_record/attribute_methods/primary_key.rb +6 -8
  34. data/lib/active_record/attribute_methods/read.rb +14 -57
  35. data/lib/active_record/attribute_methods/serialization.rb +12 -146
  36. data/lib/active_record/attribute_methods/time_zone_conversion.rb +32 -40
  37. data/lib/active_record/attribute_methods/write.rb +8 -23
  38. data/lib/active_record/attribute_set.rb +77 -0
  39. data/lib/active_record/attribute_set/builder.rb +32 -0
  40. data/lib/active_record/attributes.rb +122 -0
  41. data/lib/active_record/autosave_association.rb +11 -21
  42. data/lib/active_record/base.rb +9 -19
  43. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +69 -45
  44. data/lib/active_record/connection_adapters/abstract/database_statements.rb +22 -42
  45. data/lib/active_record/connection_adapters/abstract/quoting.rb +59 -60
  46. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +37 -2
  47. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +102 -21
  48. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +9 -33
  49. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +178 -55
  50. data/lib/active_record/connection_adapters/abstract/transaction.rb +120 -115
  51. data/lib/active_record/connection_adapters/abstract_adapter.rb +143 -57
  52. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +156 -107
  53. data/lib/active_record/connection_adapters/column.rb +13 -244
  54. data/lib/active_record/connection_adapters/connection_specification.rb +6 -20
  55. data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -15
  56. data/lib/active_record/connection_adapters/mysql_adapter.rb +55 -143
  57. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +15 -27
  58. data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
  59. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +39 -20
  60. data/lib/active_record/connection_adapters/postgresql/oid.rb +29 -388
  61. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +96 -0
  62. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
  63. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
  64. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +14 -0
  65. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
  66. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
  67. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +27 -0
  68. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
  69. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +17 -0
  70. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
  71. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
  72. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
  73. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
  74. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
  75. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
  76. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
  77. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
  78. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
  79. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +76 -0
  80. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
  81. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
  82. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +85 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +26 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
  86. data/lib/active_record/connection_adapters/postgresql/quoting.rb +42 -122
  87. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +4 -4
  88. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +154 -0
  89. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +86 -34
  90. data/lib/active_record/connection_adapters/postgresql/utils.rb +66 -0
  91. data/lib/active_record/connection_adapters/postgresql_adapter.rb +188 -452
  92. data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
  93. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +54 -47
  94. data/lib/active_record/connection_handling.rb +1 -1
  95. data/lib/active_record/core.rb +119 -22
  96. data/lib/active_record/counter_cache.rb +60 -6
  97. data/lib/active_record/enum.rb +9 -10
  98. data/lib/active_record/errors.rb +27 -26
  99. data/lib/active_record/explain.rb +1 -1
  100. data/lib/active_record/fixtures.rb +52 -45
  101. data/lib/active_record/gem_version.rb +3 -3
  102. data/lib/active_record/inheritance.rb +33 -8
  103. data/lib/active_record/integration.rb +4 -4
  104. data/lib/active_record/locking/optimistic.rb +34 -16
  105. data/lib/active_record/migration.rb +22 -32
  106. data/lib/active_record/migration/command_recorder.rb +19 -2
  107. data/lib/active_record/migration/join_table.rb +1 -1
  108. data/lib/active_record/model_schema.rb +39 -48
  109. data/lib/active_record/nested_attributes.rb +8 -18
  110. data/lib/active_record/persistence.rb +39 -22
  111. data/lib/active_record/query_cache.rb +3 -3
  112. data/lib/active_record/querying.rb +1 -8
  113. data/lib/active_record/railtie.rb +17 -10
  114. data/lib/active_record/railties/databases.rake +47 -42
  115. data/lib/active_record/readonly_attributes.rb +0 -1
  116. data/lib/active_record/reflection.rb +225 -92
  117. data/lib/active_record/relation.rb +35 -11
  118. data/lib/active_record/relation/batches.rb +0 -2
  119. data/lib/active_record/relation/calculations.rb +28 -32
  120. data/lib/active_record/relation/delegation.rb +1 -1
  121. data/lib/active_record/relation/finder_methods.rb +42 -20
  122. data/lib/active_record/relation/merger.rb +0 -1
  123. data/lib/active_record/relation/predicate_builder.rb +1 -22
  124. data/lib/active_record/relation/predicate_builder/array_handler.rb +16 -11
  125. data/lib/active_record/relation/predicate_builder/relation_handler.rb +0 -4
  126. data/lib/active_record/relation/query_methods.rb +98 -62
  127. data/lib/active_record/relation/spawn_methods.rb +6 -7
  128. data/lib/active_record/result.rb +16 -9
  129. data/lib/active_record/sanitization.rb +8 -1
  130. data/lib/active_record/schema.rb +0 -1
  131. data/lib/active_record/schema_dumper.rb +51 -9
  132. data/lib/active_record/schema_migration.rb +4 -0
  133. data/lib/active_record/scoping/default.rb +5 -4
  134. data/lib/active_record/serializers/xml_serializer.rb +3 -7
  135. data/lib/active_record/statement_cache.rb +79 -5
  136. data/lib/active_record/store.rb +5 -5
  137. data/lib/active_record/tasks/database_tasks.rb +37 -5
  138. data/lib/active_record/tasks/mysql_database_tasks.rb +10 -16
  139. data/lib/active_record/tasks/postgresql_database_tasks.rb +2 -2
  140. data/lib/active_record/timestamp.rb +9 -7
  141. data/lib/active_record/transactions.rb +35 -21
  142. data/lib/active_record/type.rb +20 -0
  143. data/lib/active_record/type/binary.rb +40 -0
  144. data/lib/active_record/type/boolean.rb +19 -0
  145. data/lib/active_record/type/date.rb +46 -0
  146. data/lib/active_record/type/date_time.rb +43 -0
  147. data/lib/active_record/type/decimal.rb +40 -0
  148. data/lib/active_record/type/decimal_without_scale.rb +11 -0
  149. data/lib/active_record/type/float.rb +19 -0
  150. data/lib/active_record/type/hash_lookup_type_map.rb +19 -0
  151. data/lib/active_record/type/integer.rb +23 -0
  152. data/lib/active_record/type/mutable.rb +16 -0
  153. data/lib/active_record/type/numeric.rb +36 -0
  154. data/lib/active_record/type/serialized.rb +51 -0
  155. data/lib/active_record/type/string.rb +36 -0
  156. data/lib/active_record/type/text.rb +11 -0
  157. data/lib/active_record/type/time.rb +26 -0
  158. data/lib/active_record/type/time_value.rb +38 -0
  159. data/lib/active_record/type/type_map.rb +48 -0
  160. data/lib/active_record/type/value.rb +101 -0
  161. data/lib/active_record/validations.rb +21 -16
  162. data/lib/active_record/validations/uniqueness.rb +9 -23
  163. data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -4
  164. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +1 -1
  165. data/lib/rails/generators/active_record/model/templates/model.rb +1 -1
  166. metadata +71 -14
  167. data/lib/active_record/connection_adapters/postgresql/cast.rb +0 -168
@@ -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
+ # roundtripping 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 = type_cast_for_database(type_cast_from_database(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,43 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module PostgreSQL
4
+ module OID # :nodoc:
5
+ class Money < Type::Decimal # :nodoc:
6
+ include Infinity
7
+
8
+ class_attribute :precision
9
+
10
+ def type
11
+ :money
12
+ end
13
+
14
+ def scale
15
+ 2
16
+ end
17
+
18
+ def cast_value(value)
19
+ return value unless ::String === value
20
+
21
+ # Because money output is formatted according to the locale, there are two
22
+ # cases to consider (note the decimal separators):
23
+ # (1) $12,345,678.12
24
+ # (2) $12.345.678,12
25
+ # Negative values are represented as follows:
26
+ # (3) -$2.55
27
+ # (4) ($2.55)
28
+
29
+ value.sub!(/^\((.+)\)$/, '-\1') # (4)
30
+ case value
31
+ when /^-?\D+[\d,]+\.\d{2}$/ # (1)
32
+ value.gsub!(/[^-\d.]/, '')
33
+ when /^-?\D+[\d.]+,\d{2}$/ # (2)
34
+ value.gsub!(/[^-\d,]/, '').sub!(/,/, '.')
35
+ end
36
+
37
+ super(value)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ 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::Mutable
7
+
8
+ def type
9
+ :point
10
+ end
11
+
12
+ def type_cast(value)
13
+ case value
14
+ when ::String
15
+ if value[0] == '(' && value[-1] == ')'
16
+ value = value[1...-1]
17
+ end
18
+ type_cast(value.split(','))
19
+ when ::Array
20
+ value.map { |v| Float(v) }
21
+ else
22
+ value
23
+ end
24
+ end
25
+
26
+ def type_cast_for_database(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,76 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module PostgreSQL
4
+ module OID # :nodoc:
5
+ class Range < Type::Value # :nodoc:
6
+ attr_reader :subtype, :type
7
+
8
+ def initialize(subtype, type)
9
+ @subtype = subtype
10
+ @type = type
11
+ end
12
+
13
+ def type_cast_for_schema(value)
14
+ value.inspect.gsub('Infinity', '::Float::INFINITY')
15
+ end
16
+
17
+ def cast_value(value)
18
+ return if value == 'empty'
19
+ return value if value.is_a?(::Range)
20
+
21
+ extracted = extract_bounds(value)
22
+ from = type_cast_single extracted[:from]
23
+ to = type_cast_single extracted[:to]
24
+
25
+ if !infinity?(from) && extracted[:exclude_start]
26
+ if from.respond_to?(:succ)
27
+ from = from.succ
28
+ ActiveSupport::Deprecation.warn <<-MESSAGE
29
+ Excluding the beginning of a Range is only partialy supported through `#succ`.
30
+ This is not reliable and will be removed in the future.
31
+ MESSAGE
32
+ else
33
+ raise ArgumentError, "The Ruby Range object does not support excluding the beginning of a Range. (unsupported value: '#{value}')"
34
+ end
35
+ end
36
+ ::Range.new(from, to, extracted[:exclude_end])
37
+ end
38
+
39
+ def type_cast_for_database(value)
40
+ if value.is_a?(::Range)
41
+ from = type_cast_single_for_database(value.begin)
42
+ to = type_cast_single_for_database(value.end)
43
+ "[#{from},#{to}#{value.exclude_end? ? ')' : ']'}"
44
+ else
45
+ super
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ def type_cast_single(value)
52
+ infinity?(value) ? value : @subtype.type_cast_from_database(value)
53
+ end
54
+
55
+ def type_cast_single_for_database(value)
56
+ infinity?(value) ? '' : @subtype.type_cast_for_database(value)
57
+ end
58
+
59
+ def extract_bounds(value)
60
+ from, to = value[1..-2].split(',')
61
+ {
62
+ from: (value[1] == ',' || from == '-infinity') ? @subtype.infinity(negative: true) : from,
63
+ to: (value[-2] == ',' || to == 'infinity') ? @subtype.infinity : to,
64
+ exclude_start: (value[0] == '('),
65
+ exclude_end: (value[-1] == ')')
66
+ }
67
+ end
68
+
69
+ def infinity?(value)
70
+ value.respond_to?(:infinite?) && value.infinite?
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,15 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module PostgreSQL
4
+ module OID # :nodoc:
5
+ class SpecializedString < Type::String # :nodoc:
6
+ attr_reader :type
7
+
8
+ def initialize(type)
9
+ @type = type
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module PostgreSQL
4
+ module OID # :nodoc:
5
+ class Time < Type::Time # :nodoc:
6
+ include Infinity
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,85 @@
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 and 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' }
19
+ enums, nodes = nodes.partition { |row| row['typtype'] == 'e' }
20
+ domains, nodes = nodes.partition { |row| row['typtype'] == 'd' }
21
+ arrays, nodes = nodes.partition { |row| row['typinput'] == 'array_in' }
22
+ composites, nodes = nodes.partition { |row| row['typelem'] != '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
+ private
33
+ def register_mapped_type(row)
34
+ alias_type row['oid'], row['typname']
35
+ end
36
+
37
+ def register_enum_type(row)
38
+ register row['oid'], OID::Enum.new
39
+ end
40
+
41
+ def register_array_type(row)
42
+ if subtype = @store.lookup(row['typelem'].to_i)
43
+ register row['oid'], OID::Array.new(subtype, row['typdelim'])
44
+ end
45
+ end
46
+
47
+ def register_range_type(row)
48
+ if subtype = @store.lookup(row['rngsubtype'].to_i)
49
+ register row['oid'], OID::Range.new(subtype, row['typname'].to_sym)
50
+ end
51
+ end
52
+
53
+ def register_domain_type(row)
54
+ if base_type = @store.lookup(row["typbasetype"].to_i)
55
+ register row['oid'], base_type
56
+ else
57
+ warn "unknown base type (OID: #{row["typbasetype"]}) for domain #{row["typname"]}."
58
+ end
59
+ end
60
+
61
+ def register_composite_type(row)
62
+ if subtype = @store.lookup(row['typelem'].to_i)
63
+ register row['oid'], OID::Vector.new(row['typdelim'], subtype)
64
+ end
65
+ end
66
+
67
+ def register(oid, oid_type)
68
+ oid = assert_valid_registration(oid, oid_type)
69
+ @store.register_type(oid, oid_type)
70
+ end
71
+
72
+ def alias_type(oid, target)
73
+ oid = assert_valid_registration(oid, target)
74
+ @store.alias_type(oid, target)
75
+ end
76
+
77
+ def assert_valid_registration(oid, oid_type)
78
+ raise ArgumentError, "can't register nil type for OID #{oid}" if oid_type.nil?
79
+ oid.to_i
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,26 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module PostgreSQL
4
+ module OID # :nodoc:
5
+ class Uuid < Type::Value # :nodoc:
6
+ RFC_4122 = %r{\A\{?[a-fA-F0-9]{4}-?
7
+ [a-fA-F0-9]{4}-?
8
+ [a-fA-F0-9]{4}-?
9
+ [1-5][a-fA-F0-9]{3}-?
10
+ [8-Bab][a-fA-F0-9]{3}-?
11
+ [a-fA-F0-9]{4}-?
12
+ [a-fA-F0-9]{4}-?
13
+ [a-fA-F0-9]{4}-?\}?\z}x
14
+
15
+ def type
16
+ :uuid
17
+ end
18
+
19
+ def type_cast(value)
20
+ value.to_s[RFC_4122, 0]
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ 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 type_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 type_cast_for_database(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
@@ -1,142 +1,35 @@
1
1
  module ActiveRecord
2
2
  module ConnectionAdapters
3
- class PostgreSQLAdapter < AbstractAdapter
3
+ module PostgreSQL
4
4
  module Quoting
5
5
  # Escapes binary strings for bytea input to the database.
6
6
  def escape_bytea(value)
7
- PGconn.escape_bytea(value) if value
7
+ @connection.escape_bytea(value) if value
8
8
  end
9
9
 
10
10
  # Unescapes bytea output from a database to the binary string it represents.
11
11
  # NOTE: This is NOT an inverse of escape_bytea! This is only to be used
12
12
  # on escaped binary output from database drive.
13
13
  def unescape_bytea(value)
14
- PGconn.unescape_bytea(value) if value
14
+ @connection.unescape_bytea(value) if value
15
15
  end
16
16
 
17
17
  # Quotes PostgreSQL-specific data types for SQL input.
18
18
  def quote(value, column = nil) #:nodoc:
19
- return super unless column && column.type
20
-
21
- sql_type = type_to_sql(column.type, column.limit, column.precision, column.scale)
19
+ return super unless column
22
20
 
23
21
  case value
24
- when Range
25
- if /range$/ =~ sql_type
26
- escaped = quote_string(PostgreSQLColumn.range_to_string(value))
27
- "'#{escaped}'::#{sql_type}"
28
- else
29
- super
30
- end
31
- when Array
32
- case sql_type
33
- when 'point' then super(PostgreSQLColumn.point_to_string(value))
34
- when 'json' then super(PostgreSQLColumn.json_to_string(value))
35
- else
36
- if column.array
37
- "'#{PostgreSQLColumn.array_to_string(value, column, self).gsub(/'/, "''")}'"
38
- else
39
- super
40
- end
41
- end
42
- when Hash
43
- case sql_type
44
- when 'hstore' then super(PostgreSQLColumn.hstore_to_string(value), column)
45
- when 'json' then super(PostgreSQLColumn.json_to_string(value), column)
46
- else super
47
- end
48
- when IPAddr
49
- case sql_type
50
- when 'inet', 'cidr' then super(PostgreSQLColumn.cidr_to_string(value), column)
51
- else super
52
- end
53
22
  when Float
54
- if value.infinite? && column.type == :datetime
55
- "'#{value.to_s.downcase}'"
56
- elsif value.infinite? || value.nan?
23
+ if value.infinite? || value.nan?
57
24
  "'#{value.to_s}'"
58
25
  else
59
26
  super
60
27
  end
61
- when Numeric
62
- if sql_type == 'money' || [:string, :text].include?(column.type)
63
- # Not truly string input, so doesn't require (or allow) escape string syntax.
64
- "'#{value}'"
65
- else
66
- super
67
- end
68
- when String
69
- case sql_type
70
- when 'bytea' then "'#{escape_bytea(value)}'"
71
- when 'xml' then "xml '#{quote_string(value)}'"
72
- when /^bit/
73
- case value
74
- when /\A[01]*\Z/ then "B'#{value}'" # Bit-string notation
75
- when /\A[0-9A-F]*\Z/i then "X'#{value}'" # Hexadecimal notation
76
- end
77
- else
78
- super
79
- end
80
28
  else
81
29
  super
82
30
  end
83
31
  end
84
32
 
85
- def type_cast(value, column, array_member = false)
86
- return super(value, column) unless column
87
-
88
- case value
89
- when Range
90
- if /range$/ =~ column.sql_type
91
- PostgreSQLColumn.range_to_string(value)
92
- else
93
- super(value, column)
94
- end
95
- when NilClass
96
- if column.array && array_member
97
- 'NULL'
98
- elsif column.array
99
- value
100
- else
101
- super(value, column)
102
- end
103
- when Array
104
- case column.sql_type
105
- when 'point' then PostgreSQLColumn.point_to_string(value)
106
- when 'json' then PostgreSQLColumn.json_to_string(value)
107
- else
108
- if column.array
109
- PostgreSQLColumn.array_to_string(value, column, self)
110
- else
111
- super(value, column)
112
- end
113
- end
114
- when String
115
- if 'bytea' == column.sql_type
116
- # Return a bind param hash with format as binary.
117
- # See http://deveiate.org/code/pg/PGconn.html#method-i-exec_prepared-doc
118
- # for more information
119
- { value: value, format: 1 }
120
- else
121
- super(value, column)
122
- end
123
- when Hash
124
- case column.sql_type
125
- when 'hstore' then PostgreSQLColumn.hstore_to_string(value, array_member)
126
- when 'json' then PostgreSQLColumn.json_to_string(value)
127
- else super(value, column)
128
- end
129
- when IPAddr
130
- if %w(inet cidr).include? column.sql_type
131
- PostgreSQLColumn.cidr_to_string(value)
132
- else
133
- super(value, column)
134
- end
135
- else
136
- super(value, column)
137
- end
138
- end
139
-
140
33
  # Quotes strings for use in SQL input.
141
34
  def quote_string(s) #:nodoc:
142
35
  @connection.escape(s)
@@ -151,14 +44,7 @@ module ActiveRecord
151
44
  # - "schema.name".table_name
152
45
  # - "schema.name"."table.name"
153
46
  def quote_table_name(name)
154
- schema, name_part = extract_pg_identifier_from_name(name.to_s)
155
-
156
- unless name_part
157
- quote_column_name(schema)
158
- else
159
- table_name, name_part = extract_pg_identifier_from_name(name_part)
160
- "#{quote_column_name(schema)}.#{quote_column_name(table_name)}"
161
- end
47
+ Utils.extract_schema_qualified_name(name.to_s).quoted
162
48
  end
163
49
 
164
50
  def quote_table_name_for_assignment(table, attr)
@@ -178,8 +64,9 @@ module ActiveRecord
178
64
  result = "#{result}.#{sprintf("%06d", value.usec)}"
179
65
  end
180
66
 
181
- if value.year < 0
182
- result = result.sub(/^-/, "") + " BC"
67
+ if value.year <= 0
68
+ bce_year = format("%04d", -value.year + 1)
69
+ result = result.sub(/^-?\d+/, bce_year) + " BC"
183
70
  end
184
71
  result
185
72
  end
@@ -192,6 +79,39 @@ module ActiveRecord
192
79
  quote(value, column)
193
80
  end
194
81
  end
82
+
83
+ private
84
+
85
+ def _quote(value)
86
+ case value
87
+ when Type::Binary::Data
88
+ "'#{escape_bytea(value.to_s)}'"
89
+ when OID::Xml::Data
90
+ "xml '#{quote_string(value.to_s)}'"
91
+ when OID::Bit::Data
92
+ if value.binary?
93
+ "B'#{value}'"
94
+ elsif value.hex?
95
+ "X'#{value}'"
96
+ end
97
+ else
98
+ super
99
+ end
100
+ end
101
+
102
+ def _type_cast(value)
103
+ case value
104
+ when Type::Binary::Data
105
+ # Return a bind param hash with format as binary.
106
+ # See http://deveiate.org/code/pg/PGconn.html#method-i-exec_prepared-doc
107
+ # for more information
108
+ { value: value.to_s, format: 1 }
109
+ when OID::Xml::Data, OID::Bit::Data
110
+ value.to_s
111
+ else
112
+ super
113
+ end
114
+ end
195
115
  end
196
116
  end
197
117
  end