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.
- package/esm/plugins/index.d.ts +1 -1
- package/esm/plugins/meta-schema.d.ts +3 -18
- package/esm/plugins/meta-schema.js +3 -19
- package/package.json +3 -2
- package/plugins/index.d.ts +1 -1
- package/plugins/meta-schema.d.ts +3 -18
- package/plugins/meta-schema.js +11 -16
- package/esm/plugins/meta-schema/cache.d.ts +0 -4
- package/esm/plugins/meta-schema/cache.js +0 -7
- package/esm/plugins/meta-schema/constraint-meta-builders.d.ts +0 -13
- package/esm/plugins/meta-schema/constraint-meta-builders.js +0 -51
- package/esm/plugins/meta-schema/encoding-meta-builders.d.ts +0 -2
- package/esm/plugins/meta-schema/encoding-meta-builders.js +0 -84
- package/esm/plugins/meta-schema/graphql-meta-field.d.ts +0 -4
- package/esm/plugins/meta-schema/graphql-meta-field.js +0 -314
- package/esm/plugins/meta-schema/inflection-utils.d.ts +0 -4
- package/esm/plugins/meta-schema/inflection-utils.js +0 -20
- package/esm/plugins/meta-schema/name-meta-builders.d.ts +0 -4
- package/esm/plugins/meta-schema/name-meta-builders.js +0 -38
- package/esm/plugins/meta-schema/plugin.d.ts +0 -2
- package/esm/plugins/meta-schema/plugin.js +0 -23
- package/esm/plugins/meta-schema/relation-meta-builders.d.ts +0 -8
- package/esm/plugins/meta-schema/relation-meta-builders.js +0 -119
- package/esm/plugins/meta-schema/scope-meta-builders.d.ts +0 -15
- package/esm/plugins/meta-schema/scope-meta-builders.js +0 -40
- package/esm/plugins/meta-schema/storage-search-meta-builders.d.ts +0 -29
- package/esm/plugins/meta-schema/storage-search-meta-builders.js +0 -180
- package/esm/plugins/meta-schema/table-meta-builder.d.ts +0 -2
- package/esm/plugins/meta-schema/table-meta-builder.js +0 -99
- package/esm/plugins/meta-schema/table-meta-context.d.ts +0 -13
- package/esm/plugins/meta-schema/table-meta-context.js +0 -11
- package/esm/plugins/meta-schema/table-resource-utils.d.ts +0 -12
- package/esm/plugins/meta-schema/table-resource-utils.js +0 -50
- package/esm/plugins/meta-schema/type-mappings.d.ts +0 -7
- package/esm/plugins/meta-schema/type-mappings.js +0 -100
- package/esm/plugins/meta-schema/types.d.ts +0 -325
- package/esm/plugins/meta-schema/types.js +0 -1
- package/plugins/meta-schema/cache.d.ts +0 -4
- package/plugins/meta-schema/cache.js +0 -12
- package/plugins/meta-schema/constraint-meta-builders.d.ts +0 -13
- package/plugins/meta-schema/constraint-meta-builders.js +0 -58
- package/plugins/meta-schema/encoding-meta-builders.d.ts +0 -2
- package/plugins/meta-schema/encoding-meta-builders.js +0 -87
- package/plugins/meta-schema/graphql-meta-field.d.ts +0 -4
- package/plugins/meta-schema/graphql-meta-field.js +0 -317
- package/plugins/meta-schema/inflection-utils.d.ts +0 -4
- package/plugins/meta-schema/inflection-utils.js +0 -25
- package/plugins/meta-schema/name-meta-builders.d.ts +0 -4
- package/plugins/meta-schema/name-meta-builders.js +0 -43
- package/plugins/meta-schema/plugin.d.ts +0 -2
- package/plugins/meta-schema/plugin.js +0 -26
- package/plugins/meta-schema/relation-meta-builders.d.ts +0 -8
- package/plugins/meta-schema/relation-meta-builders.js +0 -124
- package/plugins/meta-schema/scope-meta-builders.d.ts +0 -15
- package/plugins/meta-schema/scope-meta-builders.js +0 -43
- package/plugins/meta-schema/storage-search-meta-builders.d.ts +0 -29
- package/plugins/meta-schema/storage-search-meta-builders.js +0 -186
- package/plugins/meta-schema/table-meta-builder.d.ts +0 -2
- package/plugins/meta-schema/table-meta-builder.js +0 -102
- package/plugins/meta-schema/table-meta-context.d.ts +0 -13
- package/plugins/meta-schema/table-meta-context.js +0 -15
- package/plugins/meta-schema/table-resource-utils.d.ts +0 -12
- package/plugins/meta-schema/table-resource-utils.js +0 -60
- package/plugins/meta-schema/type-mappings.d.ts +0 -7
- package/plugins/meta-schema/type-mappings.js +0 -104
- package/plugins/meta-schema/types.d.ts +0 -325
- 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,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,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;
|