-
Notifications
You must be signed in to change notification settings - Fork 0
/
mod.ts
159 lines (155 loc) · 4.47 KB
/
mod.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
export class Deta {
private projectId: string;
private projectKey: string;
rootUrl: URL;
auth: Headers;
/**
* @param projectId The project ID which can be found in Deta dashboard
* @param projectKey The project key
*/
constructor(projectId: string, projectKey: string) {
this.projectId = projectId;
this.projectKey = projectKey;
this.auth = new Headers({ "X-API-Key": projectKey });
this.auth.append("Content-Type", "application/json");
this.rootUrl = new URL(
`https://database.deta.sh/v1/${projectId}/`,
);
}
/**
* @param name The name of your database
* @returns A new database instance
*/
Base<Schema extends object>(name: string) {
return new Base<Schema>(this, name);
}
}
class Base<Schema extends object> {
name: string;
rootUrl: URL;
deta: Deta;
constructor(deta: Deta, name: string) {
this.name = name;
this.deta = deta;
this.rootUrl = new URL(deta.rootUrl + name);
}
/**
* Stores multiple items in a single request. This request overwrites an item if the key already exists.
* @param items A list of items to put
* @returns
*/
async put(items: Schema[]) {
const url = new URL(this.rootUrl + "/items");
const body = JSON.stringify({ items });
const response = await fetch(url, {
method: "PUT",
headers: this.deta.auth,
body,
});
const data = await response.json();
return data;
}
/**
* @param key The key of the item to fetch
* @returns The item with the given key
*/
async get(key: string) {
const url = new URL(this.rootUrl + "/items/" + key);
const response = await fetch(url, {
method: "GET",
headers: this.deta.auth,
});
return response.ok ? await response.json() as Schema : null;
}
/**
* @param key The key of the item to delete
* @returns
*/
async delete(key: string) {
const url = new URL(this.rootUrl + "/items/" + key);
const response = await fetch(url, {
method: "DELETE",
headers: this.deta.auth,
});
const data = await response.json();
return data;
}
/**
* Creates a new item only if no item with the same key exists.
* @param item The item to update
* @returns
*/
async insert(item: Schema) {
const url = new URL(this.rootUrl + "/items");
const body = JSON.stringify({ item });
const response = await fetch(url, {
method: "POST",
headers: this.deta.auth,
body,
});
const data = await response.json();
return data;
}
/**
* Updates an item only if an item with key exists.
* @param key The key of the item to update
* @param updates The updates to make to the item
* @returns
*/
async update(key: string, updates: Updates<Schema>) {
const url = new URL(this.rootUrl + "/items/" + key);
const body = JSON.stringify(updates);
const response = await fetch(url, {
method: "PATCH",
headers: this.deta.auth,
body,
});
const data = await response.json();
return data;
}
/**
* @param query The query to run
* @returns The items that match the query
*/
async query(
query: unknown[],
limit?: number,
last?: string,
): Promise<QueryResponse<Schema>> {
const url = new URL(this.rootUrl + "/query");
const response = await fetch(url, {
method: "POST",
headers: this.deta.auth,
body: JSON.stringify({ query, limit, last }),
});
const data = await response.json();
return data;
}
}
interface Updates<Schema extends object> {
/**Fields to update*/
set?: Partial<Schema>;
/**Fields to increment by a number.*/
increment?: Partial<Record<KeysMatching<Schema, number>, number>>;
/**Fields to append a list of values*/
append?: Partial<Record<KeysMatching<Schema, []>, unknown[]>>;
/**Fields to prepend a list of values*/
prepend?: Partial<Record<KeysMatching<Schema, []>, unknown[]>>;
/**List of fields to remove*/
delete?: (keyof Schema)[];
}
interface QueryResponse<Schema> {
paging: {
size: number;
last: string;
};
items: Schema[];
}
// Utility types
/**
* Get the keys of an object that match a given type
* https://stackoverflow.com/questions/56863875/typescript-how-do-you-filter-a-types-properties-to-those-of-a-certain-type
*/
type KeysMatching<T extends object, V> = {
[K in keyof T]-?: [V] extends [T[K]] ? K : never
}[keyof T];