Skip to content
antomorelPublic

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

@effect-kv

An exploratory study of a typed key-value client for Effect, with Redis-style data structures and optimistic transactions.

How it works

A Key declares a name, a data structure (value, set, hash, sorted set or list) and the Schema codecs of its content. Reads decode with these codecs, and the type checker rejects operations that do not match the structure.

const Views = Key.value("views:/home", Schema.NumberFromString)
const Usernames = Key.set("usernames", Schema.String)

const program = Effect.gen(function*() {
  const kv = yield* KvClient.KvClient
  yield* kv.execute(Command.increment(Views), Command.addToSet(Usernames, "ada"))
  const views = yield* kv.get(Views)
  yield* Effect.log(views)
})

Writes are described as Command values. execute commits a batch of commands atomically.

transaction runs a read phase and commits the commands it returns:

const UsernameOwner = (username: string) => Key.value(`username:${username}`, Schema.String)

const claimUsername = (username: string, userId: string) =>
  Effect.gen(function*() {
    const kv = yield* KvClient.KvClient
    yield* kv.transaction((client) =>
      Effect.gen(function*() {
        const owner = yield* client.get(UsernameOwner(username))
        if (Option.isSome(owner)) return yield* new UsernameTaken({ username })
        return [Command.set(UsernameOwner(username), userId), Command.addToSet(Usernames, username)]
      })
    )
  })

Every key read during the read phase is watched. If one of them changes before the commit, the read phase runs again.

Command exists to prevent reads of uncommitted data inside transactions. The read phase only receives a read-only client, so a transaction cannot write a value and then read it back before the commit. Redis applies the writes of a transaction only at EXEC, so such a read would return the old value. Returning writes as data makes this situation impossible to express.

Motivation

The Persistence module of Effect offers poor support for the built-in features of Redis: it has no transactions and only stores simple values, with no sets, hashes, sorted sets or lists.

This repository is a study of what a key-value package for Effect could look like.

Limitations

The API is designed around how Redis works: optimistic transactions with watched keys, writes applied at commit, and Redis data structures.

Other technologies fit this model less well. LMDB, for instance, allows a transaction to read its own uncommitted writes. With this API, a transaction on such a backend still has to describe its writes as commands returned at the end of the read phase, which gives up that capability. The PostgreSQL and in-memory backends also emulate Redis structures and semantics, which costs more than a schema designed for these technologies.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages