graphile-settings 6.5.2 → 6.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/esm/plugins/index.d.ts +1 -1
  2. package/esm/plugins/meta-schema.d.ts +3 -18
  3. package/esm/plugins/meta-schema.js +3 -19
  4. package/package.json +3 -2
  5. package/plugins/index.d.ts +1 -1
  6. package/plugins/meta-schema.d.ts +3 -18
  7. package/plugins/meta-schema.js +11 -16
  8. package/esm/plugins/meta-schema/cache.d.ts +0 -4
  9. package/esm/plugins/meta-schema/cache.js +0 -7
  10. package/esm/plugins/meta-schema/constraint-meta-builders.d.ts +0 -13
  11. package/esm/plugins/meta-schema/constraint-meta-builders.js +0 -51
  12. package/esm/plugins/meta-schema/encoding-meta-builders.d.ts +0 -2
  13. package/esm/plugins/meta-schema/encoding-meta-builders.js +0 -84
  14. package/esm/plugins/meta-schema/graphql-meta-field.d.ts +0 -4
  15. package/esm/plugins/meta-schema/graphql-meta-field.js +0 -314
  16. package/esm/plugins/meta-schema/inflection-utils.d.ts +0 -4
  17. package/esm/plugins/meta-schema/inflection-utils.js +0 -20
  18. package/esm/plugins/meta-schema/name-meta-builders.d.ts +0 -4
  19. package/esm/plugins/meta-schema/name-meta-builders.js +0 -38
  20. package/esm/plugins/meta-schema/plugin.d.ts +0 -2
  21. package/esm/plugins/meta-schema/plugin.js +0 -23
  22. package/esm/plugins/meta-schema/relation-meta-builders.d.ts +0 -8
  23. package/esm/plugins/meta-schema/relation-meta-builders.js +0 -119
  24. package/esm/plugins/meta-schema/scope-meta-builders.d.ts +0 -15
  25. package/esm/plugins/meta-schema/scope-meta-builders.js +0 -40
  26. package/esm/plugins/meta-schema/storage-search-meta-builders.d.ts +0 -29
  27. package/esm/plugins/meta-schema/storage-search-meta-builders.js +0 -180
  28. package/esm/plugins/meta-schema/table-meta-builder.d.ts +0 -2
  29. package/esm/plugins/meta-schema/table-meta-builder.js +0 -99
  30. package/esm/plugins/meta-schema/table-meta-context.d.ts +0 -13
  31. package/esm/plugins/meta-schema/table-meta-context.js +0 -11
  32. package/esm/plugins/meta-schema/table-resource-utils.d.ts +0 -12
  33. package/esm/plugins/meta-schema/table-resource-utils.js +0 -50
  34. package/esm/plugins/meta-schema/type-mappings.d.ts +0 -7
  35. package/esm/plugins/meta-schema/type-mappings.js +0 -100
  36. package/esm/plugins/meta-schema/types.d.ts +0 -325
  37. package/esm/plugins/meta-schema/types.js +0 -1
  38. package/plugins/meta-schema/cache.d.ts +0 -4
  39. package/plugins/meta-schema/cache.js +0 -12
  40. package/plugins/meta-schema/constraint-meta-builders.d.ts +0 -13
  41. package/plugins/meta-schema/constraint-meta-builders.js +0 -58
  42. package/plugins/meta-schema/encoding-meta-builders.d.ts +0 -2
  43. package/plugins/meta-schema/encoding-meta-builders.js +0 -87
  44. package/plugins/meta-schema/graphql-meta-field.d.ts +0 -4
  45. package/plugins/meta-schema/graphql-meta-field.js +0 -317
  46. package/plugins/meta-schema/inflection-utils.d.ts +0 -4
  47. package/plugins/meta-schema/inflection-utils.js +0 -25
  48. package/plugins/meta-schema/name-meta-builders.d.ts +0 -4
  49. package/plugins/meta-schema/name-meta-builders.js +0 -43
  50. package/plugins/meta-schema/plugin.d.ts +0 -2
  51. package/plugins/meta-schema/plugin.js +0 -26
  52. package/plugins/meta-schema/relation-meta-builders.d.ts +0 -8
  53. package/plugins/meta-schema/relation-meta-builders.js +0 -124
  54. package/plugins/meta-schema/scope-meta-builders.d.ts +0 -15
  55. package/plugins/meta-schema/scope-meta-builders.js +0 -43
  56. package/plugins/meta-schema/storage-search-meta-builders.d.ts +0 -29
  57. package/plugins/meta-schema/storage-search-meta-builders.js +0 -186
  58. package/plugins/meta-schema/table-meta-builder.d.ts +0 -2
  59. package/plugins/meta-schema/table-meta-builder.js +0 -102
  60. package/plugins/meta-schema/table-meta-context.d.ts +0 -13
  61. package/plugins/meta-schema/table-meta-context.js +0 -15
  62. package/plugins/meta-schema/table-resource-utils.d.ts +0 -12
  63. package/plugins/meta-schema/table-resource-utils.js +0 -60
  64. package/plugins/meta-schema/type-mappings.d.ts +0 -7
  65. package/plugins/meta-schema/type-mappings.js +0 -104
  66. package/plugins/meta-schema/types.d.ts +0 -325
  67. package/plugins/meta-schema/types.js +0 -2
@@ -1,4 +0,0 @@
1
- import type { MetaInflection, PgCodec } from './types';
2
- export declare function safeInflection<T>(fn: () => T, fallback: T): T;
3
- export declare function createAttributeInflector(inflection: MetaInflection): (attrName: string, codec: PgCodec) => string;
4
- export declare function fallbackTableType(codecName: string): string;
@@ -1,20 +0,0 @@
1
- export function safeInflection(fn, fallback) {
2
- try {
3
- return fn() ?? fallback;
4
- }
5
- catch {
6
- return fallback;
7
- }
8
- }
9
- export function createAttributeInflector(inflection) {
10
- return (attrName, codec) => {
11
- const attributeName = safeInflection(() => inflection._attributeName?.({ attributeName: attrName, codec }), attrName);
12
- return safeInflection(() => inflection.camelCase?.(attributeName), attributeName);
13
- };
14
- }
15
- export function fallbackTableType(codecName) {
16
- return codecName
17
- .replace(/_/g, ' ')
18
- .replace(/\b\w/g, (char) => char.toUpperCase())
19
- .replace(/ /g, '');
20
- }
@@ -1,4 +0,0 @@
1
- import type { InflectionMeta, MetaBuild, PgCodec, PgTableResource, PgUnique, QueryMeta } from './types';
2
- export declare function resolveTableType(build: MetaBuild, codec: PgCodec): string;
3
- export declare function buildInflectionMeta(resource: PgTableResource, tableType: string, build: MetaBuild): InflectionMeta;
4
- export declare function buildQueryMeta(resource: PgTableResource, uniques: PgUnique[], tableType: string, build: MetaBuild): QueryMeta;
@@ -1,38 +0,0 @@
1
- import { fallbackTableType, safeInflection } from './inflection-utils';
2
- export function resolveTableType(build, codec) {
3
- return safeInflection(() => build.inflection.tableType(codec), fallbackTableType(codec.name));
4
- }
5
- export function buildInflectionMeta(resource, tableType, build) {
6
- const inflection = build.inflection;
7
- return {
8
- tableType,
9
- allRows: safeInflection(() => inflection.allRows?.(resource), `${tableType.toLowerCase()}s`),
10
- connection: safeInflection(() => inflection.connectionType?.(tableType), `${tableType}Connection`),
11
- edge: safeInflection(() => inflection.edgeType?.(tableType), `${tableType}Edge`),
12
- filterType: safeInflection(() => inflection.filterType?.(tableType), `${tableType}Filter`),
13
- orderByType: safeInflection(() => inflection.orderByType?.(tableType), `${tableType}OrderBy`),
14
- conditionType: safeInflection(() => inflection.conditionType?.(tableType), `${tableType}Condition`),
15
- patchType: safeInflection(() => inflection.patchType?.(tableType), `${tableType}Patch`),
16
- createInputType: safeInflection(() => inflection.createInputType?.(resource), `Create${tableType}Input`),
17
- createPayloadType: safeInflection(() => inflection.createPayloadType?.(resource), `Create${tableType}Payload`),
18
- updatePayloadType: safeInflection(() => inflection.updatePayloadType?.(resource), `Update${tableType}Payload`),
19
- deletePayloadType: safeInflection(() => inflection.deletePayloadType?.(resource), `Delete${tableType}Payload`),
20
- };
21
- }
22
- export function buildQueryMeta(resource, uniques, tableType, build) {
23
- const inflection = build.inflection;
24
- const hasPrimaryKey = uniques.some((unique) => unique.isPrimary);
25
- return {
26
- all: safeInflection(() => inflection.allRows?.(resource), `${tableType.toLowerCase()}s`),
27
- one: hasPrimaryKey
28
- ? safeInflection(() => inflection.tableFieldName?.(resource), tableType.toLowerCase())
29
- : null,
30
- create: safeInflection(() => inflection.createField?.(resource), `create${tableType}`),
31
- update: hasPrimaryKey
32
- ? safeInflection(() => inflection.updateByKeys?.(resource), `update${tableType}`)
33
- : null,
34
- delete: hasPrimaryKey
35
- ? safeInflection(() => inflection.deleteByKeys?.(resource), `delete${tableType}`)
36
- : null,
37
- };
38
- }
@@ -1,2 +0,0 @@
1
- import type { GraphileConfig } from 'graphile-config';
2
- export declare const MetaSchemaPlugin: GraphileConfig.Plugin;
@@ -1,23 +0,0 @@
1
- import { getCachedTablesMeta, setCachedTablesMeta } from './cache';
2
- import { extendQueryWithMetaField } from './graphql-meta-field';
3
- import { collectTablesMeta } from './table-meta-builder';
4
- export const MetaSchemaPlugin = {
5
- name: 'MetaSchemaPlugin',
6
- version: '1.0.0',
7
- description: 'Exposes _meta query for database schema introspection',
8
- schema: {
9
- hooks: {
10
- init(input, rawBuild) {
11
- const build = rawBuild;
12
- setCachedTablesMeta(collectTablesMeta(build));
13
- return input;
14
- },
15
- GraphQLObjectType_fields(rawFields, _rawBuild, rawContext) {
16
- const context = rawContext;
17
- if (context.Self?.name !== 'Query')
18
- return rawFields;
19
- return extendQueryWithMetaField(rawFields, getCachedTablesMeta());
20
- },
21
- },
22
- },
23
- };
@@ -1,8 +0,0 @@
1
- import { type BuildContext } from './table-meta-context';
2
- import type { BelongsToRelation, HasRelation, ManyToManyRelation, PgAttribute, PgCodec, PgRelation, PgTableResource, PgUnique } from './types';
3
- export declare function buildBelongsToRelations(codec: PgCodec, attributes: Record<string, PgAttribute>, uniques: PgUnique[], relations: Record<string, PgRelation>, context: BuildContext): BelongsToRelation[];
4
- export declare function buildReverseRelations(codec: PgCodec, attributes: Record<string, PgAttribute>, relations: Record<string, PgRelation>, context: BuildContext): {
5
- hasOne: HasRelation[];
6
- hasMany: HasRelation[];
7
- };
8
- export declare function buildManyToManyRelations(resource: PgTableResource, codec: PgCodec, context: BuildContext): ManyToManyRelation[];
@@ -1,119 +0,0 @@
1
- import { safeInflection } from './inflection-utils';
2
- import { buildForeignKeyConstraint, } from './constraint-meta-builders';
3
- import { buildFieldList } from './table-meta-context';
4
- import { getRelation, getResourceCodec, getUniques, sameAttributes, } from './table-resource-utils';
5
- function isRecord(value) {
6
- return typeof value === 'object' && value !== null;
7
- }
8
- export function buildBelongsToRelations(codec, attributes, uniques, relations, context) {
9
- const belongsTo = [];
10
- for (const [relationName, relation] of Object.entries(relations)) {
11
- // PostGraphile only sets isReferencee when true (reverse FK);
12
- // forward relations have isReferencee undefined, not false.
13
- if (relation.isReferencee)
14
- continue;
15
- const localAttributes = relation.localAttributes || [];
16
- const isUnique = uniques.some((unique) => sameAttributes(unique.attributes, localAttributes));
17
- const remoteCodec = relation.remoteResource?.codec;
18
- belongsTo.push({
19
- fieldName: relationName,
20
- isUnique,
21
- type: remoteCodec?.name || null,
22
- keys: buildFieldList(localAttributes, codec, attributes, context),
23
- references: { name: remoteCodec?.name || 'unknown' },
24
- });
25
- }
26
- return belongsTo;
27
- }
28
- export function buildReverseRelations(codec, attributes, relations, context) {
29
- const hasOne = [];
30
- const hasMany = [];
31
- for (const [relationName, relation] of Object.entries(relations)) {
32
- if (relation.isReferencee !== true)
33
- continue;
34
- const remoteUniques = getUniques(relation.remoteResource || {});
35
- const remoteAttributes = relation.remoteAttributes || [];
36
- const isUnique = remoteUniques.some((unique) => sameAttributes(unique.attributes, remoteAttributes));
37
- const remoteCodec = relation.remoteResource?.codec;
38
- const meta = {
39
- fieldName: relationName,
40
- isUnique,
41
- type: remoteCodec?.name || null,
42
- keys: buildFieldList(relation.localAttributes || [], codec, attributes, context),
43
- referencedBy: { name: remoteCodec?.name || 'unknown' },
44
- };
45
- if (isUnique) {
46
- hasOne.push(meta);
47
- }
48
- else {
49
- hasMany.push(meta);
50
- }
51
- }
52
- return { hasOne, hasMany };
53
- }
54
- function isManyToManyDetails(value) {
55
- if (!isRecord(value))
56
- return false;
57
- return (isRecord(value.leftTable) &&
58
- isRecord(value.junctionTable) &&
59
- isRecord(value.rightTable) &&
60
- typeof value.leftRelationName === 'string' &&
61
- typeof value.rightRelationName === 'string');
62
- }
63
- function parseManyToManyRelationships(value) {
64
- if (!Array.isArray(value))
65
- return [];
66
- return value.filter(isManyToManyDetails);
67
- }
68
- function getManyToManyRelationships(build, tableResource, codec) {
69
- const relationshipsByResource = build.pgManyToManyRealtionshipsByResource;
70
- if (!(relationshipsByResource instanceof Map))
71
- return [];
72
- const direct = parseManyToManyRelationships(relationshipsByResource.get(tableResource));
73
- if (direct.length > 0)
74
- return direct;
75
- for (const [leftTable, relationships] of relationshipsByResource.entries()) {
76
- const details = parseManyToManyRelationships(relationships);
77
- if (details.length === 0 || !isRecord(leftTable))
78
- continue;
79
- if (leftTable.codec === codec) {
80
- return details;
81
- }
82
- }
83
- return [];
84
- }
85
- function buildManyToManyRelation(details, context) {
86
- const leftCodec = getResourceCodec(details.leftTable);
87
- const junctionCodec = getResourceCodec(details.junctionTable);
88
- const rightCodec = getResourceCodec(details.rightTable);
89
- if (!leftCodec || !junctionCodec || !rightCodec)
90
- return null;
91
- const leftRelation = getRelation(details.leftTable, details.leftRelationName);
92
- const junctionRightRelation = getRelation(details.junctionTable, details.rightRelationName);
93
- if (!leftRelation || !junctionRightRelation)
94
- return null;
95
- const leftJunctionAttributes = leftRelation.remoteAttributes || [];
96
- const leftTableAttributes = leftRelation.localAttributes || [];
97
- const rightJunctionAttributes = junctionRightRelation.localAttributes || [];
98
- const rightTableAttributes = junctionRightRelation.remoteAttributes || [];
99
- const relationFieldName = safeInflection(() => context.build.inflection._manyToManyRelation?.(details), details.rightRelationName || rightCodec.name || null);
100
- const junctionLeftConstraint = buildForeignKeyConstraint(details.leftRelationName || `${junctionCodec.name}_${leftCodec.name}_fkey`, junctionCodec, junctionCodec.attributes, leftJunctionAttributes, leftCodec, leftCodec.attributes, leftTableAttributes, context);
101
- const junctionRightConstraint = buildForeignKeyConstraint(details.rightRelationName || `${junctionCodec.name}_${rightCodec.name}_fkey`, junctionCodec, junctionCodec.attributes, rightJunctionAttributes, rightCodec, rightCodec.attributes, rightTableAttributes, context);
102
- return {
103
- fieldName: relationFieldName,
104
- type: rightCodec.name || null,
105
- junctionTable: { name: junctionCodec.name || 'unknown' },
106
- junctionLeftConstraint,
107
- junctionLeftKeyAttributes: buildFieldList(leftJunctionAttributes, junctionCodec, junctionCodec.attributes, context),
108
- junctionRightConstraint,
109
- junctionRightKeyAttributes: buildFieldList(rightJunctionAttributes, junctionCodec, junctionCodec.attributes, context),
110
- leftKeyAttributes: buildFieldList(leftTableAttributes, leftCodec, leftCodec.attributes, context),
111
- rightKeyAttributes: buildFieldList(rightTableAttributes, rightCodec, rightCodec.attributes, context),
112
- rightTable: { name: rightCodec.name || 'unknown' },
113
- };
114
- }
115
- export function buildManyToManyRelations(resource, codec, context) {
116
- return getManyToManyRelationships(context.build, resource, codec)
117
- .map((details) => buildManyToManyRelation(details, context))
118
- .filter((relation) => relation !== null);
119
- }
@@ -1,15 +0,0 @@
1
- import type { PgCodec, ScopeMeta } from './types';
2
- /**
3
- * Detect provisioning scope metadata for a table.
4
- *
5
- * The `@scope` smart tag emitted by the constructive-db generators is the sole
6
- * source of truth. `apply_scope_fields` knows the exact scope, tier, key column,
7
- * and entity table, and emits them via
8
- * `metaschema.append_table_smart_tags(id, { scope, scopeTier, scopeKey, scopeEntityTable })`.
9
- * PostGraphile surfaces these as `codec.extensions.tags.*`.
10
- *
11
- * There is NO inference from column names — a table without the tag returns
12
- * `null` (the same convention as every other nullable metadata block). This
13
- * avoids guessing key columns, whose names are chosen freely by each generator.
14
- */
15
- export declare function buildScopeMeta(codec: PgCodec, inflectAttr: (attrName: string, codec: PgCodec) => string): ScopeMeta | null;
@@ -1,40 +0,0 @@
1
- const VALID_TIERS = new Set(['global', 'database', 'entity']);
2
- function readString(value) {
3
- return typeof value === 'string' && value.length > 0 ? value : null;
4
- }
5
- /**
6
- * Detect provisioning scope metadata for a table.
7
- *
8
- * The `@scope` smart tag emitted by the constructive-db generators is the sole
9
- * source of truth. `apply_scope_fields` knows the exact scope, tier, key column,
10
- * and entity table, and emits them via
11
- * `metaschema.append_table_smart_tags(id, { scope, scopeTier, scopeKey, scopeEntityTable })`.
12
- * PostGraphile surfaces these as `codec.extensions.tags.*`.
13
- *
14
- * There is NO inference from column names — a table without the tag returns
15
- * `null` (the same convention as every other nullable metadata block). This
16
- * avoids guessing key columns, whose names are chosen freely by each generator.
17
- */
18
- export function buildScopeMeta(codec, inflectAttr) {
19
- const tags = codec.extensions?.tags;
20
- const scope = readString(tags?.scope);
21
- if (!scope)
22
- return null;
23
- const rawTier = readString(tags.scopeTier);
24
- const tier = rawTier && VALID_TIERS.has(rawTier)
25
- ? rawTier
26
- : null;
27
- if (!tier) {
28
- throw new Error(`@scope tag on codec "${codec.name}" is missing a valid scopeTier ` +
29
- `(expected one of global|database|entity, got ${JSON.stringify(rawTier)})`);
30
- }
31
- const keyColumn = readString(tags.scopeKey);
32
- const entityTable = readString(tags.scopeEntityTable);
33
- return {
34
- scope,
35
- tier,
36
- keyColumn: keyColumn ? inflectAttr(keyColumn, codec) : null,
37
- entityTable,
38
- source: 'smartTag'
39
- };
40
- }
@@ -1,29 +0,0 @@
1
- import type { I18nMeta, PgCodec, RealtimeMeta, SearchMeta, StorageMeta } from './types';
2
- /**
3
- * Detect storage metadata from a codec's smart tags.
4
- * Storage tables are identified by @storageFiles and @storageBuckets smart tags.
5
- */
6
- export declare function buildStorageMeta(codec: PgCodec): StorageMeta | null;
7
- /**
8
- * Detect search metadata from a codec's columns and smart tags.
9
- *
10
- * Looks for:
11
- * - tsvector columns (full-text search)
12
- * - vector columns (pgvector semantic search)
13
- * - @searchConfig smart tag (per-table search configuration)
14
- * - @bm25Index smart tag on columns (BM25 search)
15
- * - @trgmSearch smart tag (trigram search)
16
- */
17
- export declare function buildSearchMeta(codec: PgCodec, _build: unknown, inflectAttr: (attrName: string, codec: PgCodec) => string): SearchMeta | null;
18
- /**
19
- * Detect i18n metadata from a codec's @i18n smart tag.
20
- * The @i18n tag value is the name of the translation table.
21
- * Translatable fields are discovered by matching text/citext columns
22
- * between the base table and the translation table codec.
23
- */
24
- export declare function buildI18nMeta(codec: PgCodec, build: unknown, inflectAttr: (attrName: string, codec: PgCodec) => string): I18nMeta | null;
25
- /**
26
- * Detect realtime metadata from a codec's @realtime smart tag.
27
- * Tables tagged with @realtime get subscription fields generated.
28
- */
29
- export declare function buildRealtimeMeta(codec: PgCodec, build: unknown): RealtimeMeta | null;
@@ -1,180 +0,0 @@
1
- /**
2
- * Detect storage metadata from a codec's smart tags.
3
- * Storage tables are identified by @storageFiles and @storageBuckets smart tags.
4
- */
5
- export function buildStorageMeta(codec) {
6
- const tags = codec.extensions?.tags;
7
- if (!tags)
8
- return null;
9
- const isFilesTable = !!tags.storageFiles;
10
- const isBucketsTable = !!tags.storageBuckets;
11
- if (!isFilesTable && !isBucketsTable)
12
- return null;
13
- return {
14
- isFilesTable,
15
- isBucketsTable,
16
- };
17
- }
18
- /**
19
- * Detect search metadata from a codec's columns and smart tags.
20
- *
21
- * Looks for:
22
- * - tsvector columns (full-text search)
23
- * - vector columns (pgvector semantic search)
24
- * - @searchConfig smart tag (per-table search configuration)
25
- * - @bm25Index smart tag on columns (BM25 search)
26
- * - @trgmSearch smart tag (trigram search)
27
- */
28
- export function buildSearchMeta(codec, _build, inflectAttr) {
29
- const attributes = codec.attributes;
30
- if (!attributes)
31
- return null;
32
- const tags = codec.extensions?.tags || {};
33
- const columns = [];
34
- const algorithmSet = new Set();
35
- // Detect columns by type
36
- for (const [attrName, attr] of Object.entries(attributes)) {
37
- const pgType = attr?.codec?.name;
38
- if (!pgType)
39
- continue;
40
- const inflectedName = inflectAttr(attrName, codec);
41
- if (pgType === 'tsvector') {
42
- columns.push({ name: inflectedName, algorithm: 'tsvector' });
43
- algorithmSet.add('tsvector');
44
- }
45
- else if (pgType === 'vector') {
46
- columns.push({ name: inflectedName, algorithm: 'vector' });
47
- algorithmSet.add('vector');
48
- }
49
- // Check per-column @bm25Index tag
50
- const attrTags = attr?.extensions?.tags;
51
- if (attrTags?.bm25Index) {
52
- columns.push({ name: inflectedName, algorithm: 'bm25' });
53
- algorithmSet.add('bm25');
54
- }
55
- }
56
- // Check for table-level @trgmSearch tag
57
- if (tags.trgmSearch) {
58
- algorithmSet.add('trgm');
59
- // trgm operates on text columns — detect which ones
60
- for (const [attrName, attr] of Object.entries(attributes)) {
61
- const pgType = attr?.codec?.name;
62
- if (pgType === 'text' || pgType === 'varchar' || pgType === 'citext') {
63
- const attrTags = attr?.extensions?.tags;
64
- if (attrTags?.trgmSearch) {
65
- columns.push({ name: inflectAttr(attrName, codec), algorithm: 'trgm' });
66
- }
67
- }
68
- }
69
- }
70
- // Parse @searchConfig smart tag
71
- const config = parseSearchConfig(tags);
72
- // If nothing search-related was found, return null
73
- if (columns.length === 0 && !config)
74
- return null;
75
- // Determine if unified search is available
76
- // unifiedSearch requires at least one text-compatible adapter (tsvector or bm25)
77
- const hasUnifiedSearch = algorithmSet.has('tsvector') || algorithmSet.has('bm25');
78
- return {
79
- algorithms: Array.from(algorithmSet).sort(),
80
- columns,
81
- hasUnifiedSearch,
82
- config,
83
- };
84
- }
85
- /**
86
- * Detect i18n metadata from a codec's @i18n smart tag.
87
- * The @i18n tag value is the name of the translation table.
88
- * Translatable fields are discovered by matching text/citext columns
89
- * between the base table and the translation table codec.
90
- */
91
- export function buildI18nMeta(codec, build, inflectAttr) {
92
- const tags = codec.extensions?.tags;
93
- if (!tags)
94
- return null;
95
- const i18nTag = tags.i18n;
96
- if (typeof i18nTag !== 'string' || i18nTag.length === 0)
97
- return null;
98
- const attributes = codec.attributes;
99
- if (!attributes)
100
- return { translationTable: i18nTag, translatableFields: [] };
101
- // Discover translatable fields: text/citext columns on the base table
102
- const allowedTypes = ['text', 'citext'];
103
- const translatableFields = [];
104
- // Try to find the translation codec to get the intersection of fields
105
- const pgRegistry = build?.input?.pgRegistry;
106
- let translationAttrs = null;
107
- if (pgRegistry?.pgResources) {
108
- for (const r of Object.values(pgRegistry.pgResources)) {
109
- const sqlName = r?.codec?.extensions?.pg?.name ?? r?.codec?.name;
110
- if (sqlName === i18nTag) {
111
- const tAttrs = r?.codec?.attributes;
112
- if (tAttrs) {
113
- translationAttrs = new Set(Object.keys(tAttrs));
114
- }
115
- break;
116
- }
117
- }
118
- }
119
- for (const [attrName, attr] of Object.entries(attributes)) {
120
- const pgType = attr?.codec?.name;
121
- if (!pgType || !allowedTypes.includes(pgType))
122
- continue;
123
- // If we found the translation table, only include columns that exist there too
124
- if (translationAttrs && !translationAttrs.has(attrName))
125
- continue;
126
- translatableFields.push({
127
- name: inflectAttr(attrName, codec),
128
- type: pgType,
129
- });
130
- }
131
- return {
132
- translationTable: i18nTag,
133
- translatableFields,
134
- };
135
- }
136
- /**
137
- * Detect realtime metadata from a codec's @realtime smart tag.
138
- * Tables tagged with @realtime get subscription fields generated.
139
- */
140
- export function buildRealtimeMeta(codec, build) {
141
- const tags = codec.extensions?.tags;
142
- if (!tags?.realtime)
143
- return null;
144
- const typeName = build.inflection?.tableType?.(codec);
145
- if (!typeName)
146
- return null;
147
- return {
148
- subscriptionFieldName: `on${typeName}Changed`,
149
- };
150
- }
151
- function parseSearchConfig(tags) {
152
- const raw = tags.searchConfig;
153
- if (!raw)
154
- return null;
155
- let parsed;
156
- if (typeof raw === 'string') {
157
- try {
158
- parsed = JSON.parse(raw);
159
- }
160
- catch {
161
- return null;
162
- }
163
- }
164
- else if (typeof raw === 'object') {
165
- parsed = raw;
166
- }
167
- else {
168
- return null;
169
- }
170
- return {
171
- weights: parsed.weights && typeof parsed.weights === 'object'
172
- ? parsed.weights
173
- : null,
174
- boostRecent: !!parsed.boost_recent,
175
- boostRecencyField: parsed.boost_recency_field || null,
176
- boostRecencyDecay: typeof parsed.boost_recency_decay === 'number'
177
- ? parsed.boost_recency_decay
178
- : null,
179
- };
180
- }
@@ -1,2 +0,0 @@
1
- import type { MetaBuild, TableMeta } from './types';
2
- export declare function collectTablesMeta(build: MetaBuild): TableMeta[];
@@ -1,99 +0,0 @@
1
- import { buildForeignKeyConstraints, buildIndexes, buildPrimaryKey, buildUniqueConstraints } from './constraint-meta-builders';
2
- import { buildInflectionMeta, buildQueryMeta, resolveTableType } from './name-meta-builders';
3
- import { buildBelongsToRelations, buildManyToManyRelations, buildReverseRelations } from './relation-meta-builders';
4
- import { buildScopeMeta } from './scope-meta-builders';
5
- import { buildI18nMeta, buildRealtimeMeta, buildSearchMeta, buildStorageMeta } from './storage-search-meta-builders';
6
- import { createBuildContext } from './table-meta-context';
7
- import { getConfiguredSchemas, getRelations, getSchemaName, getUniques, isTableResource } from './table-resource-utils';
8
- import { buildFieldMeta } from './type-mappings';
9
- function buildTableMeta(resource, schemaName, context) {
10
- const codec = resource.codec;
11
- const attributes = codec.attributes;
12
- const uniques = getUniques(resource);
13
- const relations = getRelations(resource);
14
- // Compute PK and FK attribute name sets for field metadata
15
- const pkAttrNames = new Set();
16
- const fkAttrNames = new Set();
17
- for (const unique of uniques) {
18
- if (unique.isPrimary) {
19
- for (const attrName of unique.attributes)
20
- pkAttrNames.add(attrName);
21
- }
22
- }
23
- for (const relation of Object.values(relations)) {
24
- if (relation.isReferencee)
25
- continue;
26
- for (const attrName of relation.localAttributes || [])
27
- fkAttrNames.add(attrName);
28
- }
29
- const fields = Object.entries(attributes).map(([attrName, attr]) => buildFieldMeta(context.inflectAttr(attrName, codec), attr, context.build, {
30
- isPrimaryKey: pkAttrNames.has(attrName),
31
- isForeignKey: fkAttrNames.has(attrName)
32
- }));
33
- const indexes = buildIndexes(codec, attributes, uniques, context);
34
- const primaryKey = buildPrimaryKey(codec, attributes, uniques, context);
35
- const uniqueConstraints = buildUniqueConstraints(codec, attributes, uniques, context);
36
- const foreignKeyConstraints = buildForeignKeyConstraints(codec, attributes, relations, context);
37
- const constraints = {
38
- primaryKey,
39
- unique: uniqueConstraints,
40
- foreignKey: foreignKeyConstraints
41
- };
42
- const belongsTo = buildBelongsToRelations(codec, attributes, uniques, relations, context);
43
- const { hasOne, hasMany } = buildReverseRelations(codec, attributes, relations, context);
44
- const manyToMany = buildManyToManyRelations(resource, codec, context);
45
- const relationsMeta = {
46
- belongsTo,
47
- has: [...hasOne, ...hasMany],
48
- hasOne,
49
- hasMany,
50
- manyToMany
51
- };
52
- const tableType = resolveTableType(context.build, codec);
53
- const storage = buildStorageMeta(codec);
54
- const search = buildSearchMeta(codec, context.build, context.inflectAttr);
55
- const i18n = buildI18nMeta(codec, context.build, context.inflectAttr);
56
- const realtime = buildRealtimeMeta(codec, context.build);
57
- const scope = buildScopeMeta(codec, context.inflectAttr);
58
- return {
59
- name: tableType,
60
- schemaName,
61
- fields,
62
- indexes,
63
- constraints,
64
- foreignKeyConstraints,
65
- primaryKeyConstraints: primaryKey ? [primaryKey] : [],
66
- uniqueConstraints,
67
- relations: relationsMeta,
68
- inflection: buildInflectionMeta(resource, tableType, context.build),
69
- query: buildQueryMeta(resource, uniques, tableType, context.build),
70
- storage,
71
- search,
72
- i18n,
73
- realtime,
74
- scope
75
- };
76
- }
77
- export function collectTablesMeta(build) {
78
- const configuredSchemas = getConfiguredSchemas(build);
79
- const context = createBuildContext(build);
80
- const seenCodecs = new Set();
81
- const tablesMeta = [];
82
- for (const resource of Object.values(build.input.pgRegistry.pgResources || {})) {
83
- if (!isTableResource(resource))
84
- continue;
85
- const codec = resource.codec;
86
- if (seenCodecs.has(codec))
87
- continue;
88
- seenCodecs.add(codec);
89
- const schemaName = getSchemaName(resource);
90
- if (!schemaName)
91
- continue;
92
- if (configuredSchemas.length > 0 &&
93
- !configuredSchemas.includes(schemaName)) {
94
- continue;
95
- }
96
- tablesMeta.push(buildTableMeta(resource, schemaName, context));
97
- }
98
- return tablesMeta;
99
- }
@@ -1,13 +0,0 @@
1
- import type { FieldMeta, MetaBuild, PgAttribute, PgCodec, PgTableResource } from './types';
2
- export type AttributeInflector = (attrName: string, codec: PgCodec) => string;
3
- export interface BuildContext {
4
- build: MetaBuild;
5
- inflectAttr: AttributeInflector;
6
- }
7
- export type TableResourceWithCodec = PgTableResource & {
8
- codec: PgCodec & {
9
- attributes: Record<string, PgAttribute>;
10
- };
11
- };
12
- export declare function createBuildContext(build: MetaBuild): BuildContext;
13
- export declare function buildFieldList(attrNames: string[], codec: PgCodec, attributes: Record<string, PgAttribute>, context: BuildContext): FieldMeta[];
@@ -1,11 +0,0 @@
1
- import { createAttributeInflector } from './inflection-utils';
2
- import { buildFieldMeta } from './type-mappings';
3
- export function createBuildContext(build) {
4
- return {
5
- build,
6
- inflectAttr: createAttributeInflector(build.inflection),
7
- };
8
- }
9
- export function buildFieldList(attrNames, codec, attributes, context) {
10
- return attrNames.map((attrName) => buildFieldMeta(context.inflectAttr(attrName, codec), attributes[attrName], context.build));
11
- }
@@ -1,12 +0,0 @@
1
- import type { MetaBuild, PgAttribute, PgCodec, PgRelation, PgTableResource, PgUnique } from './types';
2
- import type { TableResourceWithCodec } from './table-meta-context';
3
- export declare function isTableResource(resource: PgTableResource): resource is TableResourceWithCodec;
4
- export declare function getSchemaName(resource: PgTableResource): string | null;
5
- export declare function getUniques(resource: PgTableResource): PgUnique[];
6
- export declare function getRelations(resource: PgTableResource): Record<string, PgRelation>;
7
- export declare function getRelation(resource: PgTableResource, relationName: string): PgRelation | null;
8
- export declare function sameAttributes(uniqueAttributes: string[] | undefined, relationAttributes: string[] | undefined): boolean;
9
- export declare function getConfiguredSchemas(build: MetaBuild): string[];
10
- export declare function getResourceCodec(resource: PgTableResource): (PgCodec & {
11
- attributes: Record<string, PgAttribute>;
12
- }) | null;