graphile-build-pg
Advanced tools
Comparing version 4.0.0-rc.9 to 4.0.0-rc.10
@@ -55,3 +55,5 @@ "use strict"; | ||
pgAddStartEndCursor: addStartEndCursor, | ||
pgViaTemporaryTable: viaTemporaryTable | ||
pgViaTemporaryTable: viaTemporaryTable, | ||
describePgEntity, | ||
sqlCommentByAddingTags | ||
}, { | ||
@@ -307,2 +309,5 @@ fieldWithHooks, | ||
}, Object.assign({}, { | ||
__origin: `Adding mutation function payload type for ${describePgEntity(proc)}. You can rename the function's GraphQL field (and its dependent types) via:\n\n ${sqlCommentByAddingTags(proc, { | ||
name: "newNameHere" | ||
})}`, | ||
isMutationPayload: true | ||
@@ -320,2 +325,5 @@ }, payloadTypeScope)); | ||
}, { | ||
__origin: `Adding mutation function input type for ${describePgEntity(proc)}. You can rename the function's GraphQL field (and its dependent types) via:\n\n ${sqlCommentByAddingTags(proc, { | ||
name: "newNameHere" | ||
})}`, | ||
isMutationInput: true | ||
@@ -322,0 +330,0 @@ }); |
@@ -40,3 +40,5 @@ "use strict"; | ||
pgAddStartEndCursor: addStartEndCursor, | ||
pgOmit: omit | ||
pgOmit: omit, | ||
sqlCommentByAddingTags, | ||
describePgEntity | ||
} = build; | ||
@@ -96,3 +98,3 @@ const { | ||
const singleRelationFieldName = isUnique ? inflection.singleRelationByKeys(keys, table, foreignTable, constraint) : null; | ||
const singleRelationFieldName = isUnique ? inflection.singleRelationByKeysBackwards(keys, table, foreignTable, constraint) : null; | ||
@@ -106,49 +108,8 @@ const primaryKeyConstraint = introspectionResultsByKind.constraint.filter(con => con.classId === table.id).filter(con => con.type === "p")[0]; | ||
if (shouldAddSingleRelation && !omit(table, "read")) { | ||
memo[singleRelationFieldName] = fieldWithHooks(singleRelationFieldName, ({ getDataFromParsedResolveInfoFragment, addDataGenerator }) => { | ||
addDataGenerator(parsedResolveInfoFragment => { | ||
return { | ||
pgQuery: queryBuilder => { | ||
queryBuilder.select(() => { | ||
const resolveData = getDataFromParsedResolveInfoFragment(parsedResolveInfoFragment, gqlTableType); | ||
const tableAlias = sql.identifier(Symbol()); | ||
const foreignTableAlias = queryBuilder.getTableAlias(); | ||
const query = queryFromResolveData(sql.identifier(schema.name, table.name), tableAlias, resolveData, { | ||
asJson: true, | ||
addNullCase: true, | ||
withPagination: false | ||
}, innerQueryBuilder => { | ||
innerQueryBuilder.parentQueryBuilder = queryBuilder; | ||
keys.forEach((key, i) => { | ||
innerQueryBuilder.where(sql.fragment`${tableAlias}.${sql.identifier(key.name)} = ${foreignTableAlias}.${sql.identifier(foreignKeys[i].name)}`); | ||
}); | ||
}); | ||
return sql.fragment`(${query})`; | ||
}, getSafeAliasFromAlias(parsedResolveInfoFragment.alias)); | ||
} | ||
}; | ||
}); | ||
return { | ||
description: constraint.tags.backwardDescription || `Reads a single \`${tableTypeName}\` that is related to this \`${foreignTableTypeName}\`.`, | ||
type: gqlTableType, | ||
args: {}, | ||
resolve: (data, _args, _context, resolveInfo) => { | ||
const safeAlias = getSafeAliasFromResolveInfo(resolveInfo); | ||
return data[safeAlias]; | ||
} | ||
}; | ||
}, { | ||
pgFieldIntrospection: table, | ||
isPgBackwardSingleRelationField: true | ||
}); | ||
} | ||
function makeFields(isConnection) { | ||
if (isUnique && !isConnection) { | ||
// Don't need this, use the singular instead | ||
return; | ||
} | ||
if (shouldAddManyRelation && !omit(table, "many")) { | ||
const manyRelationFieldName = isConnection ? inflection.manyRelationByKeys(keys, table, foreignTable, constraint) : inflection.manyRelationByKeysSimple(keys, table, foreignTable, constraint); | ||
memo[manyRelationFieldName] = fieldWithHooks(manyRelationFieldName, ({ getDataFromParsedResolveInfoFragment, addDataGenerator }) => { | ||
if (shouldAddSingleRelation && !omit(table, "read") && singleRelationFieldName) { | ||
memo = extend(memo, { | ||
[singleRelationFieldName]: fieldWithHooks(singleRelationFieldName, ({ | ||
getDataFromParsedResolveInfoFragment, | ||
addDataGenerator | ||
}) => { | ||
addDataGenerator(parsedResolveInfoFragment => { | ||
@@ -158,24 +119,11 @@ return { | ||
queryBuilder.select(() => { | ||
const resolveData = getDataFromParsedResolveInfoFragment(parsedResolveInfoFragment, isConnection ? ConnectionType : TableType); | ||
const resolveData = getDataFromParsedResolveInfoFragment(parsedResolveInfoFragment, gqlTableType); | ||
const tableAlias = sql.identifier(Symbol()); | ||
const foreignTableAlias = queryBuilder.getTableAlias(); | ||
const query = queryFromResolveData(sql.identifier(schema.name, table.name), tableAlias, resolveData, { | ||
withPagination: isConnection, | ||
withPaginationAsFields: false, | ||
asJsonAggregate: !isConnection | ||
asJson: true, | ||
addNullCase: true, | ||
withPagination: false | ||
}, innerQueryBuilder => { | ||
innerQueryBuilder.parentQueryBuilder = queryBuilder; | ||
if (primaryKeys) { | ||
innerQueryBuilder.beforeLock("orderBy", () => { | ||
// append order by primary key to the list of orders | ||
if (!innerQueryBuilder.isOrderUnique(false)) { | ||
innerQueryBuilder.data.cursorPrefix = ["primary_key_asc"]; | ||
primaryKeys.forEach(key => { | ||
innerQueryBuilder.orderBy(sql.fragment`${innerQueryBuilder.getTableAlias()}.${sql.identifier(key.name)}`, true); | ||
}); | ||
innerQueryBuilder.setOrderIsUnique(); | ||
} | ||
}); | ||
} | ||
keys.forEach((key, i) => { | ||
@@ -190,26 +138,94 @@ innerQueryBuilder.where(sql.fragment`${tableAlias}.${sql.identifier(key.name)} = ${foreignTableAlias}.${sql.identifier(foreignKeys[i].name)}`); | ||
}); | ||
const ConnectionType = getTypeByName(inflection.connection(gqlTableType.name)); | ||
const TableType = pgGetGqlTypeByTypeIdAndModifier(table.type.id, null); | ||
return { | ||
description: constraint.tags.backwardDescription || `Reads and enables pagination through a set of \`${tableTypeName}\`.`, | ||
type: isConnection ? new GraphQLNonNull(ConnectionType) : new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(TableType))), | ||
description: constraint.tags.backwardDescription || `Reads a single \`${tableTypeName}\` that is related to this \`${foreignTableTypeName}\`.`, | ||
type: gqlTableType, | ||
args: {}, | ||
resolve: (data, _args, _context, resolveInfo) => { | ||
const safeAlias = getSafeAliasFromResolveInfo(resolveInfo); | ||
if (isConnection) { | ||
return addStartEndCursor(data[safeAlias]); | ||
} else { | ||
return data[safeAlias]; | ||
} | ||
}, | ||
deprecationReason: isDeprecated ? // $FlowFixMe | ||
`Please use ${singleRelationFieldName} instead` : undefined | ||
return data[safeAlias]; | ||
} | ||
}; | ||
}, { | ||
isPgFieldConnection: isConnection, | ||
isPgFieldSimpleCollection: !isConnection, | ||
isPgBackwardRelationField: true, | ||
pgFieldIntrospection: table | ||
}); | ||
pgFieldIntrospection: table, | ||
isPgBackwardSingleRelationField: true | ||
}) | ||
}, `Backward relation (single) for ${describePgEntity(constraint)}. To rename this relation with smart comments:\n\n ${sqlCommentByAddingTags(constraint, { | ||
foreignSingleFieldName: "newNameHere" | ||
})}`); | ||
} | ||
function makeFields(isConnection) { | ||
if (isUnique && !isConnection) { | ||
// Don't need this, use the singular instead | ||
return; | ||
} | ||
if (shouldAddManyRelation && !omit(table, "many")) { | ||
const manyRelationFieldName = isConnection ? inflection.manyRelationByKeys(keys, table, foreignTable, constraint) : inflection.manyRelationByKeysSimple(keys, table, foreignTable, constraint); | ||
memo = extend(memo, { | ||
[manyRelationFieldName]: fieldWithHooks(manyRelationFieldName, ({ | ||
getDataFromParsedResolveInfoFragment, | ||
addDataGenerator | ||
}) => { | ||
addDataGenerator(parsedResolveInfoFragment => { | ||
return { | ||
pgQuery: queryBuilder => { | ||
queryBuilder.select(() => { | ||
const resolveData = getDataFromParsedResolveInfoFragment(parsedResolveInfoFragment, isConnection ? ConnectionType : TableType); | ||
const tableAlias = sql.identifier(Symbol()); | ||
const foreignTableAlias = queryBuilder.getTableAlias(); | ||
const query = queryFromResolveData(sql.identifier(schema.name, table.name), tableAlias, resolveData, { | ||
withPagination: isConnection, | ||
withPaginationAsFields: false, | ||
asJsonAggregate: !isConnection | ||
}, innerQueryBuilder => { | ||
innerQueryBuilder.parentQueryBuilder = queryBuilder; | ||
if (primaryKeys) { | ||
innerQueryBuilder.beforeLock("orderBy", () => { | ||
// append order by primary key to the list of orders | ||
if (!innerQueryBuilder.isOrderUnique(false)) { | ||
innerQueryBuilder.data.cursorPrefix = ["primary_key_asc"]; | ||
primaryKeys.forEach(key => { | ||
innerQueryBuilder.orderBy(sql.fragment`${innerQueryBuilder.getTableAlias()}.${sql.identifier(key.name)}`, true); | ||
}); | ||
innerQueryBuilder.setOrderIsUnique(); | ||
} | ||
}); | ||
} | ||
keys.forEach((key, i) => { | ||
innerQueryBuilder.where(sql.fragment`${tableAlias}.${sql.identifier(key.name)} = ${foreignTableAlias}.${sql.identifier(foreignKeys[i].name)}`); | ||
}); | ||
}); | ||
return sql.fragment`(${query})`; | ||
}, getSafeAliasFromAlias(parsedResolveInfoFragment.alias)); | ||
} | ||
}; | ||
}); | ||
const ConnectionType = getTypeByName(inflection.connection(gqlTableType.name)); | ||
const TableType = pgGetGqlTypeByTypeIdAndModifier(table.type.id, null); | ||
return { | ||
description: constraint.tags.backwardDescription || `Reads and enables pagination through a set of \`${tableTypeName}\`.`, | ||
type: isConnection ? new GraphQLNonNull(ConnectionType) : new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(TableType))), | ||
args: {}, | ||
resolve: (data, _args, _context, resolveInfo) => { | ||
const safeAlias = getSafeAliasFromResolveInfo(resolveInfo); | ||
if (isConnection) { | ||
return addStartEndCursor(data[safeAlias]); | ||
} else { | ||
return data[safeAlias]; | ||
} | ||
}, | ||
deprecationReason: isDeprecated ? // $FlowFixMe | ||
`Please use ${singleRelationFieldName} instead` : undefined | ||
}; | ||
}, { | ||
isPgFieldConnection: isConnection, | ||
isPgFieldSimpleCollection: !isConnection, | ||
isPgBackwardRelationField: true, | ||
pgFieldIntrospection: table | ||
}) | ||
}, `Backward relation (${isConnection ? "connection" : "simple collection"}) for ${describePgEntity(constraint)}. To rename this relation with smart comments:\n\n ${sqlCommentByAddingTags(constraint, { | ||
[isConnection ? "foreignFieldName" : "foreignSimpleFieldName"]: "newNameHere" | ||
})}`); | ||
} | ||
} | ||
@@ -216,0 +232,0 @@ if (hasConnections) { |
@@ -38,2 +38,10 @@ "use strict"; | ||
var _chalk = require("chalk"); | ||
var _chalk2 = _interopRequireDefault(_chalk); | ||
var _pickBy = require("lodash/pickBy"); | ||
var _pickBy2 = _interopRequireDefault(_pickBy); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
@@ -44,2 +52,6 @@ | ||
const defaultPgColumnFilter = (_attr, _build, _context) => true; | ||
const identity = _ => _; | ||
function preventEmptyResult(obj) { | ||
@@ -104,2 +116,39 @@ return Object.keys(obj).reduce((memo, key) => { | ||
function describePgEntity(entity, includeAlias = true) { | ||
const getAlias = !includeAlias ? () => "" : () => { | ||
const tags = (0, _pickBy2.default)(entity.tags, (value, key) => key === "name" || key.endsWith("Name")); | ||
if (Object.keys(tags).length) { | ||
return ` (with smart comments: ${_chalk2.default.bold(Object.keys(tags).map(t => `@${t} ${tags[t]}`).join(" | "))})`; | ||
} | ||
return ""; | ||
}; | ||
try { | ||
if (entity.kind === "constraint") { | ||
return `constraint ${_chalk2.default.bold(`"${entity.name}"`)} on ${describePgEntity(entity.class, false)}${getAlias()}`; | ||
} else if (entity.kind === "class") { | ||
// see pg_class.relkind https://www.postgresql.org/docs/10/static/catalog-pg-class.html | ||
const kind = { | ||
c: "composite type", | ||
f: "foreign table", | ||
p: "partitioned table", | ||
r: "table", | ||
v: "view", | ||
m: "materialized view" | ||
}[entity.classKind] || "table-like"; | ||
return `${kind} ${_chalk2.default.bold(`"${entity.namespaceName}"."${entity.name}"`)}${getAlias()}`; | ||
} else if (entity.kind === "procedure") { | ||
return `function ${_chalk2.default.bold(`"${entity.namespaceName}"."${entity.name}"(...args...)`)}${getAlias()}`; | ||
} else if (entity.kind === "attribute") { | ||
return `column ${_chalk2.default.bold(`"${entity.name}"`)} on ${describePgEntity(entity.class, false)}${getAlias()}`; | ||
} | ||
} catch (e) { | ||
// eslint-disable-next-line no-console | ||
console.error("Error occurred while attempting to debug entity:", entity); | ||
// eslint-disable-next-line no-console | ||
console.error(e); | ||
} | ||
return `entity of kind '${entity.kind}' with oid '${entity.oid}'`; | ||
} | ||
exports.default = function PgBasicsPlugin(builder, { | ||
@@ -122,3 +171,57 @@ pgStrictFunctions = false, | ||
pgParseIdentifier: _parseIdentifier2.default, | ||
pgViaTemporaryTable: _viaTemporaryTable2.default | ||
pgViaTemporaryTable: _viaTemporaryTable2.default, | ||
describePgEntity, | ||
sqlCommentByAddingTags: (entity, tagsToAdd) => { | ||
// NOTE: this function is NOT intended to be SQL safe; it's for | ||
// displaying in error messages. Nonetheless if you find issues with | ||
// SQL compatibility, please send a PR or issue. | ||
// Ref: https://www.postgresql.org/docs/current/static/sql-syntax-lexical.html#SQL-BACKSLASH-TABLE | ||
const escape = str => str.replace(/['\\\b\f\n\r\t]/g, chr => ({ | ||
"\b": "\\b", | ||
"\f": "\\f", | ||
"\n": "\\n", | ||
"\r": "\\r", | ||
"\t": "\\t" | ||
})[chr] || "\\" + chr); | ||
// tagsToAdd is here twice to ensure that the keys in tagsToAdd come first, but that they also "win" any conflicts. | ||
const tags = Object.assign({}, tagsToAdd, entity.tags, tagsToAdd); | ||
const description = entity.description; | ||
const tagsSql = Object.keys(tags).reduce((memo, tag) => { | ||
const tagValue = tags[tag]; | ||
const valueArray = Array.isArray(tagValue) ? tagValue : [tagValue]; | ||
const highlightOrNot = tag in tagsToAdd ? _chalk2.default.bold : identity; | ||
valueArray.forEach(value => { | ||
memo.push(highlightOrNot(`@${escape(escape(tag))}${value === true ? "" : " " + escape(escape(value))}`)); | ||
}); | ||
return memo; | ||
}, []).join("\\n"); | ||
const commentValue = `E'${tagsSql}${description ? "\\n" + escape(description) : ""}'`; | ||
let sqlThing; | ||
if (entity.kind === "class") { | ||
const identifier = `"${entity.namespaceName}"."${entity.name}"`; | ||
if (entity.classKind === "r") { | ||
sqlThing = `TABLE ${identifier}`; | ||
} else if (entity.classKind === "v") { | ||
sqlThing = `VIEW ${identifier}`; | ||
} else if (entity.classKind === "m") { | ||
sqlThing = `MATERIALIZED VIEW ${identifier}`; | ||
} else { | ||
sqlThing = `PLEASE_SEND_A_PULL_REQUEST_TO_FIX_THIS ${identifier}`; | ||
} | ||
} else if (entity.kind === "attribute") { | ||
sqlThing = `COLUMN "${entity.class.namespaceName}"."${entity.class.name}"."${entity.name}"`; | ||
} else if (entity.kind === "procedure") { | ||
sqlThing = `FUNCTION "${entity.namespaceName}"."${entity.name}"(...arg types go here...)`; | ||
} else if (entity.kind === "constraint") { | ||
// TODO: TEST! | ||
sqlThing = `CONSTRAINT "${entity.name}" ON "${entity.class.namespaceName}"."${entity.class.name}"`; | ||
} else { | ||
sqlThing = `UNKNOWN_ENTITY_PLEASE_SEND_A_PULL_REQUEST`; | ||
} | ||
return `COMMENT ON ${sqlThing} IS ${commentValue};`; | ||
} | ||
}); | ||
@@ -323,2 +426,11 @@ }); | ||
}, | ||
singleRelationByKeysBackwards(detailedKeys, table, _foreignTable, constraint) { | ||
if (constraint.tags.foreignSingleFieldName) { | ||
return constraint.tags.foreignSingleFieldName; | ||
} | ||
if (constraint.tags.foreignFieldName) { | ||
return constraint.tags.foreignFieldName; | ||
} | ||
return this.singleRelationByKeys(detailedKeys, table, _foreignTable, constraint); | ||
}, | ||
manyRelationByKeys(detailedKeys, table, _foreignTable, constraint) { | ||
@@ -331,2 +443,5 @@ if (constraint.tags.foreignFieldName) { | ||
manyRelationByKeysSimple(detailedKeys, table, _foreignTable, constraint) { | ||
if (constraint.tags.foreignSimpleFieldName) { | ||
return constraint.tags.foreignSimpleFieldName; | ||
} | ||
if (constraint.tags.foreignFieldName) { | ||
@@ -333,0 +448,0 @@ return constraint.tags.foreignFieldName; |
@@ -60,8 +60,9 @@ "use strict"; | ||
pgOmit: omit, | ||
pgGetSelectValueForFieldAndTypeAndModifier: getSelectValueForFieldAndTypeAndModifier | ||
pgGetSelectValueForFieldAndTypeAndModifier: getSelectValueForFieldAndTypeAndModifier, | ||
describePgEntity, | ||
sqlCommentByAddingTags | ||
} = build; | ||
const { | ||
scope: { isPgRowType, isPgCompoundType, pgIntrospection: table }, | ||
fieldWithHooks, | ||
Self | ||
fieldWithHooks | ||
} = context; | ||
@@ -87,23 +88,27 @@ if (!(isPgRowType || isPgCompoundType) || !table || table.kind !== "class") { | ||
} | ||
memo[fieldName] = fieldWithHooks(fieldName, fieldContext => { | ||
const { addDataGenerator } = fieldContext; | ||
const ReturnType = pgGetGqlTypeByTypeIdAndModifier(attr.typeId, attr.typeModifier) || GraphQLString; | ||
addDataGenerator(parsedResolveInfoFragment => { | ||
memo = extend(memo, { | ||
[fieldName]: fieldWithHooks(fieldName, fieldContext => { | ||
const { addDataGenerator } = fieldContext; | ||
const ReturnType = pgGetGqlTypeByTypeIdAndModifier(attr.typeId, attr.typeModifier) || GraphQLString; | ||
addDataGenerator(parsedResolveInfoFragment => { | ||
return { | ||
pgQuery: queryBuilder => { | ||
queryBuilder.select(getSelectValueForFieldAndTypeAndModifier(ReturnType, fieldContext, parsedResolveInfoFragment, sql.fragment`(${queryBuilder.getTableAlias()}.${sql.identifier(attr.name)})`, // The brackets are necessary to stop the parser getting confused, ref: https://www.postgresql.org/docs/9.6/static/rowtypes.html#ROWTYPES-ACCESSING | ||
attr.type, attr.typeModifier), fieldName); | ||
} | ||
}; | ||
}); | ||
return { | ||
pgQuery: queryBuilder => { | ||
queryBuilder.select(getSelectValueForFieldAndTypeAndModifier(ReturnType, fieldContext, parsedResolveInfoFragment, sql.fragment`(${queryBuilder.getTableAlias()}.${sql.identifier(attr.name)})`, // The brackets are necessary to stop the parser getting confused, ref: https://www.postgresql.org/docs/9.6/static/rowtypes.html#ROWTYPES-ACCESSING | ||
attr.type, attr.typeModifier), fieldName); | ||
description: attr.description, | ||
type: nullableIf(GraphQLNonNull, !attr.isNotNull && !attr.type.domainIsNotNull, ReturnType), | ||
resolve: (data, _args, _context, _resolveInfo) => { | ||
return pg2gql(data[fieldName], attr.type); | ||
} | ||
}; | ||
}); | ||
return { | ||
description: attr.description, | ||
type: nullableIf(GraphQLNonNull, !attr.isNotNull && !attr.type.domainIsNotNull, ReturnType), | ||
resolve: (data, _args, _context, _resolveInfo) => { | ||
return pg2gql(data[fieldName], attr.type); | ||
} | ||
}; | ||
}, { pgFieldIntrospection: attr }); | ||
}, { pgFieldIntrospection: attr }) | ||
}, `Adding field for ${describePgEntity(attr)}. You can rename this field with:\n\n ${sqlCommentByAddingTags(attr, { | ||
name: "newNameHere" | ||
})}`); | ||
return memo; | ||
}, {}), `Adding columns to '${Self.name}'`); | ||
}, {}), `Adding columns to '${describePgEntity(table)}'`); | ||
}); | ||
@@ -118,3 +123,5 @@ builder.hook("GraphQLInputObjectType:fields", (fields, build, context) => { | ||
inflection, | ||
pgOmit: omit | ||
pgOmit: omit, | ||
describePgEntity, | ||
sqlCommentByAddingTags | ||
} = build; | ||
@@ -130,4 +137,3 @@ const { | ||
}, | ||
fieldWithHooks, | ||
Self | ||
fieldWithHooks | ||
} = context; | ||
@@ -142,10 +148,14 @@ if (!(isPgRowType || isPgCompoundType) || !table || table.kind !== "class") { | ||
} | ||
memo[fieldName] = fieldWithHooks(fieldName, pgAddSubfield(fieldName, attr.name, attr.type, { | ||
description: attr.description, | ||
type: nullableIf(GraphQLNonNull, isPgBaseInput || isPgPatch || !attr.isNotNull && !attr.type.domainIsNotNull || attr.hasDefault, pgGetGqlInputTypeByTypeIdAndModifier(attr.typeId, attr.typeModifier) || GraphQLString) | ||
}, attr.typeModifier), { pgFieldIntrospection: attr }); | ||
memo = extend(memo, { | ||
[fieldName]: fieldWithHooks(fieldName, pgAddSubfield(fieldName, attr.name, attr.type, { | ||
description: attr.description, | ||
type: nullableIf(GraphQLNonNull, isPgBaseInput || isPgPatch || !attr.isNotNull && !attr.type.domainIsNotNull || attr.hasDefault, pgGetGqlInputTypeByTypeIdAndModifier(attr.typeId, attr.typeModifier) || GraphQLString) | ||
}, attr.typeModifier), { pgFieldIntrospection: attr }) | ||
}, `Adding input object field for ${describePgEntity(attr)}. You can rename this field with:\n\n ${sqlCommentByAddingTags(attr, { | ||
name: "newNameHere" | ||
})}`); | ||
return memo; | ||
}, {}), `Adding columns to input object '${Self.name}'`); | ||
}, {}), `Adding columns to input object for ${describePgEntity(table)}`); | ||
}); | ||
}; | ||
//# sourceMappingURL=PgColumnsPlugin.js.map |
@@ -30,3 +30,5 @@ "use strict"; | ||
pgMakeProcField: makeProcField, | ||
swallowError | ||
swallowError, | ||
describePgEntity, | ||
sqlCommentByAddingTags | ||
} = build; | ||
@@ -62,7 +64,11 @@ const tableType = introspectionResultsByKind.type.filter(type => type.type === "c" && type.namespaceId === table.namespaceId && type.classId === table.id)[0]; | ||
try { | ||
memo[fieldName] = makeProcField(fieldName, proc, build, { | ||
fieldWithHooks, | ||
computed: true, | ||
forceList | ||
}); | ||
memo = extend(memo, { | ||
[fieldName]: makeProcField(fieldName, proc, build, { | ||
fieldWithHooks, | ||
computed: true, | ||
forceList | ||
}) | ||
}, `Adding computed column for ${describePgEntity(proc)}. You can rename this field with:\n\n ${sqlCommentByAddingTags(proc, { | ||
fieldName: "newNameHere" | ||
})}`); | ||
} catch (e) { | ||
@@ -69,0 +75,0 @@ swallowError(e); |
@@ -16,3 +16,5 @@ "use strict"; | ||
inflection, | ||
pgOmit: omit | ||
pgOmit: omit, | ||
describePgEntity, | ||
sqlCommentByAddingTags | ||
} = build; | ||
@@ -29,8 +31,10 @@ introspectionResultsByKind.class.filter(table => table.isSelectable && !omit(table, "filter")).filter(table => !!table.namespace).forEach(table => { | ||
const fieldName = inflection.column(attr); | ||
memo[fieldName] = fieldWithHooks(fieldName, { | ||
description: `Checks for equality with the object’s \`${fieldName}\` field.`, | ||
type: pgGetGqlInputTypeByTypeIdAndModifier(attr.typeId, attr.typeModifier) || GraphQLString | ||
}, { | ||
isPgConnectionConditionInputField: true | ||
}); | ||
memo = build.extend(memo, { | ||
[fieldName]: fieldWithHooks(fieldName, { | ||
description: `Checks for equality with the object’s \`${fieldName}\` field.`, | ||
type: pgGetGqlInputTypeByTypeIdAndModifier(attr.typeId, attr.typeModifier) || GraphQLString | ||
}, { | ||
isPgConnectionConditionInputField: true | ||
}) | ||
}, `Adding condition argument for ${describePgEntity(attr)}`); | ||
return memo; | ||
@@ -40,2 +44,5 @@ }, {}); | ||
}, { | ||
__origin: `Adding condition type for ${describePgEntity(table)}. You can rename the table's GraphQL type via:\n\n ${sqlCommentByAddingTags(table, { | ||
name: "newNameHere" | ||
})}`, | ||
pgIntrospection: table, | ||
@@ -42,0 +49,0 @@ isPgCondition: true |
@@ -20,3 +20,5 @@ "use strict"; | ||
inflection, | ||
pgOmit: omit | ||
pgOmit: omit, | ||
sqlCommentByAddingTags, | ||
describePgEntity | ||
} = build; | ||
@@ -38,2 +40,5 @@ introspectionResultsByKind.class.filter(table => table.isSelectable && !omit(table, "order")).filter(table => !!table.namespace).forEach(table => { | ||
}, { | ||
__origin: `Adding connection "orderBy" argument for ${describePgEntity(table)}. You can rename the table's GraphQL type via:\n\n ${sqlCommentByAddingTags(table, { | ||
name: "newNameHere" | ||
})}`, | ||
pgIntrospection: table, | ||
@@ -114,5 +119,5 @@ isPgRowSortEnum: true | ||
} | ||
}, `Adding 'orderBy' to field '${field.name}' of '${Self.name}'`); | ||
}, `Adding 'orderBy' argument to field '${field.name}' of '${Self.name}'`); | ||
}); | ||
}; | ||
//# sourceMappingURL=PgConnectionArgOrderBy.js.map |
@@ -26,3 +26,4 @@ "use strict"; | ||
pgQueryFromResolveData: queryFromResolveData, | ||
pgOmit: omit | ||
pgOmit: omit, | ||
describePgEntity | ||
} = build; | ||
@@ -88,33 +89,35 @@ const { | ||
memo[fieldName] = fieldWithHooks(fieldName, ({ getDataFromParsedResolveInfoFragment, addDataGenerator }) => { | ||
addDataGenerator(parsedResolveInfoFragment => { | ||
memo = extend(memo, { | ||
[fieldName]: fieldWithHooks(fieldName, ({ getDataFromParsedResolveInfoFragment, addDataGenerator }) => { | ||
addDataGenerator(parsedResolveInfoFragment => { | ||
return { | ||
pgQuery: queryBuilder => { | ||
queryBuilder.select(() => { | ||
const resolveData = getDataFromParsedResolveInfoFragment(parsedResolveInfoFragment, gqlForeignTableType); | ||
const foreignTableAlias = sql.identifier(Symbol()); | ||
const query = queryFromResolveData(sql.identifier(foreignSchema.name, foreignTable.name), foreignTableAlias, resolveData, { asJson: true }, innerQueryBuilder => { | ||
innerQueryBuilder.parentQueryBuilder = queryBuilder; | ||
keys.forEach((key, i) => { | ||
innerQueryBuilder.where(sql.fragment`${queryBuilder.getTableAlias()}.${sql.identifier(key.name)} = ${foreignTableAlias}.${sql.identifier(foreignKeys[i].name)}`); | ||
}); | ||
}); | ||
return sql.fragment`(${query})`; | ||
}, getSafeAliasFromAlias(parsedResolveInfoFragment.alias)); | ||
} | ||
}; | ||
}); | ||
return { | ||
pgQuery: queryBuilder => { | ||
queryBuilder.select(() => { | ||
const resolveData = getDataFromParsedResolveInfoFragment(parsedResolveInfoFragment, gqlForeignTableType); | ||
const foreignTableAlias = sql.identifier(Symbol()); | ||
const query = queryFromResolveData(sql.identifier(foreignSchema.name, foreignTable.name), foreignTableAlias, resolveData, { asJson: true }, innerQueryBuilder => { | ||
innerQueryBuilder.parentQueryBuilder = queryBuilder; | ||
keys.forEach((key, i) => { | ||
innerQueryBuilder.where(sql.fragment`${queryBuilder.getTableAlias()}.${sql.identifier(key.name)} = ${foreignTableAlias}.${sql.identifier(foreignKeys[i].name)}`); | ||
}); | ||
}); | ||
return sql.fragment`(${query})`; | ||
}, getSafeAliasFromAlias(parsedResolveInfoFragment.alias)); | ||
description: constraint.tags.forwardDescription || `Reads a single \`${foreignTableTypeName}\` that is related to this \`${tableTypeName}\`.`, | ||
type: gqlForeignTableType, // Nullable since RLS may forbid fetching | ||
resolve: (rawData, _args, _context, resolveInfo) => { | ||
const data = isMutationPayload ? rawData.data : rawData; | ||
const safeAlias = getSafeAliasFromResolveInfo(resolveInfo); | ||
return data[safeAlias]; | ||
} | ||
}; | ||
}); | ||
return { | ||
description: constraint.tags.forwardDescription || `Reads a single \`${foreignTableTypeName}\` that is related to this \`${tableTypeName}\`.`, | ||
type: gqlForeignTableType, // Nullable since RLS may forbid fetching | ||
resolve: (rawData, _args, _context, resolveInfo) => { | ||
const data = isMutationPayload ? rawData.data : rawData; | ||
const safeAlias = getSafeAliasFromResolveInfo(resolveInfo); | ||
return data[safeAlias]; | ||
} | ||
}; | ||
}, { | ||
pgFieldIntrospection: constraint, | ||
isPgForwardRelationField: true | ||
}); | ||
}, { | ||
pgFieldIntrospection: constraint, | ||
isPgForwardRelationField: true | ||
}) | ||
}, `Adding forward relation for ${describePgEntity(constraint)}`); | ||
return memo; | ||
@@ -121,0 +124,0 @@ }, {}), `Adding forward relations to '${Self.name}'`); |
@@ -5,2 +5,3 @@ export interface PgNamespace { | ||
name: string; | ||
comment: string | void; | ||
description: string | void; | ||
@@ -13,4 +14,6 @@ tags: { [tag: string]: string }; | ||
name: string; | ||
comment: string | void; | ||
description: string | void; | ||
namespaceId: string; | ||
namespaceName: string; | ||
isStrict: boolean; | ||
@@ -32,2 +35,3 @@ returnsSet: boolean; | ||
name: string; | ||
comment: string | void; | ||
description: string | void; | ||
@@ -57,2 +61,3 @@ classKind: string; | ||
name: string; | ||
comment: string | void; | ||
description: string | void; | ||
@@ -78,2 +83,3 @@ namespaceId: string; | ||
name: string; | ||
comment: string | void; | ||
description: string | void; | ||
@@ -98,3 +104,5 @@ typeId: string; | ||
classId: string; | ||
class: PgClass | void; | ||
foreignClassId: string | void; | ||
comment: string | void; | ||
description: string | void; | ||
@@ -115,4 +123,5 @@ keyAttributeNums: Array<number>; | ||
configurationClassIds?: Array<string>; | ||
comment: string | void; | ||
description: string | void; | ||
tags: { [tag: string]: string | Array<string> }; | ||
} |
@@ -95,2 +95,4 @@ "use strict"; | ||
result[kind].forEach(object => { | ||
// Keep a copy of the raw comment | ||
object.comment = object.description; | ||
if (pgEnableTags && object.description) { | ||
@@ -189,2 +191,4 @@ const parsed = (0, _utils.parseTags)(object.description); | ||
relate(introspectionResultsByKind.constraint, "class", "classId", introspectionResultsByKind.classById, true); | ||
relate(introspectionResultsByKind.extension, "namespace", "namespaceId", introspectionResultsByKind.namespaceById, true // Because the extension could be a defined in a different namespace | ||
@@ -191,0 +195,0 @@ ); |
@@ -20,3 +20,4 @@ "use strict"; | ||
inflection, | ||
pgParseIdentifier: parseIdentifier | ||
pgParseIdentifier: parseIdentifier, | ||
describePgEntity | ||
} = build; | ||
@@ -67,2 +68,3 @@ if (!pgJwtTypeIdentifier) { | ||
}, { | ||
__origin: `Adding JWT type based on ${describePgEntity(compositeType)}`, | ||
isPgJwtType: true | ||
@@ -69,0 +71,0 @@ }); |
@@ -39,3 +39,5 @@ "use strict"; | ||
pgOmit: omit, | ||
pgViaTemporaryTable: viaTemporaryTable | ||
pgViaTemporaryTable: viaTemporaryTable, | ||
describePgEntity, | ||
sqlCommentByAddingTags | ||
} = build; | ||
@@ -77,2 +79,5 @@ const { | ||
}, { | ||
__origin: `Adding table create input type for ${describePgEntity(table)}. You can rename the table's GraphQL type via:\n\n ${sqlCommentByAddingTags(table, { | ||
name: "newNameHere" | ||
})}`, | ||
isPgCreateInputType: true, | ||
@@ -102,2 +107,5 @@ pgInflection: table | ||
}, { | ||
__origin: `Adding table create payload type for ${describePgEntity(table)}. You can rename the table's GraphQL type via:\n\n ${sqlCommentByAddingTags(table, { | ||
name: "newNameHere" | ||
})}`, | ||
isMutationPayload: true, | ||
@@ -108,30 +116,31 @@ isPgCreatePayloadType: true, | ||
const fieldName = inflection.createField(table); | ||
memo[fieldName] = fieldWithHooks(fieldName, context => { | ||
const { getDataFromParsedResolveInfoFragment } = context; | ||
return { | ||
description: `Creates a single \`${tableTypeName}\`.`, | ||
type: PayloadType, | ||
args: { | ||
input: { | ||
type: new GraphQLNonNull(InputType) | ||
} | ||
}, | ||
async resolve(data, { input }, { pgClient }, resolveInfo) { | ||
const parsedResolveInfoFragment = parseResolveInfo(resolveInfo); | ||
const resolveData = getDataFromParsedResolveInfoFragment(parsedResolveInfoFragment, PayloadType); | ||
const insertedRowAlias = sql.identifier(Symbol()); | ||
const query = queryFromResolveData(insertedRowAlias, insertedRowAlias, resolveData, {}); | ||
const sqlColumns = []; | ||
const sqlValues = []; | ||
const inputData = input[inflection.tableFieldName(table)]; | ||
pgIntrospectionResultsByKind.attribute.filter(attr => attr.classId === table.id).filter(attr => pgColumnFilter(attr, build, context)).filter(attr => !omit(attr, "create")).forEach(attr => { | ||
const fieldName = inflection.column(attr); | ||
const val = inputData[fieldName]; | ||
if (Object.prototype.hasOwnProperty.call(inputData, fieldName)) { | ||
sqlColumns.push(sql.identifier(attr.name)); | ||
sqlValues.push(gql2pg(val, attr.type, attr.typeModifier)); | ||
memo = build.extend(memo, { | ||
[fieldName]: fieldWithHooks(fieldName, context => { | ||
const { getDataFromParsedResolveInfoFragment } = context; | ||
return { | ||
description: `Creates a single \`${tableTypeName}\`.`, | ||
type: PayloadType, | ||
args: { | ||
input: { | ||
type: new GraphQLNonNull(InputType) | ||
} | ||
}); | ||
}, | ||
async resolve(data, { input }, { pgClient }, resolveInfo) { | ||
const parsedResolveInfoFragment = parseResolveInfo(resolveInfo); | ||
const resolveData = getDataFromParsedResolveInfoFragment(parsedResolveInfoFragment, PayloadType); | ||
const insertedRowAlias = sql.identifier(Symbol()); | ||
const query = queryFromResolveData(insertedRowAlias, insertedRowAlias, resolveData, {}); | ||
const sqlColumns = []; | ||
const sqlValues = []; | ||
const inputData = input[inflection.tableFieldName(table)]; | ||
pgIntrospectionResultsByKind.attribute.filter(attr => attr.classId === table.id).filter(attr => pgColumnFilter(attr, build, context)).filter(attr => !omit(attr, "create")).forEach(attr => { | ||
const fieldName = inflection.column(attr); | ||
const val = inputData[fieldName]; | ||
if (Object.prototype.hasOwnProperty.call(inputData, fieldName)) { | ||
sqlColumns.push(sql.identifier(attr.name)); | ||
sqlValues.push(gql2pg(val, attr.type, attr.typeModifier)); | ||
} | ||
}); | ||
const mutationQuery = sql.query` | ||
const mutationQuery = sql.query` | ||
insert into ${sql.identifier(table.namespace.name, table.name)} ${sqlColumns.length ? sql.fragment`( | ||
@@ -141,22 +150,25 @@ ${sql.join(sqlColumns, ", ")} | ||
let row; | ||
try { | ||
await pgClient.query("SAVEPOINT graphql_mutation"); | ||
const rows = await viaTemporaryTable(pgClient, sql.identifier(table.namespace.name, table.name), mutationQuery, insertedRowAlias, query); | ||
row = rows[0]; | ||
await pgClient.query("RELEASE SAVEPOINT graphql_mutation"); | ||
} catch (e) { | ||
await pgClient.query("ROLLBACK TO SAVEPOINT graphql_mutation"); | ||
throw e; | ||
let row; | ||
try { | ||
await pgClient.query("SAVEPOINT graphql_mutation"); | ||
const rows = await viaTemporaryTable(pgClient, sql.identifier(table.namespace.name, table.name), mutationQuery, insertedRowAlias, query); | ||
row = rows[0]; | ||
await pgClient.query("RELEASE SAVEPOINT graphql_mutation"); | ||
} catch (e) { | ||
await pgClient.query("ROLLBACK TO SAVEPOINT graphql_mutation"); | ||
throw e; | ||
} | ||
return { | ||
clientMutationId: input.clientMutationId, | ||
data: row | ||
}; | ||
} | ||
return { | ||
clientMutationId: input.clientMutationId, | ||
data: row | ||
}; | ||
} | ||
}; | ||
}, { | ||
pgFieldIntrospection: table, | ||
isPgCreateMutationField: true | ||
}); | ||
}; | ||
}, { | ||
pgFieldIntrospection: table, | ||
isPgCreateMutationField: true | ||
}) | ||
}, `Adding create mutation for ${describePgEntity(table)}. You can omit this default mutation with:\n\n ${sqlCommentByAddingTags(table, { | ||
omit: "create" | ||
})}`); | ||
return memo; | ||
@@ -163,0 +175,0 @@ }, {}), `Adding default 'create' mutation to root mutation`); |
@@ -23,3 +23,4 @@ "use strict"; | ||
inflection, | ||
pgOmit: omit | ||
pgOmit: omit, | ||
describePgEntity | ||
} = build; | ||
@@ -124,5 +125,5 @@ const { | ||
}) | ||
}, `Adding edge field to mutation payload '${Self.name}'`); | ||
}, `Adding edge field for table ${describePgEntity(table)} to mutation payload '${Self.name}'`); | ||
}); | ||
}; | ||
//# sourceMappingURL=PgMutationPayloadEdgePlugin.js.map |
@@ -15,3 +15,5 @@ "use strict"; | ||
pgOmit: omit, | ||
swallowError | ||
swallowError, | ||
describePgEntity, | ||
sqlCommentByAddingTags | ||
} = build; | ||
@@ -43,6 +45,10 @@ const { | ||
try { | ||
memo[fieldName] = makeProcField(fieldName, proc, build, { | ||
fieldWithHooks, | ||
isMutation: true | ||
}); | ||
memo = extend(memo, { | ||
[fieldName]: makeProcField(fieldName, proc, build, { | ||
fieldWithHooks, | ||
isMutation: true | ||
}) | ||
}, `Adding mutation field for ${describePgEntity(proc)}. You can rename this field with:\n\n ${sqlCommentByAddingTags(proc, { | ||
name: "newNameHere" | ||
})}`); | ||
} catch (e) { | ||
@@ -49,0 +55,0 @@ swallowError(e); |
@@ -46,3 +46,5 @@ "use strict"; | ||
pgOmit: omit, | ||
pgViaTemporaryTable: viaTemporaryTable | ||
pgViaTemporaryTable: viaTemporaryTable, | ||
describePgEntity, | ||
sqlCommentByAddingTags | ||
} = build; | ||
@@ -165,2 +167,5 @@ const { | ||
}, { | ||
__origin: `Adding table ${mode} mutation payload type for ${describePgEntity(table)}. You can rename the table's GraphQL type via:\n\n ${sqlCommentByAddingTags(table, { | ||
name: "newNameHere" | ||
})}`, | ||
isMutationPayload: true, | ||
@@ -196,2 +201,5 @@ isPgUpdatePayloadType: mode === "update", | ||
}, { | ||
__origin: `Adding table ${mode} (by node ID) mutation input type for ${describePgEntity(table)}. You can rename the table's GraphQL type via:\n\n ${sqlCommentByAddingTags(table, { | ||
name: "newNameHere" | ||
})}`, | ||
isPgUpdateInputType: mode === "update", | ||
@@ -205,36 +213,40 @@ isPgUpdateNodeInputType: mode === "update", | ||
memo[fieldName] = fieldWithHooks(fieldName, context => { | ||
const { getDataFromParsedResolveInfoFragment } = context; | ||
return { | ||
description: mode === "update" ? `Updates a single \`${tableTypeName}\` using its globally unique id and a patch.` : `Deletes a single \`${tableTypeName}\` using its globally unique id.`, | ||
type: PayloadType, | ||
args: { | ||
input: { | ||
type: new GraphQLNonNull(InputType) | ||
} | ||
}, | ||
async resolve(parent, { input }, { pgClient }, resolveInfo) { | ||
const nodeId = input[nodeIdFieldName]; | ||
try { | ||
const [alias, ...identifiers] = JSON.parse(base64Decode(nodeId)); | ||
const NodeTypeByAlias = getNodeType(alias); | ||
if (NodeTypeByAlias !== TableType) { | ||
throw new Error("Mismatched type"); | ||
memo = extend(memo, { | ||
[fieldName]: fieldWithHooks(fieldName, context => { | ||
const { | ||
getDataFromParsedResolveInfoFragment | ||
} = context; | ||
return { | ||
description: mode === "update" ? `Updates a single \`${tableTypeName}\` using its globally unique id and a patch.` : `Deletes a single \`${tableTypeName}\` using its globally unique id.`, | ||
type: PayloadType, | ||
args: { | ||
input: { | ||
type: new GraphQLNonNull(InputType) | ||
} | ||
if (identifiers.length !== primaryKeys.length) { | ||
throw new Error("Invalid ID"); | ||
}, | ||
async resolve(parent, { input }, { pgClient }, resolveInfo) { | ||
const nodeId = input[nodeIdFieldName]; | ||
try { | ||
const [alias, ...identifiers] = JSON.parse(base64Decode(nodeId)); | ||
const NodeTypeByAlias = getNodeType(alias); | ||
if (NodeTypeByAlias !== TableType) { | ||
throw new Error("Mismatched type"); | ||
} | ||
if (identifiers.length !== primaryKeys.length) { | ||
throw new Error("Invalid ID"); | ||
} | ||
return commonCodeRenameMe(pgClient, resolveInfo, getDataFromParsedResolveInfoFragment, PayloadType, input, sql.fragment`(${sql.join(primaryKeys.map((key, idx) => sql.fragment`${sql.identifier(key.name)} = ${gql2pg(identifiers[idx], key.type, key.typeModifier)}`), ") and (")})`, context); | ||
} catch (e) { | ||
debug(e); | ||
return null; | ||
} | ||
return commonCodeRenameMe(pgClient, resolveInfo, getDataFromParsedResolveInfoFragment, PayloadType, input, sql.fragment`(${sql.join(primaryKeys.map((key, idx) => sql.fragment`${sql.identifier(key.name)} = ${gql2pg(identifiers[idx], key.type, key.typeModifier)}`), ") and (")})`, context); | ||
} catch (e) { | ||
debug(e); | ||
return null; | ||
} | ||
} | ||
}; | ||
}, { | ||
isPgNodeMutation: true, | ||
pgFieldIntrospection: table, | ||
[mode === "update" ? "isPgUpdateMutationField" : "isPgDeleteMutationField"]: true | ||
}); | ||
}; | ||
}, { | ||
isPgNodeMutation: true, | ||
pgFieldIntrospection: table, | ||
[mode === "update" ? "isPgUpdateMutationField" : "isPgDeleteMutationField"]: true | ||
}) | ||
}, "Adding ${mode} mutation for ${describePgEntity(table)}"); | ||
} | ||
@@ -275,2 +287,5 @@ | ||
}, { | ||
__origin: `Adding table ${mode} mutation input type for ${describePgEntity(constraint)}. You can rename the table's GraphQL type via:\n\n ${sqlCommentByAddingTags(table, { | ||
name: "newNameHere" | ||
})}`, | ||
isPgUpdateInputType: mode === "update", | ||
@@ -285,21 +300,25 @@ isPgUpdateByKeysInputType: mode === "update", | ||
memo[fieldName] = fieldWithHooks(fieldName, context => { | ||
const { getDataFromParsedResolveInfoFragment } = context; | ||
return { | ||
description: mode === "update" ? `Updates a single \`${tableTypeName}\` using a unique key and a patch.` : `Deletes a single \`${tableTypeName}\` using a unique key.`, | ||
type: PayloadType, | ||
args: { | ||
input: { | ||
type: new GraphQLNonNull(InputType) | ||
memo = extend(memo, { | ||
[fieldName]: fieldWithHooks(fieldName, context => { | ||
const { | ||
getDataFromParsedResolveInfoFragment | ||
} = context; | ||
return { | ||
description: mode === "update" ? `Updates a single \`${tableTypeName}\` using a unique key and a patch.` : `Deletes a single \`${tableTypeName}\` using a unique key.`, | ||
type: PayloadType, | ||
args: { | ||
input: { | ||
type: new GraphQLNonNull(InputType) | ||
} | ||
}, | ||
async resolve(parent, { input }, { pgClient }, resolveInfo) { | ||
return commonCodeRenameMe(pgClient, resolveInfo, getDataFromParsedResolveInfoFragment, PayloadType, input, sql.fragment`(${sql.join(keys.map(key => sql.fragment`${sql.identifier(key.name)} = ${gql2pg(input[inflection.column(key)], key.type, key.typeModifier)}`), ") and (")})`, context); | ||
} | ||
}, | ||
async resolve(parent, { input }, { pgClient }, resolveInfo) { | ||
return commonCodeRenameMe(pgClient, resolveInfo, getDataFromParsedResolveInfoFragment, PayloadType, input, sql.fragment`(${sql.join(keys.map(key => sql.fragment`${sql.identifier(key.name)} = ${gql2pg(input[inflection.column(key)], key.type, key.typeModifier)}`), ") and (")})`, context); | ||
} | ||
}; | ||
}, { | ||
isPgNodeMutation: false, | ||
pgFieldIntrospection: table, | ||
[mode === "update" ? "isPgUpdateMutationField" : "isPgDeleteMutationField"]: true | ||
}); | ||
}; | ||
}, { | ||
isPgNodeMutation: false, | ||
pgFieldIntrospection: table, | ||
[mode === "update" ? "isPgUpdateMutationField" : "isPgDeleteMutationField"]: true | ||
}) | ||
}, `Adding ${mode} mutation for ${describePgEntity(constraint)}`); | ||
}); | ||
@@ -306,0 +325,0 @@ } |
@@ -14,3 +14,5 @@ "use strict"; | ||
inflection, | ||
pgOmit: omit | ||
pgOmit: omit, | ||
describePgEntity, | ||
sqlCommentByAddingTags | ||
} = build; | ||
@@ -29,14 +31,22 @@ const { | ||
const descFieldName = inflection.orderByColumnEnum(attr, false); | ||
memo[ascFieldName] = { | ||
value: { | ||
alias: ascFieldName.toLowerCase(), | ||
specs: [[attr.name, true]] | ||
memo = extend(memo, { | ||
[ascFieldName]: { | ||
value: { | ||
alias: ascFieldName.toLowerCase(), | ||
specs: [[attr.name, true]] | ||
} | ||
} | ||
}; | ||
memo[descFieldName] = { | ||
value: { | ||
alias: descFieldName.toLowerCase(), | ||
specs: [[attr.name, false]] | ||
}, `Adding ascending orderBy enum value for ${describePgEntity(attr)}. You can rename this field with:\n\n ${sqlCommentByAddingTags(attr, { | ||
name: "newNameHere" | ||
})}`); | ||
memo = extend(memo, { | ||
[descFieldName]: { | ||
value: { | ||
alias: descFieldName.toLowerCase(), | ||
specs: [[attr.name, false]] | ||
} | ||
} | ||
}; | ||
}, `Adding descending orderBy enum value for ${describePgEntity(attr)}. You can rename this field with:\n\n ${sqlCommentByAddingTags(attr, { | ||
name: "newNameHere" | ||
})}`); | ||
return memo; | ||
@@ -43,0 +53,0 @@ }, {}), `Adding order values from table '${table.name}'`); |
@@ -28,3 +28,5 @@ "use strict"; | ||
pgMakeProcField: makeProcField, | ||
pgOmit: omit | ||
pgOmit: omit, | ||
describePgEntity, | ||
sqlCommentByAddingTags | ||
} = build; | ||
@@ -67,6 +69,10 @@ const { | ||
try { | ||
memo[fieldName] = makeProcField(fieldName, proc, build, { | ||
fieldWithHooks, | ||
forceList | ||
}); | ||
memo = extend(memo, { | ||
[fieldName]: makeProcField(fieldName, proc, build, { | ||
fieldWithHooks, | ||
forceList | ||
}) | ||
}, `Adding query field for ${describePgEntity(proc)}. You can rename this field with:\n\n ${sqlCommentByAddingTags(proc, { | ||
name: "newNameHere" | ||
})}`); | ||
} catch (e) { | ||
@@ -73,0 +79,0 @@ // eslint-disable-next-line no-console |
@@ -71,3 +71,5 @@ "use strict"; | ||
pgQueryFromResolveData: queryFromResolveData, | ||
pgOmit: omit | ||
pgOmit: omit, | ||
describePgEntity, | ||
sqlCommentByAddingTags | ||
} = build; | ||
@@ -92,46 +94,48 @@ const { | ||
const fieldName = inflection.tableNode(table); | ||
memo[fieldName] = fieldWithHooks(fieldName, ({ getDataFromParsedResolveInfoFragment }) => { | ||
return { | ||
description: `Reads a single \`${TableType.name}\` using its globally unique \`ID\`.`, | ||
type: TableType, | ||
args: { | ||
[nodeIdFieldName]: { | ||
description: `The globally unique \`ID\` to be used in selecting a single \`${TableType.name}\`.`, | ||
type: new GraphQLNonNull(GraphQLID) | ||
} | ||
}, | ||
async resolve(parent, args, { pgClient }, resolveInfo) { | ||
const nodeId = args[nodeIdFieldName]; | ||
try { | ||
const [alias, ...identifiers] = JSON.parse(base64Decode(nodeId)); | ||
const NodeTypeByAlias = getNodeType(alias); | ||
if (NodeTypeByAlias !== TableType) { | ||
throw new Error("Mismatched type"); | ||
memo = extend(memo, { | ||
[fieldName]: fieldWithHooks(fieldName, ({ getDataFromParsedResolveInfoFragment }) => { | ||
return { | ||
description: `Reads a single \`${TableType.name}\` using its globally unique \`ID\`.`, | ||
type: TableType, | ||
args: { | ||
[nodeIdFieldName]: { | ||
description: `The globally unique \`ID\` to be used in selecting a single \`${TableType.name}\`.`, | ||
type: new GraphQLNonNull(GraphQLID) | ||
} | ||
if (identifiers.length !== primaryKeys.length) { | ||
throw new Error("Invalid ID"); | ||
} | ||
}, | ||
async resolve(parent, args, { pgClient }, resolveInfo) { | ||
const nodeId = args[nodeIdFieldName]; | ||
try { | ||
const [alias, ...identifiers] = JSON.parse(base64Decode(nodeId)); | ||
const NodeTypeByAlias = getNodeType(alias); | ||
if (NodeTypeByAlias !== TableType) { | ||
throw new Error("Mismatched type"); | ||
} | ||
if (identifiers.length !== primaryKeys.length) { | ||
throw new Error("Invalid ID"); | ||
} | ||
const parsedResolveInfoFragment = parseResolveInfo(resolveInfo); | ||
const resolveData = getDataFromParsedResolveInfoFragment(parsedResolveInfoFragment, TableType); | ||
const query = queryFromResolveData(sqlFullTableName, undefined, resolveData, {}, queryBuilder => { | ||
primaryKeys.forEach((key, idx) => { | ||
queryBuilder.where(sql.fragment`${queryBuilder.getTableAlias()}.${sql.identifier(key.name)} = ${gql2pg(identifiers[idx], primaryKeys[idx].type, primaryKeys[idx].typeModifier)}`); | ||
const parsedResolveInfoFragment = parseResolveInfo(resolveInfo); | ||
const resolveData = getDataFromParsedResolveInfoFragment(parsedResolveInfoFragment, TableType); | ||
const query = queryFromResolveData(sqlFullTableName, undefined, resolveData, {}, queryBuilder => { | ||
primaryKeys.forEach((key, idx) => { | ||
queryBuilder.where(sql.fragment`${queryBuilder.getTableAlias()}.${sql.identifier(key.name)} = ${gql2pg(identifiers[idx], primaryKeys[idx].type, primaryKeys[idx].typeModifier)}`); | ||
}); | ||
}); | ||
}); | ||
const { text, values } = sql.compile(query); | ||
if (debugSql.enabled) debugSql(text); | ||
const { | ||
rows: [row] | ||
} = await pgClient.query(text, values); | ||
return row; | ||
} catch (e) { | ||
return null; | ||
const { text, values } = sql.compile(query); | ||
if (debugSql.enabled) debugSql(text); | ||
const { | ||
rows: [row] | ||
} = await pgClient.query(text, values); | ||
return row; | ||
} catch (e) { | ||
return null; | ||
} | ||
} | ||
} | ||
}; | ||
}, { | ||
isPgNodeQuery: true, | ||
pgFieldIntrospection: table | ||
}); | ||
}; | ||
}, { | ||
isPgNodeQuery: true, | ||
pgFieldIntrospection: table | ||
}) | ||
}, `Adding row by globally unique identifier field for ${describePgEntity(table)}. You can rename this table via:\n\n ${sqlCommentByAddingTags(table, { name: "newNameHere" })}`); | ||
} | ||
@@ -138,0 +142,0 @@ return memo; |
@@ -23,3 +23,5 @@ "use strict"; | ||
inflection, | ||
pgOmit: omit | ||
pgOmit: omit, | ||
describePgEntity, | ||
sqlCommentByAddingTags | ||
} = build; | ||
@@ -68,2 +70,5 @@ const nullableIf = (condition, Type) => condition ? Type : new GraphQLNonNull(Type); | ||
}, { | ||
__origin: `Adding function result edge type for ${describePgEntity(proc)}. You can rename the function's GraphQL field (and its dependent types) via:\n\n ${sqlCommentByAddingTags(proc, { | ||
name: "newNameHere" | ||
})}`, | ||
isEdgeType: true, | ||
@@ -98,2 +103,5 @@ nodeType: NodeType, | ||
}, { | ||
__origin: `Adding function connection type for ${describePgEntity(proc)}. You can rename the function's GraphQL field (and its dependent types) via:\n\n ${sqlCommentByAddingTags(proc, { | ||
name: "newNameHere" | ||
})}`, | ||
isConnectionType: true, | ||
@@ -100,0 +108,0 @@ edgeType: EdgeType, |
@@ -54,3 +54,5 @@ "use strict"; | ||
}, | ||
inflection | ||
inflection, | ||
describePgEntity, | ||
sqlCommentByAddingTags | ||
} = build; | ||
@@ -126,2 +128,5 @@ const nullableIf = (condition, Type) => condition ? Type : new GraphQLNonNull(Type); | ||
}, { | ||
__origin: `Adding table type for ${describePgEntity(table)}. You can rename the table's GraphQL type via:\n\n ${sqlCommentByAddingTags(table, { | ||
name: "newNameHere" | ||
})}`, | ||
pgIntrospection: table, | ||
@@ -139,2 +144,5 @@ isPgRowType: table.isSelectable, | ||
}, { | ||
__origin: `Adding table input type for ${describePgEntity(table)}. You can rename the table's GraphQL type via:\n\n ${sqlCommentByAddingTags(table, { | ||
name: "newNameHere" | ||
})}`, | ||
pgIntrospection: table, | ||
@@ -165,2 +173,5 @@ isInputType: true, | ||
}, { | ||
__origin: `Adding table patch type for ${describePgEntity(table)}. You can rename the table's GraphQL type via:\n\n ${sqlCommentByAddingTags(table, { | ||
name: "newNameHere" | ||
})}`, | ||
pgIntrospection: table, | ||
@@ -184,2 +195,5 @@ isPgRowType: table.isSelectable, | ||
}, { | ||
__origin: `Adding table base input type for ${describePgEntity(table)}. You can rename the table's GraphQL type via:\n\n ${sqlCommentByAddingTags(table, { | ||
name: "newNameHere" | ||
})}`, | ||
pgIntrospection: table, | ||
@@ -259,2 +273,5 @@ isPgRowType: table.isSelectable, | ||
}, { | ||
__origin: `Adding table edge type for ${describePgEntity(table)}. You can rename the table's GraphQL type via:\n\n ${sqlCommentByAddingTags(table, { | ||
name: "newNameHere" | ||
})}`, | ||
isEdgeType: true, | ||
@@ -299,2 +316,5 @@ isPgRowEdgeType: true, | ||
}, { | ||
__origin: `Adding table connection type for ${describePgEntity(table)}. You can rename the table's GraphQL type via:\n\n ${sqlCommentByAddingTags(table, { | ||
name: "newNameHere" | ||
})}`, | ||
isConnectionType: true, | ||
@@ -301,0 +321,0 @@ isPgRowConnectionType: true, |
@@ -83,3 +83,2 @@ "use strict"; | ||
getTypeByName, | ||
addType, | ||
pgSql: sql, | ||
@@ -89,2 +88,3 @@ inflection, | ||
} = build; | ||
const addType = build.addType.bind(build); | ||
const { | ||
@@ -198,3 +198,3 @@ GraphQLNonNull, | ||
}); | ||
addType(GQLInterval); | ||
addType(GQLInterval, "graphile-build-pg built-in"); | ||
@@ -206,3 +206,3 @@ const GQLIntervalInput = new GraphQLInputObjectType({ | ||
}); | ||
addType(GQLIntervalInput); | ||
addType(GQLIntervalInput, "graphile-build-pg built-in"); | ||
@@ -224,4 +224,4 @@ const stringType = (name, description) => new GraphQLScalarType({ | ||
const BitString = stringType("BitString", "A string representing a series of binary bits"); | ||
addType(BigFloat); | ||
addType(BitString); | ||
addType(BigFloat, "graphile-build-pg built-in"); | ||
addType(BitString, "graphile-build-pg built-in"); | ||
@@ -337,7 +337,7 @@ const rawTypes = [1186, // interval | ||
// Other plugins might want to use JSON | ||
addType(JSONType); | ||
addType(UUIDType); | ||
addType(DateType); | ||
addType(DateTimeType); | ||
addType(TimeType); | ||
addType(JSONType, "graphile-build-pg built-in"); | ||
addType(UUIDType, "graphile-build-pg built-in"); | ||
addType(DateType, "graphile-build-pg built-in"); | ||
addType(DateTimeType, "graphile-build-pg built-in"); | ||
addType(TimeType, "graphile-build-pg built-in"); | ||
@@ -553,4 +553,4 @@ const oidLookup = { | ||
}); | ||
addType(Range); | ||
addType(RangeInput); | ||
addType(Range, "graphile-build-pg built-in"); | ||
addType(RangeInput, "graphile-build-pg built-in"); | ||
} else { | ||
@@ -557,0 +557,0 @@ RangeInput = getTypeByName(inflection.inputType(Range.name)); |
{ | ||
"name": "graphile-build-pg", | ||
"version": "4.0.0-rc.9", | ||
"version": "4.0.0-rc.10", | ||
"description": "Build a GraphQL schema by reflection over a PostgreSQL schema. Easy to customize since it's built with plugins on graphile-build", | ||
@@ -40,3 +40,3 @@ "main": "node8plus/index.js", | ||
"debug": ">=2 <3", | ||
"graphile-build": "4.0.0-rc.9", | ||
"graphile-build": "4.0.0-rc.10", | ||
"graphql-iso-date": "^3.2.0", | ||
@@ -43,0 +43,0 @@ "jsonwebtoken": "^8.1.1", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1160396
6410
+ Addedgraphile-build@4.0.0-rc.10(transitive)
- Removedgraphile-build@4.0.0-rc.9(transitive)
Updatedgraphile-build@4.0.0-rc.10