Skip to content

Commit

Permalink
feat: cache prelude
Browse files Browse the repository at this point in the history
  • Loading branch information
Tim Smart committed Dec 10, 2022
1 parent 346c682 commit 6cf5237
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 33 deletions.
16 changes: 2 additions & 14 deletions examples/src/interactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import * as Cause from "@effect/io/Cause"
import * as Effect from "@effect/io/Effect"
import * as Exit from "@effect/io/Exit"
import { pipe } from "@fp-ts/data/Function"
import { Cache, Discord, Ix, rest } from "dfx"
import { CacheOps, make, runIx } from "dfx/gateway"
import { Discord, Ix } from "dfx"
import { make, runIx } from "dfx/gateway"
import Dotenv from "dotenv"

Dotenv.config()
Expand All @@ -13,16 +13,6 @@ const LiveEnv = make({
token: process.env.DISCORD_BOT_TOKEN!,
})

const guilds = Cache.makeNonParent({
driver: Cache.nonParentMemoryDriver<Discord.Guild>(),
ops: CacheOps.guilds,
onMiss: (id) =>
pipe(
rest.getGuild(id),
Effect.flatMap((r) => r.json),
),
})

// Create your interaction definitions.
// Here we are creating a global application command.
const hello = Ix.global(
Expand Down Expand Up @@ -89,9 +79,7 @@ pipe(
}),
),
),
Effect.zipPar(guilds.run),
Effect.provideSomeLayer(LiveEnv),
Effect.provideSomeLayer(guilds.Layer),
Effect.unsafeRunPromiseExit,
).then((exit) => {
if (Exit.isFailure(exit)) {
Expand Down
21 changes: 11 additions & 10 deletions src/Cache/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import { ParentCacheStoreDriver, CacheStoreDriver } from "./driver.js"
export * from "./driver.js"

export {
createWithParent as memoryDriver,
create as nonParentMemoryDriver,
createWithParent as memoryParentDriver,
create as memoryDriver,
} from "./memory.js"

export {
createWithParent as memoryTTLDriver,
create as nonParentMemoryTTLDriver,
createWithParent as memoryTTLParentDriver,
create as memoryTTLDriver,
} from "./memoryTTL.js"

export type ParentCacheOp<T> =
Expand All @@ -23,11 +23,7 @@ export type CacheOp<T> =
| { op: "update"; resourceId: string; resource: T }
| { op: "delete"; resourceId: string }

export class CacheMissError {
readonly _tag = "CacheMissError"
}

export const make = <T, R, E, RMD, EMD, ED, RM, EM, RPM, EPM>({
export const makeParent = <T, R, E, RMD, EMD, ED, RM, EM, RPM, EPM>({
driver: makeDriver,
ops = EffectSource.empty,
onMiss,
Expand Down Expand Up @@ -81,7 +77,7 @@ export const make = <T, R, E, RMD, EMD, ED, RM, EM, RPM, EPM>({
}
})

export const makeNonParent = <T, R, E, RMD, EMD, ED, RM, EM>({
export const make = <T, R, E, RMD, EMD, ED, RM, EM>({
driver: makeDriver,
ops = EffectSource.empty,
onMiss,
Expand Down Expand Up @@ -113,3 +109,8 @@ export const makeNonParent = <T, R, E, RMD, EMD, ED, RM, EM>({
run: sync.zipPar(driver.run).asUnit,
}
})

export class CacheMissError {
readonly _tag = "CacheMissError"
constructor(readonly cacheName: string, readonly id: string) {}
}
53 changes: 53 additions & 0 deletions src/Cache/prelude.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { Cache } from "dfx"
import { CacheOps } from "dfx/gateway"
import { Effect, toLayer } from "@effect/io/Effect"

const makeGuilds = <RM, EM, E>(
driver: Effect<RM, EM, Cache.CacheStoreDriver<E, Discord.Guild>>,
) =>
Cache.make({
driver,
ops: CacheOps.guilds,
onMiss: (id) => rest.getGuild(id).flatMap((r) => r.json),
})

export interface GuildsCache extends Success<ReturnType<typeof makeGuilds>> {}
export const GuildsCache = Tag<GuildsCache>()
export const guilds = flow(makeGuilds, toLayer(GuildsCache))

const makeChannels = <RM, EM, E>(
driver: Effect<RM, EM, Cache.ParentCacheStoreDriver<E, Discord.Channel>>,
) =>
Cache.makeParent({
driver,
ops: CacheOps.channels,
onMiss: (id) => rest.getChannel(id).flatMap((r) => r.json),
onParentMiss: (guildId) =>
rest
.getGuildChannels(guildId)
.flatMap((r) => r.json)
.map((a) => a.map((a) => [a.id, a])),
})

export interface ChannelsCache
extends Success<ReturnType<typeof makeChannels>> {}
export const ChannelsCache = Tag<ChannelsCache>()
export const channels = flow(makeChannels, toLayer(ChannelsCache))

const makeRoles = <RM, EM, E>(
driver: Effect<RM, EM, Cache.ParentCacheStoreDriver<E, Discord.Role>>,
) =>
Cache.makeParent({
driver,
ops: CacheOps.roles,
onMiss: (id) => Effect.fail(new Cache.CacheMissError("RolesCache", id)),
onParentMiss: (guildId) =>
rest
.getGuildRoles(guildId)
.flatMap((r) => r.json)
.map((a) => a.map((a) => [a.id, a])),
})

export interface RolesCache extends Success<ReturnType<typeof makeRoles>> {}
export const RolesCache = Tag<RolesCache>()
export const roles = flow(makeRoles, toLayer(RolesCache))
16 changes: 9 additions & 7 deletions src/Interactions/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,16 @@ export interface SubCommandContext {
}
export const SubCommandContext = Tag<SubCommandContext>()

export const getCommand = Effect.service(ApplicationCommandContext)
export const interaction = Effect.service(InteractionContext)

export const command = Effect.service(ApplicationCommandContext)

export class ResolvedDataNotFound {
readonly _tag = "ResolvedDataNotFound"
constructor(readonly data: Discord.Interaction, readonly name?: string) {}
}

export const getResolvedValues = <A>(
export const resolvedValues = <A>(
f: (id: Discord.Snowflake, data: Discord.ResolvedDatum) => A | undefined,
) =>
Effect.serviceWithEffect(InteractionContext)((a) =>
Expand All @@ -34,7 +36,7 @@ export const getResolvedValues = <A>(
),
)

export const getResolved = <A>(
export const resolved = <A>(
name: string,
f: (id: Discord.Snowflake, data: Discord.ResolvedDatum) => A | undefined,
) =>
Expand Down Expand Up @@ -114,24 +116,24 @@ export class RequiredOptionNotFound {
) {}
}

export const findOption = (name: string) =>
export const option = (name: string) =>
Effect.serviceWith(ApplicationCommandContext)(IxHelpers.getOption(name))

export const optionValue = (name: string) =>
findOption(name).flatMap((o) =>
option(name).flatMap((o) =>
o
.flatMapNullable((a) => a.value)
.match(
() =>
getCommand.flatMap((data) =>
command.flatMap((data) =>
Effect.fail(new RequiredOptionNotFound(data, name)),
),
Effect.succeed,
),
)

export const optionValueOptional = (name: string) =>
findOption(name).map((o) => o.flatMapNullable((a) => a.value))
option(name).map((o) => o.flatMapNullable((a) => a.value))

export const modalValues = Effect.serviceWith(ModalSubmitContext)(
IxHelpers.componentsMap,
Expand Down
4 changes: 2 additions & 2 deletions src/Interactions/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ type Handler<R, E> = Effect<
>

const context: D.CommandHelper<any> = {
resolve: Ctx.getResolved,
option: Ctx.findOption,
resolve: Ctx.resolved,
option: Ctx.option,
optionValue: Ctx.optionValue,
optionValueOptional: Ctx.optionValueOptional,
subCommands: Ctx.handleSubCommands,
Expand Down
1 change: 1 addition & 0 deletions src/gateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export * as Shard from "./DiscordGateway/Shard/index.js"
export * as ShardStore from "./DiscordGateway/ShardStore/index.js"
export * as Gateway from "./DiscordGateway/index.js"
export * as CacheOps from "./Cache/gateway.js"
export * as CachePrelude from "./Cache/prelude.js"
export { run as runIx } from "./Interactions/gateway.js"

export const LiveRateLimit =
Expand Down

0 comments on commit 6cf5237

Please sign in to comment.