Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for arbitrary keys and values #19

Open
dodoplus opened this issue Mar 11, 2022 · 1 comment
Open

Support for arbitrary keys and values #19

dodoplus opened this issue Mar 11, 2022 · 1 comment

Comments

@dodoplus
Copy link

It seems that this module only supports Vector{UInt8} keys and values, which makes it pretty unusable.

Why not add support for general types?

E.g. something like:

using LevelDB
using Serialization

function obj2buf(t::T) where T
    io = IOBuffer()
    serialize(io, t)
    return take!(io)
end

buf2obj(v::Vector{UInt8}) = deserialize(IOBuffer(v))

Base.setindex!(db::LevelDB.DB, i::T, v::S) where {T,S} = Base.setindex!(db, obj2buf(i), obj2buf(v))
Base.getindex(db::LevelDB.DB, i::T) where T = buf2obj(Base.getindex(db, obj2buf(i)))

...

db = LevelDB.DB("level.db", create_if_missing = true)
db["aa"] = "bb"
db["aa"]
# "aa"

Obviously, a faster/more stable serialization should be used -- e.g. code from JLD2 could be used.

@dodoplus
Copy link
Author

A hack implementation with JSON serialization:

using LevelDB
using JSON3
abstract type AbstractLDB{K,V,S} end

abstract type AbstractSerializer end

function serialize end
serialize(s, k) = error("not implemented")
deserialize(s, k, ::Type) = error("not implemented")

struct JSONSerializer <: AbstractSerializer end
serialize(::Type{JSONSerializer}, k) = Vector{UInt8}(JSON3.write(k))
deserialize(::Type{JSONSerializer}, k::Vector{UInt8}, ::Type{K}) where K = JSON3.read(String(k), K)

Base.eltype(::Type{<:AbstractLDB{K}}) where {K} = K
Base.valtype(::Type{<:AbstractLDB{K,V}}) where {K,V} = V

struct DB{K,V,S} <: AbstractLDB{K,V,S}
    db::LevelDB.DB
end

DB{K,V,S}(dir::String; create_if_missing::Bool = false, error_if_exists::Bool = false)  where {K,V,S} = 
            DB{K,V,S}(LevelDB.DB(dir; create_if_missing, error_if_exists))

DB{K,V}(dir::String; create_if_missing::Bool = false, error_if_exists::Bool = false)  where {K,V} = 
            DB{K,V,JSONSerializer}(dir; create_if_missing, error_if_exists)

DB{K}(dir::String; create_if_missing::Bool = false, error_if_exists::Bool = false)  where {K} = 
            DB{K,Dict,JSONSerializer}(dir; create_if_missing, error_if_exists)

DB(dir::String; create_if_missing::Bool = false, error_if_exists::Bool = false) = 
            DB{String,Dict,JSONSerializer}(dir; create_if_missing, error_if_exists)


function Base.show(io::IO, db::DB{K,V,S}) where {K,V,S}
    print(io, "LDB $(K) -> $(V): ", db.db.dir)
end

Base.isopen(db::DB) = Base.isopen(db.db)
Base.close(db::DB) = Base.close(db.db)

function Base.getindex(db::DB{K,V,S}, i::K) where {K,V,S}
    k = serialize(S, i)
    v = Base.getindex(db.db, k)
    return deserialize(S, v, V)
end

function Base.setindex!(db::DB{K,V,S}, v::V, i::K) where {K,V,S}
    k = serialize(S, i)
    v = serialize(S, v)
    return Base.setindex!(db.db, v, k)
end

function Base.delete!(db::DB{K,V,S}, i::K) where {K,V,S}
    k = deserialize(S, i, K)
    Base.delete!(db.db, k)
end

function Base.setindex!(db::DB{K,V,S}, v, k) where{K,V,S}
    kk = map(s -> serialize(S, s), k)
    vv = map(s -> serialize(S, s), v)
    
    Base.setindex!(db.db, vv, kk)
end

abstract type AbstractIterator end

mutable struct Iterator <: AbstractIterator
    handle::LevelDB.Iterator
end

Base.IteratorEltype(::DB{K,V}) where{K,V} = V
Base.IteratorSize(::DB) = SizeUnknown()
Base.seekstart(it::Iterator) = Base.seekstart(it.handle)

function ithelper(x, ::Type{K}, ::Type{V}, ::Type{S}) where {K,V,S}
    kv, it = x
    k, v = kv
    k = deserialize(S, k, K)
    v = deserialize(S, v, V)
    kv = k => v
    it = Iterator(it)
    return (kv, it)
end

function Base.iterate(db::DB{K,V,S}) where{K,V,S}
    x = LevelDB.iterate(db.db)
    x !== nothing || return
    return ithelper(x,K,V,S)
end

function Base.iterate(db::DB{K,V,S}, it::Iterator) where{K,V,S}
    x = LevelDB.iterate(db.db, it.handle)
    x !== nothing || return
    return ithelper(x,K,V,S)
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant