Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

get_indexed_slices: key_start -> start_key (for API consistency) #155

Merged
merged 9 commits into from

2 participants

This page is out of date. Refresh to see the latest.
View
6 conf/1.0/schema.txt
@@ -15,7 +15,11 @@ create column family UserRelationships with
column_type = 'Super' and
subcomparator = 'TimeUUIDType';
create column family Usernames with comparator = 'UTF8Type';
-create column family Statuses with comparator = 'UTF8Type';
+create column family Statuses
+ with comparator = 'UTF8Type'
+ and column_metadata = [
+ {column_name: 'tags', validation_class: 'BytesType', index_type: 'KEYS'}
+ ];
create column family StatusAudits with comparator = 'UTF8Type';
create column family StatusRelationships with
comparator = 'UTF8Type' and
View
53 lib/cassandra/cassandra.rb
@@ -3,7 +3,7 @@
Create a new Cassandra client instance. Accepts a keyspace name, and optional host and port.
client = Cassandra.new('twitter', '127.0.0.1:9160')
-
+
If the server requires authentication, you must authenticate before make calls
client.login!('username','password')
@@ -466,7 +466,7 @@ def insert(column_family, key, hash, options = {})
##
# This method is used to delete (actually marking them as deleted with a
- # tombstone) rows, columns, or super columns depending on the parameters
+ # tombstone) rows, columns, or super columns depending on the parameters
# passed. If only a key is passed the entire row will be marked as deleted.
# If a column name is passed in that column will be deleted.
#
@@ -487,14 +487,14 @@ def remove(column_family, key, *columns_and_options)
column_family, column, sub_column, options = extract_and_validate_params(column_family, key, columns_and_options, WRITE_DEFAULTS)
if @batch
- mutation_map =
+ mutation_map =
{
key => {
column_family => [ _delete_mutation(column_family, column, sub_column, options[:timestamp]|| Time.stamp) ]
}
}
@batch << [mutation_map, options[:consistency]]
- else
+ else
# Let's continue using the 'remove' thrift method...not sure about the implications/performance of using the mutate instead
# Otherwise we coul get use the mutation_map above, and do _mutate(mutation_map, options[:consistency])
args = {:column_family => column_family}
@@ -518,8 +518,8 @@ def remove(column_family, key, *columns_and_options)
# * :consistency - Uses the default read consistency if none specified.
#
def count_columns(column_family, key, *columns_and_options)
- column_family, super_column, _, options =
- extract_and_validate_params(column_family, key, columns_and_options, READ_DEFAULTS)
+ column_family, super_column, _, options =
+ extract_and_validate_params(column_family, key, columns_and_options, READ_DEFAULTS)
_count_columns(column_family, key, super_column, options[:start], options[:stop], options[:count], options[:consistency])
end
@@ -542,7 +542,7 @@ def multi_count_columns(column_family, keys, *options)
end
##
- # Return a hash of column value pairs for the path you request.
+ # Return a hash of column value pairs for the path you request.
#
# * column_family - The column_family that you are inserting into.
# * key - The row key to insert.
@@ -552,8 +552,8 @@ def multi_count_columns(column_family, keys, *options)
# * :consistency - Uses the default read consistency if none specified.
#
def get_columns(column_family, key, *columns_and_options)
- column_family, columns, sub_columns, options =
- extract_and_validate_params(column_family, key, columns_and_options, READ_DEFAULTS)
+ column_family, columns, sub_columns, options =
+ extract_and_validate_params(column_family, key, columns_and_options, READ_DEFAULTS)
_get_columns(column_family, key, columns, sub_columns, options[:consistency])
end
@@ -578,7 +578,7 @@ def multi_get_columns(column_family, keys, *options)
##
# Return a hash (actually, a Cassandra::OrderedHash) or a single value
# representing the element at the column_family:key:[column]:[sub_column]
- # path you request.
+ # path you request.
#
# * column_family - The column_family that you are inserting into.
# * key - The row key to insert.
@@ -617,7 +617,7 @@ def get(column_family, key, *columns_and_options)
# * :consistency - Uses the default read consistency if none specified.
#
def multi_get(column_family, keys, *columns_and_options)
- column_family, column, sub_column, options =
+ column_family, column, sub_column, options =
extract_and_validate_params(column_family, keys, columns_and_options, READ_DEFAULTS)
hash = _multiget(column_family, keys, column, sub_column, options[:count], options[:start], options[:finish], options[:reversed], options[:consistency])
@@ -646,7 +646,7 @@ def multi_get(column_family, keys, *columns_and_options)
# * :consistency - Uses the default read consistency if none specified.
#
def exists?(column_family, key, *columns_and_options)
- column_family, column, sub_column, options =
+ column_family, column, sub_column, options =
extract_and_validate_params(column_family, key, columns_and_options, READ_DEFAULTS)
result = if column
_multiget(column_family, [key], column, sub_column, 1, '', '', false, options[:consistency])[key]
@@ -667,7 +667,7 @@ def exists?(column_family, key, *columns_and_options)
# Cassandra#get_range_single will be used.
#
# The start_key and finish_key parameters are only useful for iterating of all records
- # as is done in the Cassandra#each and Cassandra#each_key methods if you are using the
+ # as is done in the Cassandra#each and Cassandra#each_key methods if you are using the
# RandomPartitioner.
#
# If the table is partitioned with OrderPreservingPartitioner you may
@@ -678,11 +678,11 @@ def exists?(column_family, key, *columns_and_options)
# each record returned.
#
# Please note that Cassandra returns a row for each row that has existed in the
- # system since gc_grace_seconds. This is because deleted row keys are marked as
+ # system since gc_grace_seconds. This is because deleted row keys are marked as
# deleted, but left in the system until the cluster has had resonable time to replicate the deletion.
# This function attempts to suppress deleted rows (actually any row returned without
# columns is suppressed).
- #
+ #
# Please note that when enabling the :reversed option, :start and :finish should be swapped (e.g.
# reversal happens before selecting the range).
#
@@ -716,8 +716,8 @@ def get_range(column_family, options = {}, &blk)
def get_range_single(column_family, options = {})
return_empty_rows = options.delete(:return_empty_rows) || false
- column_family, _, _, options =
- extract_and_validate_params(column_family, "", [options],
+ column_family, _, _, options =
+ extract_and_validate_params(column_family, "", [options],
READ_DEFAULTS.merge(:start_key => '',
:finish_key => '',
:key_count => 100,
@@ -851,10 +851,10 @@ def batch(options = {})
@batch = []
yield(self)
compacted_map,seen_clevels = compact_mutations!
- clevel = if options[:consistency] != nil # Override any clevel from individual mutations if
+ clevel = if options[:consistency] != nil # Override any clevel from individual mutations if
options[:consistency]
elsif seen_clevels.length > 1 # Cannot choose which CLevel to use if there are several ones
- raise "Multiple consistency levels used in the batch, and no override...cannot pick one"
+ raise "Multiple consistency levels used in the batch, and no override...cannot pick one"
else # if no consistency override has been provided but all the clevels in the batch are the same: use that one
seen_clevels.first
end
@@ -954,7 +954,7 @@ def create_index_clause(index_expressions, start = "", count = 100)
##
# This method is used to query a secondary index with a set of
- # provided search parameters
+ # provided search parameters.
#
# Please note that you can either specify a
# CassandraThrift::IndexClause or an array of hashes with the
@@ -967,7 +967,7 @@ def create_index_clause(index_expressions, start = "", count = 100)
# * :comparison - Type of comparison to do.
# * options
# * :key_count - Set maximum number of rows to return. (Only works if CassandraThrift::IndexClause is not passed in.)
- # * :key_start - Set starting row key for search. (Only works if CassandraThrift::IndexClause is not passed in.)
+ # * :start_key - Set starting row key for search. (Only works if CassandraThrift::IndexClause is not passed in.)
# * :consistency
#
# TODO: Supercolumn support.
@@ -975,14 +975,17 @@ def get_indexed_slices(column_family, index_clause, *columns_and_options)
return false if Cassandra.VERSION.to_f < 0.7
column_family, columns, _, options =
- extract_and_validate_params(column_family, [], columns_and_options, READ_DEFAULTS.merge(:key_count => 100, :key_start => ""))
+ extract_and_validate_params(column_family, [], columns_and_options,
+ READ_DEFAULTS.merge(:key_count => 100, :start_key => nil, :key_start => nil))
+
+ start_key = options[:start_key] || options[:key_start] || ""
if index_clause.class != CassandraThrift::IndexClause
index_expressions = index_clause.collect do |expression|
create_index_expression(expression[:column_name], expression[:value], expression[:comparison])
end
- index_clause = create_index_clause(index_expressions, options[:key_start], options[:key_count])
+ index_clause = create_index_clause(index_expressions, start_key, options[:key_count])
end
key_slices = _get_indexed_slices(column_family, index_clause, columns, options[:count], options[:start],
@@ -1009,13 +1012,13 @@ def compact_mutations!
@batch.each do |mutation_op|
# A single mutation op looks like:
# For an insert/update
- #[ { key1 =>
+ #[ { key1 =>
# { CF1 => [several of CassThrift:Mutation(colname,value,TS,ttl)]
# CF2 => [several mutations]
# },
# key2 => {...} # Not sure if they can come batched like this...so there might only be a single key (and CF)
# }, # [0]
- # consistency # [1]
+ # consistency # [1]
#]
mmap = mutation_op[0] # :remove OR a hash like {"key"=> {"CF"=>[mutationclass1,...] } }
used_clevels[mutation_op[1]] = true #save the clevel required for this operation
View
7 lib/cassandra/mock.rb
@@ -295,10 +295,13 @@ def create_index_clause(idx_expressions, start = "", count = 100)
def get_indexed_slices(column_family, idx_clause, *columns_and_options)
column_family, columns, _, options =
- extract_and_validate_params_for_real(column_family, [], columns_and_options, READ_DEFAULTS.merge(:key_count => 100, :key_start => ""))
+ extract_and_validate_params_for_real(column_family, [], columns_and_options,
+ READ_DEFAULTS.merge(:key_count => 100, :start_key => nil, :key_start => nil))
+
+ start_key = options[:start_key] || options[:key_start] || ""
unless [Hash, OrderedHash].include?(idx_clause.class) && idx_clause[:type] == :index_clause
- idx_clause = create_index_clause(idx_clause, options[:key_start], options[:key_count])
+ idx_clause = create_index_clause(idx_clause, start_key, options[:key_count])
end
ret = {}
View
372 test/cassandra_test.rb
@@ -3,6 +3,10 @@
class CassandraTest < Test::Unit::TestCase
include Cassandra::Constants
+ def assert_has_keys(keys, hash)
+ assert_equal Set.new(keys), Set.new(hash.keys)
+ end
+
def setup
@twitter = Cassandra.new('Twitter', "127.0.0.1:9160", :retries => 2, :connect_timeout => 0.1, :timeout => 5, :exception_classes => [])
@twitter.clear_keyspace!
@@ -720,69 +724,361 @@ def test_each_column_types
if CASSANDRA_VERSION.to_f >= 0.7
def test_creating_and_dropping_new_index
- @twitter.create_index('Twitter', 'Statuses', 'column_name', 'LongType')
- assert_nil @twitter.create_index('Twitter', 'Statuses', 'column_name', 'LongType')
+ @twitter.create_index('Twitter', 'Statuses', 'column_name', 'BytesType')
+ assert_nil @twitter.create_index('Twitter', 'Statuses', 'column_name', 'BytesType')
@twitter.drop_index('Twitter', 'Statuses', 'column_name')
assert_nil @twitter.drop_index('Twitter', 'Statuses', 'column_name')
# Recreating and redropping the same index should not error either.
- @twitter.create_index('Twitter', 'Statuses', 'column_name', 'LongType')
+ @twitter.create_index('Twitter', 'Statuses', 'column_name', 'BytesType')
@twitter.drop_index('Twitter', 'Statuses', 'column_name')
end
def test_get_indexed_slices
- @twitter.create_index('Twitter', 'Statuses', 'x', 'LongType')
+ @twitter.insert(:Statuses, 'row_a', {
+ 'tags' => 'a',
+ 'y' => 'foo'
+ })
+ @twitter.insert(:Statuses, 'row_b', {
+ 'tags' => 'b',
+ 'y' => 'foo'
+ })
+ [1,2].each do |i|
+ @twitter.insert(:Statuses, "row_c_#{i}", {
+ 'tags' => 'c',
+ 'y' => 'a'
+ })
+ end
+ [3,4].each do |i|
+ @twitter.insert(:Statuses, "row_c_#{i}", {
+ 'tags' => 'c',
+ 'y' => 'b'
+ })
+ end
+ @twitter.insert(:Statuses, 'row_d', {
+ 'tags' => 'd',
+ 'y' => 'foo'
+ })
+ @twitter.insert(:Statuses, 'row_e', {
+ 'tags' => 'e',
+ 'y' => 'bar'
+ })
+
+ # Test == operator (single clause)
+ rows = @twitter.get_indexed_slices(:Statuses, [
+ {:column_name => 'tags',
+ :value => 'c',
+ :comparison => "=="}
+ ])
+ assert_has_keys %w[row_c_1 row_c_2 row_c_3 row_c_4], rows
+
+ # Test other operators
+ # Currently (as of Cassandra 1.1) you can't use anything but == as the
+ # primary query -- you must match on == first, and subsequent clauses are
+ # then applied as filters -- so that's what we are doing here.
+
+ # Test > operator
+ rows = @twitter.get_indexed_slices(:Statuses, [
+ {:column_name => 'tags',
+ :value => 'c',
+ :comparison => "=="},
+ {:column_name => 'y',
+ :value => 'a',
+ :comparison => ">"}
+ ])
+ assert_has_keys %w[row_c_3 row_c_4], rows
+
+ # Test >= operator
+ rows = @twitter.get_indexed_slices(:Statuses, [
+ {:column_name => 'tags',
+ :value => 'c',
+ :comparison => "=="},
+ {:column_name => 'y',
+ :value => 'a',
+ :comparison => ">="}
+ ])
+ assert_has_keys %w[row_c_1 row_c_2 row_c_3 row_c_4], rows
+
+ # Test < operator
+ rows = @twitter.get_indexed_slices(:Statuses, [
+ {:column_name => 'tags',
+ :value => 'c',
+ :comparison => "=="},
+ {:column_name => 'y',
+ :value => 'b',
+ :comparison => "<"}
+ ])
+ assert_has_keys %w[row_c_1 row_c_2], rows
+
+ # Test <= operator
+ rows = @twitter.get_indexed_slices(:Statuses, [
+ {:column_name => 'tags',
+ :value => 'c',
+ :comparison => "=="},
+ {:column_name => 'y',
+ :value => 'b',
+ :comparison => "<="}
+ ])
+ assert_has_keys %w[row_c_1 row_c_2 row_c_3 row_c_4], rows
+
+ # Test query on a non-indexed column
+ unless self.is_a?(CassandraMockTest)
+ assert_raises(CassandraThrift::InvalidRequestException) do
+ @twitter.get_indexed_slices(:Statuses, [
+ {:column_name => 'y',
+ :value => 'foo',
+ :comparison => "=="}
+ ])
+ end
+ end
- @twitter.insert(:Statuses, 'row1', { 'x' => [0,10].pack("NN") })
+ # Test start key
+ rows = @twitter.get_indexed_slices(:Statuses, [
+ {:column_name => 'tags',
+ :value => 'c',
+ :comparison => "=="},
+ ], :start_key => 'row_c_2')
+ assert_equal 'row_c_2', rows.keys.first
+ # <- can't test any keys after that since it's going to be random
+
+ # Test key_start option
+ rows = @twitter.get_indexed_slices(:Statuses, [
+ {:column_name => 'tags',
+ :value => 'c',
+ :comparison => "=="},
+ ], :key_start => 'row_c_2')
+ assert_equal 'row_c_2', rows.keys.first
+ # <- can't test any keys after that since it's going to be random
+
+ # Test key count
+ rows = @twitter.get_indexed_slices(:Statuses, [
+ {:column_name => 'tags',
+ :value => 'c',
+ :comparison => "=="}
+ ], :key_count => 2)
+ assert_equal 2, rows.length
+ # <- can't test which keys are present since it's going to be random
+ end
- (2..10).to_a.each do |i|
- @twitter.insert(:Statuses, 'row' + i.to_s, { 'x' => [0,20].pack("NN"), 'non_indexed' => [i].pack('N*') })
+ def test_get_indexed_slices_with_IndexClause_objects
+ @twitter.insert(:Statuses, 'row_a', {
+ 'tags' => 'a',
+ 'y' => 'foo'
+ })
+ @twitter.insert(:Statuses, 'row_b', {
+ 'tags' => 'b',
+ 'y' => 'foo'
+ })
+ [1,2].each do |i|
+ @twitter.insert(:Statuses, "row_c_#{i}", {
+ 'tags' => 'c',
+ 'y' => 'a'
+ })
+ end
+ [3,4].each do |i|
+ @twitter.insert(:Statuses, "row_c_#{i}", {
+ 'tags' => 'c',
+ 'y' => 'b'
+ })
+ end
+ @twitter.insert(:Statuses, 'row_d', {
+ 'tags' => 'd',
+ 'y' => 'foo'
+ })
+ @twitter.insert(:Statuses, 'row_e', {
+ 'tags' => 'e',
+ 'y' => 'bar'
+ })
+
+ # Test == operator (single clause)
+ index_clause = @twitter.create_index_clause([
+ @twitter.create_index_expression('tags', 'c', '==')
+ ])
+ rows = @twitter.get_indexed_slices(:Statuses, index_clause)
+ assert_has_keys %w[row_c_1 row_c_2 row_c_3 row_c_4], rows
+
+ # Test other operators
+ # Currently (as of Cassandra 1.1) you can't use anything but == as the
+ # primary query -- you must match on == first, and subsequent clauses are
+ # then applied as filters -- so that's what we are doing here.
+
+ # Test > operator
+ index_clause = @twitter.create_index_clause([
+ @twitter.create_index_expression('tags', 'c', '=='),
+ @twitter.create_index_expression('y', 'a', '>'),
+ ])
+ rows = @twitter.get_indexed_slices(:Statuses, index_clause)
+ assert_has_keys %w[row_c_3 row_c_4], rows
+
+ # Test >= operator
+ index_clause = @twitter.create_index_clause([
+ @twitter.create_index_expression('tags', 'c', '=='),
+ @twitter.create_index_expression('y', 'a', '>=')
+ ])
+ rows = @twitter.get_indexed_slices(:Statuses, index_clause)
+ assert_has_keys %w[row_c_1 row_c_2 row_c_3 row_c_4], rows
+
+ # Test < operator
+ index_clause = @twitter.create_index_clause([
+ @twitter.create_index_expression('tags', 'c', '=='),
+ @twitter.create_index_expression('y', 'b', '<')
+ ])
+ rows = @twitter.get_indexed_slices(:Statuses, index_clause)
+ assert_has_keys %w[row_c_1 row_c_2], rows
+
+ # Test <= operator
+ index_clause = @twitter.create_index_clause([
+ @twitter.create_index_expression('tags', 'c', '=='),
+ @twitter.create_index_expression('y', 'b', '<=')
+ ])
+ rows = @twitter.get_indexed_slices(:Statuses, index_clause)
+ assert_has_keys %w[row_c_1 row_c_2 row_c_3 row_c_4], rows
+
+ # Test query on a non-indexed column
+ unless self.is_a?(CassandraMockTest)
+ assert_raises(CassandraThrift::InvalidRequestException) do
+ index_clause = @twitter.create_index_clause([
+ @twitter.create_index_expression('y', 'foo', '==')
+ ])
+ @twitter.get_indexed_slices(:Statuses, index_clause)
+ end
end
- @twitter.insert(:Statuses, 'row11', { 'x' => [0,30].pack("NN") })
+ # Test start key
+ index_clause = @twitter.create_index_clause([
+ @twitter.create_index_expression('tags', 'c', '==')
+ ], 'row_c_2')
+ rows = @twitter.get_indexed_slices(:Statuses, index_clause)
+ assert_equal 'row_c_2', rows.keys.first
+ # <- can't test any keys after that since it's going to be random
+
+ # Test key count
+ index_clause = @twitter.create_index_clause([
+ @twitter.create_index_expression('tags', 'c', '==')
+ ], "", 2)
+ rows = @twitter.get_indexed_slices(:Statuses, index_clause)
+ assert_equal 2, rows.length
+ # <- can't test which keys are present since it's going to be random
+ end
- expressions = [{:column_name => 'x', :value => [0,20].pack("NN"), :comparison => "=="}]
+ def test_create_index_clause
+ return if self.is_a?(CassandraMockTest)
- # verify multiples will be returned
- assert_equal 9, @twitter.get_indexed_slices(:Statuses, expressions).length
+ ie = CassandraThrift::IndexExpression.new(
+ :column_name => 'foo',
+ :value => 'x',
+ :op => '=='
+ )
- # verify that GT and LT queries perform properly
- expressions = [
- {:column_name => 'x', :value => [0,20].pack("NN"), :comparison => "=="},
- {:column_name => 'non_indexed', :value => [5].pack("N*"), :comparison => ">"}
- ]
- assert_equal(5, @twitter.get_indexed_slices(:Statuses, expressions).length)
+ ic = @twitter.create_index_clause([ie], 'aaa', 250)
+ assert_instance_of CassandraThrift::IndexClause, ic
+ assert_equal 'aaa', ic.start_key
+ assert_equal ie, ic.expressions[0]
+ assert_equal 250, ic.count
+
+ # test alias
+ ic = @twitter.create_idx_clause([ie], 'aaa', 250)
+ assert_instance_of CassandraThrift::IndexClause, ic
+ assert_equal 'aaa', ic.start_key
+ assert_equal ie, ic.expressions[0]
+ assert_equal 250, ic.count
end
- def test_old_get_indexed_slices
- @twitter.create_index('Twitter', 'Statuses', 'x', 'LongType')
+ def test_create_index_expression
+ return if self.is_a?(CassandraMockTest)
- @twitter.insert(:Statuses, 'row1', { 'x' => [0,10].pack("NN") })
-
- (2..10).to_a.each do |i|
- @twitter.insert(:Statuses, 'row' + i.to_s, { 'x' => [0,20].pack("NN"), 'non_indexed' => [i].pack('N*') })
+ # EQ operator
+ [nil, "EQ", "eq", "=="].each do |op|
+ ie = @twitter.create_index_expression('foo', 'x', op)
+ assert_instance_of CassandraThrift::IndexExpression, ie
+ assert_equal 'foo', ie.column_name
+ assert_equal 'x', ie.value
+ assert_equal CassandraThrift::IndexOperator::EQ, ie.op
+ end
+ # alias
+ [nil, "EQ", "eq", "=="].each do |op|
+ ie = @twitter.create_idx_expr('foo', 'x', op)
+ assert_instance_of CassandraThrift::IndexExpression, ie
+ assert_equal 'foo', ie.column_name
+ assert_equal 'x', ie.value
+ assert_equal CassandraThrift::IndexOperator::EQ, ie.op
end
- @twitter.insert(:Statuses, 'row11', { 'x' => [0,30].pack("NN") })
+ # GTE operator
+ ["GTE", "gte", ">="].each do |op|
+ ie = @twitter.create_index_expression('foo', 'x', op)
+ assert_instance_of CassandraThrift::IndexExpression, ie
+ assert_equal 'foo', ie.column_name
+ assert_equal 'x', ie.value
+ assert_equal CassandraThrift::IndexOperator::GTE, ie.op
+ end
+ # alias
+ ["GTE", "gte", ">="].each do |op|
+ ie = @twitter.create_idx_expr('foo', 'x', op)
+ assert_instance_of CassandraThrift::IndexExpression, ie
+ assert_equal 'foo', ie.column_name
+ assert_equal 'x', ie.value
+ assert_equal CassandraThrift::IndexOperator::GTE, ie.op
+ end
- idx_expr = @twitter.create_idx_expr('x', [0,20].pack("NN"), "==")
+ # GT operator
+ ["GT", "gt", ">"].each do |op|
+ ie = @twitter.create_index_expression('foo', 'x', op)
+ assert_instance_of CassandraThrift::IndexExpression, ie
+ assert_equal 'foo', ie.column_name
+ assert_equal 'x', ie.value
+ assert_equal CassandraThrift::IndexOperator::GT, ie.op
+ end
+ # alias
+ ["GT", "gt", ">"].each do |op|
+ ie = @twitter.create_idx_expr('foo', 'x', op)
+ assert_instance_of CassandraThrift::IndexExpression, ie
+ assert_equal 'foo', ie.column_name
+ assert_equal 'x', ie.value
+ assert_equal CassandraThrift::IndexOperator::GT, ie.op
+ end
- # verify count is observed
- idx_clause = @twitter.create_idx_clause([idx_expr], "", 1)
- assert_equal 1, @twitter.get_indexed_slices(:Statuses, idx_clause).length
+ # LTE operator
+ ["LTE", "lte", "<="].each do |op|
+ ie = @twitter.create_index_expression('foo', 'x', op)
+ assert_instance_of CassandraThrift::IndexExpression, ie
+ assert_equal 'foo', ie.column_name
+ assert_equal 'x', ie.value
+ assert_equal CassandraThrift::IndexOperator::LTE, ie.op
+ end
+ # alias
+ ["LTE", "lte", "<="].each do |op|
+ ie = @twitter.create_idx_expr('foo', 'x', op)
+ assert_instance_of CassandraThrift::IndexExpression, ie
+ assert_equal 'foo', ie.column_name
+ assert_equal 'x', ie.value
+ assert_equal CassandraThrift::IndexOperator::LTE, ie.op
+ end
- # verify multiples will be returned
- idx_clause = @twitter.create_idx_clause([idx_expr])
- assert_equal 9, @twitter.get_indexed_slices(:Statuses, idx_clause).length
+ # LT operator
+ ["LT", "lt", "<"].each do |op|
+ ie = @twitter.create_index_expression('foo', 'x', op)
+ assert_instance_of CassandraThrift::IndexExpression, ie
+ assert_equal 'foo', ie.column_name
+ assert_equal 'x', ie.value
+ assert_equal CassandraThrift::IndexOperator::LT, ie.op
+ end
+ # alias
+ ["LT", "lt", "<"].each do |op|
+ ie = @twitter.create_idx_expr('foo', 'x', op)
+ assert_instance_of CassandraThrift::IndexExpression, ie
+ assert_equal 'foo', ie.column_name
+ assert_equal 'x', ie.value
+ assert_equal CassandraThrift::IndexOperator::LT, ie.op
+ end
- # verify that GT and LT queries perform properly
- idx_expr = [
- @twitter.create_idx_expr('x', [0,20].pack("NN"), "=="),
- @twitter.create_idx_expr('non_indexed', [5].pack("N*"), ">")
- ]
- idx_clause = @twitter.create_idx_clause(idx_expr)
- assert_equal(5, @twitter.get_indexed_slices(:Statuses, idx_clause).length)
+ # unknown operator
+ ie = @twitter.create_index_expression('foo', 'x', '~$')
+ assert_equal nil, ie.op
+ # alias
+ ie = @twitter.create_idx_expr('foo', 'x', '~$')
+ assert_equal nil, ie.op
end
def test_column_family_mutation
Something went wrong with that request. Please try again.