Skip to content

Commit b677569

Browse files
fix: replace duck-typing with @storagefiles smart tag for downloadUrl detection
Uses codec.extensions.tags.storageFiles instead of checking for 6 specific column names. The storage module generator in constructive-db will set this tag on the generated files table via a smart comment.
1 parent 7276344 commit b677569

1 file changed

Lines changed: 13 additions & 17 deletions

File tree

graphile/graphile-presigned-url-plugin/src/download-url-field.ts

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,12 @@
55
* For public files, returns the public URL prefix + key.
66
* For private files, generates a presigned GET URL.
77
*
8-
* This plugin uses the GraphQLObjectType_fields hook to detect file tables
9-
* (by checking for the storage module's files table) and add the computed field.
8+
* Detection: Uses the `@storageFiles` smart tag on the codec (table).
9+
* The storage module generator in constructive-db sets this tag on the
10+
* generated files table via a smart comment:
11+
* COMMENT ON TABLE files IS E'@storageFiles\nStorage files table';
12+
*
13+
* This is explicit and reliable — no duck-typing on column names.
1014
*/
1115

1216
import type { GraphileConfig } from 'graphile-config';
@@ -23,7 +27,8 @@ const log = new Logger('graphile-presigned-url:download-url');
2327
* This is a separate plugin from the main presigned URL plugin because it
2428
* uses the GraphQLObjectType_fields hook (low-level) rather than extendSchema.
2529
* The downloadUrl field needs to be added dynamically to whatever table is
26-
* the storage module's files table, which we discover at schema-build time.
30+
* the storage module's files table, which we discover at schema-build time
31+
* via the `@storageFiles` smart tag.
2732
*/
2833
export function createDownloadUrlPlugin(
2934
options: PresignedUrlPluginOptions,
@@ -34,7 +39,7 @@ export function createDownloadUrlPlugin(
3439
return {
3540
name: 'PresignedUrlDownloadPlugin',
3641
version: '0.1.0',
37-
description: 'Adds downloadUrl computed field to File types',
42+
description: 'Adds downloadUrl computed field to File types tagged with @storageFiles',
3843

3944
schema: {
4045
hooks: {
@@ -48,22 +53,13 @@ export function createDownloadUrlPlugin(
4853
return fields;
4954
}
5055

51-
const attrs = pgCodec.attributes as Record<string, any>;
52-
53-
// Detect if this is a files table by checking for characteristic columns:
54-
// key, content_type, content_hash, status, bucket_id, is_public
55-
const hasKey = 'key' in attrs;
56-
const hasContentType = 'content_type' in attrs;
57-
const hasContentHash = 'content_hash' in attrs;
58-
const hasStatus = 'status' in attrs;
59-
const hasBucketId = 'bucket_id' in attrs;
60-
const hasIsPublic = 'is_public' in attrs;
61-
62-
if (!hasKey || !hasContentType || !hasContentHash || !hasStatus || !hasBucketId || !hasIsPublic) {
56+
// Check for @storageFiles smart tag — set by the storage module generator
57+
const tags = (pgCodec.extensions as any)?.tags;
58+
if (!tags?.storageFiles) {
6359
return fields;
6460
}
6561

66-
log.debug(`Adding downloadUrl field to type: ${pgCodec.name}`);
62+
log.debug(`Adding downloadUrl field to type: ${pgCodec.name} (has @storageFiles tag)`);
6763

6864
const {
6965
graphql: { GraphQLString },

0 commit comments

Comments
 (0)