@aws-amplify/data-schema 1.2.0 → 1.2.2

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 (30) hide show
  1. package/dist/cjs/runtime/internals/APIClient.js +132 -22
  2. package/dist/cjs/runtime/internals/APIClient.js.map +1 -1
  3. package/dist/cjs/runtime/internals/operations/list.js +4 -1
  4. package/dist/cjs/runtime/internals/operations/list.js.map +1 -1
  5. package/dist/cjs/runtime/utils/index.js +5 -1
  6. package/dist/cjs/runtime/utils/index.js.map +1 -1
  7. package/dist/cjs/runtime/utils/stringTransformation.js +13 -0
  8. package/dist/cjs/runtime/utils/stringTransformation.js.map +1 -0
  9. package/dist/esm/MappedTypes/MapIndexes.d.ts +13 -3
  10. package/dist/esm/ModelType.d.ts +1 -0
  11. package/dist/esm/runtime/client/index.d.ts +57 -8
  12. package/dist/esm/runtime/internals/APIClient.mjs +129 -18
  13. package/dist/esm/runtime/internals/APIClient.mjs.map +1 -1
  14. package/dist/esm/runtime/internals/operations/list.mjs +4 -1
  15. package/dist/esm/runtime/internals/operations/list.mjs.map +1 -1
  16. package/dist/esm/runtime/utils/index.d.ts +2 -0
  17. package/dist/esm/runtime/utils/index.mjs +2 -0
  18. package/dist/esm/runtime/utils/index.mjs.map +1 -1
  19. package/dist/esm/runtime/utils/stringTransformation.d.ts +5 -0
  20. package/dist/esm/runtime/utils/stringTransformation.mjs +10 -0
  21. package/dist/esm/runtime/utils/stringTransformation.mjs.map +1 -0
  22. package/dist/meta/cjs.tsbuildinfo +1 -1
  23. package/package.json +2 -1
  24. package/src/MappedTypes/MapIndexes.ts +26 -3
  25. package/src/ModelType.ts +1 -1
  26. package/src/runtime/client/index.ts +70 -15
  27. package/src/runtime/internals/APIClient.ts +147 -27
  28. package/src/runtime/internals/operations/list.ts +6 -1
  29. package/src/runtime/utils/index.ts +2 -0
  30. package/src/runtime/utils/stringTransformation.ts +7 -0
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../../src/runtime/utils/index.ts"],"sourcesContent":["\"use strict\";\n// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.findIndexByFields = exports.resolvePKFields = void 0;\nvar resolvePKFields_1 = require(\"./resolvePKFields\");\nObject.defineProperty(exports, \"resolvePKFields\", { enumerable: true, get: function () { return resolvePKFields_1.resolvePKFields; } });\nvar findIndexByFields_1 = require(\"./findIndexByFields\");\nObject.defineProperty(exports, \"findIndexByFields\", { enumerable: true, get: function () { return findIndexByFields_1.findIndexByFields; } });\n"],"names":[],"mappings":";;AACA;AACA;AACA,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AAC9D,OAAO,CAAC,iBAAiB,GAAG,OAAO,CAAC,eAAe,GAAG,KAAK,CAAC,CAAC;AAC7D,IAAI,iBAAiB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;AACrD,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,iBAAiB,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,EAAE,YAAY,EAAE,OAAO,iBAAiB,CAAC,eAAe,CAAC,EAAE,EAAE,CAAC,CAAC;AACxI,IAAI,mBAAmB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;AACzD,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,mBAAmB,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,EAAE,YAAY,EAAE,OAAO,mBAAmB,CAAC,iBAAiB,CAAC,EAAE,EAAE,CAAC;;"}
1
+ {"version":3,"file":"index.js","sources":["../../../../src/runtime/utils/index.ts"],"sourcesContent":["\"use strict\";\n// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.capitalize = exports.resolveOwnerFields = exports.findIndexByFields = exports.resolvePKFields = void 0;\nvar resolvePKFields_1 = require(\"./resolvePKFields\");\nObject.defineProperty(exports, \"resolvePKFields\", { enumerable: true, get: function () { return resolvePKFields_1.resolvePKFields; } });\nvar findIndexByFields_1 = require(\"./findIndexByFields\");\nObject.defineProperty(exports, \"findIndexByFields\", { enumerable: true, get: function () { return findIndexByFields_1.findIndexByFields; } });\nvar resolveOwnerFields_1 = require(\"./resolveOwnerFields\");\nObject.defineProperty(exports, \"resolveOwnerFields\", { enumerable: true, get: function () { return resolveOwnerFields_1.resolveOwnerFields; } });\nvar stringTransformation_1 = require(\"./stringTransformation\");\nObject.defineProperty(exports, \"capitalize\", { enumerable: true, get: function () { return stringTransformation_1.capitalize; } });\n"],"names":[],"mappings":";;AACA;AACA;AACA,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AAC9D,OAAO,CAAC,UAAU,GAAG,OAAO,CAAC,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,GAAG,OAAO,CAAC,eAAe,GAAG,KAAK,CAAC,CAAC;AAC/G,IAAI,iBAAiB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;AACrD,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,iBAAiB,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,EAAE,YAAY,EAAE,OAAO,iBAAiB,CAAC,eAAe,CAAC,EAAE,EAAE,CAAC,CAAC;AACxI,IAAI,mBAAmB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;AACzD,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,mBAAmB,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,EAAE,YAAY,EAAE,OAAO,mBAAmB,CAAC,iBAAiB,CAAC,EAAE,EAAE,CAAC,CAAC;AAC9I,IAAI,oBAAoB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;AAC3D,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,oBAAoB,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,EAAE,YAAY,EAAE,OAAO,oBAAoB,CAAC,kBAAkB,CAAC,EAAE,EAAE,CAAC,CAAC;AACjJ,IAAI,sBAAsB,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAAC;AAC/D,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,EAAE,YAAY,EAAE,OAAO,sBAAsB,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC;;"}
@@ -0,0 +1,13 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.capitalize = void 0;
5
+ /**
6
+ * @param s string to capitalize
7
+ * @returns capitalized string
8
+ */
9
+ function capitalize(s) {
10
+ return `${s[0].toUpperCase()}${s.slice(1)}`;
11
+ }
12
+ exports.capitalize = capitalize;
13
+ //# sourceMappingURL=stringTransformation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stringTransformation.js","sources":["../../../../src/runtime/utils/stringTransformation.ts"],"sourcesContent":["\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.capitalize = void 0;\n/**\n * @param s string to capitalize\n * @returns capitalized string\n */\nfunction capitalize(s) {\n return `${s[0].toUpperCase()}${s.slice(1)}`;\n}\nexports.capitalize = capitalize;\n"],"names":[],"mappings":";;AACA,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AAC9D,OAAO,CAAC,UAAU,GAAG,KAAK,CAAC,CAAC;AAC5B;AACA;AACA;AACA;AACA,SAAS,UAAU,CAAC,CAAC,EAAE;AACvB,IAAI,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChD,CAAC;AACD,OAAO,CAAC,UAAU,GAAG,UAAU;;"}
@@ -1,11 +1,20 @@
1
1
  import { ModelIndexType } from '../ModelIndex';
2
2
  type ModelIndexTypeShape = ModelIndexType<any, any, any, any, any>;
3
- export type PrimaryIndexFieldsToIR<IdxFields extends ReadonlyArray<string>, ResolvedFields> = IdxFields extends readonly [infer PK, ...infer SK] ? {
3
+ export type PrimaryIndexFieldsToIR<IdxFields extends ReadonlyArray<string>, ResolvedFields> = IdxFields extends readonly [
4
+ infer PK,
5
+ ...infer SK extends never | readonly string[]
6
+ ] ? {
4
7
  pk: PK extends keyof ResolvedFields ? {
5
8
  [Key in PK]: Exclude<ResolvedFields[PK], null> & (string | number);
6
9
  } : never;
7
10
  sk: unknown extends SK ? never : ResolvedSortKeyFields<SK, ResolvedFields>;
11
+ compositeSk: SK['length'] extends 0 | 1 ? never : CompositeSkFieldName<ArrayShift<SK>, SK[0]>;
8
12
  } : never;
13
+ type ArrayShift<Arr extends ReadonlyArray<any>> = Arr extends readonly [
14
+ infer _Shift,
15
+ ...infer Rest
16
+ ] ? Rest : never;
17
+ type CompositeSkFieldName<SK, Result extends string = ''> = SK extends readonly [infer A extends string, ...infer B extends string[]] ? CompositeSkFieldName<B, `${Result}${Capitalize<A>}`> : Result;
9
18
  /**
10
19
  * Maps array of ModelIndexType to SecondaryIndexIrShape (defined in in data-schema-types)
11
20
  * */
@@ -29,13 +38,14 @@ export type SecondaryIndexToIR<Idxs extends ReadonlyArray<ModelIndexTypeShape>,
29
38
  *
30
39
  * @remarks - the IR type alias is defined as SecondaryIndexIrShape in data-schema-types
31
40
  */
32
- type SingleIndexIrFromType<Idx extends ModelIndexTypeShape, ResolvedFields> = Idx extends ModelIndexType<any, infer PK extends string, infer SK, infer QueryField extends string | never, any> ? {
33
- defaultQueryFieldSuffix: `${QueryFieldLabelFromTuple<SK, Capitalize<PK>>}`;
41
+ type SingleIndexIrFromType<Idx extends ModelIndexTypeShape, ResolvedFields> = Idx extends ModelIndexType<any, infer PK extends string, infer SK extends readonly string[], infer QueryField extends string | never, any> ? {
42
+ defaultQueryFieldSuffix: QueryFieldLabelFromTuple<SK, Capitalize<PK>>;
34
43
  queryField: QueryField;
35
44
  pk: PK extends keyof ResolvedFields ? {
36
45
  [Key in PK]: Exclude<ResolvedFields[PK], null>;
37
46
  } : never;
38
47
  sk: unknown extends SK ? never : ResolvedSortKeyFields<SK, ResolvedFields>;
48
+ compositeSk: SK['length'] extends 0 | 1 ? never : CompositeSkFieldName<ArrayShift<SK>, SK[0]>;
39
49
  } : never;
40
50
  /**
41
51
  * @typeParam SK - tuple of SortKey field names, e.g. ['viewCount', 'createdAt']
@@ -94,6 +94,7 @@ export declare function model<T extends ModelFields>(fields: T): ModelType<{
94
94
  id: string;
95
95
  };
96
96
  sk: never;
97
+ compositeSk: never;
97
98
  };
98
99
  secondaryIndexes: [];
99
100
  authorization: [];
@@ -289,7 +289,7 @@ type SizeFilter = {
289
289
  /**
290
290
  * Filters options that can be used on string-like fields.
291
291
  */
292
- type StringFilter<T extends string = string> = {
292
+ export type StringFilter<T extends string = string> = {
293
293
  attributeExists?: boolean;
294
294
  beginsWith?: string;
295
295
  between?: [string, string];
@@ -303,7 +303,7 @@ type StringFilter<T extends string = string> = {
303
303
  notContains?: string;
304
304
  size?: SizeFilter;
305
305
  };
306
- type NumericFilter = {
306
+ export type NumericFilter = {
307
307
  attributeExists?: boolean;
308
308
  between?: [number, number];
309
309
  eq?: number;
@@ -318,8 +318,52 @@ type BooleanFilters = {
318
318
  eq?: boolean;
319
319
  ne?: boolean;
320
320
  };
321
+ /**
322
+ * A composite SK (in an identifier or secondaryIndex) resolves to this type for
323
+ * list queries and index queries
324
+ *
325
+ * @example
326
+ * Given
327
+ * ```ts
328
+ * MyModel: a
329
+ .model({
330
+ pk: a.string().required(),
331
+ sk1: a.string().required(),
332
+ sk2: a.integer().required(),
333
+ })
334
+ .identifier(['pk', 'sk1', 'sk2']),
335
+ * ```
336
+ * Expected list options:
337
+ * ```ts
338
+ * {
339
+ * pk?: string
340
+ * sk1Sk2?: ModelPrimaryCompositeKeyConditionInput
341
+ * }
342
+ * ```
343
+ * Where ModelPrimaryCompositeKeyConditionInput resolves to:
344
+ * ```ts
345
+ * {
346
+ * eq: {sk1: string; sk2: number};
347
+ * le: {sk1: string; sk2: number};
348
+ * lt: {sk1: string; sk2: number};
349
+ * ge: {sk1: string; sk2: number};
350
+ * gt: {sk1: string; sk2: number};
351
+ * between: [ {sk1: string; sk2: number} ];
352
+ * beginsWith: {sk1: string; sk2: number};
353
+ * }
354
+ * ```
355
+ * */
356
+ export type ModelPrimaryCompositeKeyInput<SkIr extends Record<string, string | number>> = {
357
+ eq?: SkIr;
358
+ le?: SkIr;
359
+ lt?: SkIr;
360
+ ge?: SkIr;
361
+ gt?: SkIr;
362
+ between?: [SkIr];
363
+ beginsWith?: SkIr;
364
+ };
321
365
  type ModelFilter<Model extends Record<any, any>> = LogicalFilters<Model> & {
322
- [K in keyof Model as Model[K] extends LazyLoader<any, any> ? never : K]?: Model[K] extends boolean ? BooleanFilters : Model[K] extends number ? NumericFilter : StringFilter;
366
+ [K in keyof Model as Model[K] extends LazyLoader<any, any> ? never : K]?: boolean extends Model[K] ? BooleanFilters : number extends Model[K] ? NumericFilter : StringFilter;
323
367
  };
324
368
  export type ModelSortDirection = 'ASC' | 'DESC';
325
369
  type ModelMetaShape = {
@@ -524,6 +568,7 @@ export interface PrimaryIndexIrShape {
524
568
  sk: {
525
569
  [key: string]: string | number;
526
570
  } | never;
571
+ compositeSk: never | string;
527
572
  }
528
573
  /**
529
574
  * SecondaryIndex field types and query methods
@@ -532,21 +577,25 @@ export interface SecondaryIndexIrShape extends PrimaryIndexIrShape {
532
577
  defaultQueryFieldSuffix: string;
533
578
  queryField: string;
534
579
  }
535
- type IndexQueryMethodsFromIR<SecondaryIdxTuple extends SecondaryIndexIrShape[], ModelName extends string, Model extends Record<string, unknown>, Enums extends Record<string, string>, Res = unknown> = SecondaryIdxTuple extends [
580
+ export type IndexQueryMethodsFromIR<SecondaryIdxTuple extends SecondaryIndexIrShape[], ModelName extends string, Model extends Record<string, unknown>, Enums extends Record<string, string>, Res = unknown> = SecondaryIdxTuple extends [
536
581
  infer A extends SecondaryIndexIrShape,
537
582
  ...infer B extends SecondaryIndexIrShape[]
538
583
  ] ? IndexQueryMethodsFromIR<B, ModelName, Model, Enums, IndexQueryMethodSignature<A, ModelName, Model, Enums> & Res> : Res;
539
- type ListPkOptions<ModelMeta extends ModelMetaShape, Enums extends Record<string, string>> = ModelMeta['identifier']['sk'] extends never ? unknown : Prettify<Partial<IndexQueryInput<ModelMeta['identifier'], Enums>> & {
584
+ export type ListPkOptions<ModelMeta extends ModelMetaShape, Enums extends Record<string, string>> = ModelMeta['identifier']['sk'] extends never ? unknown : Prettify<Partial<IndexQueryInput<ModelMeta['identifier'], Enums>> & {
540
585
  sortDirection?: ModelSortDirection;
541
586
  }>;
542
587
  /**
543
588
  * Accepts a PrimaryIndexIr or SecondaryIndexIr and returns resolved parameters
544
589
  */
545
- type IndexQueryInput<Idx extends PrimaryIndexIrShape, Enums extends Record<string, string>> = {
590
+ export type IndexQueryInput<Idx extends PrimaryIndexIrShape, Enums extends Record<string, string>> = {
546
591
  [PKField in keyof Idx['pk']]: Idx['pk'][PKField] extends `${deferredRefResolvingPrefix}${infer R}` ? Enums[R] : Idx['pk'][PKField];
547
- } & {
592
+ } & (Idx['compositeSk'] extends never ? {
548
593
  [SKField in keyof Idx['sk']]+?: number extends Idx['sk'][SKField] ? NumericFilter : Idx['sk'][SKField] extends `${deferredRefResolvingPrefix}${infer R}` ? StringFilter<Enums[R]> : StringFilter<Idx['sk'][SKField] & string>;
549
- };
594
+ } : {
595
+ [CompositeSk in Idx['compositeSk']]+?: ModelPrimaryCompositeKeyInput<{
596
+ [SKField in keyof Idx['sk']]: Idx['sk'][SKField] extends `${deferredRefResolvingPrefix}${infer _R}` ? string : Idx['sk'][SKField];
597
+ }>;
598
+ });
550
599
  type IndexQueryMethodSignature<Idx extends SecondaryIndexIrShape, ModelName extends string, Model extends Record<string, unknown>, Enums extends Record<string, string>> = Record<IsEmptyStringOrNever<Idx['queryField']> extends false ? Idx['queryField'] : `list${ModelName}By${Idx['defaultQueryFieldSuffix']}`, <FlatModel extends Record<string, unknown> = ResolvedModel<Model>, SelectionSet extends ReadonlyArray<ModelPath<FlatModel>> = never[]>(input: IndexQueryInput<Idx, Enums>, options?: {
551
600
  filter?: ModelFilter<Model>;
552
601
  sortDirection?: ModelSortDirection;
@@ -1,4 +1,5 @@
1
1
  import { resolveOwnerFields } from '../utils/resolveOwnerFields.mjs';
2
+ import { capitalize } from '../utils/stringTransformation.mjs';
2
3
 
3
4
  // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
4
5
  const connectionType = {
@@ -6,6 +7,39 @@ const connectionType = {
6
7
  HAS_MANY: 'HAS_MANY',
7
8
  BELONGS_TO: 'BELONGS_TO',
8
9
  };
10
+ // When generating an SK's KeyConditionInput name, string-like types map to String
11
+ const skGraphQlFieldTypeMap = {
12
+ ID: 'ID',
13
+ String: 'String',
14
+ AWSDate: 'String',
15
+ AWSTime: 'String',
16
+ AWSDateTime: 'String',
17
+ AWSTimestamp: 'String',
18
+ AWSEmail: 'String',
19
+ AWSPhone: 'String',
20
+ AWSURL: 'String',
21
+ AWSIPAddress: 'String',
22
+ AWSJSON: 'String',
23
+ Boolean: 'Boolean',
24
+ Int: 'Int',
25
+ Float: 'Float',
26
+ };
27
+ // move to util
28
+ const resolvedSkName = (sk) => {
29
+ if (sk.length === 1) {
30
+ return sk[0];
31
+ }
32
+ else {
33
+ return sk.reduce((acc, curr, idx) => {
34
+ if (idx === 0) {
35
+ return curr;
36
+ }
37
+ else {
38
+ return acc + capitalize(curr);
39
+ }
40
+ }, '');
41
+ }
42
+ };
9
43
  /**
10
44
  *
11
45
  * @param GraphQL response object
@@ -426,7 +460,7 @@ function generateSelectionSet(modelIntrospection, modelName, selectionSet) {
426
460
  }
427
461
  function generateGraphQLDocument(modelIntrospection, modelName, modelOperation, listArgs, indexMeta) {
428
462
  const modelDefinition = modelIntrospection.models[modelName];
429
- const { name, pluralName, fields, primaryKeyInfo: { isCustomPrimaryKey, primaryKeyFieldName, sortKeyFieldNames, }, } = modelDefinition;
463
+ const { name, pluralName, fields, primaryKeyInfo: { isCustomPrimaryKey, primaryKeyFieldName, sortKeyFieldNames, }, attributes, } = modelDefinition;
430
464
  // Use pascal case of the model name to generate the operations and the arguments.
431
465
  // This is required to be in sync with the resources generated by the GraphQL transformers.
432
466
  const namePascalCase = name.charAt(0).toUpperCase() + name.slice(1);
@@ -441,13 +475,38 @@ function generateGraphQLDocument(modelIntrospection, modelName, modelOperation,
441
475
  else if (indexMeta) {
442
476
  const { queryField, pk, sk = [] } = indexMeta;
443
477
  graphQLFieldName = queryField;
444
- const skQueryArgs = sk.reduce((acc, fieldName) => {
445
- const fieldType = Object.prototype.hasOwnProperty.call(fields[fieldName].type, 'enum')
446
- ? 'String' // AppSync schema sets `ModelStringKeyConditionInput` as the type of the enum field that's used as SK
447
- : fields[fieldName].type;
448
- acc[fieldName] = `Model${fieldType}KeyConditionInput`;
449
- return acc;
450
- }, {});
478
+ /**
479
+ * **a. Single field SK** -> single arg where name is the field name and the type is `Model${gqlFieldType}KeyConditionInput` (nullable)
480
+ * Note: string-like data types e.g., AWSDateTime, AWSEmail, AWSPhone, etc. should map to String. See `skGraphQlFieldTypeMap` above
481
+ * @example
482
+ * ```
483
+ * sk1: ModelStringKeyConditionInput
484
+ * ```
485
+ *
486
+ * **b. Composite SK** -> single arg where the name is camelCase concatenation of all the field names that comprise the SK
487
+ * and the type is `Model${modelName}${keyAttributeName}CompositeKeyConditionInput` (nullable)
488
+ * @example
489
+ * ```
490
+ * sk1Sk2: ModelMyModelMyModelByPkAndSk1AndSk2CompositeKeyConditionInput
491
+ */
492
+ let skQueryArgs = {};
493
+ if (sk.length === 1) {
494
+ const [skField] = sk;
495
+ const type = (typeof fields[skField].type === 'string'
496
+ ? fields[skField].type
497
+ : 'String');
498
+ const normalizedType = skGraphQlFieldTypeMap[type];
499
+ skQueryArgs = {
500
+ [skField]: `Model${normalizedType}KeyConditionInput`,
501
+ };
502
+ }
503
+ else if (sk.length > 1) {
504
+ const compositeSkArgName = resolvedSkName(sk);
505
+ const keyName = attributes?.find((attr) => attr?.properties?.queryField === queryField)?.properties?.name;
506
+ skQueryArgs = {
507
+ [compositeSkArgName]: `Model${capitalize(modelName)}${capitalize(keyName)}CompositeKeyConditionInput`,
508
+ };
509
+ }
451
510
  indexQueryArgs = {
452
511
  [pk]: `${Object.prototype.hasOwnProperty.call(fields[pk].type, 'enum')
453
512
  ? fields[pk].type.enum // AppSync schema sets enum type as the type of the enum fields that's used as PK
@@ -468,17 +527,62 @@ function generateGraphQLDocument(modelIntrospection, modelName, modelOperation,
468
527
  [primaryKeyFieldName]: `${fields[primaryKeyFieldName].type}!`,
469
528
  };
470
529
  const listPkArgs = {};
530
+ /**
531
+ * Generate query field args for the SK if it's defined
532
+ *
533
+ * **1. Get queries** require each SK field to be present as a separate arg where the type is the field's GraphQL scalar type (non-nullable)
534
+ * @example
535
+ * ```
536
+ * sk1: String!, sk2: Int!
537
+ * ```
538
+ *
539
+ * **2. List queries**
540
+ *
541
+ * **a. Single field SK** -> single arg where name is the field name and the type is `Model${gqlFieldType}KeyConditionInput` (nullable)
542
+ * Note: string-like data types e.g., AWSDateTime, AWSEmail, AWSPhone, etc. should map to String. See `skGraphQlFieldTypeMap` above
543
+ * @example
544
+ * ```
545
+ * sk1: ModelStringKeyConditionInput
546
+ * ```
547
+ *
548
+ * **b. Composite SK** -> single arg where the name is camelCase concatenation of all the field names that comprise the SK
549
+ * and the type is `Model${modelName}PrimaryCompositeKeyConditionInput` (nullable)
550
+ * @example
551
+ * ```
552
+ * sk1Sk2: ModelMyModelPrimaryCompositeKeyConditionInput
553
+ * ```
554
+ */
471
555
  const generateSkArgs = (op) => {
472
- return sortKeyFieldNames.reduce((acc, fieldName) => {
473
- const fieldType = fields[fieldName].type;
474
- if (op === 'get') {
475
- acc[fieldName] = `${fieldType}!`;
556
+ if (sortKeyFieldNames.length === 0)
557
+ return {};
558
+ if (op === 'get') {
559
+ return sortKeyFieldNames.reduce((acc, fieldName) => {
560
+ const fieldType = fields[fieldName].type;
561
+ if (op === 'get') {
562
+ acc[fieldName] = `${fieldType}!`; // ! - SK args are non-nullable in Get queries
563
+ }
564
+ return acc;
565
+ }, {});
566
+ }
567
+ else {
568
+ // list SK
569
+ if (sortKeyFieldNames.length === 1) {
570
+ // Single SK
571
+ const [sk] = sortKeyFieldNames;
572
+ const type = (typeof fields[sk].type === 'string' ? fields[sk].type : 'String');
573
+ const normalizedType = skGraphQlFieldTypeMap[type];
574
+ return {
575
+ [sk]: `Model${normalizedType}KeyConditionInput`,
576
+ };
476
577
  }
477
- else if (op === 'list') {
478
- acc[fieldName] = `Model${fieldType}KeyConditionInput`;
578
+ else {
579
+ // Composite SK
580
+ const compositeSkArgName = resolvedSkName(sortKeyFieldNames);
581
+ return {
582
+ [compositeSkArgName]: `Model${capitalize(modelName)}PrimaryCompositeKeyConditionInput`,
583
+ };
479
584
  }
480
- return acc;
481
- }, {});
585
+ }
482
586
  };
483
587
  if (isCustomPrimaryKey) {
484
588
  Object.assign(getPkArgs, generateSkArgs('get'));
@@ -562,6 +666,7 @@ function generateGraphQLDocument(modelIntrospection, modelName, modelOperation,
562
666
  }
563
667
  function buildGraphQLVariables(modelDefinition, operation, arg, modelIntrospection, indexMeta) {
564
668
  const { fields, primaryKeyInfo: { isCustomPrimaryKey, primaryKeyFieldName, sortKeyFieldNames, }, } = modelDefinition;
669
+ const skName = sortKeyFieldNames?.length && resolvedSkName(sortKeyFieldNames);
565
670
  let variables = {};
566
671
  // TODO: process input
567
672
  switch (operation) {
@@ -604,8 +709,13 @@ function buildGraphQLVariables(modelDefinition, operation, arg, modelIntrospecti
604
709
  }
605
710
  if (arg?.sortDirection) {
606
711
  variables.sortDirection = arg.sortDirection;
712
+ }
713
+ if (arg && arg[primaryKeyFieldName]) {
607
714
  variables[primaryKeyFieldName] = arg[primaryKeyFieldName];
608
715
  }
716
+ if (skName && arg && arg[skName]) {
717
+ variables[skName] = arg[skName];
718
+ }
609
719
  if (arg?.nextToken) {
610
720
  variables.nextToken = arg.nextToken;
611
721
  }
@@ -615,9 +725,10 @@ function buildGraphQLVariables(modelDefinition, operation, arg, modelIntrospecti
615
725
  break;
616
726
  case 'INDEX_QUERY': {
617
727
  const { pk, sk = [] } = indexMeta;
728
+ const indexQuerySkName = sk?.length && resolvedSkName(sk);
618
729
  variables[pk] = arg[pk];
619
- for (const skField of sk) {
620
- variables[skField] = arg[skField];
730
+ if (indexQuerySkName && arg && arg[indexQuerySkName]) {
731
+ variables[indexQuerySkName] = arg[indexQuerySkName];
621
732
  }
622
733
  if (arg?.filter) {
623
734
  variables.filter = arg.filter;