Class: ActiveRecord::ConnectionAdapters::VirgodbTimestamp
- Inherits:
-
Type::DateTime
- Object
- Type::DateTime
- ActiveRecord::ConnectionAdapters::VirgodbTimestamp
- Defined in:
- lib/active_record/connection_adapters/virgodb_adapter.rb
Overview
virgodb's raw "Timestamp" type (crates/compact/src/schema.rs) is plain UNIX seconds -- an Integer, not a real SQL DATETIME/TIMESTAMP string -- but it still matches Rails' generic %r(time)i registration (see VirgodbAdapter.initialize_type_map below), landing on the stock ActiveRecord::Type::DateTime, which only knows how to parse a real date/time STRING (or an already-real Time/Date/Hash). Two confirmed, real failure modes from that mismatch, not just cosmetic ones:
Type::DateTime.new.cast("0")-- "0" being a perfectly valid epoch-seconds default (e.g. exit_page_at/split_test_id_at's own DEFAULT 0 sentinel, see db/migrate_virgodb/20260727000002_create_ahoy_visits.rb in hintpot) -- returns nil.Column#defaultitself is unaffected (DateTime ismutable?, soColumn#initializekeeps the raw string rather than deserializing it -- see ActiveModel::Type::DateTime#mutable?'s own comment), which is why the schema_versions capture above was never wrong. ButModel.column_defaults(what a real host app's own schema-annotation tooling reads) DOES deserialize through the cast type, surfacing as a misleadingdefault(NULL)in a real model's annotation for a column that has a perfectly real default.Type::DateTime.new.cast(1753000000)(a real Integer write-time value) ALSO doesn't produce a real Time object -- DateTime#cast only recognizes String/Time/Date/Hash input, so an Integer just passes through unchanged. Harmless today (nothing in this codebase reads a Timestamp column back through a real ActiveRecord attribute -- see Virgodb::Registry.query, which returns raw parsed JSON, bypassing AR type casting entirely), but a real latent gap the moment anything ever does.
Subclassing ActiveRecord::Type::DateTime (not building from scratch)
keeps .type == :datetime -- the semantically correct label for a
timestamp column, unlike the columns String fix above where Rails had
no keyword at all -- and keeps every other DateTime behavior (real
date strings, Time/Date input, timezone handling) working exactly as
before; only the epoch-seconds-as-Integer-or-String case needed a
fix. deserialize isn't overridden separately -- ActiveModel::Type
::Value#deserialize just calls cast by default (confirmed: neither
ActiveModel::Type::DateTime nor ActiveRecord::Type::DateTime override
it), so fixing cast alone is enough for both directions.
Instance Method Summary collapse
Instance Method Details
#cast(value) ⇒ Object
84 85 86 87 88 89 |
# File 'lib/active_record/connection_adapters/virgodb_adapter.rb', line 84 def cast(value) return value if value.nil? || value.is_a?(::Time) || value.is_a?(::DateTime) seconds = Float(value, exception: false) seconds ? ::Time.at(seconds).utc : super end |
#serialize(value) ⇒ Object
91 92 93 |
# File 'lib/active_record/connection_adapters/virgodb_adapter.rb', line 91 def serialize(value) value.respond_to?(:to_time) ? value.to_time.to_i : value end |