Skip to content

Commit

Permalink
feat: added KeyValueStore.layerStorage (#2737)
Browse files Browse the repository at this point in the history
Co-authored-by: Tim <hello@timsmart.co>
  • Loading branch information
jessekelly881 and tim-smart authored May 30, 2024
1 parent e2740fc commit 2c2280b
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 127 deletions.
5 changes: 5 additions & 0 deletions .changeset/fifty-chairs-jam.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@effect/platform": patch
---

added KeyValueStore.layerStorage to wrap instances of the `Storage` type.
131 changes: 4 additions & 127 deletions packages/platform-browser/src/internal/keyValueStore.ts
Original file line number Diff line number Diff line change
@@ -1,130 +1,7 @@
import * as PlatformError from "@effect/platform/Error"
import * as KeyValueStore from "@effect/platform/KeyValueStore"
import * as Effect from "effect/Effect"
import * as Layer from "effect/Layer"
import * as Option from "effect/Option"

const storageError = (props: Omit<Parameters<typeof PlatformError.SystemError>[0], "reason" | "module">) =>
PlatformError.SystemError({
reason: "PermissionDenied",
module: "KeyValueStore",
...props
})
/** @internal */
export const layerSessionStorage = KeyValueStore.layerStorage(sessionStorage)

/** @internal */
export const layerLocalStorage = Layer.succeed(
KeyValueStore.KeyValueStore,
KeyValueStore.make({
get: (key: string) =>
Effect.try({
try: () => Option.fromNullable(localStorage.getItem(key)),
catch: () =>
storageError({
pathOrDescriptor: "layerLocalStorage",
method: "get",
message: `Unable to get item with key ${key}`
})
}),

set: (key: string, value: string) =>
Effect.try({
try: () => localStorage.setItem(key, value),
catch: () =>
storageError({
pathOrDescriptor: "layerLocalStorage",
method: "set",
message: `Unable to set item with key ${key}`
})
}),

remove: (key: string) =>
Effect.try({
try: () => localStorage.removeItem(key),
catch: () =>
storageError({
pathOrDescriptor: "layerLocalStorage",
method: "remove",
message: `Unable to remove item with key ${key}`
})
}),

clear: Effect.try({
try: () => localStorage.clear(),
catch: () =>
storageError({
pathOrDescriptor: "layerLocalStorage",
method: "clear",
message: `Unable to clear storage`
})
}),

size: Effect.try({
try: () => localStorage.length,
catch: () =>
storageError({
pathOrDescriptor: "layerLocalStorage",
method: "size",
message: `Unable to get size`
})
})
})
)

/** @internal */
export const layerSessionStorage = Layer.succeed(
KeyValueStore.KeyValueStore,
KeyValueStore.make({
get: (key: string) =>
Effect.try({
try: () => Option.fromNullable(sessionStorage.getItem(key)),
catch: () =>
storageError({
pathOrDescriptor: "layerSessionStorage",
method: "get",
message: `Unable to get item with key ${key}`
})
}),

set: (key: string, value: string) =>
Effect.try({
try: () => sessionStorage.setItem(key, value),
catch: () =>
storageError({
pathOrDescriptor: "layerSessionStorage",
method: "set",
message: `Unable to set item with key ${key}`
})
}),

remove: (key: string) =>
Effect.try({
try: () => sessionStorage.removeItem(key),
catch: () =>
storageError({
pathOrDescriptor: "layerSessionStorage",
method: "remove",
message: `Unable to remove item with key ${key}`
})
}),

clear: Effect.try({
try: () => sessionStorage.clear(),
catch: () =>
storageError({
pathOrDescriptor: "layerSessionStorage",
method: "clear",
message: `Unable to clear storage`
})
}),

size: Effect.try({
try: () => sessionStorage.length,
catch: () =>
storageError({
pathOrDescriptor: "layerSessionStorage",
method: "size",
message: `Unable to get size`
})
})
})
)
/** @internal */
export const layerLocalStorage = KeyValueStore.layerStorage(localStorage)
9 changes: 9 additions & 0 deletions packages/platform/src/KeyValueStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,3 +205,12 @@ export const layerSchema: <A, I, R>(
readonly tag: Context.Tag<SchemaStore<A, R>, SchemaStore<A, R>>
readonly layer: Layer.Layer<SchemaStore<A, R>, never, KeyValueStore>
} = internal.layerSchema

/**
* Creates an KeyValueStorage from an instance of the `Storage` api.
*
* @since 1.0.0
* @category layers
* @see https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API
*/
export const layerStorage: (storage: Storage) => Layer.Layer<KeyValueStore> = internal.layerStorage
69 changes: 69 additions & 0 deletions packages/platform/src/internal/keyValueStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as Effect from "effect/Effect"
import { dual, pipe } from "effect/Function"
import * as Layer from "effect/Layer"
import * as Option from "effect/Option"
import * as PlatformError from "../Error.js"
import * as FileSystem from "../FileSystem.js"
import type * as KeyValueStore from "../KeyValueStore.js"
import * as Path from "../Path.js"
Expand Down Expand Up @@ -174,3 +175,71 @@ export const layerSchema = <A, I, R>(
const layer = Layer.effect(tag, Effect.map(keyValueStoreTag, (store) => store.forSchema(schema)))
return { tag, layer } as const
}

/** @internal */
const storageError = (props: Omit<Parameters<typeof PlatformError.SystemError>[0], "reason" | "module">) =>
PlatformError.SystemError({
reason: "PermissionDenied",
module: "KeyValueStore",
...props
})

/** @internal */
export const layerStorage = (storage: Storage) =>
Layer.succeed(
keyValueStoreTag,
make({
get: (key: string) =>
Effect.try({
try: () => Option.fromNullable(storage.getItem(key)),
catch: () =>
storageError({
pathOrDescriptor: key,
method: "get",
message: `Unable to get item with key ${key}`
})
}),

set: (key: string, value: string) =>
Effect.try({
try: () => storage.setItem(key, value),
catch: () =>
storageError({
pathOrDescriptor: key,
method: "set",
message: `Unable to set item with key ${key}`
})
}),

remove: (key: string) =>
Effect.try({
try: () => storage.removeItem(key),
catch: () =>
storageError({
pathOrDescriptor: key,
method: "remove",
message: `Unable to remove item with key ${key}`
})
}),

clear: Effect.try({
try: () => storage.clear(),
catch: () =>
storageError({
pathOrDescriptor: "clear",
method: "clear",
message: `Unable to clear storage`
})
}),

size: Effect.try({
try: () => storage.length,
catch: () =>
storageError({
pathOrDescriptor: "size",
method: "size",
message: `Unable to get size`
})
})
})
)

0 comments on commit 2c2280b

Please sign in to comment.