File Coverage

blib/lib/Cassandra/Lite.pm
Criterion Covered Total %
statement 31 142 21.8
branch 0 20 0.0
condition 0 34 0.0
subroutine 11 25 44.0
pod 6 6 100.0
total 48 227 21.1


line stmt bran cond sub pod time code
1             # ABSTRACT: Simple way to access Cassandra 0.7/0.8
2             package Cassandra::Lite;
3             BEGIN {
4 1     1   19432 $Cassandra::Lite::VERSION = '0.4.0';
5             }
6 1     1   8 use strict;
  1         2  
  1         28  
7 1     1   3 use warnings;
  1         2  
  1         31  
8              
9             =head1 NAME
10              
11             Cassandra::Lite - Simple way to access Cassandra 0.7/0.8
12              
13             =head1 VERSION
14              
15             version 0.4.0
16              
17             =head1 DESCRIPTION
18              
19             This module will offer you a simple way to access Cassandra 0.7/0.8 (maybe later version).
20             Some parts are not same as standard API document (especially arguments order), it's because I want to keep this module easy to use.
21              
22             Before using this module, you need to know about the basic model of Cassandra.
23             L is a good start.
24              
25             You'll need to install L perl modules first to use Cassandra::Lite.
26              
27             B
28              
29             =head1 SYNOPSIS
30              
31             First to initialize:
32              
33             use Cassandra::Lite;
34              
35             # Create with default options (C is a mantorary option):
36             my $c = Cassandra::Lite->new(keyspace => 'Keyspace1');
37              
38             # Now just define $columnFamily and $key
39             my $columnFamily = 'BlogArticle';
40             my $key = 'key12345';
41              
42             Then you can insert data:
43              
44             # Insert it.
45             $c->put($columnFamily, $key, {title => 'testing title', body => '...'});
46              
47             And get data:
48              
49             # Get a column
50             my $scalarValue = $c->get($columnFamily, $key, 'title');
51              
52             # Get all columns
53             my $hashRef = $c->get($columnFamily, $key);
54              
55             More, to delete data:
56              
57             # Remove it
58             $c->delete($columnFamily, $key);
59              
60             Others:
61              
62             # Change keyspace
63             $c->keyspace('BlogArticleComment');
64              
65             # Get count
66             my $num2 = $c->get_count('Foo', 'key1');
67              
68             # Truncate column family
69             $c->truncate('Foo');
70              
71             =cut
72              
73 1     1   783 use Any::Moose;
  1         361753  
  1         8  
74             has 'client' => (is => 'rw', isa => 'Cassandra::CassandraClient', lazy_build => 1);
75             has 'consistency_level_read' => (is => 'rw', isa => 'Str', default => 'ONE');
76             has 'consistency_level_write' => (is => 'rw', isa => 'Str', default => 'ONE');
77             has 'keyspace' => (is => 'rw', isa => 'Str', trigger => \&_trigger_keyspace);
78             has 'password' => (is => 'rw', isa => 'Str', default => '');
79             has 'protocol' => (is => 'rw', isa => 'Thrift::BinaryProtocol', lazy_build => 1);
80             has 'server_name' => (is => 'rw', isa => 'Str', default => '127.0.0.1');
81             has 'server_port' => (is => 'rw', isa => 'Int', default => 9160);
82             has 'socket' => (is => 'rw', isa => 'Thrift::Socket', lazy_build => 1);
83             has 'transport' => (is => 'rw', isa => 'Thrift::FramedTransport', lazy_build => 1);
84             has 'transport_read' => (is => 'rw', isa => 'Int', default => 1024);
85             has 'transport_write' => (is => 'rw', isa => 'Int', default => 1024);
86             has 'username' => (is => 'rw', isa => 'Str', default => '');
87              
88 1     1   815 use 5.010;
  1         3  
  1         40  
89 1     1   1824 use Cassandra::Cassandra;
  1         3  
  1         68  
90 1     1   15 use Cassandra::Types;
  1         3  
  1         21  
91 1     1   6 use Thrift;
  1         2  
  1         22  
92 1     1   1029 use Thrift::BinaryProtocol;
  1         341270  
  1         33  
93 1     1   808 use Thrift::FramedTransport;
  1         2869  
  1         25  
94 1     1   730 use Thrift::Socket;
  1         645605  
  1         1919  
95              
96             =head1 FUNCTION
97             =cut
98              
99             sub _build_client {
100 0     0     my $self = shift;
101              
102 0           my $client = Cassandra::CassandraClient->new($self->protocol);
103 0           $self->transport->open;
104 0           $self->_login($client);
105              
106 0           $client;
107             }
108              
109             sub _build_protocol {
110 0     0     my $self = shift;
111              
112 0           Thrift::BinaryProtocol->new($self->transport);
113             }
114              
115             sub _build_socket {
116 0     0     my $self = shift;
117              
118 0           Thrift::Socket->new($self->server_name, $self->server_port);
119             }
120              
121             sub _build_transport {
122 0     0     my $self = shift;
123              
124 0           Thrift::FramedTransport->new($self->socket, $self->transport_read, $self->transport_write);
125             }
126              
127             sub _consistency_level_read {
128 0     0     my $self = shift;
129 0   0       my $opt = shift // {};
130              
131 0   0       my $level = $opt->{consistency_level} // $self->consistency_level_read;
132              
133 0           eval "\$level = Cassandra::ConsistencyLevel::$level;";
134 0           $level;
135             }
136              
137             sub _consistency_level_write {
138 0     0     my $self = shift;
139 0   0       my $opt = shift // {};
140              
141 0   0       my $level = $opt->{consistency_level} // $self->consistency_level_write;
142              
143 0           eval "\$level = Cassandra::ConsistencyLevel::$level;";
144 0           $level;
145             }
146              
147             sub _login {
148 0     0     my $self = shift;
149 0           my $client = shift;
150              
151 0           my $auth = Cassandra::AuthenticationRequest->new;
152 0           $auth->{credentials} = {username => $self->username, password => $self->password};
153 0           $client->login($auth);
154             }
155              
156             sub _trigger_keyspace {
157 0     0     my ($self, $keyspace) = @_;
158              
159 0           $self->client->set_keyspace($keyspace);
160             }
161              
162             =item
163             C
164              
165             All supported options:
166              
167             my $c = Cassandra::Lite->new(
168             server_name => 'server1', # optional, default to '127.0.0.1'
169             server_port => 9160, # optional, default to 9160
170             username => 'username', # optional, default to empty string ''
171             password => 'xxx', # optional, default to empty string ''
172             consistency_level_read => 'ONE' # optional, default to 'ONE'
173             consistency_level_write => 'ONE' # optional, default to 'ONE'
174             transport_read => 1024, # optional, default to 1024
175             transport_write => 1024, # optional, default to 1024
176             keyspace => 'Keyspace1',
177             );
178              
179             So, usually we can use this in dev environment:
180              
181             my $c = Cassandra::Lite->new(keyspace => 'Keyspace1');
182              
183             =cut
184              
185             =item
186             C
187             =cut
188              
189             sub cql {
190 0     0 1   my $self = shift;
191              
192 0           my $query = shift;
193              
194 0           $self->client->execute_cql_query($query, Cassandra::Compression::NONE);
195             }
196              
197             =item
198             C
199              
200             Delete entire row.
201             =cut
202              
203             sub delete {
204 0     0 1   my $self = shift;
205              
206 0           my $columnFamily = shift;
207 0           my $key = shift;
208 0   0       my $opt = shift // {};
209              
210 0           my $columnPath = Cassandra::ColumnPath->new({column_family => $columnFamily});
211 0   0       my $timestamp = $opt->{timestamp} // time;
212              
213 0           my $level = $self->_consistency_level_write($opt);
214              
215 0           $self->client->remove($key, $columnPath, $timestamp, $level);
216             }
217              
218             =item
219             C
220              
221             The simplest syntax is to get all columns:
222              
223             my $cf = 'BlogArticle';
224             my $key1 = 'key12345';
225              
226             my $allColumns = $c->get($cf, $key1);
227              
228             You can get a single column:
229              
230             my $title = $c->get($cf, $key1, 'title');
231              
232             Also, you can get range column (this example will query from 'Column001' to 'Column999'):
233              
234             my $columns = $c->get($cf, $key1, {start => 'Column001', finish => 'Column999'});
235              
236             With multiple keys:
237              
238             my $key2 = 'key56789';
239              
240             my $datas1 = $c->get($cf, [$key1, $key2]);
241             my $datas2 = $c->get($cf, [$key1, $key2], {start => 'Column001', finish => 'Column999'});
242              
243             With key range:
244              
245             my $datas3 = $c->get($cf, {start_key => 'a', end_key => 'b'});
246             my $datas4 = $c->get($cf, {start_key => 'a', end_key => 'b'}, 'column');
247             my $datas5 = $c->get($cf, {start_key => 'a', end_key => 'b'},
248             {start => 'Column001', finish => 'Column999'});
249              
250             In order words, C<$key> can be scalar string (single key) or array reference (multiple keys).
251             And C<$column> can be undef (to get all columns), scalar string (to get one column), or hash reference (to get columns by range).
252              
253             =cut
254              
255             sub get {
256 0     0 1   my $self = shift;
257              
258 0           my $columnFamily = shift;
259 0           my $key = shift;
260 0           my $column = shift;
261 0   0       my $opt = shift // {};
262              
263             # Simple get is a totally different case. It doesn't use columnParent.
264 0 0 0       if ('SCALAR' eq ref \$key and defined $column and 'SCALAR' eq ref \$column) {
      0        
265 0           my $columnPath = Cassandra::ColumnPath->new({column_family => $columnFamily, column => $column});
266 0           my $level = $self->_consistency_level_read($opt);
267              
268 0           return $self->client->get($key, $columnPath, $level)->column->value;
269             }
270              
271 0           my $columnParent = Cassandra::ColumnParent->new({column_family => $columnFamily});
272              
273 0           my $sliceRange;
274 0 0         if (!defined $column) {
    0          
    0          
275 0           $sliceRange = Cassandra::SliceRange->new({start => '', finish => ''});
276             } elsif ('HASH' eq ref $column) {
277 0           $sliceRange = Cassandra::SliceRange->new($column);
278             } elsif ('SCALAR' eq ref \$column) {
279 0           $sliceRange = Cassandra::SliceRange->new({start => $column, finish => $column});
280             }
281              
282 0           my $predicate = Cassandra::SlicePredicate->new;
283 0           $predicate->{slice_range} = $sliceRange;
284              
285 0           my $level = $self->_consistency_level_read($opt);
286              
287 0 0         if ('SCALAR' eq ref \$key) {
288 0           return {map {$_->column->name => $_->column->value} @{$self->client->get_slice($key, $columnParent, $predicate, $level)}};
  0            
  0            
289             }
290              
291 0 0         if ('ARRAY' eq ref $key) {
    0          
292 0           my $ret = $self->client->multiget_slice($key, $columnParent, $predicate, $level);
293              
294 0 0 0       if (defined $column and 'SCALAR' eq ref \$column) {
295 0           while (my ($k, $columns) = each %$ret) {
296 0           $ret->{$k} = $columns->[0]->column->value;
297             }
298             } else {
299 0           while (my ($k, $columns) = each %$ret) {
300 0           $ret->{$k} = {map {$_->column->name => $_->column->value} @$columns};
  0            
301             }
302             }
303              
304 0           return $ret;
305             } elsif ('HASH' eq ref $key) {
306 0           my $range = Cassandra::KeyRange->new($key);
307 0           my $ret = $self->client->get_range_slices($columnParent, $predicate, $range, $level);
308              
309 0           my $ret2 = {};
310              
311 0 0 0       if (defined $column and 'SCALAR' eq ref \$column) {
312 0           foreach my $row (@$ret) {
313 0           $ret2->{$row->key} = $row->columns->[0]->column->value;
314             }
315             } else {
316 0           foreach my $row (@$ret) {
317 0           $ret2->{$row->key} = {map {$_->column->name => $_->column->value} @{$row->columns}};
  0            
  0            
318             }
319             }
320              
321 0           return $ret2;
322             }
323             }
324              
325             =item
326             C
327             =cut
328              
329             sub get_count {
330 0     0 1   my $self = shift;
331              
332 0           my $columnFamily = shift;
333 0           my $key = shift;
334 0           my $column = shift;
335 0           my $opt = shift;
336              
337 0           my $columnParent = Cassandra::ColumnParent->new({column_family => $columnFamily});
338 0           my $sliceRange = Cassandra::SliceRange->new($column);
339 0           my $predicate = Cassandra::SlicePredicate->new({slice_range => $sliceRange});
340              
341 0           my $level = $self->_consistency_level_read($opt);
342              
343 0 0         if ('ARRAY' eq ref $key) {
344 0           my $sliceRange = Cassandra::SliceRange->new($column);
345 0           my $predicate = Cassandra::SlicePredicate->new({slice_range => $sliceRange});
346              
347 0           return $self->client->multiget_count($key, $columnParent, $predicate, $level);
348             }
349              
350 0           $self->client->get_count($key, $columnParent, $predicate, $level);
351             }
352              
353             =item
354             C
355             =cut
356              
357             sub put {
358 0     0 1   my $self = shift;
359              
360 0           my $columnFamily = shift;
361 0           my $key = shift;
362 0           my $columns = shift;
363 0   0       my $opt = shift // {};
364              
365 0           my $level = $self->_consistency_level_write($opt);
366 0           my $columnParent = Cassandra::ColumnParent->new({column_family => $columnFamily});
367 0           my $column = Cassandra::Column->new;
368              
369 0           while (my ($k, $v) = each %$columns) {
370 0           $column->{name} = $k;
371 0           $column->{value} = $v;
372 0   0       $column->{timestamp} = $opt->{timestamp} // time;
373              
374 0           $self->client->insert($key, $columnParent, $column, $level);
375             }
376             }
377              
378             =item
379             C
380              
381             Truncate entire column family.
382             =cut
383              
384             sub truncate {
385 0     0 1   my $self = shift;
386              
387 0           my $columnFamily = shift;
388              
389 0           $self->client->truncate($columnFamily);
390             }
391              
392             =head1 SEE ALSO
393              
394             =over
395              
396             =item *
397              
398             Cassandra API
399              
400             L
401              
402             =item *
403              
404             Cassandra Thrift Interface
405              
406             L
407              
408             =back
409              
410             =head1 AUTHOR
411              
412             Gea-Suan Lin, C<< >>
413              
414             =head1 LICENSE AND COPYRIGHT
415              
416             Copyright 2011 Gea-Suan Lin.
417              
418             This software is released under 3-clause BSD license.
419             See L for more information.
420              
421             =cut
422              
423             1;