@model-ts/dynamodb 2.0.0 → 3.0.0

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.
Files changed (55) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/cjs/__test__/client-with-cursor-encryption.test.js +298 -183
  3. package/dist/cjs/__test__/client-with-cursor-encryption.test.js.map +1 -1
  4. package/dist/cjs/__test__/client.test.js +101 -0
  5. package/dist/cjs/__test__/client.test.js.map +1 -1
  6. package/dist/cjs/client.d.ts +6 -1
  7. package/dist/cjs/client.js +7 -2
  8. package/dist/cjs/client.js.map +1 -1
  9. package/dist/cjs/dynamodb-model.d.ts +33 -8
  10. package/dist/cjs/gsi.d.ts +4 -0
  11. package/dist/cjs/gsi.js +24 -0
  12. package/dist/cjs/gsi.js.map +1 -0
  13. package/dist/cjs/operations.d.ts +4 -8
  14. package/dist/cjs/operations.js.map +1 -1
  15. package/dist/cjs/pagination.d.ts +48 -59
  16. package/dist/cjs/pagination.js +18 -26
  17. package/dist/cjs/pagination.js.map +1 -1
  18. package/dist/cjs/provider.d.ts +135 -17
  19. package/dist/cjs/provider.js +5 -12
  20. package/dist/cjs/provider.js.map +1 -1
  21. package/dist/cjs/sandbox.js +10 -43
  22. package/dist/cjs/sandbox.js.map +1 -1
  23. package/dist/esm/__test__/client-with-cursor-encryption.test.js +298 -183
  24. package/dist/esm/__test__/client-with-cursor-encryption.test.js.map +1 -1
  25. package/dist/esm/__test__/client.test.js +101 -0
  26. package/dist/esm/__test__/client.test.js.map +1 -1
  27. package/dist/esm/client.d.ts +6 -1
  28. package/dist/esm/client.js +7 -2
  29. package/dist/esm/client.js.map +1 -1
  30. package/dist/esm/dynamodb-model.d.ts +33 -8
  31. package/dist/esm/gsi.d.ts +4 -0
  32. package/dist/esm/gsi.js +21 -0
  33. package/dist/esm/gsi.js.map +1 -0
  34. package/dist/esm/operations.d.ts +4 -8
  35. package/dist/esm/operations.js.map +1 -1
  36. package/dist/esm/pagination.d.ts +48 -59
  37. package/dist/esm/pagination.js +19 -26
  38. package/dist/esm/pagination.js.map +1 -1
  39. package/dist/esm/provider.d.ts +135 -17
  40. package/dist/esm/provider.js +5 -12
  41. package/dist/esm/provider.js.map +1 -1
  42. package/dist/esm/sandbox.js +10 -43
  43. package/dist/esm/sandbox.js.map +1 -1
  44. package/package.json +1 -1
  45. package/src/__test__/client-with-cursor-encryption.test.ts +365 -183
  46. package/src/__test__/client.test.ts +168 -0
  47. package/src/client.ts +20 -19
  48. package/src/dynamodb-model.ts +31 -9
  49. package/src/gsi.ts +25 -0
  50. package/src/operations.ts +4 -10
  51. package/src/pagination.ts +37 -46
  52. package/src/provider.ts +9 -9
  53. package/src/sandbox.ts +10 -43
  54. package/tsconfig.esm.json +14 -4
  55. package/tsconfig.json +14 -4
@@ -134,6 +134,10 @@ beforeEach(async () => {
134
134
  sandbox = await createSandbox(client)
135
135
  })
136
136
 
137
+ afterEach(async () => {
138
+ await sandbox.destroy()
139
+ })
140
+
137
141
  describe("put", () => {
138
142
  describe("via instance", () => {
139
143
  test("it inserts a simple model", async () => {
@@ -2135,6 +2139,56 @@ describe("paginate", () => {
2135
2139
  expect(page1.edges[0].node.c).toBe("0")
2136
2140
  expect(page1.edges[49].node.c).toBe("49")
2137
2141
  })
2142
+
2143
+ test("it respects custom pagination default", async () => {
2144
+ client.paginationOptions = {
2145
+ default: 40,
2146
+ }
2147
+
2148
+ const items = Array.from({ length: 50 }).map(
2149
+ (_, i) =>
2150
+ new C({ pk: "PK", sk: String(i).padStart(3, "0"), c: String(i) })
2151
+ )
2152
+
2153
+ await sandbox.seed(...items)
2154
+
2155
+ const page = await client.paginate(
2156
+ C,
2157
+ {},
2158
+ {
2159
+ KeyConditionExpression: "PK = :pk",
2160
+ ExpressionAttributeValues: { ":pk": "PK" },
2161
+ }
2162
+ )
2163
+ expect(page.edges.length).toBe(40)
2164
+
2165
+ delete client.paginationOptions
2166
+ })
2167
+
2168
+ test("it respects custom pagination limit", async () => {
2169
+ client.paginationOptions = {
2170
+ limit: 100,
2171
+ }
2172
+
2173
+ const items = Array.from({ length: 120 }).map(
2174
+ (_, i) =>
2175
+ new C({ pk: "PK", sk: String(i).padStart(3, "0"), c: String(i) })
2176
+ )
2177
+
2178
+ await sandbox.seed(...items)
2179
+
2180
+ const page = await client.paginate(
2181
+ C,
2182
+ { first: 110 },
2183
+ {
2184
+ KeyConditionExpression: "PK = :pk",
2185
+ ExpressionAttributeValues: { ":pk": "PK" },
2186
+ }
2187
+ )
2188
+ expect(page.edges.length).toBe(100)
2189
+
2190
+ delete client.paginationOptions
2191
+ })
2138
2192
  })
2139
2193
 
2140
2194
  describe("model", () => {
@@ -2301,6 +2355,54 @@ describe("paginate", () => {
2301
2355
  expect(page1.edges[0].node.c).toBe("0")
2302
2356
  expect(page1.edges[49].node.c).toBe("49")
2303
2357
  })
2358
+
2359
+ test("it respects custom pagination default", async () => {
2360
+ client.paginationOptions = {
2361
+ default: 40,
2362
+ }
2363
+
2364
+ const items = Array.from({ length: 50 }).map(
2365
+ (_, i) =>
2366
+ new C({ pk: "PK", sk: String(i).padStart(3, "0"), c: String(i) })
2367
+ )
2368
+
2369
+ await sandbox.seed(...items)
2370
+
2371
+ const page = await C.paginate(
2372
+ {},
2373
+ {
2374
+ KeyConditionExpression: "PK = :pk",
2375
+ ExpressionAttributeValues: { ":pk": "PK" },
2376
+ }
2377
+ )
2378
+ expect(page.edges.length).toBe(40)
2379
+
2380
+ delete client.paginationOptions
2381
+ })
2382
+
2383
+ test("it respects custom pagination limit", async () => {
2384
+ client.paginationOptions = {
2385
+ limit: 100,
2386
+ }
2387
+
2388
+ const items = Array.from({ length: 120 }).map(
2389
+ (_, i) =>
2390
+ new C({ pk: "PK", sk: String(i).padStart(3, "0"), c: String(i) })
2391
+ )
2392
+
2393
+ await sandbox.seed(...items)
2394
+
2395
+ const page = await C.paginate(
2396
+ { first: 110 },
2397
+ {
2398
+ KeyConditionExpression: "PK = :pk",
2399
+ ExpressionAttributeValues: { ":pk": "PK" },
2400
+ }
2401
+ )
2402
+ expect(page.edges.length).toBe(100)
2403
+
2404
+ delete client.paginationOptions
2405
+ })
2304
2406
  })
2305
2407
 
2306
2408
  describe("union", () => {
@@ -2470,5 +2572,71 @@ describe("paginate", () => {
2470
2572
  expect(page1.edges[0].node.SK).toBe("000")
2471
2573
  expect(page1.edges[49].node.SK).toBe("049")
2472
2574
  })
2575
+
2576
+ test("it respects custom pagination default", async () => {
2577
+ client.paginationOptions = {
2578
+ default: 40,
2579
+ }
2580
+
2581
+ const items = Array.from({ length: 50 }).map((_, i) =>
2582
+ i > 30
2583
+ ? new C({
2584
+ pk: "PK",
2585
+ sk: String(i).padStart(3, "0"),
2586
+ c: String(i),
2587
+ })
2588
+ : new D({
2589
+ pk: "PK",
2590
+ sk: String(i).padStart(3, "0"),
2591
+ d: String(i),
2592
+ })
2593
+ )
2594
+
2595
+ await sandbox.seed(...items)
2596
+
2597
+ const page = await Union.paginate(
2598
+ {},
2599
+ {
2600
+ KeyConditionExpression: "PK = :pk",
2601
+ ExpressionAttributeValues: { ":pk": "PK" },
2602
+ }
2603
+ )
2604
+ expect(page.edges.length).toBe(40)
2605
+
2606
+ delete client.paginationOptions
2607
+ })
2608
+
2609
+ test("it respects custom pagination limit", async () => {
2610
+ client.paginationOptions = {
2611
+ limit: 100,
2612
+ }
2613
+
2614
+ const items = Array.from({ length: 110 }).map((_, i) =>
2615
+ i > 30
2616
+ ? new C({
2617
+ pk: "PK",
2618
+ sk: String(i).padStart(3, "0"),
2619
+ c: String(i),
2620
+ })
2621
+ : new D({
2622
+ pk: "PK",
2623
+ sk: String(i).padStart(3, "0"),
2624
+ d: String(i),
2625
+ })
2626
+ )
2627
+
2628
+ await sandbox.seed(...items)
2629
+
2630
+ const page = await Union.paginate(
2631
+ { first: 110 },
2632
+ {
2633
+ KeyConditionExpression: "PK = :pk",
2634
+ ExpressionAttributeValues: { ":pk": "PK" },
2635
+ }
2636
+ )
2637
+ expect(page.edges.length).toBe(100)
2638
+
2639
+ delete client.paginationOptions
2640
+ })
2473
2641
  })
2474
2642
  })
package/src/client.ts CHANGED
@@ -40,8 +40,10 @@ import {
40
40
  encodeDDBCursor,
41
41
  PaginationDirection,
42
42
  PaginationInput,
43
+ PaginationOptions,
43
44
  PaginationResult,
44
45
  } from "./pagination"
46
+ import { GSI, GSI_NAMES, GSIPK, GSISK } from "./gsi"
45
47
 
46
48
  export type QueryParams = Omit<
47
49
  DocumentClient.QueryInput,
@@ -85,6 +87,11 @@ export interface ClientProps
85
87
  * Must be a 32 character string, 256 bits.
86
88
  */
87
89
  cursorEncryptionKey?: Buffer
90
+
91
+ /**
92
+ * Defaults for pagination.
93
+ */
94
+ paginationOptions?: PaginationOptions
88
95
  }
89
96
 
90
97
  export interface Key {
@@ -97,10 +104,12 @@ export class Client {
97
104
  documentClient: DocumentClient
98
105
  dataLoader: DataLoader<GetOperation<Decodable>, DynamoDBModelInstance, string>
99
106
  cursorEncryptionKey?: Buffer
107
+ paginationOptions?: PaginationOptions
100
108
 
101
109
  constructor(props: ClientProps) {
102
110
  this.tableName = props?.tableName
103
111
  this.cursorEncryptionKey = props?.cursorEncryptionKey
112
+ this.paginationOptions = props?.paginationOptions
104
113
  this.documentClient = new DocumentClient(props)
105
114
  this.dataLoader = new DataLoader<
106
115
  GetOperation<Decodable>,
@@ -525,7 +534,10 @@ export class Client {
525
534
  args: PaginationInput,
526
535
  params: PaginationParams
527
536
  ): Promise<PaginationResult<DecodableInstance<M>>> {
528
- const { cursor, limit, direction } = decodePagination(args)
537
+ const { cursor, limit, direction } = decodePagination(
538
+ args,
539
+ this.paginationOptions
540
+ )
529
541
 
530
542
  const { results } = await this.query(
531
543
  {
@@ -537,7 +549,7 @@ export class Client {
537
549
  cursor,
538
550
  // GSI1 is the inverse index and uses PK and SK (switched around)
539
551
  params.IndexName && params.IndexName !== "GSI1"
540
- ? (params.IndexName as "GSI2" | "GSI3" | "GSI4" | "GSI5")
552
+ ? (params.IndexName as GSI)
541
553
  : undefined,
542
554
  this.cursorEncryptionKey
543
555
  )
@@ -888,15 +900,8 @@ export class Client {
888
900
  T extends {
889
901
  PK: string
890
902
  SK: string
891
- GSI2PK?: string
892
- GSI2SK?: string
893
- GSI3PK?: string
894
- GSI3SK?: string
895
- GSI4PK?: string
896
- GSI4SK?: string
897
- GSI5PK?: string
898
- GSI5SK?: string
899
- }
903
+ } & { [key in GSIPK]?: string } &
904
+ { [key in GSISK]?: string }
900
905
  >(item: T): T {
901
906
  const prefix = "$$DELETED$$"
902
907
 
@@ -908,14 +913,10 @@ export class Client {
908
913
  ...item,
909
914
  PK: maybeWithPrefix(item.PK),
910
915
  SK: maybeWithPrefix(item.SK),
911
- GSI2PK: maybeWithPrefix(item.GSI2PK),
912
- GSI2SK: maybeWithPrefix(item.GSI2SK),
913
- GSI3PK: maybeWithPrefix(item.GSI3PK),
914
- GSI3SK: maybeWithPrefix(item.GSI3SK),
915
- GSI4PK: maybeWithPrefix(item.GSI4PK),
916
- GSI4SK: maybeWithPrefix(item.GSI4SK),
917
- GSI5PK: maybeWithPrefix(item.GSI5PK),
918
- GSI5SK: maybeWithPrefix(item.GSI5SK),
916
+ ...GSI_NAMES.map((GSI) => ({
917
+ [`${GSI}PK`]: maybeWithPrefix(item[`${GSI}PK` as const]),
918
+ [`${GSI}SK`]: maybeWithPrefix(item[`${GSI}SK` as const]),
919
+ })).reduce((acc, cur) => Object.assign(acc, cur), {}),
919
920
  }
920
921
  }
921
922
  }
@@ -1,4 +1,5 @@
1
1
  import { ModelInstance, ModelConstructor, Union } from "@model-ts/core"
2
+ import { GSIPK, GSISK } from "./gsi"
2
3
 
3
4
  export interface DynamoDBModelInstance extends ModelInstance<string, any> {
4
5
  /**
@@ -7,15 +8,8 @@ export interface DynamoDBModelInstance extends ModelInstance<string, any> {
7
8
  keys(): {
8
9
  PK: string
9
10
  SK: string
10
- GSI2PK?: string
11
- GSI2SK?: string
12
- GSI3PK?: string
13
- GSI3SK?: string
14
- GSI4PK?: string
15
- GSI4SK?: string
16
- GSI5PK?: string
17
- GSI5SK?: string
18
- }
11
+ } & { [key in GSIPK]?: string } &
12
+ { [key in GSISK]?: string }
19
13
 
20
14
  PK: string
21
15
  SK: string
@@ -27,6 +21,34 @@ export interface DynamoDBModelInstance extends ModelInstance<string, any> {
27
21
  GSI4SK?: string
28
22
  GSI5PK?: string
29
23
  GSI5SK?: string
24
+ GSI6PK?: string
25
+ GSI6SK?: string
26
+ GSI7PK?: string
27
+ GSI7SK?: string
28
+ GSI8PK?: string
29
+ GSI8SK?: string
30
+ GSI9PK?: string
31
+ GSI9SK?: string
32
+ GSI10PK?: string
33
+ GSI10SK?: string
34
+ GSI11PK?: string
35
+ GSI11SK?: string
36
+ GSI12PK?: string
37
+ GSI12SK?: string
38
+ GSI13PK?: string
39
+ GSI13SK?: string
40
+ GSI14PK?: string
41
+ GSI14SK?: string
42
+ GSI15PK?: string
43
+ GSI15SK?: string
44
+ GSI16PK?: string
45
+ GSI16SK?: string
46
+ GSI17PK?: string
47
+ GSI17SK?: string
48
+ GSI18PK?: string
49
+ GSI18SK?: string
50
+ GSI19PK?: string
51
+ GSI19SK?: string
30
52
  }
31
53
 
32
54
  // export interface DynamoDBModel {}
package/src/gsi.ts ADDED
@@ -0,0 +1,25 @@
1
+ export const GSI_NAMES = [
2
+ "GSI2",
3
+ "GSI3",
4
+ "GSI4",
5
+ "GSI5",
6
+ "GSI6",
7
+ "GSI7",
8
+ "GSI8",
9
+ "GSI9",
10
+ "GSI10",
11
+ "GSI11",
12
+ "GSI12",
13
+ "GSI13",
14
+ "GSI14",
15
+ "GSI15",
16
+ "GSI16",
17
+ "GSI17",
18
+ "GSI18",
19
+ "GSI19",
20
+ ] as const
21
+
22
+ export type GSI = typeof GSI_NAMES[number]
23
+
24
+ export type GSIPK = `${GSI}PK`
25
+ export type GSISK = `${GSI}SK`
package/src/operations.ts CHANGED
@@ -6,6 +6,7 @@ import {
6
6
  Decodable,
7
7
  } from "./dynamodb-model"
8
8
  import { Key } from "./client"
9
+ import { GSIPK, GSISK } from "./gsi"
9
10
 
10
11
  export type Operation<
11
12
  T extends DynamoDBModelInstance,
@@ -57,16 +58,9 @@ export interface UpdateRawOperation<M extends DynamoDBModelConstructor<any>>
57
58
  _operation: "updateRaw"
58
59
  _model: M
59
60
  key: Key
60
- attributes: Partial<TypeOf<M>> & {
61
- GSI2PK?: string | null
62
- GSI2SK?: string | null
63
- GSI3PK?: string | null
64
- GSI3SK?: string | null
65
- GSI4PK?: string | null
66
- GSI4SK?: string | null
67
- GSI5PK?: string | null
68
- GSI5SK?: string | null
69
- }
61
+ attributes: Partial<TypeOf<M>> &
62
+ { [key in GSIPK]?: string | null } &
63
+ { [key in GSISK]?: string | null }
70
64
  }
71
65
 
72
66
  // -------------------------------------------------------------------------------------
package/src/pagination.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import crypto from "crypto"
2
2
  import { PaginationError } from "./errors"
3
+ import { GSI, GSI_NAMES, GSIPK, GSISK } from "./gsi"
3
4
 
4
5
  const SIV = "Q05yyCR+0tyWl6glrZhlNw=="
5
6
  const ENCRYPTION_ALG = "aes-256-ctr"
@@ -33,13 +34,27 @@ export interface PaginationInput {
33
34
  after?: string | null
34
35
  }
35
36
 
36
- // TODO: make configurable
37
+ export interface PaginationOptions {
38
+ /**
39
+ * Maximum number of items to return.
40
+ */
41
+ limit?: number
42
+
43
+ /**
44
+ * Default number of items to return if no limit is provided.
45
+ */
46
+ default?: number
47
+ }
48
+
37
49
  const DEFAULT_OPTIONS = {
38
50
  limit: 50,
39
51
  default: 20,
40
52
  }
41
53
 
42
- export function decodePagination(pagination: PaginationInput): {
54
+ export function decodePagination(
55
+ pagination: PaginationInput,
56
+ paginationOptions: PaginationOptions = DEFAULT_OPTIONS
57
+ ): {
43
58
  cursor?: string
44
59
  limit: number
45
60
  direction: PaginationDirection
@@ -65,8 +80,8 @@ export function decodePagination(pagination: PaginationInput): {
65
80
  return {
66
81
  cursor: before ?? after ?? undefined,
67
82
  limit: Math.min(
68
- first ?? last ?? DEFAULT_OPTIONS.default,
69
- DEFAULT_OPTIONS.limit
83
+ first ?? last ?? paginationOptions.default ?? DEFAULT_OPTIONS.default,
84
+ paginationOptions.limit ?? DEFAULT_OPTIONS.limit
70
85
  ),
71
86
  direction:
72
87
  before || last
@@ -120,40 +135,22 @@ export const encodeDDBCursor = (
120
135
  {
121
136
  PK,
122
137
  SK,
123
- GSI2PK,
124
- GSI2SK,
125
- GSI3PK,
126
- GSI3SK,
127
- GSI4PK,
128
- GSI4SK,
129
- GSI5PK,
130
- GSI5SK,
138
+ ...values
131
139
  }: {
132
140
  PK: string
133
141
  SK: string
134
- GSI2PK?: string
135
- GSI2SK?: string
136
- GSI3PK?: string
137
- GSI3SK?: string
138
- GSI4PK?: string
139
- GSI4SK?: string
140
- GSI5PK?: string
141
- GSI5SK?: string
142
- },
142
+ } & { [key in GSIPK]?: string } &
143
+ { [key in GSISK]?: string },
143
144
  encryptionKey?: Buffer
144
145
  ) => {
145
146
  const cursor = Buffer.from(
146
147
  JSON.stringify({
147
148
  PK,
148
149
  SK,
149
- GSI2PK,
150
- GSI2SK,
151
- GSI3PK,
152
- GSI3SK,
153
- GSI4PK,
154
- GSI4SK,
155
- GSI5PK,
156
- GSI5SK,
150
+ ...GSI_NAMES.map((GSI) => ({
151
+ [`${GSI}PK`]: values[`${GSI}PK` as const],
152
+ [`${GSI}SK`]: values[`${GSI}SK` as const],
153
+ })).reduce((acc, cur) => Object.assign(acc, cur), {}),
157
154
  })
158
155
  ).toString("base64")
159
156
 
@@ -164,7 +161,7 @@ export const encodeDDBCursor = (
164
161
 
165
162
  export const decodeDDBCursor = (
166
163
  encoded: string,
167
- index?: "GSI2" | "GSI3" | "GSI4" | "GSI5",
164
+ index?: GSI,
168
165
  encryptionKey?: Buffer
169
166
  ) => {
170
167
  try {
@@ -173,26 +170,20 @@ export const decodeDDBCursor = (
173
170
 
174
171
  if (!json) throw new Error("Couldn't decrypt cursor")
175
172
 
176
- const {
177
- PK,
178
- SK,
179
- GSI2PK,
180
- GSI2SK,
181
- GSI3PK,
182
- GSI3SK,
183
- GSI4PK,
184
- GSI4SK,
185
- GSI5PK,
186
- GSI5SK,
187
- } = JSON.parse(Buffer.from(json, "base64").toString())
173
+ const { PK, SK, ...values } = JSON.parse(
174
+ Buffer.from(json, "base64").toString()
175
+ )
188
176
 
189
177
  if (typeof PK !== "string" || typeof SK !== "string") throw new Error()
190
178
 
191
179
  if (!index) return { PK, SK }
192
- if (index === "GSI2") return { PK, SK, GSI2PK, GSI2SK }
193
- if (index === "GSI3") return { PK, SK, GSI3PK, GSI3SK }
194
- if (index === "GSI4") return { PK, SK, GSI4PK, GSI4SK }
195
- if (index === "GSI5") return { PK, SK, GSI5PK, GSI5SK }
180
+
181
+ return {
182
+ PK,
183
+ SK,
184
+ [`${index}PK`]: values[`${index}PK`],
185
+ [`${index}SK`]: values[`${index}SK`],
186
+ }
196
187
  } catch (error) {
197
188
  throw new PaginationError("Couldn't decode cursor")
198
189
  }
package/src/provider.ts CHANGED
@@ -18,6 +18,7 @@ import { OutputOf, TypeOf, ModelOf } from "@model-ts/core"
18
18
  import { RaceConditionError } from "./errors"
19
19
  import { absurd } from "fp-ts/lib/function"
20
20
  import { encodeDDBCursor, PaginationInput } from "./pagination"
21
+ import { GSI_NAMES, GSIPK, GSISK } from "./gsi"
21
22
 
22
23
  export interface DynamoDBInternals<M extends Decodable> {
23
24
  __dynamoDBDecode(
@@ -512,18 +513,17 @@ export const getProvider = (client: Client) => {
512
513
  },
513
514
  instanceProps: {
514
515
  dynamodb: client,
515
- keys<T extends DynamoDBModelInstance>(this: T) {
516
+ keys<T extends DynamoDBModelInstance>(
517
+ this: T
518
+ ): { PK: string; SK: string } & { [key in GSIPK]?: string } &
519
+ { [key in GSISK]?: string } {
516
520
  return {
517
521
  PK: this.PK,
518
522
  SK: this.SK,
519
- GSI2PK: this.GSI2PK,
520
- GSI2SK: this.GSI2SK,
521
- GSI3PK: this.GSI3PK,
522
- GSI3SK: this.GSI3SK,
523
- GSI4PK: this.GSI4PK,
524
- GSI4SK: this.GSI4SK,
525
- GSI5PK: this.GSI5PK,
526
- GSI5SK: this.GSI5SK,
523
+ ...GSI_NAMES.map((GSI) => ({
524
+ [`${GSI}PK`]: this[`${GSI}PK`],
525
+ [`${GSI}SK`]: this[`${GSI}SK`],
526
+ })).reduce((acc, cur) => Object.assign(acc, cur), {}),
527
527
  }
528
528
  },
529
529
  cursor<T extends DynamoDBModelInstance>(this: T) {
package/src/sandbox.ts CHANGED
@@ -3,6 +3,7 @@ import { chunksOf } from "fp-ts/lib/Array"
3
3
  import DynamoDB from "aws-sdk/clients/dynamodb"
4
4
  import diff from "snapshot-diff"
5
5
  import { Client } from "./client"
6
+ import { GSI_NAMES } from "./gsi"
6
7
 
7
8
  const ddb = new DynamoDB({
8
9
  accessKeyId: "xxx",
@@ -27,14 +28,10 @@ export const createTable = async () => {
27
28
  AttributeDefinitions: [
28
29
  { AttributeName: "PK", AttributeType: "S" },
29
30
  { AttributeName: "SK", AttributeType: "S" },
30
- { AttributeName: "GSI2PK", AttributeType: "S" },
31
- { AttributeName: "GSI2SK", AttributeType: "S" },
32
- { AttributeName: "GSI3PK", AttributeType: "S" },
33
- { AttributeName: "GSI3SK", AttributeType: "S" },
34
- { AttributeName: "GSI4PK", AttributeType: "S" },
35
- { AttributeName: "GSI4SK", AttributeType: "S" },
36
- { AttributeName: "GSI5PK", AttributeType: "S" },
37
- { AttributeName: "GSI5SK", AttributeType: "S" },
31
+ ...GSI_NAMES.flatMap((GSI) => [
32
+ { AttributeName: `${GSI}PK`, AttributeType: "S" },
33
+ { AttributeName: `${GSI}SK`, AttributeType: "S" },
34
+ ]),
38
35
  ],
39
36
  KeySchema: [
40
37
  { AttributeName: "PK", KeyType: "HASH" },
@@ -51,46 +48,16 @@ export const createTable = async () => {
51
48
  ProjectionType: "ALL",
52
49
  },
53
50
  },
54
- {
55
- IndexName: "GSI2",
56
- KeySchema: [
57
- { AttributeName: "GSI2PK", KeyType: "HASH" },
58
- { AttributeName: "GSI2SK", KeyType: "RANGE" },
59
- ],
60
- Projection: {
61
- ProjectionType: "ALL",
62
- },
63
- },
64
- {
65
- IndexName: "GSI3",
51
+ ...GSI_NAMES.map((GSI) => ({
52
+ IndexName: GSI,
66
53
  KeySchema: [
67
- { AttributeName: "GSI3PK", KeyType: "HASH" },
68
- { AttributeName: "GSI3SK", KeyType: "RANGE" },
54
+ { AttributeName: `${GSI}PK`, KeyType: "HASH" },
55
+ { AttributeName: `${GSI}SK`, KeyType: "RANGE" },
69
56
  ],
70
57
  Projection: {
71
58
  ProjectionType: "ALL",
72
59
  },
73
- },
74
- {
75
- IndexName: "GSI4",
76
- KeySchema: [
77
- { AttributeName: "GSI4PK", KeyType: "HASH" },
78
- { AttributeName: "GSI4SK", KeyType: "RANGE" },
79
- ],
80
- Projection: {
81
- ProjectionType: "ALL",
82
- },
83
- },
84
- {
85
- IndexName: "GSI5",
86
- KeySchema: [
87
- { AttributeName: "GSI5PK", KeyType: "HASH" },
88
- { AttributeName: "GSI5SK", KeyType: "RANGE" },
89
- ],
90
- Projection: {
91
- ProjectionType: "ALL",
92
- },
93
- },
60
+ })),
94
61
  ],
95
62
  BillingMode: "PAY_PER_REQUEST",
96
63
  })
package/tsconfig.esm.json CHANGED
@@ -5,9 +5,19 @@
5
5
  "module": "ES2015",
6
6
  "outDir": "./dist/esm",
7
7
  "paths": {
8
- "@model-ts/core": ["../core"]
8
+ "@model-ts/core": [
9
+ "../core"
10
+ ]
9
11
  }
10
12
  },
11
- "references": [{ "path": "../core/tsconfig.esm.json" }],
12
- "exclude": ["__test__", "test-utils"]
13
- }
13
+ "references": [
14
+ {
15
+ "path": "../core/tsconfig.esm.json"
16
+ }
17
+ ],
18
+ "exclude": [
19
+ "dist",
20
+ "__test__",
21
+ "test-utils"
22
+ ]
23
+ }
package/tsconfig.json CHANGED
@@ -4,9 +4,19 @@
4
4
  "rootDir": "./src",
5
5
  "outDir": "./dist/cjs",
6
6
  "paths": {
7
- "@model-ts/core": ["../core"]
7
+ "@model-ts/core": [
8
+ "../core"
9
+ ]
8
10
  }
9
11
  },
10
- "references": [{ "path": "../core" }],
11
- "exclude": ["__test__", "test-utils"]
12
- }
12
+ "references": [
13
+ {
14
+ "path": "../core"
15
+ }
16
+ ],
17
+ "exclude": [
18
+ "dist",
19
+ "__test__",
20
+ "test-utils"
21
+ ]
22
+ }