Skip to content

Unstorage Integration #6061

@NMNMCC

Description

@NMNMCC

I found that unjs/unstorage is very suitable for implementing the KeyValueStore interface of Effect.

Here is a simple example implementation I wrote:

import {Effect, Layer, Option} from "effect"
import {KeyValueStore, Error as PlatformError} from "@effect/platform"
import {createStorage, type CreateStorageOptions} from "unstorage"

export const make = (options?: CreateStorageOptions) =>
  Layer.effect(
    KeyValueStore.KeyValueStore,
    Effect.gen(function* () {
      const storage = createStorage(options)

      const mapSystemError = (method: string) => (cause: unknown) =>
        new PlatformError.SystemError({
          reason: "Unknown",
          module: "KeyValueStore",
          method,
          cause
        })

      const invalidDataError = (method: string, description: string) =>
        new PlatformError.SystemError({
          reason: "InvalidData",
          module: "KeyValueStore",
          method,
          description
        })

      return KeyValueStore.make({
        get: key =>
          Effect.tryPromise(() => storage.getItem(key)).pipe(
            Effect.map(Option.fromNullable),
            Effect.mapError(mapSystemError("get")),
            Effect.flatMap(
              Option.match({
                onNone: () => Effect.succeed(Option.none()),
                onSome: value =>
                  typeof value === "string"
                    ? Effect.succeed(Option.some(value))
                    : Effect.fail(
                        invalidDataError("get", "Expected string value")
                      )
              })
            )
          ),
        getUint8Array: key =>
          Effect.tryPromise(() => storage.getItem(key)).pipe(
            Effect.map(Option.fromNullable),
            Effect.mapError(mapSystemError("getUint8Array")),
            Effect.flatMap(
              Option.match({
                onNone: () => Effect.succeed(Option.none()),
                onSome: value =>
                  value instanceof Uint8Array
                    ? Effect.succeed(Option.some(value))
                    : Effect.fail(
                        invalidDataError(
                          "getUint8Array",
                          "Expected Uint8Array value"
                        )
                      )
              })
            )
          ),
        set: (key, value) =>
          Effect.tryPromise(() => storage.setItem(key, value)).pipe(
            Effect.mapError(mapSystemError("set"))
          ),
        remove: key =>
          Effect.tryPromise(() => storage.removeItem(key)).pipe(
            Effect.mapError(mapSystemError("remove"))
          ),
        clear: Effect.tryPromise(() => storage.clear()).pipe(
          Effect.mapError(mapSystemError("clear"))
        ),
        size: Effect.tryPromise(
          () => storage.getKeys() as Promise<string[]>
        ).pipe(
          Effect.map(keys => keys.length),
          Effect.mapError(mapSystemError("size"))
        ),
        has: key =>
          Effect.tryPromise(
            () => storage.hasItem(key) as Promise<boolean>
          ).pipe(Effect.mapError(mapSystemError("has")))
      })
    })
  )

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions