devmind 1.0.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/LICENSE +191 -0
- package/README.md +148 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.js +232 -0
- package/dist/cli.js.map +1 -0
- package/dist/codebase/generators/architecture.d.ts +4 -0
- package/dist/codebase/generators/architecture.js +33 -0
- package/dist/codebase/generators/architecture.js.map +1 -0
- package/dist/codebase/generators/modules.d.ts +9 -0
- package/dist/codebase/generators/modules.js +46 -0
- package/dist/codebase/generators/modules.js.map +1 -0
- package/dist/codebase/generators/overview.d.ts +5 -0
- package/dist/codebase/generators/overview.js +34 -0
- package/dist/codebase/generators/overview.js.map +1 -0
- package/dist/codebase/generators/skeleton.d.ts +8 -0
- package/dist/codebase/generators/skeleton.js +57 -0
- package/dist/codebase/generators/skeleton.js.map +1 -0
- package/dist/codebase/index.d.ts +24 -0
- package/dist/codebase/index.js +50 -0
- package/dist/codebase/index.js.map +1 -0
- package/dist/codebase/parsers/typescript.d.ts +14 -0
- package/dist/codebase/parsers/typescript.js +145 -0
- package/dist/codebase/parsers/typescript.js.map +1 -0
- package/dist/codebase/scanners/filesystem.d.ts +17 -0
- package/dist/codebase/scanners/filesystem.js +152 -0
- package/dist/codebase/scanners/filesystem.js.map +1 -0
- package/dist/codebase/utils/hashing.d.ts +15 -0
- package/dist/codebase/utils/hashing.js +50 -0
- package/dist/codebase/utils/hashing.js.map +1 -0
- package/dist/codebase/utils/stats.d.ts +12 -0
- package/dist/codebase/utils/stats.js +55 -0
- package/dist/codebase/utils/stats.js.map +1 -0
- package/dist/codebase/utils/tree.d.ts +10 -0
- package/dist/codebase/utils/tree.js +22 -0
- package/dist/codebase/utils/tree.js.map +1 -0
- package/dist/commands/analyze.d.ts +6 -0
- package/dist/commands/analyze.js +97 -0
- package/dist/commands/analyze.js.map +1 -0
- package/dist/commands/context.d.ts +4 -0
- package/dist/commands/context.js +54 -0
- package/dist/commands/context.js.map +1 -0
- package/dist/core/config.d.ts +20 -0
- package/dist/core/config.js +40 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/errors.d.ts +18 -0
- package/dist/core/errors.js +53 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/fileio.d.ts +10 -0
- package/dist/core/fileio.js +57 -0
- package/dist/core/fileio.js.map +1 -0
- package/dist/core/index.d.ts +8 -0
- package/dist/core/index.js +9 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/logger.d.ts +15 -0
- package/dist/core/logger.js +40 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/types.d.ts +106 -0
- package/dist/core/types.js +5 -0
- package/dist/core/types.js.map +1 -0
- package/dist/database/cli.d.ts +7 -0
- package/dist/database/cli.js +132 -0
- package/dist/database/cli.js.map +1 -0
- package/dist/database/commands/checkpoint.d.ts +13 -0
- package/dist/database/commands/checkpoint.js +136 -0
- package/dist/database/commands/checkpoint.js.map +1 -0
- package/dist/database/commands/generate.d.ts +21 -0
- package/dist/database/commands/generate.js +269 -0
- package/dist/database/commands/generate.js.map +1 -0
- package/dist/database/commands/handoff.d.ts +15 -0
- package/dist/database/commands/handoff.js +332 -0
- package/dist/database/commands/handoff.js.map +1 -0
- package/dist/database/commands/history.d.ts +13 -0
- package/dist/database/commands/history.js +148 -0
- package/dist/database/commands/history.js.map +1 -0
- package/dist/database/commands/init.d.ts +10 -0
- package/dist/database/commands/init.js +28 -0
- package/dist/database/commands/init.js.map +1 -0
- package/dist/database/commands/learn.d.ts +12 -0
- package/dist/database/commands/learn.js +93 -0
- package/dist/database/commands/learn.js.map +1 -0
- package/dist/database/commands/memory.d.ts +90 -0
- package/dist/database/commands/memory.js +353 -0
- package/dist/database/commands/memory.js.map +1 -0
- package/dist/database/commands/show.d.ts +9 -0
- package/dist/database/commands/show.js +136 -0
- package/dist/database/commands/show.js.map +1 -0
- package/dist/database/commands/validate.d.ts +9 -0
- package/dist/database/commands/validate.js +200 -0
- package/dist/database/commands/validate.js.map +1 -0
- package/dist/database/commands/watch.d.ts +9 -0
- package/dist/database/commands/watch.js +77 -0
- package/dist/database/commands/watch.js.map +1 -0
- package/dist/database/extractors/drizzle.d.ts +62 -0
- package/dist/database/extractors/drizzle.js +251 -0
- package/dist/database/extractors/drizzle.js.map +1 -0
- package/dist/database/extractors/firebase.d.ts +39 -0
- package/dist/database/extractors/firebase.js +192 -0
- package/dist/database/extractors/firebase.js.map +1 -0
- package/dist/database/extractors/index.d.ts +69 -0
- package/dist/database/extractors/index.js +345 -0
- package/dist/database/extractors/index.js.map +1 -0
- package/dist/database/extractors/mongodb.d.ts +44 -0
- package/dist/database/extractors/mongodb.js +198 -0
- package/dist/database/extractors/mongodb.js.map +1 -0
- package/dist/database/extractors/mysql.d.ts +61 -0
- package/dist/database/extractors/mysql.js +173 -0
- package/dist/database/extractors/mysql.js.map +1 -0
- package/dist/database/extractors/postgres.d.ts +47 -0
- package/dist/database/extractors/postgres.js +141 -0
- package/dist/database/extractors/postgres.js.map +1 -0
- package/dist/database/extractors/prisma.d.ts +71 -0
- package/dist/database/extractors/prisma.js +270 -0
- package/dist/database/extractors/prisma.js.map +1 -0
- package/dist/database/extractors/sqlite.d.ts +50 -0
- package/dist/database/extractors/sqlite.js +148 -0
- package/dist/database/extractors/sqlite.js.map +1 -0
- package/dist/database/generators/learning-generator.d.ts +48 -0
- package/dist/database/generators/learning-generator.js +221 -0
- package/dist/database/generators/learning-generator.js.map +1 -0
- package/dist/database/generators/templates.d.ts +103 -0
- package/dist/database/generators/templates.js +1557 -0
- package/dist/database/generators/templates.js.map +1 -0
- package/dist/database/index.d.ts +15 -0
- package/dist/database/index.js +16 -0
- package/dist/database/index.js.map +1 -0
- package/dist/database/utils/json-output.d.ts +26 -0
- package/dist/database/utils/json-output.js +37 -0
- package/dist/database/utils/json-output.js.map +1 -0
- package/dist/generators/unified.d.ts +1 -0
- package/dist/generators/unified.js +173 -0
- package/dist/generators/unified.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/utils/config-detector.d.ts +1 -0
- package/dist/utils/config-detector.js +40 -0
- package/dist/utils/config-detector.js.map +1 -0
- package/dist/utils/config-loader.d.ts +16 -0
- package/dist/utils/config-loader.js +20 -0
- package/dist/utils/config-loader.js.map +1 -0
- package/package.json +78 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Firebase Firestore Schema Extractor
|
|
3
|
+
* Extracts database schema information from Firebase Firestore by sampling documents
|
|
4
|
+
*/
|
|
5
|
+
export interface FirebaseFieldInfo {
|
|
6
|
+
name: string;
|
|
7
|
+
type: string;
|
|
8
|
+
nullable: boolean;
|
|
9
|
+
isArray: boolean;
|
|
10
|
+
isReference: boolean;
|
|
11
|
+
sampleValues?: any[];
|
|
12
|
+
}
|
|
13
|
+
export interface FirebaseCollectionInfo {
|
|
14
|
+
name: string;
|
|
15
|
+
documentCount: number;
|
|
16
|
+
fields: FirebaseFieldInfo[];
|
|
17
|
+
sampleSize: number;
|
|
18
|
+
}
|
|
19
|
+
export interface FirebaseSchemaInfo {
|
|
20
|
+
collections: FirebaseCollectionInfo[];
|
|
21
|
+
databaseType: 'firebase';
|
|
22
|
+
projectId: string;
|
|
23
|
+
}
|
|
24
|
+
export declare class FirebaseExtractor {
|
|
25
|
+
private projectId;
|
|
26
|
+
private serviceAccountPath?;
|
|
27
|
+
private db;
|
|
28
|
+
private sampleSize;
|
|
29
|
+
private app;
|
|
30
|
+
constructor(projectId: string, serviceAccountPath?: string, sampleSize?: number);
|
|
31
|
+
extract(): Promise<FirebaseSchemaInfo>;
|
|
32
|
+
private extractCollectionSchema;
|
|
33
|
+
private inferSchemaFromDocuments;
|
|
34
|
+
private analyzeObject;
|
|
35
|
+
private isFirestoreReference;
|
|
36
|
+
private getFirestoreType;
|
|
37
|
+
private determinePrimaryType;
|
|
38
|
+
close(): Promise<void>;
|
|
39
|
+
}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Firebase Firestore Schema Extractor
|
|
3
|
+
* Extracts database schema information from Firebase Firestore by sampling documents
|
|
4
|
+
*/
|
|
5
|
+
import * as admin from 'firebase-admin';
|
|
6
|
+
export class FirebaseExtractor {
|
|
7
|
+
projectId;
|
|
8
|
+
serviceAccountPath;
|
|
9
|
+
db = null;
|
|
10
|
+
sampleSize = 100;
|
|
11
|
+
app = null;
|
|
12
|
+
constructor(projectId, serviceAccountPath, sampleSize = 100) {
|
|
13
|
+
this.projectId = projectId;
|
|
14
|
+
this.serviceAccountPath = serviceAccountPath;
|
|
15
|
+
this.sampleSize = sampleSize;
|
|
16
|
+
}
|
|
17
|
+
async extract() {
|
|
18
|
+
try {
|
|
19
|
+
// Initialize Firebase Admin
|
|
20
|
+
if (!this.serviceAccountPath && !process.env.GOOGLE_APPLICATION_CREDENTIALS) {
|
|
21
|
+
throw new Error('Firebase service account required. Use --firebase-key or set GOOGLE_APPLICATION_CREDENTIALS env var.');
|
|
22
|
+
}
|
|
23
|
+
const config = {
|
|
24
|
+
projectId: this.projectId,
|
|
25
|
+
};
|
|
26
|
+
if (this.serviceAccountPath) {
|
|
27
|
+
const serviceAccount = await import(this.serviceAccountPath);
|
|
28
|
+
config.credential = admin.credential.cert(serviceAccount.default || serviceAccount);
|
|
29
|
+
}
|
|
30
|
+
this.app = admin.initializeApp(config, `cohere-${Date.now()}`);
|
|
31
|
+
this.db = admin.firestore(this.app);
|
|
32
|
+
// List all collections (top-level only for now)
|
|
33
|
+
const collections = await this.db.listCollections();
|
|
34
|
+
const collectionNames = collections.map((c) => c.id);
|
|
35
|
+
console.log(` Found ${collectionNames.length} collections`);
|
|
36
|
+
// Extract schema for each collection
|
|
37
|
+
const collectionSchemas = await Promise.all(collectionNames.map((name) => this.extractCollectionSchema(name)));
|
|
38
|
+
return {
|
|
39
|
+
collections: collectionSchemas,
|
|
40
|
+
databaseType: 'firebase',
|
|
41
|
+
projectId: this.projectId,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
throw error;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
async extractCollectionSchema(collectionName) {
|
|
49
|
+
if (!this.db)
|
|
50
|
+
throw new Error('Firestore not initialized');
|
|
51
|
+
const collectionRef = this.db.collection(collectionName);
|
|
52
|
+
// Get approximate count (note: Firestore doesn't have built-in count)
|
|
53
|
+
const snapshot = await collectionRef.limit(this.sampleSize).get();
|
|
54
|
+
const sampleSize = snapshot.size;
|
|
55
|
+
// Sample documents
|
|
56
|
+
const documents = snapshot.docs;
|
|
57
|
+
// Infer schema from sampled documents
|
|
58
|
+
const fields = this.inferSchemaFromDocuments(documents);
|
|
59
|
+
return {
|
|
60
|
+
name: collectionName,
|
|
61
|
+
documentCount: sampleSize, // Approximate, as Firestore doesn't expose exact counts easily
|
|
62
|
+
fields,
|
|
63
|
+
sampleSize,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
inferSchemaFromDocuments(documents) {
|
|
67
|
+
if (documents.length === 0)
|
|
68
|
+
return [];
|
|
69
|
+
const fieldMap = new Map();
|
|
70
|
+
// Analyze all documents
|
|
71
|
+
for (const doc of documents) {
|
|
72
|
+
const data = doc.data();
|
|
73
|
+
if (data) {
|
|
74
|
+
this.analyzeObject(data, fieldMap, '');
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// Convert to field info
|
|
78
|
+
const fields = [];
|
|
79
|
+
for (const [fieldName, info] of fieldMap.entries()) {
|
|
80
|
+
const types = Array.from(info.types);
|
|
81
|
+
const primaryType = this.determinePrimaryType(types);
|
|
82
|
+
fields.push({
|
|
83
|
+
name: fieldName,
|
|
84
|
+
type: primaryType,
|
|
85
|
+
nullable: info.nullCount > 0,
|
|
86
|
+
isArray: info.isArray,
|
|
87
|
+
isReference: info.isReference,
|
|
88
|
+
sampleValues: info.samples.slice(0, 3),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
return fields.sort((a, b) => a.name.localeCompare(b.name));
|
|
92
|
+
}
|
|
93
|
+
analyzeObject(obj, fieldMap, prefix) {
|
|
94
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
95
|
+
const fieldName = prefix ? `${prefix}.${key}` : key;
|
|
96
|
+
if (!fieldMap.has(fieldName)) {
|
|
97
|
+
fieldMap.set(fieldName, {
|
|
98
|
+
types: new Set(),
|
|
99
|
+
nullCount: 0,
|
|
100
|
+
isArray: false,
|
|
101
|
+
isReference: false,
|
|
102
|
+
samples: [],
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
const fieldInfo = fieldMap.get(fieldName);
|
|
106
|
+
if (value === null || value === undefined) {
|
|
107
|
+
fieldInfo.nullCount++;
|
|
108
|
+
fieldInfo.types.add('null');
|
|
109
|
+
}
|
|
110
|
+
else if (Array.isArray(value)) {
|
|
111
|
+
fieldInfo.isArray = true;
|
|
112
|
+
fieldInfo.types.add('Array');
|
|
113
|
+
if (value.length > 0) {
|
|
114
|
+
const elementType = this.getFirestoreType(value[0]);
|
|
115
|
+
fieldInfo.types.add(`Array<${elementType}>`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
else if (this.isFirestoreReference(value)) {
|
|
119
|
+
fieldInfo.isReference = true;
|
|
120
|
+
fieldInfo.types.add('Reference');
|
|
121
|
+
}
|
|
122
|
+
else if (typeof value === 'object') {
|
|
123
|
+
const firestoreType = this.getFirestoreType(value);
|
|
124
|
+
fieldInfo.types.add(firestoreType);
|
|
125
|
+
// Don't recurse into special Firestore types
|
|
126
|
+
if (firestoreType === 'Map') {
|
|
127
|
+
this.analyzeObject(value, fieldMap, fieldName);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
const firestoreType = this.getFirestoreType(value);
|
|
132
|
+
fieldInfo.types.add(firestoreType);
|
|
133
|
+
// Store sample values
|
|
134
|
+
if (fieldInfo.samples.length < 3 && firestoreType !== 'null') {
|
|
135
|
+
fieldInfo.samples.push(value);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
isFirestoreReference(value) {
|
|
141
|
+
// Check if it's a Firestore DocumentReference
|
|
142
|
+
return value && typeof value === 'object' && '_path' in value && 'firestore' in value;
|
|
143
|
+
}
|
|
144
|
+
getFirestoreType(value) {
|
|
145
|
+
if (value === null)
|
|
146
|
+
return 'null';
|
|
147
|
+
if (value === undefined)
|
|
148
|
+
return 'undefined';
|
|
149
|
+
// Check for Firestore-specific types
|
|
150
|
+
if (this.isFirestoreReference(value))
|
|
151
|
+
return 'Reference';
|
|
152
|
+
if (value instanceof Date || (value && typeof value.toDate === 'function'))
|
|
153
|
+
return 'Timestamp';
|
|
154
|
+
if (value && value.constructor && value.constructor.name === 'GeoPoint')
|
|
155
|
+
return 'GeoPoint';
|
|
156
|
+
// Standard JavaScript types
|
|
157
|
+
if (Array.isArray(value))
|
|
158
|
+
return 'Array';
|
|
159
|
+
if (typeof value === 'string')
|
|
160
|
+
return 'String';
|
|
161
|
+
if (typeof value === 'number') {
|
|
162
|
+
return Number.isInteger(value) ? 'Number' : 'Number';
|
|
163
|
+
}
|
|
164
|
+
if (typeof value === 'boolean')
|
|
165
|
+
return 'Boolean';
|
|
166
|
+
if (typeof value === 'object')
|
|
167
|
+
return 'Map';
|
|
168
|
+
return 'Mixed';
|
|
169
|
+
}
|
|
170
|
+
determinePrimaryType(types) {
|
|
171
|
+
if (types.length === 0)
|
|
172
|
+
return 'Mixed';
|
|
173
|
+
if (types.length === 1)
|
|
174
|
+
return types[0];
|
|
175
|
+
// Filter out null
|
|
176
|
+
const nonNullTypes = types.filter((t) => t !== 'null');
|
|
177
|
+
if (nonNullTypes.length === 1)
|
|
178
|
+
return nonNullTypes[0];
|
|
179
|
+
if (nonNullTypes.length === 0)
|
|
180
|
+
return 'null';
|
|
181
|
+
// If multiple types, return Mixed
|
|
182
|
+
return `Mixed(${nonNullTypes.join('|')})`;
|
|
183
|
+
}
|
|
184
|
+
async close() {
|
|
185
|
+
if (this.app) {
|
|
186
|
+
await this.app.delete();
|
|
187
|
+
this.app = null;
|
|
188
|
+
this.db = null;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=firebase.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"firebase.js","sourceRoot":"","sources":["../../../src/database/extractors/firebase.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,KAAK,MAAM,gBAAgB,CAAC;AAyBxC,MAAM,OAAO,iBAAiB;IACpB,SAAS,CAAS;IAClB,kBAAkB,CAAU;IAC5B,EAAE,GAAqB,IAAI,CAAC;IAC5B,UAAU,GAAW,GAAG,CAAC;IACzB,GAAG,GAAyB,IAAI,CAAC;IAEzC,YAAY,SAAiB,EAAE,kBAA2B,EAAE,aAAqB,GAAG;QAClF,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,kBAAkB,GAAG,kBAAkB,CAAC;QAC7C,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;IAED,KAAK,CAAC,OAAO;QACX,IAAI,CAAC;YACH,4BAA4B;YAC5B,IAAI,CAAC,IAAI,CAAC,kBAAkB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,8BAA8B,EAAE,CAAC;gBAC5E,MAAM,IAAI,KAAK,CACb,sGAAsG,CACvG,CAAC;YACJ,CAAC;YAED,MAAM,MAAM,GAAqB;gBAC/B,SAAS,EAAE,IAAI,CAAC,SAAS;aAC1B,CAAC;YAEF,IAAI,IAAI,CAAC,kBAAkB,EAAE,CAAC;gBAC5B,MAAM,cAAc,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;gBAC7D,MAAM,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,cAAc,CAAC,OAAO,IAAI,cAAc,CAAC,CAAC;YACtF,CAAC;YAED,IAAI,CAAC,GAAG,GAAG,KAAK,CAAC,aAAa,CAAC,MAAM,EAAE,UAAU,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YAC/D,IAAI,CAAC,EAAE,GAAG,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAEpC,gDAAgD;YAChD,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,eAAe,EAAE,CAAC;YACpD,MAAM,eAAe,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAErD,OAAO,CAAC,GAAG,CAAC,YAAY,eAAe,CAAC,MAAM,cAAc,CAAC,CAAC;YAE9D,qCAAqC;YACrC,MAAM,iBAAiB,GAAG,MAAM,OAAO,CAAC,GAAG,CACzC,eAAe,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC,CAAC,CAClE,CAAC;YAEF,OAAO;gBACL,WAAW,EAAE,iBAAiB;gBAC9B,YAAY,EAAE,UAAU;gBACxB,SAAS,EAAE,IAAI,CAAC,SAAS;aAC1B,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,uBAAuB,CAAC,cAAsB;QAC1D,IAAI,CAAC,IAAI,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;QAE3D,MAAM,aAAa,GAAG,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;QAEzD,sEAAsE;QACtE,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,GAAG,EAAE,CAAC;QAClE,MAAM,UAAU,GAAG,QAAQ,CAAC,IAAI,CAAC;QAEjC,mBAAmB;QACnB,MAAM,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC;QAEhC,sCAAsC;QACtC,MAAM,MAAM,GAAG,IAAI,CAAC,wBAAwB,CAAC,SAAS,CAAC,CAAC;QAExD,OAAO;YACL,IAAI,EAAE,cAAc;YACpB,aAAa,EAAE,UAAU,EAAE,+DAA+D;YAC1F,MAAM;YACN,UAAU;SACX,CAAC;IACJ,CAAC;IAEO,wBAAwB,CAAC,SAA6B;QAC5D,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QAEtC,MAAM,QAAQ,GAAG,IAAI,GAAG,EASrB,CAAC;QAEJ,wBAAwB;QACxB,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;YAC5B,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;YACxB,IAAI,IAAI,EAAE,CAAC;gBACT,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;YACzC,CAAC;QACH,CAAC;QAED,wBAAwB;QACxB,MAAM,MAAM,GAAwB,EAAE,CAAC;QACvC,KAAK,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC;YACnD,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACrC,MAAM,WAAW,GAAG,IAAI,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC;YAErD,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,WAAW;gBACjB,QAAQ,EAAE,IAAI,CAAC,SAAS,GAAG,CAAC;gBAC5B,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,WAAW,EAAE,IAAI,CAAC,WAAW;gBAC7B,YAAY,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;aACvC,CAAC,CAAC;QACL,CAAC;QAED,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAC7D,CAAC;IAEO,aAAa,CAAC,GAAQ,EAAE,QAA0B,EAAE,MAAc;QACxE,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YAC/C,MAAM,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;YAEpD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC7B,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE;oBACtB,KAAK,EAAE,IAAI,GAAG,EAAU;oBACxB,SAAS,EAAE,CAAC;oBACZ,OAAO,EAAE,KAAK;oBACd,WAAW,EAAE,KAAK;oBAClB,OAAO,EAAE,EAAE;iBACZ,CAAC,CAAC;YACL,CAAC;YAED,MAAM,SAAS,GAAG,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAE,CAAC;YAE3C,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBAC1C,SAAS,CAAC,SAAS,EAAE,CAAC;gBACtB,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAC9B,CAAC;iBAAM,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;gBAChC,SAAS,CAAC,OAAO,GAAG,IAAI,CAAC;gBACzB,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBAE7B,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACrB,MAAM,WAAW,GAAG,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;oBACpD,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,WAAW,GAAG,CAAC,CAAC;gBAC/C,CAAC;YACH,CAAC;iBAAM,IAAI,IAAI,CAAC,oBAAoB,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC5C,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC;gBAC7B,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YACnC,CAAC;iBAAM,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;gBACrC,MAAM,aAAa,GAAG,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC;gBACnD,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;gBAEnC,6CAA6C;gBAC7C,IAAI,aAAa,KAAK,KAAK,EAAE,CAAC;oBAC5B,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;gBACjD,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,MAAM,aAAa,GAAG,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC;gBACnD,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;gBAEnC,sBAAsB;gBACtB,IAAI,SAAS,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,aAAa,KAAK,MAAM,EAAE,CAAC;oBAC7D,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBAChC,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAEO,oBAAoB,CAAC,KAAU;QACrC,8CAA8C;QAC9C,OAAO,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,IAAI,KAAK,IAAI,WAAW,IAAI,KAAK,CAAC;IACxF,CAAC;IAEO,gBAAgB,CAAC,KAAU;QACjC,IAAI,KAAK,KAAK,IAAI;YAAE,OAAO,MAAM,CAAC;QAClC,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,WAAW,CAAC;QAE5C,qCAAqC;QACrC,IAAI,IAAI,CAAC,oBAAoB,CAAC,KAAK,CAAC;YAAE,OAAO,WAAW,CAAC;QACzD,IAAI,KAAK,YAAY,IAAI,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,CAAC,MAAM,KAAK,UAAU,CAAC;YAAE,OAAO,WAAW,CAAC;QAC/F,IAAI,KAAK,IAAI,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,WAAW,CAAC,IAAI,KAAK,UAAU;YAAE,OAAO,UAAU,CAAC;QAE3F,4BAA4B;QAC5B,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YAAE,OAAO,OAAO,CAAC;QACzC,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,OAAO,QAAQ,CAAC;QAC/C,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC9B,OAAO,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;QACvD,CAAC;QACD,IAAI,OAAO,KAAK,KAAK,SAAS;YAAE,OAAO,SAAS,CAAC;QACjD,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAC;QAE5C,OAAO,OAAO,CAAC;IACjB,CAAC;IAEO,oBAAoB,CAAC,KAAe;QAC1C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,OAAO,CAAC;QACvC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;QAExC,kBAAkB;QAClB,MAAM,YAAY,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC;QACvD,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,YAAY,CAAC,CAAC,CAAC,CAAC;QACtD,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,MAAM,CAAC;QAE7C,kCAAkC;QAClC,OAAO,SAAS,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;IAC5C,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;YACxB,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC;YAChB,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC;QACjB,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extractor Index
|
|
3
|
+
* Central export for all schema extractors and unified types
|
|
4
|
+
*/
|
|
5
|
+
import type { SchemaInfo as PostgresSchemaInfo } from './postgres.js';
|
|
6
|
+
import type { MySQLSchemaInfo } from './mysql.js';
|
|
7
|
+
import type { SQLiteSchemaInfo } from './sqlite.js';
|
|
8
|
+
import type { PrismaSchemaInfo } from './prisma.js';
|
|
9
|
+
import type { DrizzleSchemaInfo } from './drizzle.js';
|
|
10
|
+
import type { MongoDBSchemaInfo } from './mongodb.js';
|
|
11
|
+
import type { FirebaseSchemaInfo } from './firebase.js';
|
|
12
|
+
export type { PostgresSchemaInfo, MySQLSchemaInfo, SQLiteSchemaInfo };
|
|
13
|
+
export type { PrismaSchemaInfo, DrizzleSchemaInfo, MongoDBSchemaInfo, FirebaseSchemaInfo };
|
|
14
|
+
export interface UnifiedColumnInfo {
|
|
15
|
+
name: string;
|
|
16
|
+
type: string;
|
|
17
|
+
nullable: boolean;
|
|
18
|
+
default: string | null;
|
|
19
|
+
isPrimaryKey: boolean;
|
|
20
|
+
isUnique: boolean;
|
|
21
|
+
isForeignKey: boolean;
|
|
22
|
+
referencesTable?: string;
|
|
23
|
+
referencesColumn?: string;
|
|
24
|
+
onDelete?: string;
|
|
25
|
+
onUpdate?: string;
|
|
26
|
+
description?: string;
|
|
27
|
+
}
|
|
28
|
+
export interface UnifiedIndexInfo {
|
|
29
|
+
name: string;
|
|
30
|
+
columns: string[];
|
|
31
|
+
unique: boolean;
|
|
32
|
+
isPrimaryKey: boolean;
|
|
33
|
+
}
|
|
34
|
+
export interface UnifiedRelationInfo {
|
|
35
|
+
fromTable: string;
|
|
36
|
+
fromColumn: string;
|
|
37
|
+
toTable: string;
|
|
38
|
+
toColumn: string;
|
|
39
|
+
cardinality: '1:1' | '1:N' | 'N:1' | 'N:M';
|
|
40
|
+
onDelete?: string;
|
|
41
|
+
onUpdate?: string;
|
|
42
|
+
}
|
|
43
|
+
export interface UnifiedTableInfo {
|
|
44
|
+
name: string;
|
|
45
|
+
description?: string;
|
|
46
|
+
columns: UnifiedColumnInfo[];
|
|
47
|
+
indexes: UnifiedIndexInfo[];
|
|
48
|
+
relations: UnifiedRelationInfo[];
|
|
49
|
+
primaryKey: string[];
|
|
50
|
+
}
|
|
51
|
+
export interface UnifiedSchemaInfo {
|
|
52
|
+
tables: UnifiedTableInfo[];
|
|
53
|
+
databaseType: 'postgresql' | 'mysql' | 'sqlite' | 'prisma' | 'drizzle' | 'mongodb' | 'firebase';
|
|
54
|
+
schemaName?: string;
|
|
55
|
+
source?: string;
|
|
56
|
+
}
|
|
57
|
+
export declare class UnifiedSchemaConverter {
|
|
58
|
+
static convert(schemaInfo: any): UnifiedSchemaInfo;
|
|
59
|
+
}
|
|
60
|
+
export type ExtractorType = 'postgresql' | 'mysql' | 'sqlite' | 'prisma' | 'drizzle' | 'mongodb' | 'firebase';
|
|
61
|
+
export interface SchemaExtractor {
|
|
62
|
+
extract(): Promise<any>;
|
|
63
|
+
close(): Promise<void>;
|
|
64
|
+
}
|
|
65
|
+
export declare function createExtractor(type: ExtractorType, connectionString: string, options?: {
|
|
66
|
+
schemaPath?: string;
|
|
67
|
+
projectId?: string;
|
|
68
|
+
serviceAccountPath?: string;
|
|
69
|
+
}): Promise<SchemaExtractor>;
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extractor Index
|
|
3
|
+
* Central export for all schema extractors and unified types
|
|
4
|
+
*/
|
|
5
|
+
// Converter Class
|
|
6
|
+
export class UnifiedSchemaConverter {
|
|
7
|
+
static convert(schemaInfo) {
|
|
8
|
+
switch (schemaInfo.databaseType) {
|
|
9
|
+
case 'postgresql':
|
|
10
|
+
return convertPostgres(schemaInfo);
|
|
11
|
+
case 'mysql':
|
|
12
|
+
return convertMySQL(schemaInfo);
|
|
13
|
+
case 'sqlite':
|
|
14
|
+
return convertSQLite(schemaInfo);
|
|
15
|
+
case 'prisma':
|
|
16
|
+
return convertPrisma(schemaInfo);
|
|
17
|
+
case 'drizzle':
|
|
18
|
+
return convertDrizzle(schemaInfo);
|
|
19
|
+
case 'mongodb':
|
|
20
|
+
return convertMongoDB(schemaInfo);
|
|
21
|
+
case 'firebase':
|
|
22
|
+
return convertFirebase(schemaInfo);
|
|
23
|
+
default:
|
|
24
|
+
throw new Error(`Unsupported database type: ${schemaInfo.databaseType}`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function convertPostgres(schema) {
|
|
29
|
+
const source = schema.schemaName ? `postgresql://${schema.schemaName}` : 'postgresql';
|
|
30
|
+
return {
|
|
31
|
+
tables: schema.tables.map((table) => convertTable(table, (table.foreignKeys || []).map((fk) => ({
|
|
32
|
+
...fk,
|
|
33
|
+
onDelete: fk.onDelete || undefined,
|
|
34
|
+
onUpdate: fk.onUpdate || undefined,
|
|
35
|
+
})), table.indexes || [])),
|
|
36
|
+
databaseType: 'postgresql',
|
|
37
|
+
schemaName: schema.schemaName,
|
|
38
|
+
source,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function convertMySQL(schema) {
|
|
42
|
+
const source = schema.databaseName ? `mysql://${schema.databaseName}` : 'mysql';
|
|
43
|
+
return {
|
|
44
|
+
tables: schema.tables.map((table) => convertTable(table, (table.foreignKeys || []).map((fk) => ({
|
|
45
|
+
...fk,
|
|
46
|
+
onDelete: fk.onDelete || undefined,
|
|
47
|
+
onUpdate: fk.onUpdate || undefined,
|
|
48
|
+
})), table.indexes || [])),
|
|
49
|
+
databaseType: 'mysql',
|
|
50
|
+
schemaName: schema.databaseName,
|
|
51
|
+
source,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function convertSQLite(schema) {
|
|
55
|
+
const source = schema.databasePath || 'sqlite';
|
|
56
|
+
return {
|
|
57
|
+
tables: schema.tables.map((table) => convertSQLiteTable(table)),
|
|
58
|
+
databaseType: 'sqlite',
|
|
59
|
+
source,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function convertPrisma(schema) {
|
|
63
|
+
const source = schema.generator?.output || 'prisma';
|
|
64
|
+
return {
|
|
65
|
+
tables: schema.tables.map((table) => ({
|
|
66
|
+
name: table.name,
|
|
67
|
+
description: table.description || undefined,
|
|
68
|
+
columns: table.columns.map((col) => ({
|
|
69
|
+
name: col.name,
|
|
70
|
+
type: col.type,
|
|
71
|
+
nullable: col.isOptional,
|
|
72
|
+
default: col.defaultValue,
|
|
73
|
+
isPrimaryKey: table.primaryKey.includes(col.name),
|
|
74
|
+
isUnique: col.isUnique,
|
|
75
|
+
isForeignKey: col.isRelation,
|
|
76
|
+
referencesTable: col.isRelation ? col.type : undefined,
|
|
77
|
+
referencesColumn: col.relationReferences?.[0],
|
|
78
|
+
onDelete: col.onDelete || undefined,
|
|
79
|
+
description: undefined,
|
|
80
|
+
})),
|
|
81
|
+
indexes: table.indexes.map((idx) => ({
|
|
82
|
+
name: idx.name,
|
|
83
|
+
columns: idx.columns,
|
|
84
|
+
unique: idx.unique,
|
|
85
|
+
isPrimaryKey: false,
|
|
86
|
+
})),
|
|
87
|
+
relations: table.relations.map((rel) => ({
|
|
88
|
+
fromTable: rel.fromTable,
|
|
89
|
+
fromColumn: rel.fromFields[0] || '',
|
|
90
|
+
toTable: rel.toTable,
|
|
91
|
+
toColumn: rel.toFields[0] || '',
|
|
92
|
+
cardinality: mapRelationCardinality(rel.type),
|
|
93
|
+
onDelete: rel.onDelete || undefined,
|
|
94
|
+
})),
|
|
95
|
+
primaryKey: table.primaryKey,
|
|
96
|
+
})),
|
|
97
|
+
databaseType: 'prisma',
|
|
98
|
+
schemaName: schema.generator?.output,
|
|
99
|
+
source,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function convertDrizzle(schema) {
|
|
103
|
+
const source = schema.dialect;
|
|
104
|
+
return {
|
|
105
|
+
tables: schema.tables.map((table) => ({
|
|
106
|
+
name: table.name,
|
|
107
|
+
description: table.description || undefined,
|
|
108
|
+
columns: table.columns.map((col) => ({
|
|
109
|
+
name: col.name,
|
|
110
|
+
type: col.type,
|
|
111
|
+
nullable: col.isOptional,
|
|
112
|
+
default: col.defaultValue,
|
|
113
|
+
isPrimaryKey: col.isPrimaryKey,
|
|
114
|
+
isUnique: col.isUnique,
|
|
115
|
+
isForeignKey: col.isRelation,
|
|
116
|
+
referencesTable: col.relationName || undefined,
|
|
117
|
+
referencesColumn: undefined,
|
|
118
|
+
onDelete: col.onDelete || undefined,
|
|
119
|
+
description: undefined,
|
|
120
|
+
})),
|
|
121
|
+
indexes: table.indexes.map((idx) => ({
|
|
122
|
+
name: idx.name,
|
|
123
|
+
columns: idx.columns,
|
|
124
|
+
unique: idx.unique,
|
|
125
|
+
isPrimaryKey: false,
|
|
126
|
+
})),
|
|
127
|
+
relations: table.relations.map((rel) => ({
|
|
128
|
+
fromTable: rel.fromTable,
|
|
129
|
+
fromColumn: rel.fromColumns[0] || '',
|
|
130
|
+
toTable: rel.toTable,
|
|
131
|
+
toColumn: rel.toColumns[0] || '',
|
|
132
|
+
cardinality: mapRelationCardinality(rel.type),
|
|
133
|
+
onDelete: rel.onDelete || undefined,
|
|
134
|
+
})),
|
|
135
|
+
primaryKey: table.primaryKey,
|
|
136
|
+
})),
|
|
137
|
+
databaseType: 'drizzle',
|
|
138
|
+
schemaName: schema.dialect,
|
|
139
|
+
source,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
function convertMongoDB(schema) {
|
|
143
|
+
const source = schema.databaseName ? `mongodb://${schema.databaseName}` : 'mongodb';
|
|
144
|
+
return {
|
|
145
|
+
tables: schema.collections.map((collection) => ({
|
|
146
|
+
name: collection.name,
|
|
147
|
+
description: `MongoDB collection (${collection.documentCount} documents, sampled ${collection.sampleSize})`,
|
|
148
|
+
columns: collection.fields.map((field) => ({
|
|
149
|
+
name: field.name,
|
|
150
|
+
type: field.isArray ? `${field.type}[]` : field.type,
|
|
151
|
+
nullable: field.nullable,
|
|
152
|
+
default: null,
|
|
153
|
+
isPrimaryKey: field.name === '_id',
|
|
154
|
+
isUnique: field.name === '_id',
|
|
155
|
+
isForeignKey: field.type === 'ObjectId' && field.name !== '_id',
|
|
156
|
+
referencesTable: undefined, // MongoDB doesn't have explicit FK constraints
|
|
157
|
+
referencesColumn: undefined,
|
|
158
|
+
description: field.sampleValues && field.sampleValues.length > 0
|
|
159
|
+
? `Sample: ${JSON.stringify(field.sampleValues[0])}`
|
|
160
|
+
: undefined,
|
|
161
|
+
})),
|
|
162
|
+
indexes: collection.indexes.map((idx) => ({
|
|
163
|
+
name: idx.name,
|
|
164
|
+
columns: Object.keys(idx.keys),
|
|
165
|
+
unique: idx.unique,
|
|
166
|
+
isPrimaryKey: idx.name === '_id_',
|
|
167
|
+
})),
|
|
168
|
+
relations: [], // MongoDB doesn't have explicit relationships
|
|
169
|
+
primaryKey: ['_id'],
|
|
170
|
+
})),
|
|
171
|
+
databaseType: 'mongodb',
|
|
172
|
+
schemaName: schema.databaseName,
|
|
173
|
+
source,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
function convertFirebase(schema) {
|
|
177
|
+
const source = schema.projectId ? `firebase://${schema.projectId}` : 'firebase';
|
|
178
|
+
return {
|
|
179
|
+
tables: schema.collections.map((collection) => ({
|
|
180
|
+
name: collection.name,
|
|
181
|
+
description: `Firestore collection (${collection.documentCount} documents sampled)`,
|
|
182
|
+
columns: collection.fields.map((field) => ({
|
|
183
|
+
name: field.name,
|
|
184
|
+
type: field.isArray ? `${field.type}[]` : field.type,
|
|
185
|
+
nullable: field.nullable,
|
|
186
|
+
default: null,
|
|
187
|
+
isPrimaryKey: field.name === 'id' || field.name === '_id',
|
|
188
|
+
isUnique: field.name === 'id' || field.name === '_id',
|
|
189
|
+
isForeignKey: field.isReference,
|
|
190
|
+
referencesTable: undefined,
|
|
191
|
+
referencesColumn: undefined,
|
|
192
|
+
description: field.sampleValues && field.sampleValues.length > 0
|
|
193
|
+
? `Sample: ${JSON.stringify(field.sampleValues[0])}`
|
|
194
|
+
: undefined,
|
|
195
|
+
})),
|
|
196
|
+
indexes: [],
|
|
197
|
+
relations: [],
|
|
198
|
+
primaryKey: ['id'],
|
|
199
|
+
})),
|
|
200
|
+
databaseType: 'firebase',
|
|
201
|
+
schemaName: schema.projectId,
|
|
202
|
+
source,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
function convertTable(table, foreignKeys, indexes) {
|
|
206
|
+
const primaryKeySet = new Set(table.primaryKey || []);
|
|
207
|
+
const uniqueColumns = new Set();
|
|
208
|
+
indexes.forEach((idx) => {
|
|
209
|
+
if (idx.unique) {
|
|
210
|
+
idx.columns.forEach((column) => uniqueColumns.add(column));
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
const fkMap = new Map();
|
|
214
|
+
foreignKeys.forEach((fk) => fkMap.set(fk.column, fk));
|
|
215
|
+
return {
|
|
216
|
+
name: table.name,
|
|
217
|
+
description: table.description || table.comment,
|
|
218
|
+
columns: (table.columns || []).map((col) => {
|
|
219
|
+
const fk = fkMap.get(col.name);
|
|
220
|
+
return {
|
|
221
|
+
name: col.name,
|
|
222
|
+
type: col.type,
|
|
223
|
+
nullable: col.nullable,
|
|
224
|
+
default: col.default || col.defaultValue || null,
|
|
225
|
+
isPrimaryKey: primaryKeySet.has(col.name),
|
|
226
|
+
isUnique: uniqueColumns.has(col.name),
|
|
227
|
+
isForeignKey: Boolean(fk),
|
|
228
|
+
referencesTable: fk?.referencesTable,
|
|
229
|
+
referencesColumn: fk?.referencesColumn,
|
|
230
|
+
onDelete: fk?.onDelete,
|
|
231
|
+
onUpdate: fk?.onUpdate,
|
|
232
|
+
description: col.description || col.comment || undefined,
|
|
233
|
+
};
|
|
234
|
+
}),
|
|
235
|
+
indexes: indexes.map((idx) => ({
|
|
236
|
+
name: idx.name,
|
|
237
|
+
columns: idx.columns || [],
|
|
238
|
+
unique: idx.unique,
|
|
239
|
+
isPrimaryKey: Boolean(idx.isPrimaryKey),
|
|
240
|
+
})),
|
|
241
|
+
relations: foreignKeys.map((fk) => ({
|
|
242
|
+
fromTable: table.name,
|
|
243
|
+
fromColumn: fk.column,
|
|
244
|
+
toTable: fk.referencesTable,
|
|
245
|
+
toColumn: fk.referencesColumn,
|
|
246
|
+
cardinality: 'N:1',
|
|
247
|
+
onDelete: fk.onDelete,
|
|
248
|
+
onUpdate: fk.onUpdate,
|
|
249
|
+
})),
|
|
250
|
+
primaryKey: table.primaryKey || [],
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
function convertSQLiteTable(table) {
|
|
254
|
+
const primaryKeySet = new Set(table.primaryKey || []);
|
|
255
|
+
const uniqueColumns = new Set();
|
|
256
|
+
table.indexes?.forEach((idx) => {
|
|
257
|
+
if (idx.unique) {
|
|
258
|
+
idx.columns.forEach((column) => uniqueColumns.add(column));
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
const fkMap = new Map();
|
|
262
|
+
table.foreignKeys?.forEach((fk) => fkMap.set(fk.from, fk));
|
|
263
|
+
return {
|
|
264
|
+
name: table.name,
|
|
265
|
+
description: undefined,
|
|
266
|
+
columns: (table.columns || []).map((col) => {
|
|
267
|
+
const fk = fkMap.get(col.name);
|
|
268
|
+
return {
|
|
269
|
+
name: col.name,
|
|
270
|
+
type: col.type,
|
|
271
|
+
nullable: col.nullable,
|
|
272
|
+
default: col.default || null,
|
|
273
|
+
isPrimaryKey: primaryKeySet.has(col.name),
|
|
274
|
+
isUnique: uniqueColumns.has(col.name),
|
|
275
|
+
isForeignKey: Boolean(fk),
|
|
276
|
+
referencesTable: fk?.table,
|
|
277
|
+
referencesColumn: fk?.to,
|
|
278
|
+
onDelete: fk?.onDelete,
|
|
279
|
+
onUpdate: fk?.onUpdate,
|
|
280
|
+
description: undefined,
|
|
281
|
+
};
|
|
282
|
+
}),
|
|
283
|
+
indexes: (table.indexes || []).map((idx) => ({
|
|
284
|
+
name: idx.name,
|
|
285
|
+
columns: idx.columns,
|
|
286
|
+
unique: idx.unique,
|
|
287
|
+
isPrimaryKey: idx.isPrimaryKey,
|
|
288
|
+
})),
|
|
289
|
+
relations: (table.foreignKeys || []).map((fk) => ({
|
|
290
|
+
fromTable: table.name,
|
|
291
|
+
fromColumn: fk.from,
|
|
292
|
+
toTable: fk.table,
|
|
293
|
+
toColumn: fk.to,
|
|
294
|
+
cardinality: 'N:1',
|
|
295
|
+
onDelete: fk.onDelete,
|
|
296
|
+
onUpdate: fk.onUpdate,
|
|
297
|
+
})),
|
|
298
|
+
primaryKey: table.primaryKey || [],
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
function mapRelationCardinality(type) {
|
|
302
|
+
switch (type) {
|
|
303
|
+
case 'one-to-one':
|
|
304
|
+
case '1:1':
|
|
305
|
+
return '1:1';
|
|
306
|
+
case 'one-to-many':
|
|
307
|
+
return '1:N';
|
|
308
|
+
case 'many-to-one':
|
|
309
|
+
return 'N:1';
|
|
310
|
+
case 'many-to-many':
|
|
311
|
+
return 'N:M';
|
|
312
|
+
default:
|
|
313
|
+
return '1:N';
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
export async function createExtractor(type, connectionString, options) {
|
|
317
|
+
switch (type) {
|
|
318
|
+
case 'postgresql':
|
|
319
|
+
const { PostgresExtractor } = await import('./postgres.js');
|
|
320
|
+
return new PostgresExtractor(connectionString);
|
|
321
|
+
case 'mysql':
|
|
322
|
+
const { MySQLExtractor } = await import('./mysql.js');
|
|
323
|
+
return new MySQLExtractor(connectionString);
|
|
324
|
+
case 'sqlite':
|
|
325
|
+
const { SQLiteExtractor } = await import('./sqlite.js');
|
|
326
|
+
return new SQLiteExtractor(connectionString);
|
|
327
|
+
case 'prisma':
|
|
328
|
+
const { PrismaExtractor } = await import('./prisma.js');
|
|
329
|
+
return new PrismaExtractor(options?.schemaPath || 'prisma/schema.prisma');
|
|
330
|
+
case 'drizzle':
|
|
331
|
+
const { DrizzleExtractor } = await import('./drizzle.js');
|
|
332
|
+
return new DrizzleExtractor(options?.schemaPath || 'src/db/schema.ts');
|
|
333
|
+
case 'mongodb':
|
|
334
|
+
const { MongoDBExtractor } = await import('./mongodb.js');
|
|
335
|
+
return new MongoDBExtractor(connectionString);
|
|
336
|
+
case 'firebase':
|
|
337
|
+
const { FirebaseExtractor } = await import('./firebase.js');
|
|
338
|
+
const projectId = options?.projectId || 'unknown';
|
|
339
|
+
const serviceAccountPath = options?.serviceAccountPath;
|
|
340
|
+
return new FirebaseExtractor(projectId, serviceAccountPath);
|
|
341
|
+
default:
|
|
342
|
+
throw new Error(`Unknown extractor type: ${type}`);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
//# sourceMappingURL=index.js.map
|