@danielfgray/pg-sourcerer 0.1.0
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/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +104 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +133 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +47 -0
- package/dist/config.js.map +1 -0
- package/dist/errors.d.ts +129 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +41 -0
- package/dist/errors.js.map +1 -0
- package/dist/generate.d.ts +75 -0
- package/dist/generate.d.ts.map +1 -0
- package/dist/generate.js +183 -0
- package/dist/generate.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +62 -0
- package/dist/index.js.map +1 -0
- package/dist/init.d.ts +4 -0
- package/dist/init.d.ts.map +1 -0
- package/dist/init.js +229 -0
- package/dist/init.js.map +1 -0
- package/dist/ir/index.d.ts +7 -0
- package/dist/ir/index.d.ts.map +1 -0
- package/dist/ir/index.js +7 -0
- package/dist/ir/index.js.map +1 -0
- package/dist/ir/relation-graph.d.ts +113 -0
- package/dist/ir/relation-graph.d.ts.map +1 -0
- package/dist/ir/relation-graph.js +232 -0
- package/dist/ir/relation-graph.js.map +1 -0
- package/dist/ir/semantic-ir.d.ts +448 -0
- package/dist/ir/semantic-ir.d.ts.map +1 -0
- package/dist/ir/semantic-ir.js +138 -0
- package/dist/ir/semantic-ir.js.map +1 -0
- package/dist/ir/smart-tags.d.ts +24 -0
- package/dist/ir/smart-tags.d.ts.map +1 -0
- package/dist/ir/smart-tags.js +30 -0
- package/dist/ir/smart-tags.js.map +1 -0
- package/dist/lib/conjure.d.ts +431 -0
- package/dist/lib/conjure.d.ts.map +1 -0
- package/dist/lib/conjure.js +697 -0
- package/dist/lib/conjure.js.map +1 -0
- package/dist/lib/field-utils.d.ts +61 -0
- package/dist/lib/field-utils.d.ts.map +1 -0
- package/dist/lib/field-utils.js +132 -0
- package/dist/lib/field-utils.js.map +1 -0
- package/dist/lib/hex.d.ts +117 -0
- package/dist/lib/hex.d.ts.map +1 -0
- package/dist/lib/hex.js +185 -0
- package/dist/lib/hex.js.map +1 -0
- package/dist/plugins/arktype.d.ts +11 -0
- package/dist/plugins/arktype.d.ts.map +1 -0
- package/dist/plugins/arktype.js +207 -0
- package/dist/plugins/arktype.js.map +1 -0
- package/dist/plugins/effect-model.d.ts +10 -0
- package/dist/plugins/effect-model.d.ts.map +1 -0
- package/dist/plugins/effect-model.js +261 -0
- package/dist/plugins/effect-model.js.map +1 -0
- package/dist/plugins/kysely-queries.d.ts +7 -0
- package/dist/plugins/kysely-queries.d.ts.map +1 -0
- package/dist/plugins/kysely-queries.js +380 -0
- package/dist/plugins/kysely-queries.js.map +1 -0
- package/dist/plugins/sql-queries.d.ts +6 -0
- package/dist/plugins/sql-queries.d.ts.map +1 -0
- package/dist/plugins/sql-queries.js +249 -0
- package/dist/plugins/sql-queries.js.map +1 -0
- package/dist/plugins/types.d.ts +18 -0
- package/dist/plugins/types.d.ts.map +1 -0
- package/dist/plugins/types.js +263 -0
- package/dist/plugins/types.js.map +1 -0
- package/dist/plugins/zod.d.ts +11 -0
- package/dist/plugins/zod.d.ts.map +1 -0
- package/dist/plugins/zod.js +180 -0
- package/dist/plugins/zod.js.map +1 -0
- package/dist/services/artifact-store.d.ts +55 -0
- package/dist/services/artifact-store.d.ts.map +1 -0
- package/dist/services/artifact-store.js +51 -0
- package/dist/services/artifact-store.js.map +1 -0
- package/dist/services/config-loader.d.ts +45 -0
- package/dist/services/config-loader.d.ts.map +1 -0
- package/dist/services/config-loader.js +113 -0
- package/dist/services/config-loader.js.map +1 -0
- package/dist/services/emissions.d.ts +89 -0
- package/dist/services/emissions.d.ts.map +1 -0
- package/dist/services/emissions.js +194 -0
- package/dist/services/emissions.js.map +1 -0
- package/dist/services/file-builder.d.ts +81 -0
- package/dist/services/file-builder.d.ts.map +1 -0
- package/dist/services/file-builder.js +112 -0
- package/dist/services/file-builder.js.map +1 -0
- package/dist/services/file-writer.d.ts +57 -0
- package/dist/services/file-writer.d.ts.map +1 -0
- package/dist/services/file-writer.js +76 -0
- package/dist/services/file-writer.js.map +1 -0
- package/dist/services/inflection.d.ts +227 -0
- package/dist/services/inflection.d.ts.map +1 -0
- package/dist/services/inflection.js +350 -0
- package/dist/services/inflection.js.map +1 -0
- package/dist/services/introspection.d.ts +46 -0
- package/dist/services/introspection.d.ts.map +1 -0
- package/dist/services/introspection.js +99 -0
- package/dist/services/introspection.js.map +1 -0
- package/dist/services/ir-builder.d.ts +46 -0
- package/dist/services/ir-builder.d.ts.map +1 -0
- package/dist/services/ir-builder.js +923 -0
- package/dist/services/ir-builder.js.map +1 -0
- package/dist/services/ir.d.ts +28 -0
- package/dist/services/ir.d.ts.map +1 -0
- package/dist/services/ir.js +25 -0
- package/dist/services/ir.js.map +1 -0
- package/dist/services/pg-types.d.ts +197 -0
- package/dist/services/pg-types.d.ts.map +1 -0
- package/dist/services/pg-types.js +274 -0
- package/dist/services/pg-types.js.map +1 -0
- package/dist/services/plugin-meta.d.ts +33 -0
- package/dist/services/plugin-meta.d.ts.map +1 -0
- package/dist/services/plugin-meta.js +24 -0
- package/dist/services/plugin-meta.js.map +1 -0
- package/dist/services/plugin-runner.d.ts +52 -0
- package/dist/services/plugin-runner.d.ts.map +1 -0
- package/dist/services/plugin-runner.js +182 -0
- package/dist/services/plugin-runner.js.map +1 -0
- package/dist/services/plugin.d.ts +286 -0
- package/dist/services/plugin.d.ts.map +1 -0
- package/dist/services/plugin.js +132 -0
- package/dist/services/plugin.js.map +1 -0
- package/dist/services/smart-tags-parser.d.ts +37 -0
- package/dist/services/smart-tags-parser.d.ts.map +1 -0
- package/dist/services/smart-tags-parser.js +79 -0
- package/dist/services/smart-tags-parser.js.map +1 -0
- package/dist/services/symbols.d.ts +85 -0
- package/dist/services/symbols.d.ts.map +1 -0
- package/dist/services/symbols.js +128 -0
- package/dist/services/symbols.js.map +1 -0
- package/dist/services/type-hints.d.ts +62 -0
- package/dist/services/type-hints.d.ts.map +1 -0
- package/dist/services/type-hints.js +117 -0
- package/dist/services/type-hints.js.map +1 -0
- package/dist/testing.d.ts +77 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +84 -0
- package/dist/testing.js.map +1 -0
- package/package.json +74 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Relation Graph Utilities
|
|
3
|
+
*
|
|
4
|
+
* Utilities for navigating entity relationships in the IR using Effect's Graph module.
|
|
5
|
+
* Useful for query builders, documentation generators, ERD tools, etc.
|
|
6
|
+
*/
|
|
7
|
+
import { Graph, Option } from "effect";
|
|
8
|
+
import type { Relation, ReverseRelation, SemanticIR, TableEntity } from "./semantic-ir.js";
|
|
9
|
+
/**
|
|
10
|
+
* Edge data stored in the relation graph.
|
|
11
|
+
* Represents a foreign key constraint between two entities.
|
|
12
|
+
*/
|
|
13
|
+
export interface RelationEdge {
|
|
14
|
+
readonly constraintName: string;
|
|
15
|
+
readonly columns: readonly {
|
|
16
|
+
readonly local: string;
|
|
17
|
+
readonly foreign: string;
|
|
18
|
+
}[];
|
|
19
|
+
/** Entity that owns the FK column (the "child" in the relationship) */
|
|
20
|
+
readonly fkHolder: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The relation graph type - a directed graph where:
|
|
24
|
+
* - Nodes are entity names (strings)
|
|
25
|
+
* - Edges point from FK holder → referenced entity
|
|
26
|
+
* - Edge data contains constraint info
|
|
27
|
+
*/
|
|
28
|
+
export type RelationGraph = Graph.DirectedGraph<string, RelationEdge>;
|
|
29
|
+
/**
|
|
30
|
+
* An entity that can be directly joined from another entity.
|
|
31
|
+
*/
|
|
32
|
+
export interface JoinableEntity {
|
|
33
|
+
readonly entity: TableEntity;
|
|
34
|
+
readonly direction: "belongsTo" | "hasMany";
|
|
35
|
+
readonly relation: Relation | ReverseRelation;
|
|
36
|
+
/** Human-readable description: "orders via user_id → users.id" */
|
|
37
|
+
readonly description: string;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* A single step in a join path between two entities.
|
|
41
|
+
*/
|
|
42
|
+
export interface JoinStep {
|
|
43
|
+
readonly from: string;
|
|
44
|
+
readonly to: string;
|
|
45
|
+
readonly direction: "belongsTo" | "hasMany";
|
|
46
|
+
readonly constraintName: string;
|
|
47
|
+
readonly columns: readonly {
|
|
48
|
+
readonly local: string;
|
|
49
|
+
readonly foreign: string;
|
|
50
|
+
}[];
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Result of path finding - either a path or information about why none exists.
|
|
54
|
+
*/
|
|
55
|
+
export type JoinPathResult = {
|
|
56
|
+
readonly _tag: "Found";
|
|
57
|
+
readonly path: readonly JoinStep[];
|
|
58
|
+
} | {
|
|
59
|
+
readonly _tag: "NotFound";
|
|
60
|
+
readonly from: string;
|
|
61
|
+
readonly to: string;
|
|
62
|
+
} | {
|
|
63
|
+
readonly _tag: "SameEntity";
|
|
64
|
+
readonly entity: string;
|
|
65
|
+
} | {
|
|
66
|
+
readonly _tag: "EntityNotFound";
|
|
67
|
+
readonly entity: string;
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* Build a directed graph from the IR's entity relations.
|
|
71
|
+
*
|
|
72
|
+
* Edges point from FK holder → referenced entity (i.e., orders → users
|
|
73
|
+
* when orders.user_id references users.id).
|
|
74
|
+
*
|
|
75
|
+
* Use with Graph.bfs/dfs and direction: 'outgoing' for belongsTo traversal,
|
|
76
|
+
* direction: 'incoming' for hasMany traversal.
|
|
77
|
+
*/
|
|
78
|
+
export declare function buildRelationGraph(ir: SemanticIR): RelationGraph;
|
|
79
|
+
/**
|
|
80
|
+
* Get the node index for an entity name in the graph.
|
|
81
|
+
*/
|
|
82
|
+
export declare function getEntityIndex(graph: RelationGraph, entityName: string): Option.Option<Graph.NodeIndex>;
|
|
83
|
+
/**
|
|
84
|
+
* Get all entities directly joinable from this entity (via FK in either direction).
|
|
85
|
+
*
|
|
86
|
+
* Returns both:
|
|
87
|
+
* - belongsTo: entities this one references (we have the FK)
|
|
88
|
+
* - hasMany: entities that reference this one (they have the FK)
|
|
89
|
+
*/
|
|
90
|
+
export declare function getJoinableEntities(ir: SemanticIR, entityName: string): readonly JoinableEntity[];
|
|
91
|
+
/**
|
|
92
|
+
* Find the shortest path between two entities using BFS.
|
|
93
|
+
*
|
|
94
|
+
* Returns a JoinPathResult indicating:
|
|
95
|
+
* - Found: path exists with the steps to take
|
|
96
|
+
* - NotFound: no path exists between the entities
|
|
97
|
+
* - SameEntity: from and to are the same entity
|
|
98
|
+
* - EntityNotFound: one of the entity names doesn't exist in the IR
|
|
99
|
+
*
|
|
100
|
+
* The algorithm explores both directions (belongsTo and hasMany) to find
|
|
101
|
+
* any valid path through the relation graph.
|
|
102
|
+
*/
|
|
103
|
+
export declare function findJoinPath(ir: SemanticIR, from: string, to: string): JoinPathResult;
|
|
104
|
+
/**
|
|
105
|
+
* Export the relation graph as a Mermaid diagram.
|
|
106
|
+
* Useful for documentation and debugging.
|
|
107
|
+
*/
|
|
108
|
+
export declare function toMermaid(graph: RelationGraph): string;
|
|
109
|
+
/**
|
|
110
|
+
* Export the relation graph as a Mermaid diagram directly from IR.
|
|
111
|
+
*/
|
|
112
|
+
export declare function irToMermaid(ir: SemanticIR): string;
|
|
113
|
+
//# sourceMappingURL=relation-graph.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relation-graph.d.ts","sourceRoot":"","sources":["../../src/ir/relation-graph.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAS,KAAK,EAAE,MAAM,EAAQ,MAAM,QAAQ,CAAA;AAEnD,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAO1F;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;IAC/B,QAAQ,CAAC,OAAO,EAAE,SAAS;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IACjF,uEAAuE;IACvE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAC1B;AAED;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GAAG,KAAK,CAAC,aAAa,CAAC,MAAM,EAAE,YAAY,CAAC,CAAA;AAErE;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;IAC5B,QAAQ,CAAC,SAAS,EAAE,WAAW,GAAG,SAAS,CAAA;IAC3C,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,eAAe,CAAA;IAC7C,kEAAkE;IAClE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,SAAS,EAAE,WAAW,GAAG,SAAS,CAAA;IAC3C,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;IAC/B,QAAQ,CAAC,OAAO,EAAE,SAAS;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAClF;AAED;;GAEG;AACH,MAAM,MAAM,cAAc,GACtB;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,QAAQ,EAAE,CAAA;CAAE,GAC9D;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GACzE;IAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACxD;IAAE,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAMhE;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,UAAU,GAAG,aAAa,CA+BhE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,aAAa,EACpB,UAAU,EAAE,MAAM,GACjB,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAEhC;AAuBD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,GAAG,SAAS,cAAc,EAAE,CA6CjG;AAeD;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,cAAc,CAmFrF;AA4CD;;;GAGG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAMtD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,UAAU,GAAG,MAAM,CAElD"}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Relation Graph Utilities
|
|
3
|
+
*
|
|
4
|
+
* Utilities for navigating entity relationships in the IR using Effect's Graph module.
|
|
5
|
+
* Useful for query builders, documentation generators, ERD tools, etc.
|
|
6
|
+
*/
|
|
7
|
+
import { Array, Graph, Option, pipe } from "effect";
|
|
8
|
+
import { getAllRelations, isTableEntity } from "./semantic-ir.js";
|
|
9
|
+
// ============================================================================
|
|
10
|
+
// Graph Construction
|
|
11
|
+
// ============================================================================
|
|
12
|
+
/**
|
|
13
|
+
* Build a directed graph from the IR's entity relations.
|
|
14
|
+
*
|
|
15
|
+
* Edges point from FK holder → referenced entity (i.e., orders → users
|
|
16
|
+
* when orders.user_id references users.id).
|
|
17
|
+
*
|
|
18
|
+
* Use with Graph.bfs/dfs and direction: 'outgoing' for belongsTo traversal,
|
|
19
|
+
* direction: 'incoming' for hasMany traversal.
|
|
20
|
+
*/
|
|
21
|
+
export function buildRelationGraph(ir) {
|
|
22
|
+
const tableEntities = pipe(Array.fromIterable(ir.entities.values()), Array.filter(isTableEntity));
|
|
23
|
+
return Graph.directed((mutable) => {
|
|
24
|
+
// Build entity name → node index mapping
|
|
25
|
+
const nodeIndices = new Map(tableEntities.map((entity) => [entity.name, Graph.addNode(mutable, entity.name)]));
|
|
26
|
+
// Add edges for all belongsTo relations
|
|
27
|
+
for (const entity of tableEntities) {
|
|
28
|
+
const fromIdx = nodeIndices.get(entity.name);
|
|
29
|
+
if (fromIdx === undefined)
|
|
30
|
+
continue;
|
|
31
|
+
for (const rel of entity.relations) {
|
|
32
|
+
if (rel.kind !== "belongsTo")
|
|
33
|
+
continue;
|
|
34
|
+
const toIdx = nodeIndices.get(rel.targetEntity);
|
|
35
|
+
if (toIdx === undefined)
|
|
36
|
+
continue; // Skip broken refs
|
|
37
|
+
Graph.addEdge(mutable, fromIdx, toIdx, {
|
|
38
|
+
constraintName: rel.constraintName,
|
|
39
|
+
columns: rel.columns,
|
|
40
|
+
fkHolder: entity.name,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Get the node index for an entity name in the graph.
|
|
48
|
+
*/
|
|
49
|
+
export function getEntityIndex(graph, entityName) {
|
|
50
|
+
return Graph.findNode(graph, (name) => name === entityName);
|
|
51
|
+
}
|
|
52
|
+
// ============================================================================
|
|
53
|
+
// Joinable Entities
|
|
54
|
+
// ============================================================================
|
|
55
|
+
/**
|
|
56
|
+
* Format a relation as a human-readable description.
|
|
57
|
+
* Example: "orders via user_id → users.id"
|
|
58
|
+
*/
|
|
59
|
+
function formatRelationDescription(fromEntity, toEntity, columns, direction) {
|
|
60
|
+
const columnPairs = columns.map((c) => `${c.local} → ${c.foreign}`).join(", ");
|
|
61
|
+
return direction === "belongsTo"
|
|
62
|
+
? `${fromEntity} via ${columnPairs}`
|
|
63
|
+
: `${toEntity} via ${columnPairs}`;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Get all entities directly joinable from this entity (via FK in either direction).
|
|
67
|
+
*
|
|
68
|
+
* Returns both:
|
|
69
|
+
* - belongsTo: entities this one references (we have the FK)
|
|
70
|
+
* - hasMany: entities that reference this one (they have the FK)
|
|
71
|
+
*/
|
|
72
|
+
export function getJoinableEntities(ir, entityName) {
|
|
73
|
+
const allRels = getAllRelations(ir, entityName);
|
|
74
|
+
if (!allRels)
|
|
75
|
+
return [];
|
|
76
|
+
const belongsToResults = pipe(allRels.belongsTo, Array.filterMap((rel) => {
|
|
77
|
+
const target = ir.entities.get(rel.targetEntity);
|
|
78
|
+
if (!target || !isTableEntity(target))
|
|
79
|
+
return Option.none();
|
|
80
|
+
return Option.some({
|
|
81
|
+
entity: target,
|
|
82
|
+
direction: "belongsTo",
|
|
83
|
+
relation: rel,
|
|
84
|
+
description: formatRelationDescription(entityName, rel.targetEntity, rel.columns, "belongsTo"),
|
|
85
|
+
});
|
|
86
|
+
}));
|
|
87
|
+
const hasManyResults = pipe(allRels.hasMany, Array.filterMap((rel) => {
|
|
88
|
+
const source = ir.entities.get(rel.sourceEntity);
|
|
89
|
+
if (!source || !isTableEntity(source))
|
|
90
|
+
return Option.none();
|
|
91
|
+
return Option.some({
|
|
92
|
+
entity: source,
|
|
93
|
+
direction: "hasMany",
|
|
94
|
+
relation: rel,
|
|
95
|
+
description: formatRelationDescription(rel.sourceEntity, entityName, rel.columns, "hasMany"),
|
|
96
|
+
});
|
|
97
|
+
}));
|
|
98
|
+
return [...belongsToResults, ...hasManyResults];
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Find the shortest path between two entities using BFS.
|
|
102
|
+
*
|
|
103
|
+
* Returns a JoinPathResult indicating:
|
|
104
|
+
* - Found: path exists with the steps to take
|
|
105
|
+
* - NotFound: no path exists between the entities
|
|
106
|
+
* - SameEntity: from and to are the same entity
|
|
107
|
+
* - EntityNotFound: one of the entity names doesn't exist in the IR
|
|
108
|
+
*
|
|
109
|
+
* The algorithm explores both directions (belongsTo and hasMany) to find
|
|
110
|
+
* any valid path through the relation graph.
|
|
111
|
+
*/
|
|
112
|
+
export function findJoinPath(ir, from, to) {
|
|
113
|
+
// Same entity check
|
|
114
|
+
if (from === to) {
|
|
115
|
+
return { _tag: "SameEntity", entity: from };
|
|
116
|
+
}
|
|
117
|
+
// Validate entities exist
|
|
118
|
+
const fromEntity = ir.entities.get(from);
|
|
119
|
+
const toEntity = ir.entities.get(to);
|
|
120
|
+
if (!fromEntity || !isTableEntity(fromEntity)) {
|
|
121
|
+
return { _tag: "EntityNotFound", entity: from };
|
|
122
|
+
}
|
|
123
|
+
if (!toEntity || !isTableEntity(toEntity)) {
|
|
124
|
+
return { _tag: "EntityNotFound", entity: to };
|
|
125
|
+
}
|
|
126
|
+
// Build graph and get node indices
|
|
127
|
+
const graph = buildRelationGraph(ir);
|
|
128
|
+
const fromIdxOpt = getEntityIndex(graph, from);
|
|
129
|
+
const toIdxOpt = getEntityIndex(graph, to);
|
|
130
|
+
if (Option.isNone(fromIdxOpt) || Option.isNone(toIdxOpt)) {
|
|
131
|
+
return { _tag: "NotFound", from, to };
|
|
132
|
+
}
|
|
133
|
+
const fromIdx = fromIdxOpt.value;
|
|
134
|
+
const toIdx = toIdxOpt.value;
|
|
135
|
+
// BFS with parent tracking for path reconstruction
|
|
136
|
+
// We need to explore both edge directions (outgoing = belongsTo, incoming = hasMany)
|
|
137
|
+
const visited = new Set();
|
|
138
|
+
const parents = new Map();
|
|
139
|
+
const queue = [{ nodeIdx: fromIdx }];
|
|
140
|
+
visited.add(fromIdx);
|
|
141
|
+
while (queue.length > 0) {
|
|
142
|
+
const { nodeIdx: currentIdx } = queue.shift();
|
|
143
|
+
if (currentIdx === toIdx) {
|
|
144
|
+
// Found! Reconstruct path
|
|
145
|
+
return { _tag: "Found", path: reconstructPath(graph, parents, fromIdx, toIdx) };
|
|
146
|
+
}
|
|
147
|
+
// Explore outgoing edges (belongsTo direction)
|
|
148
|
+
const outgoingEdges = graph.adjacency.get(currentIdx) ?? [];
|
|
149
|
+
for (const edgeIdx of outgoingEdges) {
|
|
150
|
+
const edge = graph.edges.get(edgeIdx);
|
|
151
|
+
if (!edge)
|
|
152
|
+
continue;
|
|
153
|
+
const neighborIdx = edge.target;
|
|
154
|
+
if (!visited.has(neighborIdx)) {
|
|
155
|
+
visited.add(neighborIdx);
|
|
156
|
+
parents.set(neighborIdx, {
|
|
157
|
+
parentIdx: currentIdx,
|
|
158
|
+
edgeIdx,
|
|
159
|
+
direction: "belongsTo",
|
|
160
|
+
});
|
|
161
|
+
queue.push({ nodeIdx: neighborIdx });
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
// Explore incoming edges (hasMany direction)
|
|
165
|
+
const incomingEdges = graph.reverseAdjacency.get(currentIdx) ?? [];
|
|
166
|
+
for (const edgeIdx of incomingEdges) {
|
|
167
|
+
const edge = graph.edges.get(edgeIdx);
|
|
168
|
+
if (!edge)
|
|
169
|
+
continue;
|
|
170
|
+
const neighborIdx = edge.source;
|
|
171
|
+
if (!visited.has(neighborIdx)) {
|
|
172
|
+
visited.add(neighborIdx);
|
|
173
|
+
parents.set(neighborIdx, {
|
|
174
|
+
parentIdx: currentIdx,
|
|
175
|
+
edgeIdx,
|
|
176
|
+
direction: "hasMany",
|
|
177
|
+
});
|
|
178
|
+
queue.push({ nodeIdx: neighborIdx });
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return { _tag: "NotFound", from, to };
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Reconstruct the path from BFS parent pointers.
|
|
186
|
+
*/
|
|
187
|
+
function reconstructPath(graph, parents, fromIdx, toIdx) {
|
|
188
|
+
const steps = [];
|
|
189
|
+
let currentIdx = toIdx;
|
|
190
|
+
while (currentIdx !== fromIdx) {
|
|
191
|
+
const parent = parents.get(currentIdx);
|
|
192
|
+
if (!parent)
|
|
193
|
+
break; // Should never happen if BFS worked correctly
|
|
194
|
+
const edge = graph.edges.get(parent.edgeIdx);
|
|
195
|
+
if (!edge)
|
|
196
|
+
break;
|
|
197
|
+
const fromName = graph.nodes.get(parent.parentIdx);
|
|
198
|
+
const toName = graph.nodes.get(currentIdx);
|
|
199
|
+
if (fromName && toName) {
|
|
200
|
+
steps.unshift({
|
|
201
|
+
from: fromName,
|
|
202
|
+
to: toName,
|
|
203
|
+
direction: parent.direction,
|
|
204
|
+
constraintName: edge.data.constraintName,
|
|
205
|
+
columns: edge.data.columns,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
currentIdx = parent.parentIdx;
|
|
209
|
+
}
|
|
210
|
+
return steps;
|
|
211
|
+
}
|
|
212
|
+
// ============================================================================
|
|
213
|
+
// Visualization Helpers
|
|
214
|
+
// ============================================================================
|
|
215
|
+
/**
|
|
216
|
+
* Export the relation graph as a Mermaid diagram.
|
|
217
|
+
* Useful for documentation and debugging.
|
|
218
|
+
*/
|
|
219
|
+
export function toMermaid(graph) {
|
|
220
|
+
return Graph.toMermaid(graph, {
|
|
221
|
+
direction: "LR",
|
|
222
|
+
nodeLabel: (name) => name,
|
|
223
|
+
edgeLabel: (edge) => edge.constraintName,
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Export the relation graph as a Mermaid diagram directly from IR.
|
|
228
|
+
*/
|
|
229
|
+
export function irToMermaid(ir) {
|
|
230
|
+
return toMermaid(buildRelationGraph(ir));
|
|
231
|
+
}
|
|
232
|
+
//# sourceMappingURL=relation-graph.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relation-graph.js","sourceRoot":"","sources":["../../src/ir/relation-graph.ts"],"names":[],"mappings":"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"}
|