diff --git a/lib/cassava/client.rb b/lib/cassava/client.rb index 67e00be..4e2f33b 100644 --- a/lib/cassava/client.rb +++ b/lib/cassava/client.rb @@ -13,8 +13,11 @@ def initialize(session, opts = {}) # @see #insert def insert_async(table, data) ttl = data.delete(:ttl) + optional_timestamp = data.delete(:optional_timestamp) consistency = data.delete(:consistency) - statement = insert_statement(table, data, ttl) + + statement = insert_statement(table, data, ttl, optional_timestamp) + if consistency.nil? executor.execute_async(statement, :arguments => data.values) else @@ -26,8 +29,11 @@ def insert_async(table, data) # @param data [Hash] A hash of column names to data, which will be inserted into the table def insert(table, data) ttl = data.delete(:ttl) + optional_timestamp = data.delete(:optional_timestamp) consistency = data.delete(:consistency) - statement = insert_statement(table, data, ttl) + + statement = insert_statement(table, data, ttl, optional_timestamp) + if consistency.nil? executor.execute(statement, :arguments => data.values) else @@ -50,11 +56,16 @@ def select_ttl(table, target_attr, where_arguments) executor.execute(prepared_statement, :arguments => where_arguments.values).rows.first["ttl(#{target_attr})"] end + def select_writetime(table, target_attr, where_arguments) + prepared_statement = select_writetime_statement(table, target_attr, where_arguments) + executor.execute(prepared_statement, :arguments => where_arguments.values).rows.first["writetime(#{target_attr})"] + end + # @param table [Symbol] the table name # @param columns [Array] Columns to delete -- defaults to all. # @return [StatementBuilder] - def delete(table, columns = nil) - add_clause(DeleteClause.new(table, columns), :main) + def delete(table, columns = nil, timestamp=nil) + add_clause(DeleteClause.new(table, columns, timestamp), :main) end # Condition the query based on a condition @@ -215,10 +242,14 @@ def to_s end end - DeleteClause = Struct.new(:table, :columns) do + DeleteClause = Struct.new(:table, :columns, :timestamp) do def to_s - if columns + if columns && timestamp + "DELETE #{columns.join(', ')} from #{table} USING TIMESTAMP #{timestamp}" + elsif columns "DELETE #{columns.join(', ')} from #{table}" + elsif timestamp + "DELETE from #{table} USING TIMESTAMP #{timestamp}" else "DELETE from #{table}" end diff --git a/lib/cassava/version.rb b/lib/cassava/version.rb index a17a101..00d3bac 100644 --- a/lib/cassava/version.rb +++ b/lib/cassava/version.rb @@ -1,3 +1,3 @@ module Cassava - VERSION = "0.1.4" + VERSION = "0.1.5" end diff --git a/test/cassava/client_test.rb b/test/cassava/client_test.rb index b7116cb..af3a17b 100644 --- a/test/cassava/client_test.rb +++ b/test/cassava/client_test.rb @@ -47,9 +47,31 @@ def string_keys(hash) item = { :id => 'i', :a => 1, :b => 'b', :c => "'\"item(", :d => 1, :ttl => ttl } @client.insert(:test, item) - assert @client.send(:insert_statement, :test, item, ttl).cql =~ /\sUSING\sTTL\s#{ttl}$/ + assert @client.send(:insert_statement, :test, item, ttl).cql =~ /\sUSING\sTTL\s#{ttl}/ assert_equal string_keys(item), @client.select(:test).execute.first end + + should 'allow the insertion with a timestamp' do + timestamp = Time.now.to_i * 1000000 + Time.now.usec + item = { :id => 'i', :a => 1, :b => 'b', :c => "'\"item(", :d => 1, :optional_timestamp => timestamp } + @client.insert(:test, item) + + assert @client.send(:insert_statement, :test, item, nil, timestamp).cql =~ /\sUSING\sTIMESTAMP\s#{timestamp}/ + saved_timestamp = @client.select_writetime(:test, :d, { :id => 'i' }) + assert_equal timestamp, saved_timestamp + end + + should 'allow the insertion of a ttl and a timestamp' do + ttl = 12345 + timestamp = Time.now.to_i * 1000000 + Time.now.usec + item = { :id => 'i', :a => 1, :b => 'b', :c => "'\"item(", :d => 1, :ttl => ttl, :optional_timestamp => timestamp } + @client.insert(:test, item) + + assert @client.send(:insert_statement, :test, item, ttl, timestamp).cql =~ /\sUSING\sTTL\s#{ttl}\sAND\sTIMESTAMP\s#{timestamp}/ + assert_equal string_keys(item), @client.select(:test).execute.first + saved_timestamp = @client.select_writetime(:test, :d, { :id => 'i' }) + assert_equal timestamp, saved_timestamp + end end context 'select' do @@ -180,6 +202,21 @@ def string_keys(hash) end end + context 'select_writetime' do + should 'build the correct writetime select statement' do + statement = @client.send(:select_writetime_statement, :test, :d, { :id => 'i' }) + assert_match /SELECT WRITETIME/, statement.cql + end + + should 'correctly fetch the timestamp of a given column' do + item = { :id => 'i', :a => 1, :b => 'b', :c => "item", :d => 1 } + @client.insert(:test, item) + + timestamp = @client.select_writetime(:test, :d, { :id => 'i' }) + assert timestamp + end + end + context 'delete' do setup do @client.insert(:test, :id => 'i', :a => 2, :b => 'a', :c => '1', :d => 1) @@ -205,6 +242,15 @@ def string_keys(hash) assert_nil items.first['d'] end + should 'delete with a timestamp' do + timestamp = Time.now.to_i * 1000000 + Time.now.usec + assert @client.delete(:test, [:c, :d], timestamp).where(:id => 'i', :a => 2, :b => 'a').statement =~ /\sUSING\sTIMESTAMP\s#{timestamp}/ + @client.delete(:test, [:c, :d]).where(:id => 'i', :a => 2, :b => 'a').execute + items = @client.select(:test).where(:id => 'i', :a => 2).execute + assert_nil items.first['c'] + assert_nil items.first['d'] + end + context 'hash arguments' do should 'allow single and double quotes in the value' do # no error raised