Skip to content

Commit d3a58f2

Browse files
authored
Merge pull request #1124 from jruby/test_private
More work needed on type registration but this advances state of posgresql.
2 parents 540d42c + 4b95b87 commit d3a58f2

File tree

4 files changed

+135
-51
lines changed

4 files changed

+135
-51
lines changed

lib/arjdbc/postgresql/adapter.rb

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,38 @@ def extensions
320320
exec_query("SELECT extname FROM pg_extension", "SCHEMA").cast_values
321321
end
322322

323+
# Returns a list of defined enum types, and their values.
324+
def enum_types
325+
query = <<~SQL
326+
SELECT
327+
type.typname AS name,
328+
string_agg(enum.enumlabel, ',' ORDER BY enum.enumsortorder) AS value
329+
FROM pg_enum AS enum
330+
JOIN pg_type AS type
331+
ON (type.oid = enum.enumtypid)
332+
GROUP BY type.typname;
333+
SQL
334+
exec_query(query, "SCHEMA").cast_values
335+
end
336+
337+
# Given a name and an array of values, creates an enum type.
338+
def create_enum(name, values)
339+
sql_values = values.map { |s| "'#{s}'" }.join(", ")
340+
query = <<~SQL
341+
DO $$
342+
BEGIN
343+
IF NOT EXISTS (
344+
SELECT 1 FROM pg_type t
345+
WHERE t.typname = '#{name}'
346+
) THEN
347+
CREATE TYPE \"#{name}\" AS ENUM (#{sql_values});
348+
END IF;
349+
END
350+
$$;
351+
SQL
352+
exec_query(query)
353+
end
354+
323355
# Returns the configured supported identifier length supported by PostgreSQL
324356
def max_identifier_length
325357
@max_identifier_length ||= query_value("SHOW max_identifier_length", "SCHEMA").to_i
@@ -672,6 +704,37 @@ module ActiveRecord::ConnectionAdapters
672704
class PostgreSQLAdapter < AbstractAdapter
673705
class_attribute :create_unlogged_tables, default: false
674706

707+
##
708+
# :singleton-method:
709+
# PostgreSQL allows the creation of "unlogged" tables, which do not record
710+
# data in the PostgreSQL Write-Ahead Log. This can make the tables faster,
711+
# but significantly increases the risk of data loss if the database
712+
# crashes. As a result, this should not be used in production
713+
# environments. If you would like all created tables to be unlogged in
714+
# the test environment you can add the following line to your test.rb
715+
# file:
716+
#
717+
# ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.create_unlogged_tables = true
718+
class_attribute :create_unlogged_tables, default: false
719+
720+
##
721+
# :singleton-method:
722+
# PostgreSQL supports multiple types for DateTimes. By default, if you use +datetime+
723+
# in migrations, Rails will translate this to a PostgreSQL "timestamp without time zone".
724+
# Change this in an initializer to use another NATIVE_DATABASE_TYPES. For example, to
725+
# store DateTimes as "timestamp with time zone":
726+
#
727+
# ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.datetime_type = :timestamptz
728+
#
729+
# Or if you are adding a custom type:
730+
#
731+
# ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::NATIVE_DATABASE_TYPES[:my_custom_type] = { name: "my_custom_type_name" }
732+
# ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.datetime_type = :my_custom_type
733+
#
734+
# If you're using +:ruby+ as your +config.active_record.schema_format+ and you change this
735+
# setting, you should immediately run <tt>bin/rails db:migrate</tt> to update the types in your schema.rb.
736+
class_attribute :datetime_type, default: :timestamp
737+
675738
# Try to use as much of the built in postgres logic as possible
676739
# maybe someday we can extend the actual adapter
677740
include ActiveRecord::ConnectionAdapters::PostgreSQL::ReferentialIntegrity

lib/arjdbc/postgresql/oid_types.rb

Lines changed: 68 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -116,54 +116,57 @@ def reload_type_map
116116

117117
private
118118

119-
def initialize_type_map(m = type_map)
120-
register_class_with_limit m, 'int2', Type::Integer
121-
register_class_with_limit m, 'int4', Type::Integer
122-
register_class_with_limit m, 'int8', Type::Integer
123-
m.register_type 'oid', OID::Oid.new
124-
m.register_type 'float4', Type::Float.new
125-
m.alias_type 'float8', 'float4'
126-
m.register_type 'text', Type::Text.new
127-
register_class_with_limit m, 'varchar', Type::String
128-
m.alias_type 'char', 'varchar'
129-
m.alias_type 'name', 'varchar'
130-
m.alias_type 'bpchar', 'varchar'
131-
m.register_type 'bool', Type::Boolean.new
132-
register_class_with_limit m, 'bit', OID::Bit
133-
register_class_with_limit m, 'varbit', OID::BitVarying
134-
m.alias_type 'timestamptz', 'timestamp'
135-
m.register_type 'date', OID::Date.new
136-
137-
m.register_type 'money', OID::Money.new
138-
m.register_type 'bytea', OID::Bytea.new
139-
m.register_type 'point', OID::Point.new
140-
m.register_type 'hstore', OID::Hstore.new
141-
m.register_type 'json', Type::Json.new
142-
m.register_type 'jsonb', OID::Jsonb.new
143-
m.register_type 'cidr', OID::Cidr.new
144-
m.register_type 'inet', OID::Inet.new
145-
m.register_type 'uuid', OID::Uuid.new
146-
m.register_type 'xml', OID::Xml.new
147-
m.register_type 'tsvector', OID::SpecializedString.new(:tsvector)
148-
m.register_type 'macaddr', OID::Macaddr.new
149-
m.register_type 'citext', OID::SpecializedString.new(:citext)
150-
m.register_type 'ltree', OID::SpecializedString.new(:ltree)
151-
m.register_type 'line', OID::SpecializedString.new(:line)
152-
m.register_type 'lseg', OID::SpecializedString.new(:lseg)
153-
m.register_type 'box', OID::SpecializedString.new(:box)
154-
m.register_type 'path', OID::SpecializedString.new(:path)
155-
m.register_type 'polygon', OID::SpecializedString.new(:polygon)
156-
m.register_type 'circle', OID::SpecializedString.new(:circle)
157-
158-
m.register_type 'interval' do |*args, sql_type|
159-
precision = extract_precision(sql_type)
160-
OID::Interval.new(precision: precision)
161-
end
119+
def register_class_with_limit(...)
120+
::ActiveRecord::ConnectionAdapters::AbstractAdapter.send(:register_class_with_limit, ...)
121+
end
162122

163-
register_class_with_precision m, 'time', Type::Time
164-
register_class_with_precision m, 'timestamp', OID::DateTime
123+
def register_class_with_precision(...)
124+
::ActiveRecord::ConnectionAdapters::AbstractAdapter.send(:register_class_with_precision, ...)
125+
end
165126

166-
m.register_type 'numeric' do |_, fmod, sql_type|
127+
def initialize_type_map(m = type_map)
128+
m.register_type "int2", Type::Integer.new(limit: 2)
129+
m.register_type "int4", Type::Integer.new(limit: 4)
130+
m.register_type "int8", Type::Integer.new(limit: 8)
131+
m.register_type "oid", OID::Oid.new
132+
m.register_type "float4", Type::Float.new
133+
m.alias_type "float8", "float4"
134+
m.register_type "text", Type::Text.new
135+
register_class_with_limit m, "varchar", Type::String
136+
m.alias_type "char", "varchar"
137+
m.alias_type "name", "varchar"
138+
m.alias_type "bpchar", "varchar"
139+
m.register_type "bool", Type::Boolean.new
140+
register_class_with_limit m, "bit", OID::Bit
141+
register_class_with_limit m, "varbit", OID::BitVarying
142+
m.register_type "date", OID::Date.new
143+
144+
m.register_type "money", OID::Money.new
145+
m.register_type "bytea", OID::Bytea.new
146+
m.register_type "point", OID::Point.new
147+
m.register_type "hstore", OID::Hstore.new
148+
m.register_type "json", Type::Json.new
149+
m.register_type "jsonb", OID::Jsonb.new
150+
m.register_type "cidr", OID::Cidr.new
151+
m.register_type "inet", OID::Inet.new
152+
m.register_type "uuid", OID::Uuid.new
153+
m.register_type "xml", OID::Xml.new
154+
m.register_type "tsvector", OID::SpecializedString.new(:tsvector)
155+
m.register_type "macaddr", OID::Macaddr.new
156+
m.register_type "citext", OID::SpecializedString.new(:citext)
157+
m.register_type "ltree", OID::SpecializedString.new(:ltree)
158+
m.register_type "line", OID::SpecializedString.new(:line)
159+
m.register_type "lseg", OID::SpecializedString.new(:lseg)
160+
m.register_type "box", OID::SpecializedString.new(:box)
161+
m.register_type "path", OID::SpecializedString.new(:path)
162+
m.register_type "polygon", OID::SpecializedString.new(:polygon)
163+
m.register_type "circle", OID::SpecializedString.new(:circle)
164+
165+
register_class_with_precision m, "time", Type::Time
166+
register_class_with_precision m, "timestamp", OID::Timestamp
167+
register_class_with_precision m, "timestamptz", OID::TimestampWithTimeZone
168+
169+
m.register_type "numeric" do |_, fmod, sql_type|
167170
precision = extract_precision(sql_type)
168171
scale = extract_scale(sql_type)
169172

@@ -183,7 +186,10 @@ def initialize_type_map(m = type_map)
183186
end
184187
end
185188

186-
load_additional_types(m)
189+
m.register_type "interval" do |*args, sql_type|
190+
precision = extract_precision(sql_type)
191+
OID::Interval.new(precision: precision)
192+
end
187193

188194
# pgjdbc returns these if the column is auto-incrmenting
189195
m.alias_type 'serial', 'int4'
@@ -231,6 +237,21 @@ def load_additional_types(type_map, oid = nil) # :nodoc:
231237
initializer.run(records)
232238
end
233239

240+
def extract_scale(sql_type)
241+
case sql_type
242+
when /\((\d+)\)/ then 0
243+
when /\((\d+)(,(\d+))\)/ then $3.to_i
244+
end
245+
end
246+
247+
def extract_precision(sql_type)
248+
$1.to_i if sql_type =~ /\((\d+)(,\d+)?\)/
249+
end
250+
251+
def extract_limit(sql_type)
252+
$1.to_i if sql_type =~ /\((.*)\)/
253+
end
254+
234255
# Support arrays/ranges for defining attributes that don't exist in the db
235256
ActiveRecord::Type.add_modifier({ array: true }, OID::Array, adapter: :postgresql)
236257
ActiveRecord::Type.add_modifier({ range: true }, OID::Range, adapter: :postgresql)

test/db/postgresql/simple_test.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,8 +209,8 @@ def test_extensions
209209
end
210210

211211
test 'type cast (without column)' do
212-
assert_equal 1, connection.type_cast(1, false)
213-
assert_equal 'some', connection.type_cast(:some, nil)
212+
assert_equal 1, connection.type_cast(1)
213+
assert_equal 'some', connection.type_cast(:some)
214214
end
215215

216216
# def test_jdbc_error

test/db/postgresql/unit_test.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,8 @@ def test_rename_index
9595

9696
private
9797

98-
def method_missing(method_symbol, *arguments)
99-
ActiveRecord::Base.connection.send(method_symbol, *arguments)
98+
def method_missing(method_symbol, ...)
99+
ActiveRecord::Base.connection.send(method_symbol, ...)
100100
end
101101

102102
end

0 commit comments

Comments
 (0)