operation: str()

in packages/graphql-key-transformer/src/KeyTransformer.ts [995:1321]


            operation: str('Query'),
            limit: ref('limit'),
            query: ref(ResourceConstants.SNIPPETS.ModelQueryExpression),
            index: str(index),
          }),
        ),
        ifElse(
          raw(`!$util.isNull($ctx.args.sortDirection)
                    && $ctx.args.sortDirection == "DESC"`),
          set(ref(`${requestVariable}.scanIndexForward`), bool(false)),
          set(ref(`${requestVariable}.scanIndexForward`), bool(true)),
        ),
        iff(ref('context.args.nextToken'), set(ref(`${requestVariable}.nextToken`), ref('context.args.nextToken')), true),
        iff(
          ref('context.args.filter'),
          set(ref(`${requestVariable}.filter`), ref('util.parseJson("$util.transform.toDynamoDBFilterExpression($ctx.args.filter)")')),
          true,
        ),
        raw(`$util.toJson($${requestVariable})`),
      ]),
    ),
    ResponseMappingTemplate: print(
      compoundExpression([
        iff(ref('ctx.error'), raw('$util.error($ctx.error.message, $ctx.error.type)')),
        raw('$util.toJson($ctx.result)'),
      ]),
    ),
  });
}

function setQuerySnippet(definition: ObjectTypeDefinitionNode, directive: DirectiveNode, ctx: TransformerContext, isListResolver: boolean) {
  const args: KeyArguments = getDirectiveArguments(directive);
  const keys = args.fields;
  const keyTypes = keys.map(k => {
    const field = definition.fields.find(f => f.name.value === k);
    return attributeTypeFromType(field.type, ctx);
  });

  const expressions: Expression[] = [];

  // if @key has only Hash key then we've to add sortDirection validation to the VTL as it will not work
  // TODO: when we will have featureflags we can fix it by not generating sortDirection parameter at all for these operations
  if (keys.length === 1) {
    const sortDirectionValidation = iff(
      raw(`!$util.isNull($ctx.args.sortDirection)`),
      raw(`$util.error("sortDirection is not supported for List operations without a Sort key defined.", "InvalidArgumentsError")`),
    );

    expressions.push(sortDirectionValidation);
  } else if (isListResolver === true && keys.length >= 1) {
    // We only need this check for List queries, and not for @key queries
    const sortDirectionValidation = iff(
      and([raw(`$util.isNull($ctx.args.${keys[0]})`), raw(`!$util.isNull($ctx.args.sortDirection)`)]),
      raw(`$util.error("When providing argument 'sortDirection' you must also provide argument '${keys[0]}'.", "InvalidArgumentsError")`),
    );

    expressions.push(sortDirectionValidation);
  }

  expressions.push(
    set(ref(ResourceConstants.SNIPPETS.ModelQueryExpression), obj({})),
    applyKeyExpressionForCompositeKey(keys, keyTypes, ResourceConstants.SNIPPETS.ModelQueryExpression),
  );

  return block(`Set query expression for @key`, expressions);
}

function addHashField(
  definition: ObjectTypeDefinitionNode,
  args: KeyArguments,
  elems: InputValueDefinitionNode[],
): InputValueDefinitionNode[] {
  let hashFieldName = args.fields[0];
  const hashField = definition.fields.find(field => field.name.value === hashFieldName);
  const hashKey = makeInputValueDefinition(hashFieldName, makeNamedType(getBaseType(hashField.type)));
  return [hashKey, ...elems];
}
function addSimpleSortKey(
  ctx: TransformerContext,
  definition: ObjectTypeDefinitionNode,
  args: KeyArguments,
  elems: InputValueDefinitionNode[],
): InputValueDefinitionNode[] {
  let sortKeyName = args.fields[1];
  const sortField = definition.fields.find(field => field.name.value === sortKeyName);
  const baseType = getBaseType(sortField.type);
  const resolvedTypeIfEnum = (ctx.getType(baseType) as EnumTypeDefinitionNode) ? 'String' : undefined;
  const resolvedType = resolvedTypeIfEnum ? resolvedTypeIfEnum : baseType;
  const hashKey = makeInputValueDefinition(sortKeyName, makeNamedType(ModelResourceIDs.ModelKeyConditionInputTypeName(resolvedType)));
  return [hashKey, ...elems];
}
function addCompositeSortKey(
  definition: ObjectTypeDefinitionNode,
  args: KeyArguments,
  elems: InputValueDefinitionNode[],
): InputValueDefinitionNode[] {
  let sortKeyNames = args.fields.slice(1);
  const compositeSortKeyName = toCamelCase(sortKeyNames);
  const hashKey = makeInputValueDefinition(
    compositeSortKeyName,
    makeNamedType(ModelResourceIDs.ModelCompositeKeyConditionInputTypeName(definition.name.value, toUpper(args.name || 'Primary'))),
  );
  return [hashKey, ...elems];
}
function joinSnippets(lines: string[]): string {
  return lines.join('\n');
}

// QueryMap doesnt Support Composite Keys
function setSyncQueryMapSnippet(directive: DirectiveNode, isTable: boolean) {
  const args: KeyArguments = getDirectiveArguments(directive);
  const keys = args.fields;
  const expressions: Expression[] = [];
  const index: String = isTable ? 'dbTable' : args.name;
  let key: String = '';
  if (keys.length === 1) {
    key = `${keys[0]}+null`;
  } else if (keys.length > 1) {
    key = keys.join('+');
  }
  expressions.push(raw(`$util.qr($QueryMap.put('${key}' , '${index}'))`), raw(`$util.qr($PkMap.put('${keys[0]}' , '${index}'))`));
  return block(`Set query expression for @key`, expressions);
}

function setSyncQueryFilterSnippet() {
  const expressions: Expression[] = [];
  expressions.push(
    compoundExpression([
      set(ref('filterArgsMap'), ref('ctx.args.filter.get("and")')),
      ifElse(
        raw(`!$util.isNullOrEmpty($filterArgsMap) && ($util.isNull($ctx.args.lastSync) || $ctx.args.lastSync == 0)`),
        compoundExpression([
          set(ref('json'), raw(`$filterArgsMap`)),
          forEach(ref('item'), ref(`json`), [
            set(ref('ind'), ref('foreach.index')),
            forEach(ref('entry'), ref('item.entrySet()'), [
              iff(
                raw(`$ind == 0 && !$util.isNullOrEmpty($entry.value.eq) && !$util.isNullOrEmpty($PkMap.get($entry.key))`),
                compoundExpression([
                  set(ref('pk'), ref('entry.key')),
                  set(ref('scan'), bool(false)),
                  raw('$util.qr($ctx.args.put($pk,$entry.value.eq))'),
                  set(ref('index'), ref('PkMap.get($pk)')),
                ]),
              ),
              ifElse(
                raw('$ind == 1 && !$util.isNullOrEmpty($pk) && !$util.isNullOrEmpty($QueryMap.get("${pk}+$entry.key"))'),
                compoundExpression([
                  set(ref('sk'), ref('entry.key')),
                  raw('$util.qr($ctx.args.put($sk,$entry.value))'),
                  set(ref('index'), ref('QueryMap.get("${pk}+$sk")')),
                ]),
                iff(raw('$ind > 0'), qref('$filterMap.put($entry.key,$entry.value)')),
              ),
            ]),
          ]),
        ]),
        set(ref(`filterMap`), raw(`$ctx.args.filter`)),
      ),
    ]),
  );
  return block(`Set query expression for @key`, expressions);
}

function generateSyncResolverInit() {
  const expressions: Expression[] = [];
  expressions.push(
    set(ref('index'), str('')),
    set(ref('scan'), bool(true)),
    set(ref('filterMap'), obj({})),
    set(ref('QueryMap'), obj({})),
    set(ref('PkMap'), obj({})),
    set(ref('filterArgsMap'), obj({})),
  );
  return block(`Set map initialization for @key`, expressions);
}

function setSyncKeyExpressionForHashKey(queryExprReference: string) {
  const expressions: Expression[] = [];
  expressions.push(
    set(ref(ResourceConstants.SNIPPETS.ModelQueryExpression), obj({})),
    iff(
      raw(`!$util.isNull($pk)`),
      compoundExpression([
        set(ref(`${queryExprReference}.expression`), str(`#pk = :pk`)),
        set(ref(`${queryExprReference}.expressionNames`), obj({ [`#pk`]: str('$pk') })),
        set(
          ref(`${queryExprReference}.expressionValues`),
          obj({ [`:pk`]: ref('util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.get($pk)))') }),
        ),
      ]),
    ),
  );
  return block(`Set Primary Key initialization @key`, expressions);
}

function setSyncKeyExpressionForRangeKey(queryExprReference: string) {
  return block('Applying Key Condition', [
    iff(
      raw(`!$util.isNull($ctx.args.get($sk)) && !$util.isNull($ctx.args.get($sk).beginsWith)`),
      compoundExpression([
        set(ref(`${queryExprReference}.expression`), raw(`"$${queryExprReference}.expression AND begins_with(#sortKey, :sortKey)"`)),
        qref(`$${queryExprReference}.expressionNames.put("#sortKey", $sk)`),
        qref(
          `$${queryExprReference}.expressionValues.put(":sortKey", $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.get($sk).beginsWith)))`,
        ),
      ]),
    ),
    iff(
      raw(`!$util.isNull($ctx.args.get($sk)) && !$util.isNull($ctx.args.get($sk).between)`),
      compoundExpression([
        set(
          ref(`${queryExprReference}.expression`),
          raw(`"$${queryExprReference}.expression AND #sortKey BETWEEN :sortKey0 AND :sortKey1"`),
        ),
        qref(`$${queryExprReference}.expressionNames.put("#sortKey", $sk)`),
        qref(
          `$${queryExprReference}.expressionValues.put(":sortKey", $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.get($sk).between[0])))`,
        ),
        qref(
          `$${queryExprReference}.expressionValues.put(":sortKey", $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.get($sk).between[1])))`,
        ),
      ]),
    ),
    iff(
      raw(`!$util.isNull($ctx.args.get($sk)) && !$util.isNull($ctx.args.get($sk).eq)`),
      compoundExpression([
        set(ref(`${queryExprReference}.expression`), raw(`"$${queryExprReference}.expression AND #sortKey = :sortKey"`)),
        qref(`$${queryExprReference}.expressionNames.put("#sortKey", $sk)`),
        qref(
          `$${queryExprReference}.expressionValues.put(":sortKey", $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.get($sk).eq)))`,
        ),
      ]),
    ),
    iff(
      raw(`!$util.isNull($ctx.args.get($sk)) && !$util.isNull($ctx.args.get($sk).lt)`),
      compoundExpression([
        set(ref(`${queryExprReference}.expression`), raw(`"$${queryExprReference}.expression AND #sortKey < :sortKey"`)),
        qref(`$${queryExprReference}.expressionNames.put("#sortKey", $sk)`),
        qref(
          `$${queryExprReference}.expressionValues.put(":sortKey", $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.get($sk).lt)))`,
        ),
      ]),
    ),
    iff(
      raw(`!$util.isNull($ctx.args.get($sk)) && !$util.isNull($ctx.args.get($sk).le)`),
      compoundExpression([
        set(ref(`${queryExprReference}.expression`), raw(`"$${queryExprReference}.expression AND #sortKey <= :sortKey"`)),
        qref(`$${queryExprReference}.expressionNames.put("#sortKey", $sk)`),
        qref(
          `$${queryExprReference}.expressionValues.put(":sortKey", $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.get($sk).le)))`,
        ),
      ]),
    ),
    iff(
      raw(`!$util.isNull($ctx.args.get($sk)) && !$util.isNull($ctx.args.get($sk).gt)`),
      compoundExpression([
        set(ref(`${queryExprReference}.expression`), raw(`"$${queryExprReference}.expression AND #sortKey > :sortKey"`)),
        qref(`$${queryExprReference}.expressionNames.put("#sortKey", $sk)`),
        qref(
          `$${queryExprReference}.expressionValues.put(":sortKey", $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.get($sk).gt)))`,
        ),
      ]),
    ),
    iff(
      raw(`!$util.isNull($ctx.args.get($sk)) && !$util.isNull($ctx.args.get($sk).ge)`),
      compoundExpression([
        set(ref(`${queryExprReference}.expression`), raw(`"$${queryExprReference}.expression AND #sortKey >= :sortKey"`)),
        qref(`$${queryExprReference}.expressionNames.put("#sortKey", $sk)`),
        qref(
          `$${queryExprReference}.expressionValues.put(":sortKey", $util.parseJson($util.dynamodb.toDynamoDBJson($ctx.args.get($sk).ge)))`,
        ),
      ]),
    ),
  ]);
}

function makeSyncQueryResolver() {
  const requestVariable = 'QueryRequest';
  const expressions: Expression[] = [];
  expressions.push(
    ifElse(
      raw('!$scan'),
      compoundExpression([
        set(ref('limit'), ref(`util.defaultIfNull($context.args.limit, ${ResourceConstants.DEFAULT_PAGE_LIMIT})`)),
        set(
          ref(requestVariable),
          obj({
            version: str(RESOLVER_VERSION_ID),
            operation: str('Sync'),
            limit: ref('limit'),
            query: ref(ResourceConstants.SNIPPETS.ModelQueryExpression),
          }),
        ),
        ifElse(
          raw(`!$util.isNull($ctx.args.sortDirection)
                    && $ctx.args.sortDirection == "DESC"`),
          set(ref(`${requestVariable}.scanIndexForward`), bool(false)),
          set(ref(`${requestVariable}.scanIndexForward`), bool(true)),
        ),
        iff(ref('context.args.nextToken'), set(ref(`${requestVariable}.nextToken`), ref('context.args.nextToken')), true),
        iff(
          raw('!$util.isNullOrEmpty($filterMap)'),
          set(ref(`${requestVariable}.filter`), ref('util.parseJson($util.transform.toDynamoDBFilterExpression($filterMap))')),
        ),
        iff(raw(`$index != "dbTable"`), set(ref(`${requestVariable}.index`), ref('index'))),
        raw(`$util.toJson($${requestVariable})`),
      ]),
      DynamoDBMappingTemplate.syncItem({
        filter: ifElse(
          raw('!$util.isNullOrEmpty($ctx.args.filter)'),
          ref('util.transform.toDynamoDBFilterExpression($ctx.args.filter)'),
          nul(),
        ),
        limit: ref(`util.defaultIfNull($ctx.args.limit, ${ResourceConstants.DEFAULT_SYNC_QUERY_PAGE_LIMIT})`),
        lastSync: ref('util.toJson($util.defaultIfNull($ctx.args.lastSync, null))'),
        nextToken: ref('util.toJson($util.defaultIfNull($ctx.args.nextToken, null))'),
      }),
    ),
  );
  return block(` Set query expression for @key`, expressions);
}

function constructSyncResolver(directive: DirectiveNode, ctx: TransformerContext, syncResolver: any, isTable: boolean) {
  if (ctx.metadata.has(ResourceConstants.SNIPPETS.SyncResolverKey)) {
    const resolverMap = ctx.metadata.get(ResourceConstants.SNIPPETS.SyncResolverKey);
    if (resolverMap.has(syncResolver)) {