Skip to content

Commit

Permalink
Better error formatting and another error page with more details #452
Browse files Browse the repository at this point in the history
  • Loading branch information
benjie committed Aug 4, 2023
2 parents 76a960e + 17215a4 commit 16881f5
Show file tree
Hide file tree
Showing 9 changed files with 76 additions and 13 deletions.
7 changes: 7 additions & 0 deletions .changeset/tame-files-hang.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"graphile-build-pg": patch
"graphile-build": patch
"@dataplan/pg": patch
---

Improve error messages with links to more details.
11 changes: 5 additions & 6 deletions grafast/dataplan-pg/src/datasource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1321,12 +1321,11 @@ export function makeRegistryBuilder(): PgRegistryBuilder<{}, {}, {}> {
throw new Error(
`Attempted to add a second resource named '${
resource.name
}' (first represented ${printResourceFrom(
}':\n First represented ${printResourceFrom(
existing,
)}, second represents ${printResourceFrom(
)}.\n Second represents ${printResourceFrom(
resource,
)}):\n Details: ${chalk.bold.blue
.underline`https://err.red/p2rc`}`,
)}.\n Details: ${chalk.bold.blue.underline`https://err.red/p2rc`}`,
);
}
return builder;
Expand Down Expand Up @@ -1383,12 +1382,12 @@ exportAs("@dataplan/pg", makePgResourceOptions, "makePgResourceOptions");

function printResourceFrom(resource: PgResourceOptions): string {
if (typeof resource.from === "function") {
return `function accepting ${
return `a function accepting ${
resource.parameters?.length
} parameters and returning SQL type '${
sql.compile(resource.codec.sqlType).text
}'`;
} else {
return `table/view/etc called '${sql.compile(resource.from).text}'`;
return `a table/view/etc called '${sql.compile(resource.from).text}'`;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ function processAttribute(

const {
scope: { pgCodec: rawPgCodec },
Self,
} = context;
if (!rawPgCodec || !rawPgCodec.attributes) {
return;
Expand Down Expand Up @@ -252,7 +253,7 @@ function processAttribute(
fieldSpec,
),
},
`Adding '${attributeName}' attribute field to PgCodec '${pgCodec.name}'`,
`Adding '${attributeName}' attribute field to GraphQL type '${Self.name}' (representing PgCodec '${pgCodec.name}')`,
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1388,7 +1388,7 @@ function addRelations(
},
),
},
`Adding '${identifier}' single relation field to ${Self.name}`,
`Adding field to GraphQL type '${Self.name}' for singular relation '${identifier}'`,
"recoverable",
);
}
Expand Down
2 changes: 1 addition & 1 deletion graphile-build/graphile-build/src/extend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export default function extend<
key,
)}'.\n\n${indent(firstEntityDetails)}\n\n${indent(
secondEntityDetails,
)}`,
)}.\n Details: ${chalk.blue.bold.underline`https://err.red/pnc`}`,
);
}
if (hintB) {
Expand Down
2 changes: 1 addition & 1 deletion postgraphile/postgraphile/graphile.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ const NonNullRelationsPlugin: GraphileConfig.Plugin = {
} = build;
// Extract details about why this field was defined.
const { isPgSingleRelationField, pgRelationDetails } = context.scope;
// See if the field was defined to be a single relation field
// See if the field was defined for a singular relation
if (isPgSingleRelationField && pgRelationDetails) {
// If so, extract details about the relation
const { codec, relationName } = pgRelationDetails;
Expand Down
8 changes: 6 additions & 2 deletions postgraphile/website/postgraphile/errors/2rc.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@ title: Two resources conflicted

You're probably here because you just received an error like:

`Error: Attempted to add a second resource named 'foo' (first represented function accepting 0 parameters and returning SQL type '"bool"', second represents table/view/etc called '"public"."foo"')
Details: https://err.red/p2rc`
```
Error: Attempted to add a second resource named 'foo':
First represented a function accepting 0 parameters and returning SQL type '"bool"'.
Second represents a table/view/etc called '"public"."foo"'.
Details: https://err.red/p2rc
```

This happens when PostGraphile is building the
[resources](../registry.md#resources) for your schema, and the inflection rules
Expand Down
52 changes: 52 additions & 0 deletions postgraphile/website/postgraphile/errors/nc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
---
title: Naming conflict
---

You're probably here because you just received an error like:

```
Error: A naming conflict has occurred - two entities have tried to define the same key 'task'.
The first entity was:
Adding 'task' attribute field to GraphQL type 'Subtask' (representing PgCodec 'subtask')
The second entity was:
Adding field to GraphQL type 'Subtask' for singular relation 'taskByMyTask'
Details: https://err.red/pnc
```

This happens when PostGraphile tries to add an entry to an object, where that
object already has an entry with that name. There is a very large number of
circumstances under which this can happen since the `build.extend` method is
used to avoid conflicts throughout the PostGraphile schema building process:
when creating codecs, resources or relations; when adding attributes; when
defining GraphQL fields, arguments or enum values; and much more.

Fortunately we try and give you more details about how the error has come
about by detailing the key (`'task'` above) that has conflicted, and where the
first and second conflicting entities originated from.

When reading about the entities, you should keep in mind that codec/PgCodec,
resource/PgResource, and relation/PgCodecRelation relate to the concepts
described in the [registry documentation](../registry.md).

A common situation where this would occur is where you have two different
things (e.g. a column and a relationship) that are trying to be assigned to the
same field name in the GraphQL schema. This is particularly common when using
`@graphile/simplify-inflection` because it deliberately shortens the names of
relations for better ergonomics (e.g. `userByAuthorId` might become simply
`author`), at the risk of causing more conflicts - this is the main reason this
preset isn't enabled by default.

Another common situation is where you have two things of the same type (e.g.
two columns) whose names are made the same after inflection (e.g. columns named
`thing_2name`, `thing2_name`, `thing2name` and `thing2Name` would all transform
to a GraphQL field called `thing2Name` in the default inflectors).

To resolve the issue, you should either:

1. use a [smart tag](../smart-tags.md) to assign a different name or field name to one or both of the entities, or
2. use a custom inflector to change the way the names are generated for the entities, or
3. do something else suitable for the situation.

If you really are not sure what to do, please come ask us in the
#help-and-support channel on our Discord at https://discord.gg/graphile - we
might even add the solution to this page for future users!
2 changes: 1 addition & 1 deletion postgraphile/website/postgraphile/why-nullable.md
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ const NonNullRelationsPlugin: GraphileConfig.Plugin = {
} = build;
// Extract details about why this field was defined.
const { isPgSingleRelationField, pgRelationDetails } = context.scope;
// See if the field was defined to be a single relation field
// See if the field was defined for a singular relation
if (isPgSingleRelationField && pgRelationDetails) {
// If so, extract details about the relation
const { codec, relationName } = pgRelationDetails;
Expand Down

0 comments on commit 16881f5

Please sign in to comment.