Skip to content

Commit

Permalink
Move SQLite3Column into its own file
Browse files Browse the repository at this point in the history
- Cleans up JdbcColumn
- Override new_column_from_field method to have it select the correct column class
- Add auto_increment tracking to the class
  • Loading branch information
rdubya committed Oct 28, 2023
1 parent 379ea1e commit 291162a
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 112 deletions.
34 changes: 0 additions & 34 deletions lib/arjdbc/jdbc/column.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,45 +12,11 @@ module Jdbc
# specific type.
# @see JdbcAdapter#jdbc_column_class
class JdbcColumn < Column
# @deprecated attribute writers will be removed in 1.4
attr_writer :limit, :precision # unless ArJdbc::AR42

def initialize(config, name, *args)
if self.class == JdbcColumn
# NOTE: extending classes do not want this if they do they shall call
call_discovered_column_callbacks(config) if config
default = args.shift
else # for extending classes allow ignoring first argument :
if ! config.nil? && ! config.is_a?(Hash)
default = name; name = config # initialize(name, default, *args)
else
default = args.shift
end
end

super(name, default, *args)
init_column(name, default, *args)
end

# Additional column initialization for sub-classes.
def init_column(*args); end

# Similar to `ActiveRecord`'s `extract_value_from_default(default)`.
# @return default value for a column (possibly extracted from driver value)
def default_value(value); value; end

protected

# @private
def call_discovered_column_callbacks(config)
dialect = (config[:dialect] || config[:driver]).to_s
for matcher, block in self.class.column_types
block.call(config, self) if matcher === dialect
end
end

public

# Returns the available column types
# @return [Hash] of (matcher, block) pairs
def self.column_types
Expand Down
102 changes: 24 additions & 78 deletions lib/arjdbc/sqlite3/adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
require "active_record/connection_adapters/sqlite3/schema_dumper"
require "active_record/connection_adapters/sqlite3/schema_statements"
require "active_support/core_ext/class/attribute"
require "arjdbc/sqlite3/column"

module SQLite3
module Constants
Expand Down Expand Up @@ -403,6 +404,26 @@ def check_version
end
end

def new_column_from_field(table_name, field, definitions)
default = field["dflt_value"]

type_metadata = fetch_type_metadata(field["type"])
default_value = extract_value_from_default(default)
default_function = extract_default_function(default_value, default)
rowid = is_column_the_rowid?(field, definitions)

ActiveRecord::ConnectionAdapters::SQLite3Column.new(
field["name"],
default_value,
type_metadata,
field["notnull"].to_i == 0,
default_function,
collation: field["collation"],
auto_increment: field["auto_increment"],
rowid: rowid
)
end

private
# See https://www.sqlite.org/limits.html,
# the default value is 999 when not configured.
Expand Down Expand Up @@ -523,10 +544,9 @@ def copy_table(from, to, options = {})
primary_key: column_name == from_primary_key
}

# FIXME: This requires changes to the Column class
# unless column.auto_increment?
# column_options[:default] = default
# end
unless column.auto_increment?
column_options[:default] = default
end

column_type = column.bigint? ? :bigint : column.type
@definition.column(column_name, column_type, **column_options)
Expand Down Expand Up @@ -676,80 +696,6 @@ def configure_connection
end

module ActiveRecord::ConnectionAdapters
class SQLite3Column < JdbcColumn
def initialize(name, *args)
if Hash === name
super
else
super(nil, name, *args)
end
end

def self.string_to_binary(value)
value
end

def self.binary_to_string(value)
if value.respond_to?(:encoding) && value.encoding != Encoding::ASCII_8BIT
value = value.force_encoding(Encoding::ASCII_8BIT)
end
value
end

# @override {ActiveRecord::ConnectionAdapters::JdbcColumn#init_column}
def init_column(name, default, *args)
if default =~ /NULL/
@default = nil
else
super
end
end

# @override {ActiveRecord::ConnectionAdapters::JdbcColumn#default_value}
def default_value(value)
# JDBC returns column default strings with actual single quotes :
return $1 if value =~ /^'(.*)'$/

value
end

# @override {ActiveRecord::ConnectionAdapters::Column#type_cast}
def type_cast(value)
return nil if value.nil?
case type
when :string then value
when :primary_key
value.respond_to?(:to_i) ? value.to_i : ( value ? 1 : 0 )
when :float then value.to_f
when :decimal then self.class.value_to_decimal(value)
when :boolean then self.class.value_to_boolean(value)
else super
end
end

private

# @override {ActiveRecord::ConnectionAdapters::Column#extract_limit}
def extract_limit(sql_type)
return nil if sql_type =~ /^(real)\(\d+/i
super
end

def extract_precision(sql_type)
case sql_type
when /^(real)\((\d+)(,\d+)?\)/i then $2.to_i
else super
end
end

def extract_scale(sql_type)
case sql_type
when /^(real)\((\d+)\)/i then 0
when /^(real)\((\d+)(,(\d+))\)/i then $4.to_i
else super
end
end
end

remove_const(:SQLite3Adapter) if const_defined?(:SQLite3Adapter)

Expand Down
103 changes: 103 additions & 0 deletions lib/arjdbc/sqlite3/column.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# frozen_string_literal: true

module ActiveRecord::ConnectionAdapters
class SQLite3Column < JdbcColumn

attr_reader :rowid

def initialize(name, default, sql_type_metadata = nil, null = true, default_function = nil, collation: nil, comment: nil, auto_increment: nil, rowid: false, **)
super
@auto_increment = auto_increment
@default = nil if default =~ /NULL/
@rowid = rowid
end

def self.string_to_binary(value)
value
end

def self.binary_to_string(value)
if value.respond_to?(:encoding) && value.encoding != Encoding::ASCII_8BIT
value = value.force_encoding(Encoding::ASCII_8BIT)
end
value
end

# @override {ActiveRecord::ConnectionAdapters::JdbcColumn#default_value}
def default_value(value)
# JDBC returns column default strings with actual single quotes :
return $1 if value =~ /^'(.*)'$/

value
end

def auto_increment?
@auto_increment
end

def auto_incremented_by_db?
auto_increment? || rowid
end

def init_with(coder)
@auto_increment = coder["auto_increment"]
super
end

def encode_with(coder)
coder["auto_increment"] = @auto_increment
super
end

def ==(other)
other.is_a?(Column) &&
super &&
auto_increment? == other.auto_increment?
end
alias :eql? :==

def hash
Column.hash ^
super.hash ^
auto_increment?.hash ^
rowid.hash
end

# @override {ActiveRecord::ConnectionAdapters::Column#type_cast}
def type_cast(value)
return nil if value.nil?
case type
when :string then value
when :primary_key
value.respond_to?(:to_i) ? value.to_i : ( value ? 1 : 0 )
when :float then value.to_f
when :decimal then self.class.value_to_decimal(value)
when :boolean then self.class.value_to_boolean(value)
else super
end
end

private

# @override {ActiveRecord::ConnectionAdapters::Column#extract_limit}
def extract_limit(sql_type)
return nil if sql_type =~ /^(real)\(\d+/i
super
end

def extract_precision(sql_type)
case sql_type
when /^(real)\((\d+)(,\d+)?\)/i then $2.to_i
else super
end
end

def extract_scale(sql_type)
case sql_type
when /^(real)\((\d+)\)/i then 0
when /^(real)\((\d+)(,(\d+))\)/i then $4.to_i
else super
end
end
end
end

0 comments on commit 291162a

Please sign in to comment.