Skip to content

Conversation

@kazu-2020
Copy link
Contributor

@kazu-2020 kazu-2020 commented Nov 15, 2025

Summary of Changes

This pull request introduces support for the time data type when using the SQLite backend. The ADBC SQLite driver does not natively support a time type, so this change implements a workaround by quoting Time objects as strings, which is consistent with how Rails' built-in SQLite3 adapter handles them.

The changes include:

  • Quoting: A quoted_time method has been added to quoting.rb. For the SQLite backend, it delegates to Rails' internal SQLite3::Quoting module to ensure the time is formatted into the standard 2000-01-01 HH:MM:SS.SSSSSS string format.
  • Result Set Conversion: The Result class in result.rb now correctly converts these time strings back into an Arrow::Time64Array when processing query results for a model.
  • Testing: The Time type tests in test_type.rb, which were previously omitted for SQLite, are now enabled and passing.

Reason for Changes

Without this change, using ActiveRecord::Type::Time with the SQLite backend would fail because the ADBC driver lacks native support for this data type. This implementation bridges the gap by adopting the same string-based serialization strategy used by the standard Rails SQLite3 adapter, enabling seamless use of the time type.

Affected Components

  • lib/activerecord_adbc_adapter/quoting.rb
  • lib/activerecord_adbc_adapter/result.rb
  • test/test_type.rb

Testing

The existing tests for the time type in test/test_type.rb now run successfully against the SQLite backend.

To verify:

  1. Set the backend to SQLite.
  2. Run the test suite, specifically test_time_active_record and test_time_arrow.
        bundle exec ruby test/run.rb -n /test_time/

All tests related to the Time type should pass.

Related issue

#7

@kazu-2020 kazu-2020 force-pushed the support-time-type-for-sqlite branch from 3ff54f7 to a5628ab Compare November 16, 2025 02:51
module Quoting
class Sqlite3
include ActiveRecord::ConnectionAdapters::Quoting
include ActiveRecord::ConnectionAdapters::SQLite3::Quoting
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test passes even with only the abstract module, but in that case, the resulting string will have the year and month information removed. (Reference: https://github.com/rails/rails/blob/90a1eaa1b30ba1f2d524e197460e549c03cf5698/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb#L191-L194)

However, SQLite3 explicitly appends 2000-01-01, so the SQLite3 module is included to maintain this behavior.
(Reference: https://github.com/rails/rails/blob/90a1eaa1b30ba1f2d524e197460e549c03cf5698/activerecord/lib/active_record/connection_adapters/sqlite3/quoting.rb#L74-L77)

@kazu-2020 kazu-2020 requested a review from kou November 16, 2025 03:04
Comment on lines 26 to 31
def sqlite3_quoting_proxy
@_sqlite3_quoting_proxy ||= begin
require_relative "quoting/sqlite3"

Quoting::Sqlite3.new(self)
end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Can we move require_relative "quoting/sqlite3" to the top-level?
  • How about renaming the cached instance variable to @quoting_sqlite3 to align with Quoting::Sqlite3 name?
Suggested change
def sqlite3_quoting_proxy
@_sqlite3_quoting_proxy ||= begin
require_relative "quoting/sqlite3"
Quoting::Sqlite3.new(self)
end
def quoting_sqlite3
@quoting_sqlite3 ||= Quoting::Sqlite3.new(self)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we move require_relative "quoting/sqlite3" to the top-level?

The Quoting::Sqlite3 class is unnecessary outside of sqlite3, so it was not required at the top level.

Is top-level better?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about renaming the cached instance variable to @quoting_sqlite3 to align with Quoting::Sqlite3 name?

fix by 81552e2

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is top-level better?

Yes. We should avoid needless dynamic require/require_relative as much as possible. It may be slow. e.g.: ruby/rexml#219

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, that's very educational!

fix by 8d3f2b9

if time_str.nil?
nil
else
dt = time_str.to_time
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does dt stand for "date time"?
time may be better because we use to_time here.

BTW, should we refer default_timezone here? It seems that String#to_time uses local time by default.

Copy link
Contributor Author

@kazu-2020 kazu-2020 Nov 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW, should we refer default_timezone here? It seems that String#to_time uses local time by default.

Exactly.
When reading from or writing to the database through ActiveRecord, the value of default_timezone is used.

https://github.com/rails/rails/blob/4a3ed47ff644549ba2d98ae37ead1832101836e4/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb#L172-L181

fix by 4b25d0f 🙆🏻‍♂️

@kazu-2020 kazu-2020 requested a review from kou November 18, 2025 00:01
@kou kou merged commit 7eddfec into red-data-tools:main Nov 18, 2025
3 checks passed
@kou
Copy link
Member

kou commented Nov 18, 2025

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants