MCE::Sh...::Minidb(3)

πŸ“¦
version 1.893 Β· 4 versions
, in epel 10

okay so this is the MCE::Sh...::Minidb(3) page from the User Contributed Perl Documentation β€” and it's giving tiny data-store icon energy. πŸ’…

🌸 NAME 🌸

MCE::Shared::Minidb β€” a pure-Perl in-memory data store.

πŸŽ€ VERSION πŸŽ€

This document describes MCE::Shared::Minidb version 1.893. 🫢

πŸ’– DESCRIPTION πŸ’–

It's a tiny in-memory NoSQL-like database, and you can use it standalone or have MCE::Shared manage it. periodt.

This module mainly exists so you can manipulate hashes-of-hashes (HoH) and hashes-of-lists (HoA) structures with MCE::Shared in an efficient manner. Your app can choose to use both structures or one or the other. Internally, both structures are sitting in memory at the same time, like they're sharing a tiny apartment. 🏠

Here's the constructor vibe:

sub new {
   # Dual top-level hashes: [ HoH, HoA ]
   bless [
      MCE::Shared::Ordhash->new(),  # Stores Hash-of-Hashes (HoH)
      MCE::Shared::Ordhash->new(),  # Stores Hash-of-Lists  (HoA)
   ], shift;
}

# each Ho(H) key => MCE::Shared::Hash->new()
# each Ho(A) key => MCE::Shared::Array->new()

Several methods described below may resemble the Redis API. It is not the intent for this module to become 100% compatible. We're not doing a clone arc, bestie. 😌

✨ SYNOPSIS ✨

Here's how it looks in the wild:

# non-shared or local construction for use by a single process

use MCE::Shared::Minidb;

my $db = MCE::Shared::Minidb->new();

# construction for sharing with other threads and processes

use MCE::Shared;

my $db = MCE::Shared->minidb();

# Hash of Hashes (HoH)
# Update the hash stored at key1/key2

$db->hset( "key1", "f1", "foo" );
$db->hset( "key2", "f1", "bar", "f2", "baz" );

$val = $db->hget( "key2", "f2" );  # "baz"

# Hash of Lists (HoA)
# Update the list stored at key1/key2

$db->lset( "key1", 0, "foo" );
$db->lset( "key2", 0, "bar", 1, "baz" );

$val = $db->lget( "key2", 1 );     # "baz"

# pipeline, provides atomicity for shared objects, MCE::Shared v1.09+

$db->pipeline(
   [ "lset", "key1", 0, "foo" ],
   [ "hset", "key1", "field1", "foo" ],
   [ "lset", "key2", 0, "bar", 1, "baz" ],
   [ "hset", "key2", "field1", "bar", "field2", "baz" ]
);

πŸ¦‹ SYNTAX for QUERY STRING πŸ¦‹

Several methods take a query string for an argument. The format of that string is described below. In the context of sharing, the query mechanism is beneficial for the shared-manager process. It can perform the query where the data resides instead of the client-process grep happening locally and involving lots of IPC. iykyk.

🌟 Basic demonstration

# query the hash stored at "some key"
@keys = $db->hkeys( "some key", "query string given here" );
@keys = $db->hkeys( "some key", "val =~ /pattern/" );

# query the top-level hash (H)oH
@keys = $db->hkeys( "query string given here" );
@keys = $db->hkeys( "key =~ /pattern/" );
  • Supported operators: =~ !~ eq ne lt le gt ge == != < <= > >=
  • Multiple expressions are delimited by :AND or :OR; mixed case is allowed.
"key eq 'some key' :or (field > 5 :and field < 9)"
"key eq some key :or (field > 5 :and field < 9)"
"key =~ /pattern/i :And field =~ /pattern/i"   # HoH
"key =~ /pattern/i :And index =~ /pattern/i"   # HoA
"index eq foo baz :OR key !~ /pattern/i"       # e.g. 9 eq "foo baz"
  • key matches on primary keys in the hash (H)oH or (H)oA.
  • field matches on HoH->{key}{field} e.g. address.
  • index matches on HoA->{key}[index] e.g. 9.
  • Quoting is optional inside the string.
  • Primary keys in (H)oH may have spaces, but not so for field_names.
"key =~ /pattern/i :AND field eq 'foo bar'"    # address eq "foo bar"
"key =~ /pattern/i :AND field eq foo bar"      # address eq "foo bar"

"key =~ 'some key' :AND 'some_field' eq 'foo bar'"  # ok: some_field
"key =~ some key :AND some_field eq foo bar"

"key =~ 'some key' :AND 'some field' eq 'foo bar'"  # fail: some field
"key =~ some key :AND some field eq foo bar"

πŸ’« Examples

# search capability key/val: =~ !~ eq ne lt le gt ge == != < <= > >=
# key/val means to match against actual key/val respectively

# a query made to a hash stored at "some key"
# note that "fieldNames" must not have spaces

  @keys  = $db->hkeys(
     "some key", "key eq some_field :or (val > 5 :and val < 9)"
  );

# queries made to a list stored at "some key"

  @pairs = $db->lpairs( "some key", "key >= 50 :AND val =~ /sun|moon/" );
  @pairs = $db->lpairs( "some key", "val eq sun :OR val eq moon" );

# the key modifier is the only thing possible for top-level queries
# reason: value equals a hash or list reference containing 2nd-level data

  @keys  = $db->hkeys( "key eq 'some key'" );
  @keys  = $db->hkeys( "key eq some key" );

  @keys  = $db->hkeys( "key =~ /$pattern/i" );
  @keys  = $db->hkeys( "key !~ /$pattern/i" );

  %pairs = $db->hpairs( "key == $number" );
  %pairs = $db->hpairs( "key != $number" );
  %pairs = $db->hpairs( "key <  $number :or key > $number" );
  %pairs = $db->hpairs( "key <= $number" );
  %pairs = $db->hpairs( "key >  $number" );
  %pairs = $db->hpairs( "key >= $number" );

  @vals  = $db->hvals( "key eq $string" );
  @vals  = $db->hvals( "key ne $string with space" );
  @vals  = $db->hvals( "key lt $string :or key =~ /$pat1|$pat2/" );
  @vals  = $db->hvals( "key le $string :or key eq 'foo bar'" );
  @vals  = $db->hvals( "key le $string :or key eq foo bar" );
  @vals  = $db->hvals( "key gt $string" );
  @vals  = $db->hvals( "key ge $string" );

# see select_aref and select_href below for db-like queries against
# the underlying Ho(A) and Ho(H) structures respectively

πŸ—„οΈ API DOCUMENTATION - DB ✨

Okay bestie, this is the good part β€” all the methods you can actually call on your lil database object. Let's go πŸ’…


MCE::Shared::Minidb->new ()

MCE::Shared->minidb ()

These two literally build you a fresh, empty in-memory key-store database with HoH and HoA structure. Think of it as an empty group chat waiting for drama. 🫢

# non-shared or local construction for use by a single process

use MCE::Shared::Minidb;

$db = MCE::Shared::Minidb->new();

# construction for sharing with other threads and processes

use MCE::Shared;

$db = MCE::Shared->minidb();

So like β€” use the first one if it's just you, main character, solo. Use the second if you're sharing the vibes across threads and processes. πŸ‘‘


dump ( "file.dat" )

Dumps everything sitting in memory out to a file. A little save-the-date for your data. πŸ’Ύ

$db->dump( "content.dat" );

pipeline ( [ func1, @args ], [ func2, @args ], ... )

This one is so good β€” it combines multiple commands and makes the object process them serially, one after another, no skipping. And here's the iconic part: for shared objects the call is made atomically because it's a single IPC to the shared-manager process. One trip, many commands. Efficient queen. πŸ”₯

The pipeline method is fully wantarray-aware and takes a list of commands plus their arguments. In scalar or list context, it gives you back data from the last command in the pipeline. That's it, that's the deal. ✨

@vals = $db->pipeline(                     # ( "bar", "baz" )
   [ "hset", "some_key", "f1", "bar", "f2", "baz" ],
   [ "hget", "some_key", "f1", "f2" ]
);

$len = $db->pipeline(                      # 2, same as $db->hlen("key2)
   [ "hset", "some_key", "f1", "bar", "f2", "baz" ],
   [ "hlen", "some_key" ]
);

$db->pipeline(
   [ "lset", "key1", 0, "foo" ],
   [ "hset", "key1", "field1", "foo" ],
   [ "lset", "key2", 0, "bar", 1, "baz" ],
   [ "hset", "key2", "field1", "bar", "field2", "baz" ]
);
Current API available since 1.809. (Yes, we're citing our sources, we're not messy πŸ’…)

pipeline_ex ( [ func1, @args ], [ func2, @args ], ... )

Same energy as pipeline, except it returns data for every command in the pipeline, not just the last one. Greedy in the best way. πŸ˜­πŸ’–

@vals = $db->pipeline_ex(                  # ( "bar", "baz" )
   [ "hset", "key3", "field1", "bar" ],
   [ "hset", "key3", "field2", "baz" ]
);

$chunk_size = 3;

$db->hset("some_key", chunk_id => 0);
$db->lassign("some_key", @ARGV);

while (1) {
   ($chunk_id, @next) = $db->pipeline_ex(
      [ "hincr",   "some_key", "chunk_id"     ],
      [ "lsplice", "some_key", 0, $chunk_size ]
   );

   last unless @next;

   ...
}
Current API available since 1.809. Same era, same icon behavior. πŸŽ€

restore ( "file.dat" )

Pulls your in-memory content back from a file. The glow-up recovery arc. 🌸

$db->restore( "content.dat" );

select_aref ( ":hashes", "select string" )

select_href ( ":hashes", "select string" )

These return a list of [ key, aref ] pairs or [ key, href ] pairs pulled out of the hash of hashes (HoH). So like, array refs or hash refs, your choice, we support both. πŸ¦‹

Both select_aref and select_href take a select string that supports field names and optionally sort modifiers. The syntax for the query string β€” the part sitting between :WHERE and :ORDER BY β€” is exactly the same as described above, no cap.

The modifiers :WHERE, :AND, :OR, ORDER BY, ASC, DESC, and ALPHA may be mixed case. e.g. :Where. We're not gonna police your capitalization, that's not the vibe. ✨

HoH select string:

"f1 f2 f3 :WHERE f4 > 20 :AND key =~ /foo/ :ORDER BY f5 DESC ALPHA"
"f5 f1 f2 :WHERE fN > 40 :AND key =~ /bar/ :ORDER BY key ALPHA"
"f5 f1 f2 :WHERE fN > 40 :AND key =~ /bar/"
"f5 f1 f2"
  • key matches on keys stored in the primary level hash (H)oH

HoH select synopsis:

@rows = $db->select_aref( ":hashes", "some_field :ORDER BY some_field" );
@rows = $db->select_aref( ":hashes", "f2 f6 f5 :ORDER BY f4" );

# $rows[0] = [ "key1", [ "f2_val", "f6_val", "f5_val" ] ]
# $rows[1] = [ "key2", [ "f2_val", "f6_val", "f5_val" ] ]
# $rows[2] = [ "key3", [ "f2_val", "f6_val", "f5_val" ] ]
# ...
# $rows[N] = [ "keyN", [ "f2_val", "f6_val", "f5_val" ] ]

@rows = $db->select_href( ":hashes", "some_field :ORDER BY some_field" );
@rows = $db->select_href( ":hashes", "f2 f6 f5 :ORDER BY f4" );

# $rows[0] = [ "key1", { f2 => "val", f6 => "val", f5 => "val" } ]
# $rows[1] = [ "key2", { f2 => "val", f6 => "val", f5 => "val" } ]
# $rows[2] = [ "key3", { f2 => "val", f6 => "val", f5 => "val" } ]
# ...
# $rows[N] = [ "keyN", { f2 => "val", f6 => "val", f5 => "val" } ]

select_aref ( ":lists", "select string" )

select_href ( ":lists", "select string" )

Now the same idea but for the hash of lists (HoA) β€” returns a list of [ key, aref ] pairs or [ key, href ] pairs. Same energy, different data shape. πŸ’œ

select_aref and select_href take a select string supporting field indices and, optionally, sort modifiers. The query string syntax between :WHERE and :ORDER BY is the same as described above. Periodt.

The modifiers :WHERE, :AND, :OR, ORDER BY, ASC, DESC, and ALPHA may be mixed case. e.g. :Where. Yes, still. We told you. 😌

HoA select string:

"17 15 11 :WHERE 12 > 20 :AND key =~ /foo/ :ORDER BY 10 DESC ALPHA"
"17 15 11 :WHERE 12 > 40 :AND key =~ /bar/ :ORDER BY key ALPHA"
"17 15 11 :WHERE 12 > 40 :AND key =~ /bar/"
"17 15 11"
  • key matches on keys stored in the primary level hash (H)oA
  • above, list indices are given as 17, 15, 11, 12, and 10
  • the shorter form is allowed e.g. "4 > 20 :AND key =~ /baz/"

HoA select synopsis:

@rows = $db->select_aref( ":lists", "some_index :ORDER BY some_index" );
@rows = $db->select_aref( ":lists", "2 6 5 :ORDER BY 4" );

# $rows[0] = [ "key1", [ "2_val", "6_val", "5_val" ] ]
# $rows[1] = [ "key2", [ "2_val", "6_val", "5_val" ] ]
# $rows[2] = [ "key3", [ "2_val", "6_val", "5_val" ] ]
# ...
# $rows[N] = [ "keyN", [ "2_val", "6_val", "5_val" ] ]

@rows = $db->select_href( ":lists", "some_index :ORDER BY some_index" );
@rows = $db->select_href( ":lists", "2 6 5 :ORDER BY 4" );

# $rows[0] = [ "key1", { 2 => "val", 6 => "val", 5 => "val" } ]
# $rows[1] = [ "key2", { 2 => "val", 6 => "val", 5 => "val" } ]
# $rows[2] = [ "key3", { 2 => "val", 6 => "val", 5 => "val" } ]
# ...
# $rows[N] = [ "keyN", { 2 => "val", 6 => "val", 5 => "val" } ]

πŸ¦‹ API DOCUMENTATION - HASHES ( HoH ) πŸ¦‹

Okay bestie, this is the (H)oH part β€” hash-of-hashes energy, the whole vibe where every key up top holds its own little hash underneath. Two levels of nesting, two levels of slay. πŸ’…


hassign ( key, field, value [, field, value, ... ] )

This one clears the hash stored at key, then sets a hash field's value, and hands you back the shiny new value. You can slam multiple field/value pairs in at once too β€” in that case you get the number of fields back instead. It's literally hclear + hset in a trench coat.

$val = $db->hassign( "some_key", "field", "value" );
$len = $db->hassign( "some_key", "f1" => "val1", "f2" => "val2" );
API available since 1.007. 🫢

hclear ( key )

No arguments? It nukes every key-value pair from the first level hash (H)oH. With a key? It nukes all the field-value pairs stored at that key. Different levels of chaos, same energy.

$db->hclear;
$db->hclear( "some_key" );

hdel ( key, field [, field, ... ] )

Deletes one or more hash fields. Pass a single field and you get back the value that was chillin' there. Pass a bunch and you get the count of fields actually removed from the hash at key β€” and ngl, a field that never existed doesn't get counted, so no inflating those numbers. πŸ’€

$val = $db->hdel( "some_key", "some_field" );
$cnt = $db->hdel( "some_key", "field1", "field2" );

hdel ( key )

This form deletes and returns the MCE::Shared::Hash object stored at key β€” or undef if that key isn't in the first level hash (H)oH. Poof, gone, but you get to keep the object. ✨

$ha_obj = $db->hdel( "some_key" );

hexists ( key, field [, field, ... ] )

Does this hash field exist? For multiple fields you only get a truthy result if all of the given fields exist in the hash at key β€” it's an all-or-nothing situation, no partial credit. 🎯

if ( $db->hexists( "some_key", "some_field" ) ) { ... }
if ( $db->hexists( "some_key", "f1", "f5" ) ) { ... }

hexists ( key )

And this form just checks whether a key exists in the first level hash (H)oH. Simple. Iconic.

if ( $db->hexists( "some_key" ) ) { ... }

hget ( key, field [, field, ... ] )

Grabs the values of all the given hash fields. Fields that don't exist in the hash at key come back as undef β€” and same deal, if the key itself isn't in the first level hash (H)oH you get undef too. No drama, just undefs. 😭

$val = $db->hget( "some_key", "field" );

( $val1, $val2 ) = $db->hget( "some_key", "field1", "field2" );

hget ( key )

Fetches the MCE::Shared::Hash object for the hash stored at key, or undef if that key doesn't exist in the first level hash (H)oH.

$ha_obj = $db->hget( "some_key" );

hkeys ( key, [ field [, field, ... ] ] )

No arguments at all? You get back the keys stored in the first level hash (H)oH. Otherwise you're getting the given fields back from the hash at key β€” and fields that don't exist just have the undef value, they still show up. In scalar context you get the size of the object instead, either the hash stored at key or the first level hash, depending on which form you called.

@keys   = $db->hkeys;
@fields = $db->hkeys( "some_key" );
@fields = $db->hkeys( "some_key", "field1", "field2" );
$len    = $db->hkeys( "some_key" );
$len    = $db->hkeys;

hkeys ( key, "query string" )

Only returns the fields stored at key that match your criteria. Nothing matches? Empty list, bestie. The syntax for the "query string" is the one described above. Scalar context gives you the size of the resulting list.

@keys = $db->hkeys( "some_key", "val eq some_value" );
@keys = $db->hkeys( "some_key", "key eq some_key :AND val =~ /sun|moon/" );
@keys = $db->hkeys( "some_key", "val eq sun :OR val eq moon );
$len  = $db->hkeys( "some_key", "key =~ /$pattern/" );

hkeys ( "query string" )

One-argument form, heads up: the search only applies to keys stored in the primary hash (H)oH. So if you actually want results, the "key" modifier is literally the only thing you can use. That's it, that's the whole menu. πŸ™ˆ

@keys = $db->hkeys( "key =~ /$pattern/" );
$len  = $db->hkeys( "key =~ /$pattern/" );

hlen ( key [, field ] )

No arguments = the size of the first level hash (H)oH. Give it a key and you get the size of the hash stored there. Optionally toss in a field and you get the length of the value sitting at key-field. If either the given key or the given field doesn't exist, you get undef back. Rude but fair. πŸ’€

$len = $db->hlen;
$len = $db->hlen( $key );
$len = $db->hlen( $key, $field );

hpairs ( key, [ field [, field, ... ] ] )

No arguments β†’ key-value pairs from the first level hash (H)oH. Otherwise β†’ field-value pairs for the given fields in the hash at key. Fields that don't exist will have the undef value. Scalar context returns the size of the object, either the hash stored at key or the first level hash.

@pairs = $db->hpairs;                 # ( key => href, ... )
@pairs = $db->hpairs( "some_key" );   # ( field => value, ... )
@pairs = $db->hpairs( "some_key", "field1", "field2" );
$len   = $db->hpairs( "some_key" );
$len   = $db->hpairs;

hpairs ( key, "query string" )

Only returns the field-value pairs stored at key that match your criteria β€” empty list if the search comes up empty. "query string" syntax is described above, iykyk. Scalar context = size of the resulting list.

@pairs = $db->hpairs( "some_key", "val eq some_value" );
@pairs = $db->hpairs( "some_key", "key eq some_key :AND val =~ /sun|moon/" );
@pairs = $db->hpairs( "some_key", "val eq sun :OR val eq moon" );
$len   = $db->hpairs( "some_key", "key =~ /$pattern/" );

hpairs ( "query string" )

The one-argument form searches keys stored in the primary hash (H)oH only. So yeah β€” the "key" modifier is the only thing that'll get you any result here. Periodt.

@keys = $db->hpairs( "key =~ /$pattern/" );
$len  = $db->hpairs( "key =~ /$pattern/" );

hset ( key, field, value [, field, value, ... ] )

Sets a hash field's value and returns the new value. Multiple field/value pairs at once is totally fine β€” in that case you get the number of fields stored at key back instead.

$val = $db->hset( "some_key", "field", "value" );
$len = $db->hset( "some_key", "f1" => "val1", "f2" => "val2" );

hsetnx ( key, field, value )

Sets a hash field's value only if the field doesn't already exist. Returns 1 for a new field, or 0 if the field was already there and nothing happened. Exclusive vibes only. πŸ’…

$ret = $db->hsetnx( "some_key", "field", "value" );
Current API available since 1.872.

hshift

Removes and returns the first key-value pair from the first-level hash (H)oH β€” or just the value, if you're in scalar context. If the "HASH" is empty you get the undefined value back. Nothing to shift, nothing to give. 🫢

( $key, $href ) = $db->hshift;

$href = $db->hshift;

hsort ( "BY key [ ASC | DESC ] [ ALPHA ]" )

hsort ( "BY field [ ASC | DESC ] [ ALPHA ]" )

Returns sorted keys from the first level hash (H)oH and leaves all the elements intact β€” nobody gets deleted on this ride. In void context it sorts the first level hash in-place. Sorting is numeric by default, jsyk. πŸ”’

@keys = $db->hsort( "BY key" );
@keys = $db->hsort( "BY some_field" );

$db->hsort( "BY key" );
$db->hsort( "BY some_field" );

If your keys or field values are strings and you want them sorted lexicographically, throw in the "ALPHA" modifier. Alphabet girlies rise. 🌸

@keys = $db->hsort( "BY key ALPHA" );
@keys = $db->hsort( "BY some_field ALPHA" );

$db->hsort( "BY key ALPHA" );
$db->hsort( "BY some_field ALPHA" );

Default is "ASC" β€” small to large, ascending royalty. Wanna go large to small? Specify the "DESC" modifier. πŸ‘‘

@keys = $db->hsort( "BY key DESC ALPHA" );
@keys = $db->hsort( "BY some_field DESC ALPHA" );

$db->hsort( "BY key DESC ALPHA" );
$db->hsort( "BY some_field DESC ALPHA" );

hvals ( key, [ field [, field, ... ] ] )

No arguments β†’ the values stored in the first level hash (H)oH. Otherwise β†’ the values for the given fields in the hash at key. Fields that don't exist get the undef value. Scalar context gives you the size of the object, either the hash stored at key or the first level hash.

@hrefs = $db->hvals;
@vals  = $db->hvals( "some_key" );
@vals  = $db->hvals( "some_key", "field1", "field2" );
$len   = $db->hvals( "some_key" );
$len   = $db->hvals;

hvals ( key, "query string" )

Returns only the values stored at key that match your criteria, and an empty list if the search found nothing. "query string" syntax lives above. Scalar context = size of the resulting list.

@vals = $db->hvals( "some_key", "val eq some_value" );
@vals = $db->hvals( "some_key", "key eq some_key :AND val =~ /sun|moon/" );
@vals = $db->hvals( "some_key", "val eq sun :OR val eq moon" );
$len  = $db->hvals( "some_key", "key =~ /$pattern/" );

hvals ( "query string" )

One-argument form again, same rules: the search hits keys stored in the primary hash (H)oH only. If you want literally any result, "key" is your only modifier. Don't come for me, that's just how it is. πŸ™ˆ

@keys = $db->hvals( "key =~ /$pattern/" );
$len  = $db->hvals( "key =~ /$pattern/" );

πŸ“ SUGAR METHODS - HASHES ( HoH ) πŸ“

So this module comes with sugar methods so you don't have to call set and get explicitly like some kind of caveman. The bestie benefit in shared context? Atomicity and fewer inter-process communications. Translation: it's faster and it can't get caught mid-step. πŸ”₯


happend ( key, field, string )

Appends a value onto key-field and returns its new length. Growth mindset. 🌱

$len = $db->happend( $key, $field, "foo" );

hdecr ( key, field )

Decrements the value of key-field by one and returns the new value.

$num = $db->hdecr( $key, $field );

hdecrby ( key, field, number )

Decrements the value of key-field by the given number and returns the new value.

$num = $db->hdecrby( $key, $field, 2 );

hgetdecr ( key, field )

Decrements the value of key-field by one and returns the old value. Sneaky little time capsule. ⏳

$old = $db->hgetdecr( $key, $field );

hgetincr ( key, field )

Increments the value of key-field by one and returns the old value.

$old = $db->hgetincr( $key, $field );

hgetset ( key, field, value )

Sets the value of key-field and returns the old value. Out with the old, in with the new. ✨

$old = $db->hgetset( $key, $field, "baz" );

hincr ( key, field )

Increments the value of key-field by one and returns the new value.

$num = $db->hincr( $key, $field );

hincrby ( key, field, number )

Increments the value of key-field by the given number and returns the new value.

$num = $db->hincrby( $key, $field, 2 );

πŸ’… API DOCUMENTATION - LISTS ( HoA ) πŸ’…


🫢 lassign ( key, value [, value, ... ] )

okay so this one is the glow-up combo move bestie β€” it clears the list sitting at key, then prepends one or however many values you hand it, and gives you back the new length. it's literally just lclear followed by lpush, no cap. πŸ’–

$len = $db->lassign( "some_key", "val1", "val2" );

⭐ API available since 1.007. (yes she's a newer icon, respect her.)


🧹 lclear ( key )

two moods, one method, lowkey iconic:

  • give it no arguments and it nukes all the key-value pairs from the first level hash (H)oA πŸ—‘οΈ
  • hand it a key and it clears out just the elements in the list stored there
$db->lclear;
$db->lclear( "some_key" );

πŸ’€ ldel ( key, index [, index, ... ] )

deletes one or more elements by their indices. and here's the plot twist: if you pass just a single index, you get back the value that lived at that index. if you pass a bunch, you get back the count of elements that actually got removed from the list at key β€” and an index that isn't even in the list doesn't get counted, so don't come for her. πŸ™ˆ

$val = $db->ldel( "some_key", 20 );
$cnt = $db->ldel( "some_key", 0, 1 );

πŸ’€ ldel ( key )

same name, different era 😭 β€” this form deletes and returns the MCE::Shared::Array object stored at key, or undef if that key doesn't exist in the first level hash (H)oA.

$ar_obj = $db->ldel( "some_key" );

πŸ” lexists ( key, index [, index, ... ] )

checks whether elements actually exist at the given indices. for multiple indices you only get a truthy answer if all of the given indices exist in the list stored at key. and fr fr, this behavior is strongly tied to whether you've been using delete on lists β€” so like, keep that in mind, bestie.

$db->lset( "some_key", 0, "value0" );
$db->lset( "some_key", 1, "value1" );
$db->lset( "some_key", 2, "value2" );
$db->lset( "some_key", 3, "value3" );

$db->lexists( "some_key", 2 );     # True
$db->lexists( "some_key", 2, 3 );  # True
$db->ldel   ( "some_key", 2 );     # value2

$db->lexists( "some_key", 2 );     # False
$db->lexists( "some_key", 2, 3 );  # False
$db->lexists( "some_key", 3 );     # True

see how index 2 said goodbye after the delete? πŸ’€ she's gone, she's not coming back.

πŸ” lexists ( key )

the one-argument form just checks if a key exists in the first level hash (H)oA. simple, clean, does exactly what it says on the tin. ✨

if ( $db->lexists( "some_key" ) ) { ... }

🎁 lget ( key, index [, index, ... ] )

grabs the values of all the list indices you ask for. if an index doesn't exist in the list at key, you get undef β€” and same deal, undef comes back if the key itself doesn't exist in the first level hash (H)oA. no drama, just vibes. πŸ¦‹

$val = $db->lget( "some_key", 20 );

( $val1, $val2 ) = $db->lget( "some_key", 0, 1 );

🎁 lget ( key )

this form hands you the actual MCE::Shared::Array object for the list stored at key β€” or undef if the key isn't in the first level hash (H)oA.

$ar_obj = $db->lget( "some_key" );

πŸ”‘ lkeys ( key, [ index [, index, ... ] ] )

no arguments? it returns the keys stored in the first level hash (H)oA. πŸ‘‘

otherwise it returns the given indices in the list stored at key β€” and any index that doesn't exist just comes back as undef, she's not gonna lie to you. and in scalar context you get the size of the object β€” either the list stored at key or the first level hash, depending on what you asked for.

@keys    = $db->lkeys;
@indices = $db->lkeys( "some_key" );
@indices = $db->lkeys( "some_key", 0, 1 );
$len     = $db->lkeys( "some_key" );
$len     = $db->lkeys;

πŸ”‘ lkeys ( key, "query string" )

now we're filtering πŸ’… β€” returns only the indices stored at key that match your criteria. if the search finds nothing you get an empty list back, that's just how it is. the syntax for the "query string" is described above (go scroll, iykyk). in scalar context, returns the size of the resulting list.

@keys = $db->lkeys( "some_key", "val eq some_value" );
@keys = $db->lkeys( "some_key", "key >= 50 :AND val =~ /sun|moon/" );
@keys = $db->lkeys( "some_key", "val eq sun :OR val eq moon" );
$len  = $db->lkeys( "some_key", "key =~ /$pattern/" );

πŸ”‘ lkeys ( "query string" )

one-argument form bestie! here the search gets applied to the keys stored in the primary hash only (H)oA. so basically the "key" modifier is the only thing that can possibly get you a result β€” anything else is giving delusion. 😭

@keys = $db->lkeys( "key =~ /$pattern/" );
$len  = $db->lkeys( "key =~ /$pattern/" );

πŸ“ llen ( key [, index ] )

no arguments β†’ size of the first level hash (H)oA. πŸŽ€ with an index β†’ the size of the list stored at key, or optionally, the length of the value stored at key-index. and if either the given key or the given index doesn't exist, it returns undef. periodt.

$len = $db->llen;
$len = $db->llen( $key );
$len = $db->llen( $key, 0 );

🎯 lpairs ( key, [ index [, index, ... ] ] )

no arguments β†’ key-value pairs stored in the first level hash (H)oA. otherwise β†’ index-value pairs for the given indices in the list stored at key. indices that don't exist get the undef treatment. in scalar context, returns the size of the object β€” either the list stored at key or the first level hash. she contains multitudes. 🌈

@pairs = $db->lpairs;                 # ( key => aref, ... )
@pairs = $db->lpairs( "some_key" );   # ( index => value, ... )
@pairs = $db->lpairs( "some_key", 0, 1 );
$len   = $db->lpairs( "some_key" );
$len   = $db->lpairs;

🎯 lpairs ( key, "query string" )

filtered pairs, we love to see it ✨ β€” returns only the index-value pairs stored at key that match your criteria. nothing matches? empty list, moving on. the "query string" syntax is described above. in scalar context, returns the size of the resulting list.

@pairs = $db->lpairs( "some_key", "val eq some_value" );
@pairs = $db->lpairs( "some_key", "key >= 50 :AND val =~ /sun|moon/" );
@pairs = $db->lpairs( "some_key", "val eq sun :OR val eq moon" );
$len   = $db->lpairs( "some_key", "key =~ /$pattern/" );

🎯 lpairs ( "query string" )

one argument, one job: the search runs against the keys stored in the primary hash only (H)oA. so yeah, the "key" modifier is the only thing possible if you want any result at all. πŸ™

@keys = $db->lpairs( "key =~ /$pattern/" );
$len  = $db->lpairs( "key =~ /$pattern/" );

πŸ“ lpop ( key )

removes and returns the first value of the list stored at key. if the list is empty you get the undefined value back β€” no explosion, just undef. πŸ’€

$val = $db->lpop( $key );

🧚 lpush ( key, value [, value, ... ] )

prepends one or multiple values to the head of the list stored at key, then returns the new length. yes bestie, prepends β€” to the head. read it again. πŸ“Œ

$len = $db->lpush( "some_key", "val1", "val2" );

🌸 lrange ( key, start, stop )

returns the specified elements of the list stored at key. and plot twist: the offsets "start" and "stop" can be negative numbers, which means offsets starting from the end of the list. iconic behavior honestly. πŸ¦‹

  • empty list comes back if "start" is larger than the end of the list
  • "stop" gets set to the last index of the list if it's larger than the actual end of the list
@list = $db->lrange( "some_key", 20, 29 );
@list = $db->lrange( "some_key", -4, -1 );

⭐ lset ( key, index, value [, index, value, ... ] )

sets the value of an element in a list by its index and returns its new value. and you can set multiple index_value pairs all at once β€” in that case, you get the length of the list back instead. slay, batch mode. πŸ”₯

$val = $db->lset( "some_key", 2, "value" );
$len = $db->lset( "some_key", 0 => "val1", 1 => "val2" );

πŸ‘‘ lshift

removes and returns the first key-value pair from the first-level hash (H)oA β€” or just the value if you're in scalar context. if the "HASH" is empty, you get the undefined value. and heads up: if you actually wanted to shift the first value of the list stored at a key, go see "lpop" instead. πŸ‘€

( $key, $aref ) = $db->lshift;

$aref = $db->lshift;

πŸ”€ lsort ( "BY key [ ASC | DESC ] [ ALPHA ]" ) / lsort ( "BY index [ ASC | DESC ] [ ALPHA ]" )

returns sorted keys from the first level hash (H)oA while leaving the elements themselves intact β€” in-place sorting only happens in void context, jsyk. and sorting is numeric by default, no cap. πŸ”’

@keys = $db->lsort( "BY key" );
@keys = $db->lsort( "BY some_index" );

$db->lsort( "BY key" );
$db->lsort( "BY some_index" );

if the keys β€” or the field values given by index β€” contain string values and you want a lexicographic sort, you gotta say the "ALPHA" modifier out loud. πŸ’…

@keys = $db->lsort( "BY key ALPHA" );
@keys = $db->lsort( "BY some_index ALPHA" );

$db->lsort( "BY key ALPHA" );
$db->lsort( "BY some_index ALPHA" );

default is "ASC", aka small β†’ large. wanna go large β†’ small? that's "DESC", bestie. flip it. πŸ”

@keys = $db->lsort( "BY key DESC ALPHA" );
@keys = $db->lsort( "BY some_index DESC ALPHA" );

$db->lsort( "BY key DESC ALPHA" );
$db->lsort( "BY some_index DESC ALPHA" );

πŸ”€ lsort ( key, "BY key [ ASC | DESC ] [ ALPHA ]" ) / lsort ( key, "BY val [ ASC | DESC ] [ ALPHA ]" )

the two argument form does basically the same thing but scoped β€” here the sorting is applied to the list stored at key. for example, the following straight up reverses the list stored at the given key. and important: the "BY key" modifier refers to the indices in the list, not the values. don't get it twisted. 🫢

$db->lsort( "some_key", "BY key DESC" );

βœ‚οΈ lsplice ( key, offset [, length [, list ] ] )

removes the elements designated by "offset" and "length" from the array stored at key, and replaces them with the elements of "list" β€” if there are any to replace them with. behavior is similar to the Perl splice function, so if you already know her, you know her. πŸ’œ

@items = $db->lsplice( "some_key", 20, 2, @list );
@items = $db->lsplice( "some_key", 20, 2 );
@items = $db->lsplice( "some_key", 20 );

🍬 lvals ( key, [ index [, index, ... ] ] )

no arguments β†’ returns the values stored in the first level hash (H)oA. otherwise β†’ returns the values for the given indices in the list stored at key. indices that don't exist get undef. and in scalar context you get the size of the object β€” either the list stored at key or the first level hash. main character versatility. 🌟

@arefs = $db->lvals;
@vals  = $db->lvals( "some_key" );
@vals  = $db->lvals( "some_key", 0, 1 );
$len   = $db->lvals( "some_key" );
$len   = $db->lvals;

🍬 lvals ( key, "query string" )

returns only the values stored at key that match your criteria. nothing found β†’ empty list, that's the rule. the "query string" syntax is described above. in scalar context, returns the size of the resulting list. ✨

@keys = $db->lvals( "some_key", "val eq some_value" );
@keys = $db->lvals( "some_key", "key >= 50 :AND val =~ /sun|moon/" );
@keys = $db->lvals( "some_key", "val eq sun :OR val eq moon" );
$len  = $db->lvals( "some_key", "key =~ /$pattern/" );

🍬 lvals ( "query string" )

the one argument form, again: the search is applied to the keys stored in the primary hash only (H)oA. so the "key" modifier is the only thing possible if wanting any result. iykyk. 🌈

@keys = $db->lvals( "key =~ /$pattern/" );
$len  = $db->lvals( "key =~ /$pattern/" );

πŸŽ€ rpop ( key )

removes and returns the last value of the list stored at key. if there are no elements in the list, you get the undefined value. she's the mirror image of lpop and honestly? equally iconic. πŸ’–

$val = $db->rpop( $key );

πŸ¦‹ rpush ( key, value [, value, ... ] )

appends one or multiple values to the tail of the list stored at key and returns the new length. the polite, well-behaved sibling of lpush. 🫢

$len = $db->rpush( "some_key", "val1", "val2" );

πŸ“ SUGAR METHODS - LISTS ( HoA ) πŸ“

Okay bestie, so this module comes equipped with sugar methods β€” meaning you don't have to call set and get explicitly like some kind of peasant. πŸ’… In shared context, the whole benefit here is atomicity and a reduction in inter-process communication. Slay. ✨


lappend ( key, index, string )

Appends a value to key-index and returns its new length. Iconic append behavior, no notes. πŸŽ€

$len = $db->lappend( $key, 0, "foo" );

ldecr ( key, index )

Decrements the value of key-index by one and hands you back its new value. Little minus-one moment. πŸ¦‹

$num = $db->ldecr( $key, 0 );

ldecrby ( key, index, number )

Decrements the value of key-index by the given number and returns its new value β€” so you can be extra about how much you're subtracting. πŸ’œ

$num = $db->ldecrby( $key, 0, 2 );

lgetdecr ( key, index )

Decrements the value of key-index by one and returns its old value. Lowkey the sneaky one β€” you get the before picture, not the after. πŸ™ˆ

$old = $db->lgetdecr( $key, 0 );

lgetincr ( key, index )

Increments the value of key-index by one and returns its old value. Same energy as above but going up instead of down. 🌸

$old = $db->lgetincr( $key, 0 );

lgetset ( key, index, value )

Sets the value of key-index and returns its old value. Classic swap β€” new vibe in, old vibe out. ⭐

$old = $db->lgetset( $key, 0, "baz" );

lincr ( key, index )

Increments the value of key-index by one and returns its new value. Plus one, periodt. πŸ”₯

$num = $db->lincr( $key, 0 );

lincrby ( key, index, number )

Increments the value of key-index by the given number and returns its new value. Big jumps welcome. πŸ‘‘

$num = $db->lincrby( $key, 0, 2 );

🧚 CREDITS 🧚

So the implementation is inspired by various Redis Hash/List primitives over at https://redis.io/commands. Respect where respect is due. 🫢

🌈 INDEX 🌈

MCE, MCE::Hobo, MCE::Shared

πŸ’– AUTHOR πŸ’–

Mario E. Roy, <marioeroy AT gmail DOT com>


That's the whole page, bestie β€” shoutout to Mario E. Roy for the authoring, and this little gem's been living in the perl v5.40.0 docs since 2024-09-10. Go forth and lappend responsibly πŸ’…βœ¨πŸŽ€

πŸ“¦ where this page comes from