graphql#IntrospectionInputObjectType TypeScript Examples

The following examples show how to use graphql#IntrospectionInputObjectType. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: buildData.ts    From ra-data-prisma with MIT License 6 votes vote down vote up
getCreateInputDataTypeForList = (
  createModifier: IntrospectionInputValue,
  introspectionResults: IntrospectionResult,
) => {
  const createListModifierType =
    createModifier.type as IntrospectionListTypeRef<
      IntrospectionNonNullTypeRef<any>
    >;
  const createInputFieldType =
    createListModifierType.ofType.kind === "NON_NULL"
      ? createListModifierType.ofType.ofType
      : createListModifierType.ofType;
  return introspectionResults.types.find(
    // what about a nullable type?
    (t) => t.name === createInputFieldType.name,
  ) as IntrospectionInputObjectType;
}
Example #2
Source File: buildData.ts    From ra-data-prisma with MIT License 6 votes vote down vote up
getUpdateInputDataTypeForList = (
  updateModifier: IntrospectionInputValue,
  introspectionResults: IntrospectionResult,
) => {
  const updateListModifierType =
    updateModifier.type as IntrospectionListTypeRef<
      IntrospectionNonNullTypeRef<any>
    >;
  const updateInputFieldType = getFinalType(updateListModifierType.ofType);
  const updateListInputDataType = (
    introspectionResults.types.find(
      (introdspectionType) =>
        introdspectionType.name === updateInputFieldType.name,
    ) as IntrospectionInputObjectType
  ).inputFields.find((input) => input.name === "data")
    .type as IntrospectionTypeRef;

  const updateListInputDataName = (
    (updateListInputDataType.kind === "NON_NULL"
      ? updateListInputDataType.ofType
      : updateListInputDataType) as IntrospectionNamedTypeRef
  ).name;

  return introspectionResults.types.find(
    (introdspectionType) => introdspectionType.name === updateListInputDataName,
  ) as IntrospectionInputObjectType;
}
Example #3
Source File: buildData.ts    From ra-data-prisma with MIT License 6 votes vote down vote up
buildData = (
  inputType: IntrospectionInputObjectType,
  params: UpdateParams | CreateParams,
  introspectionResults: IntrospectionResult,
) => {
  if (!inputType) {
    return {};
  }
  return inputType.inputFields.reduce((acc, field) => {
    const key = field.name;
    const fieldType =
      field.type.kind === "NON_NULL" ? field.type.ofType : field.type;
    const fieldData = params.data[key];
    //console.log(key, fieldData, fieldType);
    const previousFieldData =
      (params as UpdateParams)?.previousData?.[key] ?? null;
    // TODO in case the content of the array has changed but not the array itself?
    if (
      isEqual(fieldData, previousFieldData) ||
      (isNil(previousFieldData) && isNil(fieldData))
    ) {
      return acc;
    }

    const newVaue = buildNewInputValue(
      params.data[key],
      previousFieldData,
      field.name,
      fieldType,
      introspectionResults,
    );

    return {
      ...acc,
      [key]: newVaue,
    };
  }, {});
}
Example #4
Source File: buildOrderBy.ts    From ra-data-prisma with MIT License 6 votes vote down vote up
function getOrderType(
  introspectionResults: IntrospectionResult,
  resource: Resource,
): IntrospectionInputObjectType {
  const withoutRelation = `${resource.type.name}OrderByInput`;
  const withRelation = `${resource.type.name}OrderByWithRelationInput`;

  return introspectionResults.types.find(
    (t) => t.name === withRelation || t.name === withoutRelation,
  ) as IntrospectionInputObjectType;
}
Example #5
Source File: index.ts    From ra-data-prisma with MIT License 6 votes vote down vote up
buildUpdateVariables =
  (introspectionResults: IntrospectionResult, options: OurOptions) =>
  (resource: Resource, params: UpdateParams, parentResource?: Resource) => {
    const inputType = introspectionResults.types.find(
      (t) => t.name === `${resource.type.name}UpdateInput`,
    ) as IntrospectionInputObjectType;

    const id = getId(introspectionResults, resource, params); // TODO: do we still need params.data.id?
    delete params.data.id;
    delete params.previousData?.id;
    let data = buildData(inputType, params, introspectionResults);

    return {
      where: {
        id,
      },
      data:
        options?.customizeInputData?.[resource.type.name]?.update?.(
          data,
          params.data,
        ) ?? data,
    };
  }
Example #6
Source File: index.ts    From ra-data-prisma with MIT License 6 votes vote down vote up
buildCreateVariables =
  (introspectionResults: IntrospectionResult, options: OurOptions) =>
  (resource: Resource, params: CreateParams, parentResource?: Resource) => {
    const inputType = introspectionResults.types.find(
      (t) => t.name === `${resource.type.name}CreateInput`,
    ) as IntrospectionInputObjectType;

    const data = buildData(inputType, params, introspectionResults);
    return {
      data:
        options?.customizeInputData?.[resource.type.name]?.create?.(
          data,
          params.data,
        ) ?? data,
    };
  }
Example #7
Source File: buildWhere.ts    From ra-data-prisma with MIT License 6 votes vote down vote up
supportsCaseInsensitive = (
  introspectionResults: IntrospectionResult,
): boolean => {
  // Prisma 2.8.0 added QueryMode enum (present in StringFilter and StringNullableFilter input objects as property `mode`)
  const queryModeExists = introspectionResults.types.find(
    (type) => type.kind === "ENUM" && type.name === "QueryMode",
  );
  const stringFilterType = introspectionResults.types.find(
    (type) => type.kind === "INPUT_OBJECT" && type.name === "StringFilter",
  ) as IntrospectionInputObjectType;
  const usesQueryMode = stringFilterType?.inputFields.find(
    (field) =>
      field.name === "mode" &&
      field.type.kind === "ENUM" &&
      field.type.name === "QueryMode",
  );
  return !!queryModeExists && !!usesQueryMode;
}
Example #8
Source File: buildWhere.ts    From ra-data-prisma with MIT License 6 votes vote down vote up
processComparisonQuery = (
  field: string,
  value: any,
  comparison: string,
  whereType: IntrospectionInputObjectType,
  introspectionResults: IntrospectionResult,
): CheckComparisonQueryResult => {
  if (!comparison) {
    return { comparisonPossible: false };
  }

  const comparisonFieldType = whereType.inputFields.find(
    (f) => f.name === field,
  )?.type as IntrospectionInputObjectType;

  if (comparisonFieldType) {
    // separated field exists on the whereType
    const filterName = comparisonFieldType.name;
    const filter = introspectionResults.types.find(
      (f) => f.name === filterName,
    ) as IntrospectionInputObjectType;
    const comparatorField = filter.inputFields.find(
      (f) => f.name === comparison,
    );
    if (comparatorField) {
      // and has the comparison field
      if (!isObject(value) && !isArray(value)) {
        // all comparison fields (equals, lt, lte, gt, gte, contains, startsWith, endsWith) use a Scalar value so it can't be object or array
        return { comparisonPossible: true, comparisonFieldType: filter };
      }
    }
  }
  return { comparisonPossible: false };
}
Example #9
Source File: buildWhere.ts    From ra-data-prisma with MIT License 6 votes vote down vote up
buildWhere = (
  filter: Filter,
  resource: Resource,
  introspectionResults: IntrospectionResult,
  options: OurOptions,
) => {
  const whereType = introspectionResults.types.find(
    (t) => t.name === `${resource.type.name}WhereInput`,
  ) as IntrospectionInputObjectType;

  return buildWhereWithType(filter, introspectionResults, options, whereType);
}
Example #10
Source File: buildWhere.ts    From ra-data-prisma with MIT License 5 votes vote down vote up
buildWhereWithType = (
  filter: Filter,
  introspectionResults: IntrospectionResult,
  options: OurOptions,
  whereType: IntrospectionInputObjectType,
) => {
  const hasAnd = whereType.inputFields.some((i) => i.name === "AND");
  const where = hasAnd
    ? Object.keys(filter ?? {}).reduce(
        (acc, key) => {
          // defaults to AND
          const filters = getFilters(
            key,
            filter[key],
            whereType,

            introspectionResults,
            options,
          );

          return { ...acc, AND: [...acc.AND, filters] };
        },
        { AND: [] },
      )
    : Object.keys(filter ?? {}).reduce((acc, key) => {
        const filters = getFilters(
          key,
          filter[key],
          whereType,

          introspectionResults,
          options,
        );

        return { ...acc, ...filters };
      }, {});
  // simplify AND if there is only one
  if (where.AND?.length === 0) {
    delete where.AND;
  }
  if (where.AND?.length === 1) {
    const singleAnd = where.AND[0];
    delete where.AND;
    return {
      ...where,
      ...singleAnd,
    };
  }
  return where;
}
Example #11
Source File: buildData.ts    From ra-data-prisma with MIT License 4 votes vote down vote up
buildNewInputValue = (
  fieldData: any,
  previousFieldData: any,
  fieldName: string,
  fieldType: IntrospectionInputTypeRef,
  introspectionResults: IntrospectionResult,
) => {
  const kind = fieldType.kind;

  switch (kind) {
    case "SCALAR":
    case "ENUM": {
      // if its a date, convert it to a date
      if (fieldType.kind === "SCALAR" && fieldType.name === "DateTime") {
        return new Date(fieldData);
      }
      if (fieldType.kind === "SCALAR" && fieldType.name === "String") {
        if (isObject(fieldData)) {
          return JSON.stringify(fieldData);
        }
      }
      return fieldData;
    }
    case "INPUT_OBJECT": {
      const fieldObjectType = fieldType as IntrospectionInputObjectType;

      const fullFieldObjectType = introspectionResults.types.find(
        (t) => t.name === fieldObjectType.name,
      ) as IntrospectionInputObjectType;

      const setModifier = fullFieldObjectType?.inputFields.find(
        (i) => i.name === ModifiersParams.set,
      );

      const connectModifier = fullFieldObjectType?.inputFields.find(
        (i) => i.name === ModifiersParams.connect,
      );

      const disconnectModifier = fullFieldObjectType?.inputFields.find(
        (i) => i.name === ModifiersParams.disconnect,
      );

      const deleteModifier = fullFieldObjectType?.inputFields.find(
        (i) => i.name === ModifiersParams.delete,
      );

      if (setModifier && !connectModifier && !disconnectModifier && !deleteModifier) {
        // if its a date, convert it to a date
        if (
          setModifier.type.kind === "SCALAR" &&
          setModifier.type.name === "DateTime"
        ) {
          return { set: new Date(fieldData) };
        }
        return { set: fieldData };
      }

      const isRelationship = fullFieldObjectType?.inputFields.every((i) => {
        return Object.keys(ModifiersParams).includes(i.name);
      });

      // is it a relation?
      if (isRelationship) {
        // if it has a set modifier, it is an update array
        const createModifier = fullFieldObjectType?.inputFields.find(
          (i) => i.name === ModifiersParams.create,
        );

        const updateModifier = fullFieldObjectType?.inputFields.find(
          (i) => i.name === ModifiersParams.update,
        );

        const isList = fullFieldObjectType?.inputFields.some((i) => {
          return i.type.kind === "LIST";
        });

        if (isList) {
          if (Array.isArray(fieldData)) {
            const createListInputType = getCreateInputDataTypeForList(
              createModifier,
              introspectionResults,
            );

            const updateListInputType = updateModifier
              ? getUpdateInputDataTypeForList(
                  updateModifier,
                  introspectionResults,
                )
              : null;

            const variables = fieldData.reduce<UpdateManyInput>(
              (inputs, referencedField) => {
                if (isObject(referencedField)) {
                  // TODO: we assume "data.id" to be the id
                  if (isObjectWithId(referencedField)) {
                    const connectRelation = !previousFieldData?.find((p) =>
                      p.id
                        ? p.id === referencedField.id
                        : p === referencedField.id,
                    );
                    if (!updateListInputType || connectRelation) {
                      inputs.connect = [
                        ...(inputs.connect || []),
                        { id: referencedField.id },
                      ];
                    } else {
                      // update
                      const data = buildData(
                        updateListInputType,
                        {
                          id: referencedField.id,
                          data: referencedField,
                          previousData: previousFieldData?.find(
                            (previousField) => {
                              // TODO: we assume ".id" to be the id
                              return previousField.id === referencedField.id;
                            },
                          ),
                        },
                        introspectionResults,
                      );
                      if (Object.keys(data).length) {
                        inputs.update = [
                          ...(inputs.update || []),
                          { where: { id: referencedField.id }, data },
                        ];
                      }
                    }
                  } else {
                    // create
                    const data = buildData(
                      createListInputType,
                      {
                        data: referencedField,
                      },
                      introspectionResults,
                    );
                    inputs.create = [...(inputs.create || []), data];
                  }
                } else {
                  // only reference id's
                  // what about multiple id's for one reference?
                  if (
                    !previousFieldData?.find((p) => {
                      // TODO: we assume "p.id" to be the id
                      return p.id
                        ? p.id === referencedField
                        : p === referencedField;
                    })
                  ) {
                    inputs.connect = [
                      ...(inputs.connect || []),
                      { id: referencedField },
                    ];
                  }
                }
                return inputs;
              },
              {},
            );

            // disconnect the ones that are not referenced anymore
            if (Array.isArray(previousFieldData)) {
              const removableRelations = (previousFieldData as any[]).reduce<
                Array<{ id: any }>
              >((inputs, data) => {
                // TODO: we assume "data.id" to be the id
                const dataId = data.id || data;
                if (
                  !fieldData.find((p) => {
                    // TODO: we assume "p.id" to be the id
                    const pId = p.id || p;
                    return pId === dataId;
                  })
                ) {
                  return [...(inputs || []), { id: dataId }];
                }
                return inputs;
              }, []);
              if (removableRelations.length) {
                if (disconnectModifier) {
                  variables.disconnect = removableRelations;
                } else if (deleteModifier) {
                  variables.delete = removableRelations;
                }
              }
            }
            return variables;
          } else {
            throw new Error(`${fieldName} should be an array`);
          }
        } else {
          if (!fieldData) {
            if (disconnectModifier) {
              return {
                disconnect: true,
              };
            } else if (deleteModifier) {
              return {
                delete: true,
              };
            }
          }

          if (isObject(fieldData)) {
            if (!isObjectWithId(fieldData)) {
              if (!createModifier) {
                return;
              }
              // TODO: we assume ".id" to be the id
              const createObjectModifierType = getFinalType(
                createModifier.type,
              );
              const createObjectInputType = introspectionResults.types.find(
                (t) => t.name === createObjectModifierType.name,
              ) as IntrospectionInputObjectType;

              // create
              const data = buildData(
                createObjectInputType,
                {
                  data: fieldData,
                },
                introspectionResults,
              );
              return { create: data };
            } else {
              if (previousFieldData?.id === fieldData.id) {
                if (!updateModifier) {
                  return;
                }
                const updateObjectModifierType = getFinalType(
                  updateModifier.type,
                );
                const updateObjectInputType = introspectionResults.types.find(
                  (t) => t.name === updateObjectModifierType.name,
                ) as IntrospectionInputObjectType;

                // update
                const data = buildData(
                  updateObjectInputType,
                  {
                    id: fieldData.id,
                    data: fieldData,
                    previousData: previousFieldData,
                  },
                  introspectionResults,
                );
                return { update: data };
              } else if (connectModifier) {
                return { connect: { id: fieldData.id } };
              }
            }
          } else if (connectModifier) {
            return { connect: { id: fieldData } };
          }
        }
      } else {
        return fieldData;
      }

      return;
    }
    case "LIST":
    case "NON_NULL":
      return;
    default:
      exhaust(kind);
  }
}
Example #12
Source File: buildWhere.ts    From ra-data-prisma with MIT License 4 votes vote down vote up
getFilters = (
  _key: string,
  value: any,
  whereType: IntrospectionInputObjectType,
  introspectionResults: IntrospectionResult,
  options: OurOptions,
) => {
  const hasCaseInsensitive = supportsCaseInsensitive(introspectionResults);
  const { originalKey, key, comparator } = processKey(_key);
  if (options.filters?.[originalKey]) {
    return options.filters[originalKey](value) ?? {}; // null values are transformed to empty objects
  }
  if (key === "NOT" || key === "OR" || key === "AND") {
    return {
      [key]:
        value === null
          ? null
          : value.map((f) =>
              buildWhereWithType(f, introspectionResults, options, whereType),
            ),
    };
  }

  // check introspection, if we can use comparison on the field before suffixes (and if possible, return the type of that field)
  const { comparisonPossible, comparisonFieldType } = processComparisonQuery(
    key,
    value,
    comparator,
    whereType,
    introspectionResults,
  );
  if (comparisonPossible) {
    if (isBooleanFilter(comparisonFieldType)) {
      // the only way we could get here is with "boolField_equals" (which is the same as "boolField")
      // but skipping here would lead to trying to find field "boolField_equals" which might not exist
      return getBooleanFilter(key, value);
    }

    if (isStringFilter(comparisonFieldType)) {
      return getStringFilter(key, value, hasCaseInsensitive, comparator);
    }
    // Nested variants don't have `mode` property
    // pass `hasCaseInsensitive=false` to bypass the check and use the original implementation
    if (isNestedStringFilter(comparisonFieldType)) {
      return getStringFilter(key, value, false, comparator);
    }

    if (isDateTimeFilter(comparisonFieldType)) {
      return getDateTimeFilter(key, value, comparator);
    }

    if (isIntFilter(comparisonFieldType)) {
      return getIntFilter(key, value, comparator);
    }

    if (isFloatFilter(comparisonFieldType)) {
      return getFloatFilter(key, value, comparator);
    }

    if (isEnumFilter(comparisonFieldType)) {
      return getEnumFilter(key, value, comparator);
    }
  }

  // we can't use comparison on the splitted field, try to use the original key in a default way (without comparator)

  const fieldType = whereType.inputFields.find((f) => f.name === originalKey)
    ?.type as IntrospectionInputObjectType;

  if (!fieldType) {
    if (originalKey === "q") {
      // special: q is universal text search
      // we search all text fields
      // additionaly we split by  space to make a AND connection
      const AND = value.split(" ").map((part: string) => ({
        OR: whereType.inputFields
          .map((f) => {
            if (f.name !== "id") {
              if (isStringFilter(f.type)) {
                return getStringFilter(f.name, part.trim(), hasCaseInsensitive);
              }
              if (isNestedStringFilter(f.type)) {
                return getStringFilter(f.name, part.trim(), false);
              }
              if (isIntFilter(f.type)) {
                const numberValue = parseInt(part.trim());
                const valueIsInt32 =
                  -(2 ** 31) <= numberValue && numberValue <= 2 ** 31 - 1;
                return valueIsInt32 ? getIntFilter(f.name, part.trim()) : null;
              }
            }
            return null;
          })
          .filter((f) => !isEmpty(f)),
      }));

      return { AND };
    } else {
      return {};
    }
  }

  if (!isObject(value) && !isArray(value)) {
    if (isBooleanFilter(fieldType)) {
      return getBooleanFilter(originalKey, value);
    }

    if (isStringFilter(fieldType)) {
      return getStringFilter(originalKey, value, hasCaseInsensitive);
    }

    if (isNestedStringFilter(fieldType)) {
      return getStringFilter(originalKey, value, false);
    }

    if (isDateTimeFilter(fieldType)) {
      return getDateTimeFilter(originalKey, value);
    }

    if (isIntFilter(fieldType)) {
      return getIntFilter(originalKey, value);
    }

    if (isFloatFilter(fieldType)) {
      return getFloatFilter(originalKey, value);
    }

    if (isEnumFilter(fieldType)) {
      return getEnumFilter(originalKey, value);
    }
  }

  if (isArray(value)) {
    if (isStringFilter(fieldType)) {
      return {
        OR: value.map((v) =>
          getStringFilter(originalKey, v, hasCaseInsensitive),
        ),
      };
    }

    if (isNestedStringFilter(fieldType)) {
      return {
        OR: value.map((v) => getStringFilter(originalKey, v, false)),
      };
    }

    if (isIntFilter(fieldType)) {
      return { OR: value.map((v) => getIntFilter(originalKey, v)) };
    }

    if (isDateTimeFilter(fieldType)) {
      return { OR: value.map((v) => getDateTimeFilter(originalKey, v)) };
    }

    if (isFloatFilter(fieldType)) {
      return { OR: value.map((v) => getFloatFilter(originalKey, v)) };
    }

    if (isEnumFilter(fieldType)) {
      return { OR: value.map((v) => getEnumFilter(originalKey, v)) };
    }
  }

  if (fieldType.kind === "INPUT_OBJECT") {
    // we asume for the moment that this is always a relation
    const inputObjectType = introspectionResults.types.find(
      (t) => t.name === fieldType.name,
    ) as IntrospectionInputObjectType;

    if (!isObject(value)) {
      //console.log({ inputObjectType });
      const hasSomeFilter = inputObjectType.inputFields.some(
        (s) => s.name === "some",
      );

      if (hasSomeFilter) {
        return {
          [originalKey]: {
            some: {
              id: {
                equals: value,
              },
            },
          },
        };
      }
      return {
        [originalKey]: {
          id: {
            equals: value,
          },
        },
      };
    }
    if (isArray(value)) {
      const hasSomeFilter = inputObjectType.inputFields.some(
        (s) => s.name === "some",
      );
      if (hasSomeFilter) {
        return {
          [originalKey]: {
            some: {
              id: {
                in: value,
              },
            },
          },
        };
      }
      return {
        [originalKey]: {
          id: {
            in: value,
          },
        },
      };
    } else {
      // its something nested

      const where = buildWhereWithType(
        value,
        introspectionResults,
        options,
        inputObjectType,
      );
      return { [originalKey]: where };
    }
  }
  return { [originalKey]: value };
}