Skip to content

fix time encoding to work with Cassandra 4 #269

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

Roguelazer
Copy link
Contributor

The default Ruby .to_s method for a Time results in output of %Y-%m-%d %H:%M:%S %z; note the space between the seconds and the time offset.

In Cassandra 4.0, the validator for the TIMESTAMP column type is stricter and there cannot be a space between the fractional part and the timezone offset and it must match the format yyyy-mm-dd[(T| )HH:MM:SS[.fff]][(+|-)NNNN].

@Roguelazer Roguelazer changed the title fix time encoding fix time encoding to work with Cassandra 4 Sep 16, 2021
@absurdfarce absurdfarce self-assigned this Oct 14, 2021
@absurdfarce absurdfarce self-requested a review October 14, 2021 22:15
@absurdfarce
Copy link
Contributor

absurdfarce commented Oct 15, 2021

Hey @Roguelazer, thanks (again) for the PR!

Do you happen to have some sample code that you can share which exercises this issue? I ask because it looks like you're trying to call Cassandra::Utils.encode_time with a Ruby Time object with the expectation that you'll get something out that can be inserted into a column of timestamp type. The problem is that the driver tries to encode Time objects via encode_timestamp while encode_time is reserved for Cassandra::Time (https://github.com/datastax/ruby-driver/blob/master/lib/cassandra/util.rb#L94-L115). So you wind up with the following behaviour here:

[mersault@linux ruby]$ irb
2.5.1 :001 > require 'cassandra'
 => true
2.5.1 :002 > Cassandra::Util.encode_timestamp(Time.now)
 => "1634273394"
2.5.1 :003 > Cassandra::Util.encode_time(Time.now)
 => "'2021-10-14 23:49:54 -0500'"
2.5.1 :004 > Cassandra::Util.encode_object(Time.now)
 => "1634273394"
2.5.1 :005 > Cassandra::Util.encode_timestamp(Cassandra::Time.new(1000000000 * 300))
Traceback (most recent call last):
        3: from /home/mersault/.rvm/rubies/ruby-2.5.1/bin/irb:11:in `<main>'
        2: from (irb):5
        1: from /home/mersault/.rvm/gems/ruby-2.5.1@countapp/gems/cassandra-driver-3.2.5/lib/cassandra/util.rb:127:in `encode_timestamp'
NoMethodError (undefined method `to_i' for #<Cassandra::Time:0x00000000031dcf88 @nanoseconds=300000000000>)
Did you mean?  to_s
2.5.1 :006 > Cassandra::Util.encode_time(Cassandra::Time.new(1000000000 * 300))
 => "'00:05:00.000'"
2.5.1 :007 > Cassandra::Util.encode_object(Cassandra::Time.new(1000000000 * 300))
 => "'00:05:00.000'"

Given that a Ruby top-level Time object maps to a "timestamp" CQL type while Cassandra::Time maps to a "time" type I'd expect that given the following:

CREATE KEYSPACE foo WITH REPLICATION = {'class' : 'SimpleStrategy', 'replication_factor' : 1};
CREATE TABLE foo.bar (key int PRIMARY KEY, ts timestamp);

this code should work without issue:

require 'cassandra'
require 'cassandra/util'
require 'time'

cluster = Cassandra.cluster
session = cluster.connect
stmt = session.prepare "insert into foo.bar (key,ts) values (?,?)"
session.execute stmt, arguments: [1, Time.now]

And indeed that's exactly what I get; the code runs without an error of any kind and after execution I observe the following:

cqlsh> select * from foo.bar;                                                                                                                                                    

 key | ts
-----+---------------------------------
   1 | 2021-10-15 05:30:53.477000+0000

(1 rows)

That's with Ruby 2.5.1 (using cassandra-driver 3.2.5) against Cassandra 4.0.0.

Please let me know if I've misunderstood something about your use case @Roguelazer.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants