From 008d6ea2f33b4fe6dbacd7aa981e95d69a13e426 Mon Sep 17 00:00:00 2001 From: Kenichi Ishigaki Date: Thu, 4 Jul 2013 13:20:58 +0900 Subject: [PATCH 1/5] tie interface --- lib/UnQLite.pm | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++ t/03_tie.t | 41 +++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 t/03_tie.t diff --git a/lib/UnQLite.pm b/lib/UnQLite.pm index 04c1a2d..93f932a 100644 --- a/lib/UnQLite.pm +++ b/lib/UnQLite.pm @@ -2,6 +2,7 @@ package UnQLite; use 5.008005; use strict; use warnings; +use Carp (); our $VERSION = "0.01"; our $rc = 0; @@ -9,6 +10,12 @@ our $rc = 0; use XSLoader; XSLoader::load(__PACKAGE__, $VERSION); +sub TIEHASH { + my $class = shift; + my $self = $class->open(@_) or croak $class->errstr; + $self->cursor_init; +} + sub rc { $UnQLite::rc } sub errstr { @@ -96,6 +103,60 @@ sub DESTROY { _release($self->[0], $self->[1]); } +# tie interface + +sub FETCH { + my ($self, $key) = @_; + $self->[1]->kv_fetch($key); +} + +sub STORE { + my ($self, $key, $value) = @_; + $self->[1]->kv_store($key, $value) or croak $self->[1]->errstr; + $value; +} + +sub DELETE { + my ($self, $key) = @_; + my $prev = $self->kv_fetch($key); + $self->[1]->kv_delete($key) or croak $self->[1]->errstr; + $prev; +} + +sub FIRSTKEY { + my $self = shift; + $self->first_entry or return; + $self->key; +} + +sub NEXTKEY { + my $self = shift; + $self->next_entry or return; + $self->key; +} + +sub EXISTS { + my ($self, $key) = @_; + $self->[1]->kv_fetch($key); + my $errstr = $self->[1]->errstr; + return $errstr eq 'UNQLITE_NOTFOUND' ? 1 : 0; +} + +sub CLEAR { + my $self = shift; + $self->first_entry or return; + $self->delete_entry while $self->valid_entry; + return; +} + +sub SCALAR { + my $self = shift; + $self->first_entry or return; + my $ct = 1; + $ct++ while $self->next_entry && $self->valid_entry; + return $ct; +} + 1; __END__ @@ -117,6 +178,11 @@ UnQLite - Perl bindings for UnQLite $db->kv_delete('foo'); undef $db; # close database + # tie interface + tie my %hash, 'UnQLite', 'foo.db'; + $hash{foo} = 'bar'; + say $hash{foo}; # => bar + =head1 DESCRIPTION UnQLite is a in-process software library which implements a self-contained, serverless, zero-configuration, transactional NoSQL database engine. UnQLite is a document store database similar to MongoDB, Redis, CouchDB etc. as well a standard Key/Value store similar to BerkeleyDB, LevelDB, etc. diff --git a/t/03_tie.t b/t/03_tie.t new file mode 100644 index 0000000..7ccf39e --- /dev/null +++ b/t/03_tie.t @@ -0,0 +1,41 @@ +use strict; +use Test::More; + +use File::Temp qw(tempdir); +use UnQLite; + +my $tmp = tempdir( CLEANUP => 1 ); + +{ + my $db = UnQLite->open("$tmp/foo.db"); + isa_ok($db, 'UnQLite'); + + ok($db->kv_store("foo", "bar")); + is($db->kv_fetch('foo'), 'bar'); + ok($db->kv_delete('foo')); + is($db->kv_fetch('foo'), undef); + $db->kv_store('yay', 'yap'); + $db->kv_append('yay', 'po'); + is($db->kv_fetch('yay'), 'yappo'); + is($db->rc,0); +} + +{ + ok -e "$tmp/foo.db", "foo.db exists"; + tie my %hash, 'UnQLite', "$tmp/foo.db"; + + # stored data can be retrieved again? + is($hash{yay}, 'yappo'); + $hash{foo} = 'baz'; + is($hash{foo}, 'baz'); + + is(join(" ", sort keys %hash), "foo yay"); + is(join(" ", sort values %hash), "baz yappo"); + is(scalar %hash, 2); + %hash = (); + is(join(" ", sort keys %hash), ""); + is(join(" ", sort values %hash), ""); + is(scalar %hash, undef); +} + +done_testing; From 317b78815a4f8571a5762438d38ada506dee910a Mon Sep 17 00:00:00 2001 From: Kenichi Ishigaki Date: Thu, 4 Jul 2013 13:23:50 +0900 Subject: [PATCH 2/5] oops --- lib/UnQLite.pm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/UnQLite.pm b/lib/UnQLite.pm index 93f932a..04c55fb 100644 --- a/lib/UnQLite.pm +++ b/lib/UnQLite.pm @@ -12,7 +12,7 @@ XSLoader::load(__PACKAGE__, $VERSION); sub TIEHASH { my $class = shift; - my $self = $class->open(@_) or croak $class->errstr; + my $self = $class->open(@_) or Carp::croak $class->errstr; $self->cursor_init; } @@ -112,14 +112,14 @@ sub FETCH { sub STORE { my ($self, $key, $value) = @_; - $self->[1]->kv_store($key, $value) or croak $self->[1]->errstr; + $self->[1]->kv_store($key, $value) or Carp::croak $self->[1]->errstr; $value; } sub DELETE { my ($self, $key) = @_; my $prev = $self->kv_fetch($key); - $self->[1]->kv_delete($key) or croak $self->[1]->errstr; + $self->[1]->kv_delete($key) or Carp::croak $self->[1]->errstr; $prev; } From a94bdc6ca250cf5144a5c9a20d90b6cbbd0eb0c6 Mon Sep 17 00:00:00 2001 From: Kenichi Ishigaki Date: Thu, 4 Jul 2013 13:32:39 +0900 Subject: [PATCH 3/5] fixed DELETE for a nonexistent entry --- lib/UnQLite.pm | 4 +++- t/03_tie.t | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/UnQLite.pm b/lib/UnQLite.pm index 04c55fb..3868d37 100644 --- a/lib/UnQLite.pm +++ b/lib/UnQLite.pm @@ -118,7 +118,9 @@ sub STORE { sub DELETE { my ($self, $key) = @_; - my $prev = $self->kv_fetch($key); + my $prev = $self->[1]->kv_fetch($key); + my $errstr = $self->[1]->errstr; + return if $errstr && $errstr eq 'UNQLITE_NOTFOUND'; $self->[1]->kv_delete($key) or Carp::croak $self->[1]->errstr; $prev; } diff --git a/t/03_tie.t b/t/03_tie.t index 7ccf39e..9c66d6c 100644 --- a/t/03_tie.t +++ b/t/03_tie.t @@ -28,6 +28,9 @@ my $tmp = tempdir( CLEANUP => 1 ); is($hash{yay}, 'yappo'); $hash{foo} = 'baz'; is($hash{foo}, 'baz'); + $hash{delete} = 'delete'; + is(delete $hash{delete}, 'delete'); + is(delete $hash{delete}, undef); is(join(" ", sort keys %hash), "foo yay"); is(join(" ", sort values %hash), "baz yappo"); From 879640f4c5d4e16f755dc77b4548fc149aff263a Mon Sep 17 00:00:00 2001 From: Kenichi Ishigaki Date: Thu, 4 Jul 2013 13:40:10 +0900 Subject: [PATCH 4/5] fixed EXISTS --- lib/UnQLite.pm | 4 ++-- t/03_tie.t | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/UnQLite.pm b/lib/UnQLite.pm index 3868d37..cabfda4 100644 --- a/lib/UnQLite.pm +++ b/lib/UnQLite.pm @@ -139,9 +139,9 @@ sub NEXTKEY { sub EXISTS { my ($self, $key) = @_; - $self->[1]->kv_fetch($key); + $self->[1]->kv_fetch($key) and return 1; my $errstr = $self->[1]->errstr; - return $errstr eq 'UNQLITE_NOTFOUND' ? 1 : 0; + return $errstr && $errstr eq 'UNQLITE_OK' ? 1 : 0; } sub CLEAR { diff --git a/t/03_tie.t b/t/03_tie.t index 9c66d6c..4d6d936 100644 --- a/t/03_tie.t +++ b/t/03_tie.t @@ -31,6 +31,8 @@ my $tmp = tempdir( CLEANUP => 1 ); $hash{delete} = 'delete'; is(delete $hash{delete}, 'delete'); is(delete $hash{delete}, undef); + ok(exists $hash{foo}); + ok(!exists $hash{delete}); is(join(" ", sort keys %hash), "foo yay"); is(join(" ", sort values %hash), "baz yappo"); From 38116a08c5da32cd7950bb57a74a2e35b38e0cd0 Mon Sep 17 00:00:00 2001 From: Kenichi Ishigaki Date: Thu, 4 Jul 2013 13:48:22 +0900 Subject: [PATCH 5/5] better use UNQLITE_OK as there may be other errors --- lib/UnQLite.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/UnQLite.pm b/lib/UnQLite.pm index cabfda4..d1ee57c 100644 --- a/lib/UnQLite.pm +++ b/lib/UnQLite.pm @@ -120,7 +120,7 @@ sub DELETE { my ($self, $key) = @_; my $prev = $self->[1]->kv_fetch($key); my $errstr = $self->[1]->errstr; - return if $errstr && $errstr eq 'UNQLITE_NOTFOUND'; + return unless $errstr && $errstr eq 'UNQLITE_OK'; $self->[1]->kv_delete($key) or Carp::croak $self->[1]->errstr; $prev; }