1import * as Lambda from "@/AWS/Lambda";
2import * as SimpleDB from "@/AWS/SimpleDB";
3import * as Effect from "effect/Effect";
4import * as Layer from "effect/Layer";
5import { HttpServerRequest } from "effect/http/HttpServerRequest";
6import * as HttpServerResponse from "effect/http/HttpServerResponse";
7import path from "pathe";
8
9const main = path.resolve(import.meta.dirname, "handler.ts");
10
11export class SimpleDBTestFunction extends Lambda.Function<Lambda.Function>()(
12 "SimpleDBTestFunction",
13) {}
14
15export default SimpleDBTestFunction.make(
16 {
17 main,
18 functionUrl: true,
19 },
20 Effect.gen(function* () {
21 const domain = yield* SimpleDB.Domain("BindingsDomain", {});
22
23 const putAttributes = yield* SimpleDB.PutAttributes(domain);
24 const getAttributes = yield* SimpleDB.GetAttributes(domain);
25 const deleteAttributes = yield* SimpleDB.DeleteAttributes(domain);
26 const batchPutAttributes = yield* SimpleDB.BatchPutAttributes(domain);
27 const batchDeleteAttributes = yield* SimpleDB.BatchDeleteAttributes(domain);
28 const domainMetadata = yield* SimpleDB.DomainMetadata(domain);
29 const select = yield* SimpleDB.Select(domain);
30 const listDomains = yield* SimpleDB.ListDomains();
31
32 return {
33 fetch: Effect.gen(function* () {
34 const request = yield* HttpServerRequest;
35 const url = new URL(request.originalUrl);
36 const pathname = url.pathname;
37
38 if (request.method === "POST" && pathname === "/put") {
39 const body = (yield* request.json) as unknown as {
40 item: string;
41 attributes: { name: string; value: string; replace?: boolean }[];
42 };
43 yield* putAttributes({
44 ItemName: body.item,
45 Attributes: body.attributes.map((a) => ({
46 Name: a.name,
47 Value: a.value,
48 Replace: a.replace ?? true,
49 })),
50 });
51 return yield* HttpServerResponse.json({ success: true });
52 }
53
54 if (request.method === "GET" && pathname === "/get") {
55 const item = url.searchParams.get("item");
56 if (!item) {
57 return HttpServerResponse.text("Missing item", { status: 400 });
58 }
59 const result = yield* getAttributes({
60 ItemName: item,
61 ConsistentRead: true,
62 });
63 return yield* HttpServerResponse.json({
64 attributes: result.Attributes ?? [],
65 });
66 }
67
68 if (request.method === "GET" && pathname === "/select") {
69 const where = url.searchParams.get("where");
70 const result = yield* select({
71 SelectExpression: (name) =>
72 where
73 ? `select * from \`${name}\` where ${where}`
74 : `select * from \`${name}\``,
75 ConsistentRead: true,
76 });
77 return yield* HttpServerResponse.json({
78 items: result.Items ?? [],
79 });
80 }
81
82 if (request.method === "POST" && pathname === "/batch-put") {
83 const body = (yield* request.json) as unknown as {
84 items: {
85 item: string;
86 attributes: { name: string; value: string }[];
87 }[];
88 };
89 yield* batchPutAttributes({
90 Items: body.items.map((i) => ({
91 ItemName: i.item,
92 Attributes: i.attributes.map((a) => ({
93 Name: a.name,
94 Value: a.value,
95 Replace: true,
96 })),
97 })),
98 });
99 return yield* HttpServerResponse.json({ success: true });
100 }
101
102 if (request.method === "POST" && pathname === "/batch-delete") {
103 const body = (yield* request.json) as unknown as {
104 items: string[];
105 };
106 yield* batchDeleteAttributes({
107 Items: body.items.map((item) => ({ ItemName: item })),
108 });
109 return yield* HttpServerResponse.json({ success: true });
110 }
111
112 if (request.method === "DELETE" && pathname === "/delete") {
113 const body = (yield* request.json) as unknown as {
114 item: string;
115 attributes?: string[];
116 };
117 yield* deleteAttributes({
118 ItemName: body.item,
119 ...(body.attributes
120 ? { Attributes: body.attributes.map((name) => ({ Name: name })) }
121 : {}),
122 });
123 return yield* HttpServerResponse.json({ success: true });
124 }
125
126 if (request.method === "GET" && pathname === "/domains") {
127 const result = yield* listDomains({ MaxNumberOfDomains: 100 });
128 return yield* HttpServerResponse.json({
129 domainNames: result.DomainNames ?? [],
130 });
131 }
132
133 if (request.method === "GET" && pathname === "/metadata") {
134 const result = yield* domainMetadata();
135 return yield* HttpServerResponse.json({
136 itemCount: result.ItemCount,
137 attributeNameCount: result.AttributeNameCount,
138 attributeValueCount: result.AttributeValueCount,
139 });
140 }
141
142 return yield* HttpServerResponse.json(
143 { error: "Not found", method: request.method, pathname },
144 { status: 404 },
145 );
146 }).pipe(Effect.orDie),
147 };
148 }).pipe(
149 Effect.provide(
150 Layer.mergeAll(
151 SimpleDB.BatchDeleteAttributesHttp,
152 SimpleDB.BatchPutAttributesHttp,
153 SimpleDB.DeleteAttributesHttp,
154 SimpleDB.DomainMetadataHttp,
155 SimpleDB.GetAttributesHttp,
156 SimpleDB.ListDomainsHttp,
157 SimpleDB.PutAttributesHttp,
158 SimpleDB.SelectHttp,
159 ),
160 ),
161 ),
162);