Skip to content

Instantly share code, notes, and snippets.

@mash
Created April 12, 2013 06:29
Show Gist options
  • Select an option

  • Save mash/5369915 to your computer and use it in GitHub Desktop.

Select an option

Save mash/5369915 to your computer and use it in GitHub Desktop.
package Redis::Custom;
use strict;
use warnings;
# Redis::Custom->setup_custom_command( $redis, 'saddnested', $lua_script, 1 );
sub setup_custom_command {
my ($package, $redis, $command_name, $lua_script, $key_count, @binded_values) = @_;
my ($sha1) = $redis->script_load( $lua_script );
{
no strict 'refs';
no warnings 'redefine';
*{ "Redis::$command_name" } = sub {
my $self = shift;
$self->evalsha( $sha1, $key_count, @binded_values, @_ );
};
}
}
1;
package Redis::Nested;
use strict;
use warnings;
use Redis::Custom;
use Data::Section::Simple qw(get_data_section);
sub setup_nested {
my ($package, $redis, $separator) = @_;
my $saddnested = get_data_section( 'saddnested.lua' );
my $smembersnested = get_data_section( 'smembersnested.lua' );
Redis::Custom->setup_custom_command( $redis, 'saddnested', $saddnested, 2, ':' );
Redis::Custom->setup_custom_command( $redis, 'smembersnested', $smembersnested, 2, ':' );
}
1;
__DATA__
@@ saddnested.lua
--thanks to http://d.aoikujira.com/blog/index.php?2009%252F04%252F16%252FLua%E3%81%AEstring%E3%81%ABsplit%E3%81%A8join%E3%82%92%E5%AE%9F%E8%A3%85%E3%81%99%E3%82%8B
--[[* split string *]]--
-- return iterator
string.split_it = function(str, sep)
if str == nil then return nil end
assert(type(str) == "string", "str must be a string")
assert(type(sep) == "string", "sep must be a string")
return string.gmatch(str, "[^\\" .. sep .. "]+")
end
-- return table
string.split = function(str, sep)
local ret = {}
for seg in string.split_it(str, sep) do
table.insert( ret, seg )
end
return ret
end
-- saddnested( '.', 'a.b.c', 'd' )
-- -> sadd('a', 'b')
-- sadd('a.b', 'c')
-- sadd('a.b.c','d')
-- return 1 on success
local saddnested = function(separator, str, val)
assert( str ~= nil, 'provide str argument' )
assert( val ~= nil, 'provide val argument' )
local parts = str:split( separator )
for i,part in ipairs(parts) do
if i == #parts then
redis.call( 'sadd', str, val )
else
redis.call( 'sadd', table.concat( parts, separator, 1, i ), parts[ i + 1 ] )
end
end
return 1
end
return saddnested( KEYS[1], KEYS[2], ARGV[1] )
@@ smembersnested.lua
-- smembersnested( '.', 'a', 2 )
-- 1. fetches smembers( 'a' )
-- 2. calls smembers( 'a.' .. smember ) for each smember, recursively
-- 3. join the results
-- return table
local function smembersnested( separator, str, depth )
assert( depth ~= nil, "provide depth argument" )
local members = redis.call( 'smembers', str )
if depth == 0 then
return members
elseif #members == 0 then
return members
end
depth = depth - 1
local ret = {}
for i,member in ipairs(members) do
local deep_members = smembersnested( separator, str .. separator .. member, depth )
for j,m in ipairs(deep_members) do
table.insert( ret, m )
end
end
return ret
end
return smembersnested( KEYS[1], KEYS[2], tonumber(ARGV[1]) )
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment