@kiyeonjeon21/datacontext 0.3.2 → 0.4.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.
Files changed (52) hide show
  1. package/dist/adapters/sqlite.d.ts.map +1 -1
  2. package/dist/adapters/sqlite.js +13 -0
  3. package/dist/adapters/sqlite.js.map +1 -1
  4. package/dist/api/server.d.ts.map +1 -1
  5. package/dist/api/server.js +115 -0
  6. package/dist/api/server.js.map +1 -1
  7. package/dist/cli/index.js +58 -14
  8. package/dist/cli/index.js.map +1 -1
  9. package/dist/core/context-service.d.ts +63 -0
  10. package/dist/core/context-service.d.ts.map +1 -1
  11. package/dist/core/context-service.js +66 -0
  12. package/dist/core/context-service.js.map +1 -1
  13. package/dist/core/harvester.d.ts +57 -5
  14. package/dist/core/harvester.d.ts.map +1 -1
  15. package/dist/core/harvester.js +86 -6
  16. package/dist/core/harvester.js.map +1 -1
  17. package/dist/core/types.d.ts +21 -5
  18. package/dist/core/types.d.ts.map +1 -1
  19. package/dist/index.d.ts +2 -1
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +9 -1
  22. package/dist/index.js.map +1 -1
  23. package/dist/knowledge/store.d.ts +186 -3
  24. package/dist/knowledge/store.d.ts.map +1 -1
  25. package/dist/knowledge/store.js +389 -5
  26. package/dist/knowledge/store.js.map +1 -1
  27. package/dist/knowledge/types.d.ts +252 -4
  28. package/dist/knowledge/types.d.ts.map +1 -1
  29. package/dist/knowledge/types.js +138 -1
  30. package/dist/knowledge/types.js.map +1 -1
  31. package/dist/mcp/tools.d.ts.map +1 -1
  32. package/dist/mcp/tools.js +231 -3
  33. package/dist/mcp/tools.js.map +1 -1
  34. package/docs/KNOWLEDGE_GRAPH.md +540 -0
  35. package/docs/KNOWLEDGE_TYPES.md +261 -0
  36. package/docs/MULTI_DB_ARCHITECTURE.md +319 -0
  37. package/package.json +1 -1
  38. package/scripts/create-sqlite-testdb.sh +75 -0
  39. package/scripts/test-databases.sh +324 -0
  40. package/sqlite:./test-sqlite.db +0 -0
  41. package/src/adapters/sqlite.ts +16 -0
  42. package/src/api/server.ts +134 -0
  43. package/src/cli/index.ts +57 -16
  44. package/src/core/context-service.ts +70 -0
  45. package/src/core/harvester.ts +120 -8
  46. package/src/core/types.ts +21 -5
  47. package/src/index.ts +19 -1
  48. package/src/knowledge/store.ts +480 -6
  49. package/src/knowledge/types.ts +321 -4
  50. package/src/mcp/tools.ts +273 -3
  51. package/test-sqlite.db +0 -0
  52. package/tests/knowledge-store.test.ts +130 -0
@@ -1,22 +1,56 @@
1
1
  /**
2
2
  * Auto-Harvester
3
- * Automatically collects metadata from database (COMMENT, indexes, etc.)
3
+ *
4
+ * Automatically collects metadata from database and syncs to Knowledge Store.
4
5
  * Platform-agnostic: works with MCP, REST API, SDK, etc.
6
+ *
7
+ * ## What Gets Harvested
8
+ *
9
+ * - **Table/Column Comments**: COMMENT ON TABLE/COLUMN statements
10
+ * - **Indexes**: Index definitions and types
11
+ * - **Foreign Keys**: FK constraints → TableRelationship edges
12
+ * - **Row Counts**: Estimated table sizes
13
+ *
14
+ * ## Relationship Harvesting (NEW in v2.0)
15
+ *
16
+ * Foreign keys are now automatically converted to TableRelationship
17
+ * entries in the Knowledge Graph:
18
+ *
19
+ * ```
20
+ * FK: orders.user_id → users.id
21
+ * ↓
22
+ * TableRelationship {
23
+ * from: { table: 'orders', schema: 'public' },
24
+ * to: { table: 'users', schema: 'public' },
25
+ * joinCondition: 'orders.user_id = users.id',
26
+ * relationshipType: 'foreign_key',
27
+ * cardinality: 'many-to-one'
28
+ * }
29
+ * ```
30
+ *
31
+ * @module core/harvester
5
32
  */
6
33
 
7
34
  import type { DatabaseAdapter } from '../adapters/base.js';
8
35
  import type { KnowledgeStore } from '../knowledge/store.js';
9
36
  import type { HarvestedMetadata } from './types.js';
37
+ import type { TableRelationship } from '../knowledge/types.js';
38
+ import { createKnowledgeMeta, createTableRef } from '../knowledge/types.js';
10
39
 
40
+ /**
41
+ * Harvester configuration options.
42
+ */
11
43
  export interface HarvesterConfig {
12
44
  /** Include table/column comments */
13
45
  includeComments: boolean;
14
46
  /** Include index information */
15
47
  includeIndexes: boolean;
16
- /** Include foreign key information */
48
+ /** Include foreign key information and convert to relationships */
17
49
  includeForeignKeys: boolean;
18
50
  /** Include estimated row counts */
19
51
  includeRowCounts: boolean;
52
+ /** Automatically create relationships from FK (default: true) */
53
+ createRelationshipsFromFK: boolean;
20
54
  }
21
55
 
22
56
  const DEFAULT_CONFIG: HarvesterConfig = {
@@ -24,6 +58,7 @@ const DEFAULT_CONFIG: HarvesterConfig = {
24
58
  includeIndexes: true,
25
59
  includeForeignKeys: true,
26
60
  includeRowCounts: true,
61
+ createRelationshipsFromFK: true,
27
62
  };
28
63
 
29
64
  /**
@@ -117,18 +152,32 @@ export class Harvester {
117
152
  }
118
153
 
119
154
  /**
120
- * Sync harvested metadata to knowledge store
121
- * Only adds new entries, doesn't overwrite user-defined ones
155
+ * Sync harvested metadata to knowledge store.
156
+ *
157
+ * Performs the following operations:
158
+ * 1. Adds table descriptions from DB COMMENT (if not already defined)
159
+ * 2. Adds column descriptions from DB COMMENT (if not already defined)
160
+ * 3. Converts FK constraints to TableRelationship entries (NEW in v2.0)
161
+ *
162
+ * Only adds new entries - doesn't overwrite user-defined descriptions.
163
+ *
164
+ * @param schema - Schema to harvest (defaults to 'public')
165
+ * @returns Summary of what was added
122
166
  */
123
167
  async syncToKnowledge(schema: string = 'public'): Promise<{
124
168
  tablesProcessed: number;
125
169
  descriptionsAdded: number;
126
170
  columnsAdded: number;
171
+ relationshipsAdded: number;
127
172
  }> {
128
173
  const harvested = await this.harvestSchema(schema);
129
174
 
130
175
  let descriptionsAdded = 0;
131
176
  let columnsAdded = 0;
177
+ let relationshipsAdded = 0;
178
+
179
+ // Collect all relationships first for batch insertion
180
+ const relationshipsToAdd: TableRelationship[] = [];
132
181
 
133
182
  for (const metadata of harvested) {
134
183
  // Check if table already has a user-defined description
@@ -139,9 +188,6 @@ export class Harvester {
139
188
  await this.knowledge.setTableDescription(metadata.tableName, metadata.tableComment, {
140
189
  schema: metadata.schema,
141
190
  });
142
-
143
- // Mark as auto-harvested by updating the source
144
- // The knowledge store will have source: 'user' by default, we need to track this
145
191
  descriptionsAdded++;
146
192
  }
147
193
 
@@ -160,6 +206,26 @@ export class Harvester {
160
206
  columnsAdded++;
161
207
  }
162
208
  }
209
+
210
+ // Convert FK to relationships (NEW in v2.0)
211
+ if (this.config.createRelationshipsFromFK && metadata.foreignKeys) {
212
+ for (const fk of metadata.foreignKeys) {
213
+ const relationship = this.createRelationshipFromFK(
214
+ metadata.tableName,
215
+ metadata.schema,
216
+ fk.column,
217
+ fk.referencedTable,
218
+ fk.referencedColumn,
219
+ fk.constraintName
220
+ );
221
+ relationshipsToAdd.push(relationship);
222
+ }
223
+ }
224
+ }
225
+
226
+ // Batch add relationships
227
+ if (relationshipsToAdd.length > 0) {
228
+ relationshipsAdded = await this.knowledge.addRelationships(relationshipsToAdd);
163
229
  }
164
230
 
165
231
  // Save changes
@@ -169,20 +235,64 @@ export class Harvester {
169
235
  tablesProcessed: harvested.length,
170
236
  descriptionsAdded,
171
237
  columnsAdded,
238
+ relationshipsAdded,
239
+ };
240
+ }
241
+
242
+ /**
243
+ * Create a TableRelationship from FK information.
244
+ *
245
+ * @internal
246
+ */
247
+ private createRelationshipFromFK(
248
+ fromTable: string,
249
+ fromSchema: string,
250
+ fromColumn: string,
251
+ toTable: string,
252
+ toColumn: string,
253
+ constraintName?: string
254
+ ): TableRelationship {
255
+ const schemaHash = this.knowledge.getSchemaHash();
256
+
257
+ return {
258
+ ...createKnowledgeMeta('auto', schemaHash),
259
+ type: 'table_relationship',
260
+ from: createTableRef(fromTable, fromSchema),
261
+ to: createTableRef(toTable, fromSchema), // Assume same schema for FK target
262
+ relationshipType: 'foreign_key',
263
+ joinCondition: `${fromTable}.${fromColumn} = ${toTable}.${toColumn}`,
264
+ cardinality: 'many-to-one', // Default for FK
265
+ fromColumns: [fromColumn],
266
+ toColumns: [toColumn],
267
+ isPreferred: true,
268
+ constraintName,
172
269
  };
173
270
  }
174
271
 
175
272
  /**
176
- * Get harvesting summary without syncing
273
+ * Get harvesting summary without syncing.
274
+ *
275
+ * Provides a preview of what would be harvested.
177
276
  */
178
277
  async getSummary(schema: string = 'public'): Promise<{
179
278
  tables: number;
180
279
  tablesWithComments: number;
181
280
  columnsWithComments: number;
182
281
  tablesWithForeignKeys: number;
282
+ totalForeignKeys: number;
283
+ existingRelationships: number;
183
284
  }> {
184
285
  const harvested = await this.harvestSchema(schema);
185
286
 
287
+ // Count total FKs
288
+ const totalFKs = harvested.reduce(
289
+ (sum, h) => sum + (h.foreignKeys?.length ?? 0),
290
+ 0
291
+ );
292
+
293
+ // Count existing relationships
294
+ const existingRels = this.knowledge.getRelationships().length;
295
+
186
296
  return {
187
297
  tables: harvested.length,
188
298
  tablesWithComments: harvested.filter(h => h.tableComment).length,
@@ -191,6 +301,8 @@ export class Harvester {
191
301
  0
192
302
  ),
193
303
  tablesWithForeignKeys: harvested.filter(h => h.foreignKeys && h.foreignKeys.length > 0).length,
304
+ totalForeignKeys: totalFKs,
305
+ existingRelationships: existingRels,
194
306
  };
195
307
  }
196
308
  }
package/src/core/types.ts CHANGED
@@ -78,26 +78,40 @@ export interface QueryFeedback {
78
78
  }
79
79
 
80
80
  /**
81
- * Harvested metadata from database
81
+ * Harvested metadata from database.
82
+ *
83
+ * This is the raw data collected from database introspection.
84
+ * Foreign keys are subsequently converted to TableRelationship entries
85
+ * by the Harvester during sync.
86
+ *
87
+ * @see TableRelationship for the graph edge representation
82
88
  */
83
89
  export interface HarvestedMetadata {
84
90
  /** Table name */
85
91
  tableName: string;
86
92
  /** Schema */
87
93
  schema: string;
88
- /** Table comment from DB */
94
+ /** Table comment from DB (COMMENT ON TABLE) */
89
95
  tableComment?: string;
90
- /** Column comments from DB */
96
+ /** Column comments from DB (COMMENT ON COLUMN) */
91
97
  columnComments: Record<string, string>;
92
98
  /** Estimated row count */
93
99
  estimatedRowCount?: number;
94
- /** Indexes */
100
+ /** Indexes (formatted as strings for display) */
95
101
  indexes?: string[];
96
- /** Foreign keys */
102
+ /**
103
+ * Foreign keys (raw data).
104
+ * These are converted to TableRelationship entries during harvesting.
105
+ */
97
106
  foreignKeys?: Array<{
107
+ /** Source column name */
98
108
  column: string;
109
+ /** Referenced table name */
99
110
  referencedTable: string;
111
+ /** Referenced column name */
100
112
  referencedColumn: string;
113
+ /** FK constraint name (optional) */
114
+ constraintName?: string;
101
115
  }>;
102
116
  }
103
117
 
@@ -175,6 +189,8 @@ export interface DataContextConfig {
175
189
  includeIndexes: boolean;
176
190
  includeForeignKeys: boolean;
177
191
  includeRowCounts: boolean;
192
+ /** Convert FK constraints to TableRelationship entries (default: true) */
193
+ createRelationshipsFromFK?: boolean;
178
194
  };
179
195
  /** Metrics configuration */
180
196
  metrics?: {
package/src/index.ts CHANGED
@@ -58,8 +58,26 @@ export type { TableInfo, ColumnInfo, SchemaInfo } from './schema/types.js';
58
58
  // === Knowledge Types ===
59
59
  export type {
60
60
  TableDescription,
61
+ TableRelationship,
62
+ TableRef,
63
+ RelationshipType,
64
+ RelationshipCardinality,
61
65
  QueryExample,
62
66
  BusinessRule,
63
- KnowledgeData
67
+ BusinessTerm,
68
+ KnowledgeData,
69
+ KnowledgeEntry,
70
+ KnowledgeMeta,
71
+ KnowledgeSource,
72
+ } from './knowledge/types.js';
73
+
74
+ // === Knowledge Factory Functions ===
75
+ export {
76
+ createTableRef,
77
+ tableRefToString,
78
+ tableRefsEqual,
79
+ createRelationshipFromFK,
80
+ createKnowledgeMeta,
81
+ generateId,
64
82
  } from './knowledge/types.js';
65
83