electrodb 1.4.0 → 1.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -4
- package/README.md +351 -138
- package/browser.js +53 -0
- package/bundle.js +9962 -0
- package/index.d.ts +10 -9
- package/notes +935 -29
- package/package.json +1 -1
- package/src/clauses.js +0 -18
- package/src/entity.js +23 -1
- package/src/schema.js +4 -1
- package/index.test-d.ts +0 -3829
package/notes
CHANGED
|
@@ -1,31 +1,937 @@
|
|
|
1
|
-
|
|
2
|
-
- validate that validation works with complex types
|
|
3
|
-
- validate enum works with complex types?
|
|
4
|
-
x build out response types for at least partial and null
|
|
5
|
-
|
|
6
|
-
For Docs
|
|
7
|
-
x enum strings must be marked `as const`
|
|
8
|
-
x set properties on attributes must be typed with a `?:`
|
|
9
|
-
- hidden attribute property disables `get`
|
|
10
|
-
x update methods examples have changed
|
|
11
|
-
x sets leverage arrays
|
|
12
|
-
x default is applied before `required`
|
|
13
|
-
x required cannot be removed
|
|
14
|
-
- removing `cast` from documentation
|
|
15
|
-
|
|
16
|
-
Needs implementing:
|
|
17
|
-
x add cast: "list", "set" (maybe dont)
|
|
18
|
-
x find usages of `.name` in errors etc and replace with `.path`
|
|
19
|
-
x sets only allowed if client is present
|
|
20
|
-
x No "removing" required attribute?
|
|
21
|
-
x No "never" objects in update
|
|
22
|
-
x does dynamodb accept empty objects/~arrays~/sets? if so, reconsider the behaviour to only call getters/setters if object/array not empty
|
|
23
|
-
x Use client to make sets if it is passed!
|
|
24
|
-
|
|
25
|
-
Questions
|
|
26
|
-
x What happens when you have a required attribute, but it has a default, and you try to put
|
|
27
|
-
x Is getReadOnly property only grabbing from top level?
|
|
28
|
-
Thoughts
|
|
29
|
-
x revisit thoughts on required, but with default, put implementation
|
|
1
|
+
import { Entity, Service, CollectionItem } from "electrodb";
|
|
30
2
|
|
|
3
|
+
const StatusTypes = ["Open", "Closed", ""] as const;
|
|
4
|
+
const IsNotTicket = "";
|
|
5
|
+
const NotYetViewed = "#";
|
|
6
|
+
const IssueTicket = "Issue";
|
|
7
|
+
const PullRequestTicket = "PullRequest";
|
|
8
|
+
const TicketTypes = [IssueTicket, PullRequestTicket, IsNotTicket] as const
|
|
31
9
|
|
|
10
|
+
type Status = typeof StatusTypes[number];
|
|
11
|
+
|
|
12
|
+
function toStatusCode(status: unknown): Status | undefined {
|
|
13
|
+
for (let index in StatusTypes) {
|
|
14
|
+
if (StatusTypes[index] === status) {
|
|
15
|
+
return index as Status;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function toStatusString(code: unknown): Status | undefined {
|
|
22
|
+
for (let index in StatusTypes) {
|
|
23
|
+
if (index === code) {
|
|
24
|
+
return StatusTypes[index];
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
const issues = new Entity({
|
|
32
|
+
model: {
|
|
33
|
+
entity: "issues",
|
|
34
|
+
service: "versioncontrol",
|
|
35
|
+
version: "1"
|
|
36
|
+
},
|
|
37
|
+
attributes: {
|
|
38
|
+
issueNumber: {
|
|
39
|
+
type: "string",
|
|
40
|
+
},
|
|
41
|
+
repoName: {
|
|
42
|
+
type: "string"
|
|
43
|
+
},
|
|
44
|
+
repoOwner: {
|
|
45
|
+
type: "string"
|
|
46
|
+
},
|
|
47
|
+
username: {
|
|
48
|
+
type: "string",
|
|
49
|
+
},
|
|
50
|
+
ticketType: {
|
|
51
|
+
type: TicketTypes,
|
|
52
|
+
set: () => IssueTicket,
|
|
53
|
+
readOnly: true
|
|
54
|
+
},
|
|
55
|
+
ticketNumber: {
|
|
56
|
+
type: "string",
|
|
57
|
+
readOnly: true,
|
|
58
|
+
watch: ["issueNumber"],
|
|
59
|
+
set: (_, {issueNumber}) => issueNumber
|
|
60
|
+
},
|
|
61
|
+
status: {
|
|
62
|
+
type: StatusTypes,
|
|
63
|
+
default: "Open",
|
|
64
|
+
set: (val) => toStatusCode(val),
|
|
65
|
+
get: (val) => toStatusString(val),
|
|
66
|
+
},
|
|
67
|
+
subject: {
|
|
68
|
+
type: "string"
|
|
69
|
+
},
|
|
70
|
+
body: {
|
|
71
|
+
type: "string"
|
|
72
|
+
},
|
|
73
|
+
createdAt: {
|
|
74
|
+
type: "string",
|
|
75
|
+
set: () => new Date().toISOString().split('T')[0],
|
|
76
|
+
readOnly: true,
|
|
77
|
+
},
|
|
78
|
+
updatedAt: {
|
|
79
|
+
type: "string",
|
|
80
|
+
watch: "*",
|
|
81
|
+
set: () => new Date().toISOString().split('T')[0],
|
|
82
|
+
readOnly: true,
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
indexes: {
|
|
86
|
+
issue: {
|
|
87
|
+
collection: "issueReview",
|
|
88
|
+
pk: {
|
|
89
|
+
composite: ["repoOwner", "repoName", "issueNumber"],
|
|
90
|
+
field: "pk"
|
|
91
|
+
},
|
|
92
|
+
sk: {
|
|
93
|
+
composite: [],
|
|
94
|
+
field: "sk"
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
created: {
|
|
98
|
+
collection: ["owned", "managed"],
|
|
99
|
+
index: "gsi1pk-gsi1sk-index",
|
|
100
|
+
pk: {
|
|
101
|
+
field: "gsi1pk",
|
|
102
|
+
composite: ["username"]
|
|
103
|
+
},
|
|
104
|
+
sk: {
|
|
105
|
+
field: "gsi1sk",
|
|
106
|
+
composite: ["createdAt"]
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
todos: {
|
|
110
|
+
collection: "activity",
|
|
111
|
+
index: "gsi2pk-gsi2sk-index",
|
|
112
|
+
pk: {
|
|
113
|
+
composite: ["repoOwner", "repoName"],
|
|
114
|
+
field: "gsi2pk"
|
|
115
|
+
},
|
|
116
|
+
sk: {
|
|
117
|
+
composite: ["createdAt"],
|
|
118
|
+
field: "gsi2sk"
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
_: {
|
|
122
|
+
collection: "subscribers",
|
|
123
|
+
index: "gsi4pk-gsi4sk-index",
|
|
124
|
+
pk: {
|
|
125
|
+
composite: ["repoOwner", "repoName", "ticketNumber"],
|
|
126
|
+
field: "gsi4pk"
|
|
127
|
+
},
|
|
128
|
+
sk: {
|
|
129
|
+
composite: [],
|
|
130
|
+
field: "gsi4sk"
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
const issueComments = new Entity({
|
|
137
|
+
model: {
|
|
138
|
+
entity: "issueComment",
|
|
139
|
+
service: "versioncontrol",
|
|
140
|
+
version: "1"
|
|
141
|
+
},
|
|
142
|
+
attributes: {
|
|
143
|
+
issueNumber: {
|
|
144
|
+
type: "string",
|
|
145
|
+
},
|
|
146
|
+
commentId: {
|
|
147
|
+
type: "string"
|
|
148
|
+
},
|
|
149
|
+
username: {
|
|
150
|
+
type: "string"
|
|
151
|
+
},
|
|
152
|
+
replyTo: {
|
|
153
|
+
type: "string"
|
|
154
|
+
},
|
|
155
|
+
replyViewed: {
|
|
156
|
+
type: "string",
|
|
157
|
+
default: NotYetViewed,
|
|
158
|
+
get: (replyViewed): string | void => {
|
|
159
|
+
if (replyViewed !== NotYetViewed) {
|
|
160
|
+
return replyViewed
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
set: (replyViewed) => {
|
|
164
|
+
if (replyViewed === undefined) {
|
|
165
|
+
return NotYetViewed;
|
|
166
|
+
}
|
|
167
|
+
return replyViewed;
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
repoName: {
|
|
171
|
+
type: "string"
|
|
172
|
+
},
|
|
173
|
+
repoOwner: {
|
|
174
|
+
type: "string"
|
|
175
|
+
},
|
|
176
|
+
body: {
|
|
177
|
+
type: "string"
|
|
178
|
+
},
|
|
179
|
+
createdAt: {
|
|
180
|
+
type: "string",
|
|
181
|
+
set: () => new Date().toISOString().split('T')[0],
|
|
182
|
+
readOnly: true,
|
|
183
|
+
},
|
|
184
|
+
updatedAt: {
|
|
185
|
+
type: "string",
|
|
186
|
+
watch: "*",
|
|
187
|
+
set: () => new Date().toISOString().split('T')[0],
|
|
188
|
+
readOnly: true,
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
indexes: {
|
|
192
|
+
comments: {
|
|
193
|
+
collection: "issueReview",
|
|
194
|
+
pk: {
|
|
195
|
+
composite: ["repoOwner", "repoName", "issueNumber"],
|
|
196
|
+
field: "pk"
|
|
197
|
+
},
|
|
198
|
+
sk: {
|
|
199
|
+
composite: ["commentId"],
|
|
200
|
+
field: "sk"
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
created: {
|
|
204
|
+
collection: "conversations",
|
|
205
|
+
index: "gsi1pk-gsi1sk-index",
|
|
206
|
+
pk: {
|
|
207
|
+
field: "gsi1pk",
|
|
208
|
+
composite: ["username"]
|
|
209
|
+
},
|
|
210
|
+
sk: {
|
|
211
|
+
field: "gsi1sk",
|
|
212
|
+
composite: ["repoOwner", "repoName", "issueNumber"]
|
|
213
|
+
}
|
|
214
|
+
},
|
|
215
|
+
replies: {
|
|
216
|
+
collection: "inbox",
|
|
217
|
+
index: "gsi2pk-gsi2sk-index",
|
|
218
|
+
pk: {
|
|
219
|
+
composite: ["replyTo"],
|
|
220
|
+
field: "gsi2pk"
|
|
221
|
+
},
|
|
222
|
+
sk: {
|
|
223
|
+
composite: ["createdAt", "replyViewed"],
|
|
224
|
+
field: "gsi2sk"
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
const pullRequests = new Entity({
|
|
231
|
+
model: {
|
|
232
|
+
entity: "pullRequest",
|
|
233
|
+
service: "versioncontrol",
|
|
234
|
+
version: "1"
|
|
235
|
+
},
|
|
236
|
+
attributes: {
|
|
237
|
+
pullRequestNumber: {
|
|
238
|
+
type: "string",
|
|
239
|
+
required: true,
|
|
240
|
+
},
|
|
241
|
+
repoName: {
|
|
242
|
+
type: "string",
|
|
243
|
+
required: true,
|
|
244
|
+
},
|
|
245
|
+
repoOwner: {
|
|
246
|
+
type: "string",
|
|
247
|
+
required: true,
|
|
248
|
+
},
|
|
249
|
+
username: {
|
|
250
|
+
type: "string",
|
|
251
|
+
required: true,
|
|
252
|
+
},
|
|
253
|
+
ticketType: {
|
|
254
|
+
type: TicketTypes,
|
|
255
|
+
default: () => PullRequestTicket,
|
|
256
|
+
set: () => PullRequestTicket,
|
|
257
|
+
readOnly: true
|
|
258
|
+
},
|
|
259
|
+
ticketNumber: {
|
|
260
|
+
type: "string",
|
|
261
|
+
readOnly: true,
|
|
262
|
+
watch: ["pullRequestNumber"],
|
|
263
|
+
set: (_, {issueNumber}) => issueNumber
|
|
264
|
+
},
|
|
265
|
+
status: {
|
|
266
|
+
type: StatusTypes,
|
|
267
|
+
default: "Open",
|
|
268
|
+
set: (val) => toStatusCode(val),
|
|
269
|
+
get: (val) => toStatusString(val)
|
|
270
|
+
},
|
|
271
|
+
reviewers: {
|
|
272
|
+
type: "list",
|
|
273
|
+
items: {
|
|
274
|
+
type: "map",
|
|
275
|
+
properties: {
|
|
276
|
+
username: {
|
|
277
|
+
type: "string",
|
|
278
|
+
required: true,
|
|
279
|
+
},
|
|
280
|
+
approved: {
|
|
281
|
+
type: "boolean",
|
|
282
|
+
required: true,
|
|
283
|
+
},
|
|
284
|
+
createdAt: {
|
|
285
|
+
type: "string",
|
|
286
|
+
default: () => new Date().toISOString().split('T')[0],
|
|
287
|
+
readOnly: true,
|
|
288
|
+
},
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
},
|
|
292
|
+
createdAt: {
|
|
293
|
+
type: "string",
|
|
294
|
+
set: () => new Date().toISOString().split('T')[0],
|
|
295
|
+
readOnly: true,
|
|
296
|
+
},
|
|
297
|
+
updatedAt: {
|
|
298
|
+
type: "string",
|
|
299
|
+
watch: "*",
|
|
300
|
+
set: () => new Date().toISOString().split('T')[0],
|
|
301
|
+
readOnly: true,
|
|
302
|
+
},
|
|
303
|
+
},
|
|
304
|
+
indexes: {
|
|
305
|
+
pullRequest: {
|
|
306
|
+
collection: "PRReview",
|
|
307
|
+
pk: {
|
|
308
|
+
composite: ["repoOwner", "repoName", "pullRequestNumber"],
|
|
309
|
+
field: "pk"
|
|
310
|
+
},
|
|
311
|
+
sk: {
|
|
312
|
+
composite: [],
|
|
313
|
+
field: "sk"
|
|
314
|
+
}
|
|
315
|
+
},
|
|
316
|
+
created: {
|
|
317
|
+
collection: ["owned", "managed"],
|
|
318
|
+
index: "gsi1pk-gsi1sk-index",
|
|
319
|
+
pk: {
|
|
320
|
+
field: "gsi1pk",
|
|
321
|
+
composite: ["username"]
|
|
322
|
+
},
|
|
323
|
+
sk: {
|
|
324
|
+
field: "gsi1sk",
|
|
325
|
+
composite: ["createdAt"]
|
|
326
|
+
}
|
|
327
|
+
},
|
|
328
|
+
enhancements: {
|
|
329
|
+
collection: "activity",
|
|
330
|
+
index: "gsi2pk-gsi2sk-index",
|
|
331
|
+
pk: {
|
|
332
|
+
field: "gsi2pk",
|
|
333
|
+
composite: ["repoOwner", "repoName"],
|
|
334
|
+
},
|
|
335
|
+
sk: {
|
|
336
|
+
field: "gsi2sk",
|
|
337
|
+
composite: ["createdAt"],
|
|
338
|
+
|
|
339
|
+
}
|
|
340
|
+
},
|
|
341
|
+
_: {
|
|
342
|
+
collection: "subscribers",
|
|
343
|
+
index: "gsi4pk-gsi4sk-index",
|
|
344
|
+
pk: {
|
|
345
|
+
composite: ["repoOwner", "repoName", "ticketNumber"],
|
|
346
|
+
field: "gsi4pk"
|
|
347
|
+
},
|
|
348
|
+
sk: {
|
|
349
|
+
composite: [],
|
|
350
|
+
field: "gsi4sk"
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
const pullRequestComments = new Entity({
|
|
357
|
+
model: {
|
|
358
|
+
entity: "pullRequestComment",
|
|
359
|
+
service: "versioncontrol",
|
|
360
|
+
version: "1"
|
|
361
|
+
},
|
|
362
|
+
attributes: {
|
|
363
|
+
repoName: {
|
|
364
|
+
type: "string"
|
|
365
|
+
},
|
|
366
|
+
username: {
|
|
367
|
+
type: "string"
|
|
368
|
+
},
|
|
369
|
+
repoOwner: {
|
|
370
|
+
type: "string"
|
|
371
|
+
},
|
|
372
|
+
pullRequestNumber: {
|
|
373
|
+
type: "string"
|
|
374
|
+
},
|
|
375
|
+
commentId: {
|
|
376
|
+
type: "string"
|
|
377
|
+
},
|
|
378
|
+
replyTo: {
|
|
379
|
+
type: "string"
|
|
380
|
+
},
|
|
381
|
+
replyViewed: {
|
|
382
|
+
type: "string",
|
|
383
|
+
default: NotYetViewed,
|
|
384
|
+
get: (replyViewed) => {
|
|
385
|
+
return replyViewed !== NotYetViewed
|
|
386
|
+
? replyViewed
|
|
387
|
+
: undefined;
|
|
388
|
+
},
|
|
389
|
+
set: (replyViewed) => {
|
|
390
|
+
if (replyViewed === undefined) {
|
|
391
|
+
return NotYetViewed;
|
|
392
|
+
}
|
|
393
|
+
return replyViewed;
|
|
394
|
+
}
|
|
395
|
+
},
|
|
396
|
+
createdAt: {
|
|
397
|
+
type: "string",
|
|
398
|
+
set: () => new Date().toISOString().split('T')[0],
|
|
399
|
+
readOnly: true,
|
|
400
|
+
},
|
|
401
|
+
updatedAt: {
|
|
402
|
+
type: "string",
|
|
403
|
+
watch: "*",
|
|
404
|
+
set: () => new Date().toISOString().split('T')[0],
|
|
405
|
+
readOnly: true,
|
|
406
|
+
},
|
|
407
|
+
},
|
|
408
|
+
indexes: {
|
|
409
|
+
comments: {
|
|
410
|
+
collection: "PRReview",
|
|
411
|
+
pk: {
|
|
412
|
+
composite: ["repoOwner", "repoName", "pullRequestNumber"],
|
|
413
|
+
field: "pk"
|
|
414
|
+
},
|
|
415
|
+
sk: {
|
|
416
|
+
composite: ["commentId"],
|
|
417
|
+
field: "sk"
|
|
418
|
+
}
|
|
419
|
+
},
|
|
420
|
+
created: {
|
|
421
|
+
collection: "conversations",
|
|
422
|
+
index: "gsi1pk-gsi1sk-index",
|
|
423
|
+
pk: {
|
|
424
|
+
field: "gsi1pk",
|
|
425
|
+
composite: ["username"]
|
|
426
|
+
},
|
|
427
|
+
sk: {
|
|
428
|
+
field: "gsi1sk",
|
|
429
|
+
composite: ["repoOwner", "repoName"]
|
|
430
|
+
}
|
|
431
|
+
},
|
|
432
|
+
replies: {
|
|
433
|
+
collection: "inbox",
|
|
434
|
+
index: "gsi2pk-gsi2sk-index",
|
|
435
|
+
pk: {
|
|
436
|
+
composite: ["replyTo"],
|
|
437
|
+
field: "gsi2pk"
|
|
438
|
+
},
|
|
439
|
+
sk: {
|
|
440
|
+
composite: ["updatedAt", "replyViewed"],
|
|
441
|
+
field: "gsi2sk"
|
|
442
|
+
}
|
|
443
|
+
},
|
|
444
|
+
}
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
const repositories = new Entity({
|
|
448
|
+
model: {
|
|
449
|
+
entity: "repositories",
|
|
450
|
+
service: "versioncontrol",
|
|
451
|
+
version: "1"
|
|
452
|
+
},
|
|
453
|
+
attributes: {
|
|
454
|
+
repoName: {
|
|
455
|
+
type: "string"
|
|
456
|
+
},
|
|
457
|
+
repoOwner: {
|
|
458
|
+
type: "string"
|
|
459
|
+
},
|
|
460
|
+
about: {
|
|
461
|
+
type: "string"
|
|
462
|
+
},
|
|
463
|
+
username: {
|
|
464
|
+
type: "string",
|
|
465
|
+
readOnly: true,
|
|
466
|
+
watch: ["repoOwner"],
|
|
467
|
+
set: (_, {repoOwner}) => repoOwner
|
|
468
|
+
},
|
|
469
|
+
description: {
|
|
470
|
+
type: "string"
|
|
471
|
+
},
|
|
472
|
+
isPrivate: {
|
|
473
|
+
type: "boolean"
|
|
474
|
+
},
|
|
475
|
+
license: {
|
|
476
|
+
type: ["apache-2.0", "mit", "none"] as const,
|
|
477
|
+
default: "none"
|
|
478
|
+
},
|
|
479
|
+
defaultBranch: {
|
|
480
|
+
type: "string",
|
|
481
|
+
default: "main"
|
|
482
|
+
},
|
|
483
|
+
topics: {
|
|
484
|
+
type: "set",
|
|
485
|
+
items: "string"
|
|
486
|
+
},
|
|
487
|
+
followers: {
|
|
488
|
+
type: "set",
|
|
489
|
+
items: "string"
|
|
490
|
+
},
|
|
491
|
+
stars: {
|
|
492
|
+
type: "set",
|
|
493
|
+
items: "string"
|
|
494
|
+
},
|
|
495
|
+
createdAt: {
|
|
496
|
+
type: "string",
|
|
497
|
+
set: () => new Date().toISOString().split('T')[0],
|
|
498
|
+
readOnly: true,
|
|
499
|
+
},
|
|
500
|
+
updatedAt: {
|
|
501
|
+
type: "string",
|
|
502
|
+
watch: "*",
|
|
503
|
+
set: () => new Date().toISOString().split('T')[0],
|
|
504
|
+
readOnly: true,
|
|
505
|
+
},
|
|
506
|
+
},
|
|
507
|
+
indexes: {
|
|
508
|
+
repositories: {
|
|
509
|
+
collection: "alerts",
|
|
510
|
+
pk: {
|
|
511
|
+
composite: ["repoOwner"],
|
|
512
|
+
field: "pk"
|
|
513
|
+
},
|
|
514
|
+
sk: {
|
|
515
|
+
composite: ["repoName"],
|
|
516
|
+
field: "sk"
|
|
517
|
+
}
|
|
518
|
+
},
|
|
519
|
+
created: {
|
|
520
|
+
collection: "owned",
|
|
521
|
+
index: "gsi1pk-gsi1sk-index",
|
|
522
|
+
pk: {
|
|
523
|
+
composite: ["username"],
|
|
524
|
+
field: "gsi1pk"
|
|
525
|
+
},
|
|
526
|
+
sk: {
|
|
527
|
+
composite: ["isPrivate", "createdAt"],
|
|
528
|
+
field: "gsi1sk"
|
|
529
|
+
}
|
|
530
|
+
},
|
|
531
|
+
}
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
const subscriptions = new Entity({
|
|
535
|
+
model: {
|
|
536
|
+
entity: "subscription",
|
|
537
|
+
service: "versioncontrol",
|
|
538
|
+
version: "1"
|
|
539
|
+
},
|
|
540
|
+
attributes: {
|
|
541
|
+
repoName: {
|
|
542
|
+
type: "string",
|
|
543
|
+
required: true,
|
|
544
|
+
},
|
|
545
|
+
repoOwner: {
|
|
546
|
+
type: "string",
|
|
547
|
+
required: true,
|
|
548
|
+
},
|
|
549
|
+
username: {
|
|
550
|
+
type: "string",
|
|
551
|
+
required: true,
|
|
552
|
+
},
|
|
553
|
+
ticketNumber: {
|
|
554
|
+
type: "string",
|
|
555
|
+
default: () => IsNotTicket,
|
|
556
|
+
set: (ticketNumber) => {
|
|
557
|
+
if (ticketNumber === IsNotTicket) {
|
|
558
|
+
return "";
|
|
559
|
+
} else {
|
|
560
|
+
return ticketNumber;
|
|
561
|
+
}
|
|
562
|
+
},
|
|
563
|
+
get: (ticketNumber) => {
|
|
564
|
+
if (ticketNumber === "") {
|
|
565
|
+
return IsNotTicket;
|
|
566
|
+
} else {
|
|
567
|
+
return ticketNumber;
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
},
|
|
571
|
+
ticketType: {
|
|
572
|
+
type: TicketTypes,
|
|
573
|
+
default: () => IsNotTicket,
|
|
574
|
+
set: (ticketType) => {
|
|
575
|
+
return ticketType === IsNotTicket
|
|
576
|
+
? "#"
|
|
577
|
+
: ticketType;
|
|
578
|
+
},
|
|
579
|
+
get: (ticketType) => {
|
|
580
|
+
if (ticketType === "") {
|
|
581
|
+
return IsNotTicket;
|
|
582
|
+
} else {
|
|
583
|
+
return ticketType;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
},
|
|
587
|
+
createdAt: {
|
|
588
|
+
type: "string",
|
|
589
|
+
set: () => new Date().toISOString().split('T')[0],
|
|
590
|
+
readOnly: true,
|
|
591
|
+
},
|
|
592
|
+
updatedAt: {
|
|
593
|
+
type: "string",
|
|
594
|
+
watch: "*",
|
|
595
|
+
set: () => new Date().toISOString().split('T')[0],
|
|
596
|
+
readOnly: true,
|
|
597
|
+
},
|
|
598
|
+
},
|
|
599
|
+
indexes: {
|
|
600
|
+
repository: {
|
|
601
|
+
pk: {
|
|
602
|
+
composite: ["repoOwner", "repoName"],
|
|
603
|
+
field: "pk"
|
|
604
|
+
},
|
|
605
|
+
sk: {
|
|
606
|
+
composite: ["username", "ticketType", "ticketNumber"],
|
|
607
|
+
field: "sk"
|
|
608
|
+
}
|
|
609
|
+
},
|
|
610
|
+
user: {
|
|
611
|
+
collection: "watching",
|
|
612
|
+
index: "gsi3pk-gsi3sk-index",
|
|
613
|
+
pk: {
|
|
614
|
+
composite: ["username"],
|
|
615
|
+
field: "gsi3pk"
|
|
616
|
+
},
|
|
617
|
+
sk: {
|
|
618
|
+
composite: ["ticketType", "ticketNumber"],
|
|
619
|
+
field: "gsi3sk"
|
|
620
|
+
}
|
|
621
|
+
},
|
|
622
|
+
tickets: {
|
|
623
|
+
collection: "subscribers",
|
|
624
|
+
index: "gsi4pk-gsi4sk-index",
|
|
625
|
+
pk: {
|
|
626
|
+
composite: ["repoOwner", "repoName", "ticketNumber"],
|
|
627
|
+
field: "gsi4pk"
|
|
628
|
+
},
|
|
629
|
+
sk: {
|
|
630
|
+
composite: ["ticketType", "username"],
|
|
631
|
+
field: "gsi4sk"
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
});
|
|
636
|
+
|
|
637
|
+
const users = new Entity({
|
|
638
|
+
model: {
|
|
639
|
+
entity: "user",
|
|
640
|
+
service: "versioncontrol",
|
|
641
|
+
version: "1"
|
|
642
|
+
},
|
|
643
|
+
attributes: {
|
|
644
|
+
username: {
|
|
645
|
+
type: "string"
|
|
646
|
+
},
|
|
647
|
+
fullName: {
|
|
648
|
+
type: "string"
|
|
649
|
+
},
|
|
650
|
+
photo: {
|
|
651
|
+
type: "string"
|
|
652
|
+
},
|
|
653
|
+
bio: {
|
|
654
|
+
type: "string"
|
|
655
|
+
},
|
|
656
|
+
location: {
|
|
657
|
+
type: "string"
|
|
658
|
+
},
|
|
659
|
+
pinned: {
|
|
660
|
+
type: "any"
|
|
661
|
+
},
|
|
662
|
+
following: {
|
|
663
|
+
type: "set",
|
|
664
|
+
items: "string"
|
|
665
|
+
},
|
|
666
|
+
followers: {
|
|
667
|
+
type: "set",
|
|
668
|
+
items: "string"
|
|
669
|
+
},
|
|
670
|
+
createdAt: {
|
|
671
|
+
type: "string",
|
|
672
|
+
set: () => new Date().toISOString().split('T')[0],
|
|
673
|
+
readOnly: true,
|
|
674
|
+
},
|
|
675
|
+
updatedAt: {
|
|
676
|
+
type: "string",
|
|
677
|
+
watch: "*",
|
|
678
|
+
set: () => new Date().toISOString().split('T')[0],
|
|
679
|
+
readOnly: true,
|
|
680
|
+
},
|
|
681
|
+
},
|
|
682
|
+
indexes: {
|
|
683
|
+
user: {
|
|
684
|
+
collection: "overview",
|
|
685
|
+
pk: {
|
|
686
|
+
composite: ["username"],
|
|
687
|
+
field: "pk"
|
|
688
|
+
},
|
|
689
|
+
sk: {
|
|
690
|
+
composite: [],
|
|
691
|
+
field: "sk"
|
|
692
|
+
}
|
|
693
|
+
},
|
|
694
|
+
_: {
|
|
695
|
+
collection: "owned",
|
|
696
|
+
index: "gsi1pk-gsi1sk-index",
|
|
697
|
+
pk: {
|
|
698
|
+
composite: ["username"],
|
|
699
|
+
field: "gsi1pk"
|
|
700
|
+
},
|
|
701
|
+
sk: {
|
|
702
|
+
field: "gsi1sk",
|
|
703
|
+
composite: []
|
|
704
|
+
}
|
|
705
|
+
},
|
|
706
|
+
subscriptions: {
|
|
707
|
+
collection: "watching",
|
|
708
|
+
index: "gsi3pk-gsi3sk-index",
|
|
709
|
+
pk: {
|
|
710
|
+
composite: ["username"],
|
|
711
|
+
field: "gsi3pk"
|
|
712
|
+
},
|
|
713
|
+
sk: {
|
|
714
|
+
composite: [],
|
|
715
|
+
field: "gsi3sk"
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
});
|
|
720
|
+
|
|
721
|
+
const versioncontrol = new Service({
|
|
722
|
+
users,
|
|
723
|
+
issues,
|
|
724
|
+
repositories,
|
|
725
|
+
pullRequests,
|
|
726
|
+
subscriptions,
|
|
727
|
+
issueComments,
|
|
728
|
+
pullRequestComments,
|
|
729
|
+
}, {table: "your_table_name"});
|
|
730
|
+
|
|
731
|
+
type IssueIds = Parameters<typeof issues.get>[0][0];
|
|
732
|
+
type IssueCommentIds = Parameters<typeof issueComments.get>[0][0];
|
|
733
|
+
type PullRequestIds = Parameters<typeof pullRequests.get>[0][0];
|
|
734
|
+
type PullRequestCommentIds = Parameters<typeof pullRequestComments.get>[0][0];
|
|
735
|
+
type OwnedItems = CollectionItem<typeof versioncontrol, "owned">;
|
|
736
|
+
|
|
737
|
+
function isIssueCommentIds(comment: any): comment is IssueCommentIds {
|
|
738
|
+
return comment.issueNumber !== undefined && comment.username !== undefined;
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
function isPullRequestCommentIds(comment: any): comment is PullRequestCommentIds {
|
|
742
|
+
return comment.pullRequestNumber !== undefined && comment.username !== undefined;
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
// Get Public Repositories By Username
|
|
746
|
+
async function getPublicRepository(username: string) {
|
|
747
|
+
return versioncontrol.entities.repositories.query.created({username, isPrivate: false});
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
// Get PullRequest and Associated Comments -- newest comments first
|
|
751
|
+
async function reviewPullRequest(pr: PullRequestIds) {
|
|
752
|
+
return versioncontrol.collections.PRReview(pr)
|
|
753
|
+
.page(null, {params: {ScanIndexForward: false}})
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
// Get Issue and Associated Comments -- newest comments first
|
|
757
|
+
async function reviewIssue(issue: IssueIds) {
|
|
758
|
+
return versioncontrol.collections.issueReview(issue).go({params: {ScanIndexForward: false}});
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
// Get PullRequests Created By User
|
|
762
|
+
async function getUserPullRequests(username: string, status: Status = "") {
|
|
763
|
+
return versioncontrol.entities.pullRequests
|
|
764
|
+
.query.created({username, status})
|
|
765
|
+
.go({params: {ScanIndexForward: false}});
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
// Close pull request -- guards: can only be performed by user who opened PR or the repo owner
|
|
769
|
+
async function closePullRequest(user: string, pr: PullRequestIds) {
|
|
770
|
+
return versioncontrol.entities.pullRequests
|
|
771
|
+
.update(pr)
|
|
772
|
+
.set({status: "Closed"})
|
|
773
|
+
.where(({username, repoOwner}, {eq}) => `
|
|
774
|
+
${eq(username, user)} OR ${eq(repoOwner, user)}
|
|
775
|
+
`)
|
|
776
|
+
.go()
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
// Get all user info, repos, pull requests, and issues in one query
|
|
780
|
+
async function getFirstPageLoad(username: string) {
|
|
781
|
+
const results: OwnedItems = {
|
|
782
|
+
issues: [],
|
|
783
|
+
pullRequests: [],
|
|
784
|
+
repositories: [],
|
|
785
|
+
users: [],
|
|
786
|
+
};
|
|
787
|
+
|
|
788
|
+
let page = null;
|
|
789
|
+
|
|
790
|
+
do {
|
|
791
|
+
const [next, data] = await versioncontrol.collections.owned({username}).page();
|
|
792
|
+
results.issues = results.issues.concat(data.issues);
|
|
793
|
+
results.pullRequests = results.pullRequests.concat(data.pullRequests);
|
|
794
|
+
results.repositories = results.repositories.concat(data.repositories);
|
|
795
|
+
results.users = results.users.concat(data.users);
|
|
796
|
+
page = next;
|
|
797
|
+
} while (page !== null);
|
|
798
|
+
|
|
799
|
+
return results;
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
// Get Subscriptions for a given Repository, PullRequest, or Issue.
|
|
803
|
+
async function getSubscribed(repoOwner: string, repoName: string, ticketNumber: string = IsNotTicket) {
|
|
804
|
+
return versioncontrol.collections.subscribers({repoOwner, repoName, ticketNumber}).go();
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
const MinDate = "0000-00-00";
|
|
808
|
+
const MaxDate = "9999-99-99";
|
|
809
|
+
|
|
810
|
+
// Get unread comment replies
|
|
811
|
+
async function getUnreadComments(user: string) {
|
|
812
|
+
const start = {
|
|
813
|
+
createdAt: MinDate,
|
|
814
|
+
replyViewed: NotYetViewed
|
|
815
|
+
};
|
|
816
|
+
const end = {
|
|
817
|
+
createdAt: MaxDate,
|
|
818
|
+
replyViewed: NotYetViewed
|
|
819
|
+
};
|
|
820
|
+
let [issues, pullRequests] = await Promise.all([
|
|
821
|
+
versioncontrol.entities
|
|
822
|
+
.issueComments.query
|
|
823
|
+
.replies({replyTo: user})
|
|
824
|
+
.between(start, end)
|
|
825
|
+
.go(),
|
|
826
|
+
|
|
827
|
+
versioncontrol.entities
|
|
828
|
+
.pullRequestComments.query
|
|
829
|
+
.replies({replyTo: user})
|
|
830
|
+
.between(start, end)
|
|
831
|
+
.go()
|
|
832
|
+
]);
|
|
833
|
+
|
|
834
|
+
return {
|
|
835
|
+
issues,
|
|
836
|
+
pullRequests
|
|
837
|
+
};
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
// Mark comment reply as read -- guards: can only be done by the user who was being replied to
|
|
841
|
+
async function readReply(user: string, comment: IssueCommentIds): Promise<boolean>;
|
|
842
|
+
async function readReply(user: string, comment: PullRequestCommentIds): Promise<boolean>;
|
|
843
|
+
async function readReply(user: string, comment: any): Promise<boolean> {
|
|
844
|
+
const replyViewed = new Date().toISOString().split('T')[0];
|
|
845
|
+
if (isIssueCommentIds(comment)) {
|
|
846
|
+
return await versioncontrol.entities.issueComments
|
|
847
|
+
.patch(comment)
|
|
848
|
+
.set({replyViewed})
|
|
849
|
+
.where(({replyTo}, {eq}) => eq(replyTo, user))
|
|
850
|
+
.go()
|
|
851
|
+
.then(() => true)
|
|
852
|
+
.catch(() => false);
|
|
853
|
+
} else if (isPullRequestCommentIds(comment)) {
|
|
854
|
+
return await versioncontrol.entities.pullRequestComments
|
|
855
|
+
.patch(comment)
|
|
856
|
+
.set({replyViewed})
|
|
857
|
+
.where(({replyTo}, {eq}) => eq(replyTo, user))
|
|
858
|
+
.go()
|
|
859
|
+
.then(() => true)
|
|
860
|
+
.catch(() => false);
|
|
861
|
+
} else {
|
|
862
|
+
return false;
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
async function approvePullRequest(repoOwner: string, repoName: string, pullRequestNumber: string, username: string) {
|
|
867
|
+
const pullRequest = await versioncontrol.entities.pullRequests
|
|
868
|
+
.get({repoOwner, repoName, pullRequestNumber})
|
|
869
|
+
.go();
|
|
870
|
+
|
|
871
|
+
if (!pullRequest || !pullRequest.reviewers) {
|
|
872
|
+
return false;
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
let index: number = -1;
|
|
876
|
+
|
|
877
|
+
for (let i = 0; i < pullRequest.reviewers.length; i++) {
|
|
878
|
+
const reviewer = pullRequest.reviewers[i];
|
|
879
|
+
if (reviewer.username === username) {
|
|
880
|
+
index = i;
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
if (index === -1) {
|
|
885
|
+
return false;
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
return versioncontrol.entities.pullRequests
|
|
889
|
+
.update({repoOwner, repoName, pullRequestNumber})
|
|
890
|
+
.data(({reviewers}, {set}) => {
|
|
891
|
+
set(reviewers[index].approved, true);
|
|
892
|
+
})
|
|
893
|
+
.where(({reviewers}, {eq}) => `
|
|
894
|
+
${eq(reviewers[index].username, username)};
|
|
895
|
+
`)
|
|
896
|
+
.go()
|
|
897
|
+
.then(() => true)
|
|
898
|
+
.catch(() => false);
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
async function followRepository(repoOwner: string, repoName: string, follower: string) {
|
|
902
|
+
await versioncontrol.entities
|
|
903
|
+
.repositories.update({repoOwner, repoName})
|
|
904
|
+
.add({followers: [follower]})
|
|
905
|
+
.go()
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
// getPublicRepository("abc");
|
|
909
|
+
reviewPullRequest({
|
|
910
|
+
pullRequestNumber: "110",
|
|
911
|
+
repoName: "electrodb",
|
|
912
|
+
repoOwner: "tywalch"
|
|
913
|
+
});
|
|
914
|
+
|
|
915
|
+
reviewIssue({
|
|
916
|
+
issueNumber: "281",
|
|
917
|
+
repoName: "electrodb",
|
|
918
|
+
repoOwner: "tywalch"
|
|
919
|
+
});
|
|
920
|
+
|
|
921
|
+
getUserPullRequests("tywalch");
|
|
922
|
+
getUserPullRequests("tywalch", "Closed");
|
|
923
|
+
|
|
924
|
+
closePullRequest("tywalch", {
|
|
925
|
+
pullRequestNumber: "301",
|
|
926
|
+
repoName: "electrodb",
|
|
927
|
+
repoOwner: "tywalch",
|
|
928
|
+
});
|
|
929
|
+
|
|
930
|
+
getFirstPageLoad("tywalch");
|
|
931
|
+
getSubscribed
|
|
932
|
+
getUnreadComments
|
|
933
|
+
readReply
|
|
934
|
+
readReply
|
|
935
|
+
readReply
|
|
936
|
+
approvePullRequest
|
|
937
|
+
followRepository
|