turbine-orm 0.3.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 (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +295 -0
  3. package/dist/cli/config.d.ts +58 -0
  4. package/dist/cli/config.d.ts.map +1 -0
  5. package/dist/cli/config.js +123 -0
  6. package/dist/cli/config.js.map +1 -0
  7. package/dist/cli/index.d.ts +23 -0
  8. package/dist/cli/index.d.ts.map +1 -0
  9. package/dist/cli/index.js +935 -0
  10. package/dist/cli/index.js.map +1 -0
  11. package/dist/cli/migrate.d.ts +94 -0
  12. package/dist/cli/migrate.d.ts.map +1 -0
  13. package/dist/cli/migrate.js +383 -0
  14. package/dist/cli/migrate.js.map +1 -0
  15. package/dist/cli/ui.d.ts +74 -0
  16. package/dist/cli/ui.d.ts.map +1 -0
  17. package/dist/cli/ui.js +220 -0
  18. package/dist/cli/ui.js.map +1 -0
  19. package/dist/client.d.ts +212 -0
  20. package/dist/client.d.ts.map +1 -0
  21. package/dist/client.js +423 -0
  22. package/dist/client.js.map +1 -0
  23. package/dist/generate.d.ts +24 -0
  24. package/dist/generate.d.ts.map +1 -0
  25. package/dist/generate.js +289 -0
  26. package/dist/generate.js.map +1 -0
  27. package/dist/index.d.ts +44 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +53 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/introspect.d.ts +22 -0
  32. package/dist/introspect.d.ts.map +1 -0
  33. package/dist/introspect.js +284 -0
  34. package/dist/introspect.js.map +1 -0
  35. package/dist/pipeline.d.ts +44 -0
  36. package/dist/pipeline.d.ts.map +1 -0
  37. package/dist/pipeline.js +69 -0
  38. package/dist/pipeline.js.map +1 -0
  39. package/dist/query.d.ts +342 -0
  40. package/dist/query.d.ts.map +1 -0
  41. package/dist/query.js +1396 -0
  42. package/dist/query.js.map +1 -0
  43. package/dist/schema-builder.d.ts +127 -0
  44. package/dist/schema-builder.d.ts.map +1 -0
  45. package/dist/schema-builder.js +164 -0
  46. package/dist/schema-builder.js.map +1 -0
  47. package/dist/schema-sql.d.ts +71 -0
  48. package/dist/schema-sql.d.ts.map +1 -0
  49. package/dist/schema-sql.js +347 -0
  50. package/dist/schema-sql.js.map +1 -0
  51. package/dist/schema.d.ts +90 -0
  52. package/dist/schema.d.ts.map +1 -0
  53. package/dist/schema.js +129 -0
  54. package/dist/schema.js.map +1 -0
  55. package/dist/serverless.d.ts +162 -0
  56. package/dist/serverless.d.ts.map +1 -0
  57. package/dist/serverless.js +195 -0
  58. package/dist/serverless.js.map +1 -0
  59. package/dist/types.d.ts +93 -0
  60. package/dist/types.d.ts.map +1 -0
  61. package/dist/types.js +126 -0
  62. package/dist/types.js.map +1 -0
  63. package/package.json +74 -0
@@ -0,0 +1,284 @@
1
+ /**
2
+ * @batadata/turbine — Schema introspection
3
+ *
4
+ * Connects to a live Postgres database, reads information_schema + pg_catalog,
5
+ * and produces a SchemaMetadata object describing every table, column, relation,
6
+ * and index in the target schema.
7
+ *
8
+ * This is the foundation of `npx turbine generate`.
9
+ */
10
+ import pg from 'pg';
11
+ import { pgTypeToTs, isDateType, pgArrayType, snakeToCamel, singularize, } from './schema.js';
12
+ // ---------------------------------------------------------------------------
13
+ // SQL queries (all parameterized, no interpolation)
14
+ // ---------------------------------------------------------------------------
15
+ const SQL_TABLES = `
16
+ SELECT table_name
17
+ FROM information_schema.tables
18
+ WHERE table_schema = $1
19
+ AND table_type = 'BASE TABLE'
20
+ ORDER BY table_name
21
+ `;
22
+ const SQL_COLUMNS = `
23
+ SELECT
24
+ table_name,
25
+ column_name,
26
+ udt_name,
27
+ data_type,
28
+ is_nullable,
29
+ column_default,
30
+ ordinal_position,
31
+ character_maximum_length
32
+ FROM information_schema.columns
33
+ WHERE table_schema = $1
34
+ ORDER BY table_name, ordinal_position
35
+ `;
36
+ const SQL_PRIMARY_KEYS = `
37
+ SELECT
38
+ tc.table_name,
39
+ kcu.column_name,
40
+ kcu.ordinal_position
41
+ FROM information_schema.table_constraints tc
42
+ JOIN information_schema.key_column_usage kcu
43
+ ON tc.constraint_name = kcu.constraint_name
44
+ AND tc.table_schema = kcu.table_schema
45
+ WHERE tc.constraint_type = 'PRIMARY KEY'
46
+ AND tc.table_schema = $1
47
+ ORDER BY tc.table_name, kcu.ordinal_position
48
+ `;
49
+ const SQL_FOREIGN_KEYS = `
50
+ SELECT
51
+ tc.table_name AS source_table,
52
+ kcu.column_name AS source_column,
53
+ ccu.table_name AS target_table,
54
+ ccu.column_name AS target_column,
55
+ tc.constraint_name
56
+ FROM information_schema.table_constraints tc
57
+ JOIN information_schema.key_column_usage kcu
58
+ ON tc.constraint_name = kcu.constraint_name
59
+ AND tc.table_schema = kcu.table_schema
60
+ JOIN information_schema.constraint_column_usage ccu
61
+ ON tc.constraint_name = ccu.constraint_name
62
+ AND tc.table_schema = ccu.table_schema
63
+ WHERE tc.constraint_type = 'FOREIGN KEY'
64
+ AND tc.table_schema = $1
65
+ `;
66
+ const SQL_UNIQUE_CONSTRAINTS = `
67
+ SELECT
68
+ tc.table_name,
69
+ kcu.column_name
70
+ FROM information_schema.table_constraints tc
71
+ JOIN information_schema.key_column_usage kcu
72
+ ON tc.constraint_name = kcu.constraint_name
73
+ AND tc.table_schema = kcu.table_schema
74
+ WHERE tc.constraint_type = 'UNIQUE'
75
+ AND tc.table_schema = $1
76
+ `;
77
+ const SQL_INDEXES = `
78
+ SELECT tablename, indexname, indexdef
79
+ FROM pg_indexes
80
+ WHERE schemaname = $1
81
+ `;
82
+ const SQL_ENUMS = `
83
+ SELECT t.typname, e.enumlabel
84
+ FROM pg_type t
85
+ JOIN pg_enum e ON t.oid = e.enumtypid
86
+ JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
87
+ WHERE n.nspname = $1
88
+ ORDER BY t.typname, e.enumsortorder
89
+ `;
90
+ // ---------------------------------------------------------------------------
91
+ // Main introspection function
92
+ // ---------------------------------------------------------------------------
93
+ export async function introspect(options) {
94
+ const schema = options.schema ?? 'public';
95
+ const pool = new pg.Pool({
96
+ connectionString: options.connectionString,
97
+ max: 1,
98
+ connectionTimeoutMillis: 10_000,
99
+ });
100
+ try {
101
+ // Run all information_schema queries in parallel
102
+ const [tablesResult, columnsResult, pkResult, fkResult, uniqueResult, indexResult, enumResult,] = await Promise.all([
103
+ pool.query(SQL_TABLES, [schema]),
104
+ pool.query(SQL_COLUMNS, [schema]),
105
+ pool.query(SQL_PRIMARY_KEYS, [schema]),
106
+ pool.query(SQL_FOREIGN_KEYS, [schema]),
107
+ pool.query(SQL_UNIQUE_CONSTRAINTS, [schema]),
108
+ pool.query(SQL_INDEXES, [schema]),
109
+ pool.query(SQL_ENUMS, [schema]),
110
+ ]);
111
+ // Filter tables by include/exclude
112
+ let tableNames = tablesResult.rows.map((r) => r.table_name);
113
+ if (options.include?.length) {
114
+ const includeSet = new Set(options.include);
115
+ tableNames = tableNames.filter((t) => includeSet.has(t));
116
+ }
117
+ if (options.exclude?.length) {
118
+ const excludeSet = new Set(options.exclude);
119
+ tableNames = tableNames.filter((t) => !excludeSet.has(t));
120
+ }
121
+ const tableSet = new Set(tableNames);
122
+ // ----- Group columns by table -----
123
+ const columnsByTable = new Map();
124
+ for (const row of columnsResult.rows) {
125
+ const tableName = row.table_name;
126
+ if (!tableSet.has(tableName))
127
+ continue;
128
+ const isNullable = row.is_nullable === 'YES';
129
+ const isArray = row.data_type === 'ARRAY';
130
+ const baseType = isArray ? row.udt_name.slice(1) : row.udt_name;
131
+ const col = {
132
+ name: row.column_name,
133
+ field: snakeToCamel(row.column_name),
134
+ pgType: row.udt_name,
135
+ tsType: pgTypeToTs(isArray ? row.udt_name : baseType, isNullable),
136
+ nullable: isNullable,
137
+ hasDefault: row.column_default !== null,
138
+ isArray,
139
+ pgArrayType: pgArrayType(baseType),
140
+ maxLength: row.character_maximum_length ?? undefined,
141
+ };
142
+ if (!columnsByTable.has(tableName))
143
+ columnsByTable.set(tableName, []);
144
+ columnsByTable.get(tableName).push(col);
145
+ }
146
+ // ----- Group primary keys by table -----
147
+ const pkByTable = new Map();
148
+ for (const row of pkResult.rows) {
149
+ if (!tableSet.has(row.table_name))
150
+ continue;
151
+ if (!pkByTable.has(row.table_name))
152
+ pkByTable.set(row.table_name, []);
153
+ pkByTable.get(row.table_name).push(row.column_name);
154
+ }
155
+ // ----- Group unique constraints by table -----
156
+ const uniqueByTable = new Map();
157
+ for (const row of uniqueResult.rows) {
158
+ if (!tableSet.has(row.table_name))
159
+ continue;
160
+ if (!uniqueByTable.has(row.table_name))
161
+ uniqueByTable.set(row.table_name, []);
162
+ // Each unique constraint may be multi-column; for simplicity, treat as single-col here
163
+ uniqueByTable.get(row.table_name).push([row.column_name]);
164
+ }
165
+ // ----- Group indexes by table -----
166
+ const indexesByTable = new Map();
167
+ for (const row of indexResult.rows) {
168
+ if (!tableSet.has(row.tablename))
169
+ continue;
170
+ if (!indexesByTable.has(row.tablename))
171
+ indexesByTable.set(row.tablename, []);
172
+ const isUnique = row.indexdef.includes('UNIQUE');
173
+ // Extract column names from indexdef (e.g. "CREATE INDEX idx ON tbl USING btree (col1, col2)")
174
+ const colMatch = row.indexdef.match(/\((.+)\)/);
175
+ const columns = colMatch
176
+ ? colMatch[1].split(',').map((c) => c.trim().replace(/ (ASC|DESC)/i, ''))
177
+ : [];
178
+ indexesByTable.get(row.tablename).push({
179
+ name: row.indexname,
180
+ columns,
181
+ unique: isUnique,
182
+ definition: row.indexdef,
183
+ });
184
+ }
185
+ // ----- Collect enums -----
186
+ const enums = {};
187
+ for (const row of enumResult.rows) {
188
+ if (!enums[row.typname])
189
+ enums[row.typname] = [];
190
+ enums[row.typname].push(row.enumlabel);
191
+ }
192
+ const foreignKeys = [];
193
+ for (const row of fkResult.rows) {
194
+ if (!tableSet.has(row.source_table) || !tableSet.has(row.target_table))
195
+ continue;
196
+ foreignKeys.push({
197
+ sourceTable: row.source_table,
198
+ sourceColumn: row.source_column,
199
+ targetTable: row.target_table,
200
+ targetColumn: row.target_column,
201
+ });
202
+ }
203
+ // ----- Build relations from foreign keys -----
204
+ // Count FKs per (source, target) pair for disambiguation
205
+ const fkCounts = new Map();
206
+ for (const fk of foreignKeys) {
207
+ const key = `${fk.sourceTable}→${fk.targetTable}`;
208
+ fkCounts.set(key, (fkCounts.get(key) ?? 0) + 1);
209
+ }
210
+ const relationsByTable = new Map();
211
+ for (const fk of foreignKeys) {
212
+ const pairKey = `${fk.sourceTable}→${fk.targetTable}`;
213
+ const needsDisambiguation = (fkCounts.get(pairKey) ?? 0) > 1;
214
+ // --- belongsTo on the source (child) table ---
215
+ // e.g. posts.user_id → users.id creates posts.user (belongsTo)
216
+ const belongsToName = needsDisambiguation
217
+ ? snakeToCamel(fk.sourceColumn.replace(/_id$/, ''))
218
+ : singularize(snakeToCamel(fk.targetTable));
219
+ if (!relationsByTable.has(fk.sourceTable))
220
+ relationsByTable.set(fk.sourceTable, {});
221
+ relationsByTable.get(fk.sourceTable)[belongsToName] = {
222
+ type: 'belongsTo',
223
+ name: belongsToName,
224
+ from: fk.sourceTable,
225
+ to: fk.targetTable,
226
+ foreignKey: fk.sourceColumn,
227
+ referenceKey: fk.targetColumn,
228
+ };
229
+ // --- hasMany on the target (parent) table ---
230
+ // e.g. posts.user_id → users.id creates users.posts (hasMany)
231
+ const hasManyName = needsDisambiguation
232
+ ? snakeToCamel(`${fk.sourceTable}_by_${fk.sourceColumn.replace(/_id$/, '')}`)
233
+ : snakeToCamel(fk.sourceTable);
234
+ if (!relationsByTable.has(fk.targetTable))
235
+ relationsByTable.set(fk.targetTable, {});
236
+ relationsByTable.get(fk.targetTable)[hasManyName] = {
237
+ type: 'hasMany',
238
+ name: hasManyName,
239
+ from: fk.targetTable,
240
+ to: fk.sourceTable,
241
+ foreignKey: fk.sourceColumn,
242
+ referenceKey: fk.targetColumn,
243
+ };
244
+ }
245
+ // ----- Assemble TableMetadata for each table -----
246
+ const tables = {};
247
+ for (const tableName of tableNames) {
248
+ const columns = columnsByTable.get(tableName) ?? [];
249
+ const columnMap = {};
250
+ const reverseColumnMap = {};
251
+ const dateColumns = new Set();
252
+ const pgTypes = {};
253
+ const allColumns = [];
254
+ for (const col of columns) {
255
+ columnMap[col.field] = col.name;
256
+ reverseColumnMap[col.name] = col.field;
257
+ allColumns.push(col.name);
258
+ pgTypes[col.name] = col.pgType;
259
+ const baseType = col.isArray ? col.pgType.slice(1) : col.pgType;
260
+ if (isDateType(baseType)) {
261
+ dateColumns.add(col.name);
262
+ }
263
+ }
264
+ tables[tableName] = {
265
+ name: tableName,
266
+ columns,
267
+ columnMap,
268
+ reverseColumnMap,
269
+ dateColumns,
270
+ pgTypes,
271
+ allColumns,
272
+ primaryKey: pkByTable.get(tableName) ?? [],
273
+ uniqueColumns: uniqueByTable.get(tableName) ?? [],
274
+ relations: relationsByTable.get(tableName) ?? {},
275
+ indexes: indexesByTable.get(tableName) ?? [],
276
+ };
277
+ }
278
+ return { tables, enums };
279
+ }
280
+ finally {
281
+ await pool.end();
282
+ }
283
+ }
284
+ //# sourceMappingURL=introspect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"introspect.js","sourceRoot":"","sources":["../src/introspect.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * @batadata/turbine — Pipeline execution
3
+ *
4
+ * Pipelines batch multiple independent queries into a single database round-trip.
5
+ * Instead of N sequential awaits (N round-trips), you get 1 round-trip for all N queries.
6
+ *
7
+ * How it works:
8
+ * 1. Each query method (findUnique, count, etc.) can produce a DeferredQuery descriptor
9
+ * containing the SQL, params, and a transform function.
10
+ * 2. pipeline() collects these descriptors, executes them in a single Postgres
11
+ * pipeline/transaction, and maps each result through its transform.
12
+ *
13
+ * In the production Turbine engine, this would go through the Rust proxy which uses
14
+ * actual Postgres pipeline protocol (libpq PQpipelineEnter). For the TS SDK prototype,
15
+ * we simulate it by running queries concurrently on a single connection or via
16
+ * a multi-statement batch.
17
+ */
18
+ import type pg from 'pg';
19
+ import type { DeferredQuery } from './query.js';
20
+ /**
21
+ * Execute multiple deferred queries in a single batch.
22
+ *
23
+ * Uses a single connection from the pool and runs all queries within
24
+ * a transaction to guarantee consistency and minimize round-trips.
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * const [user, count, posts] = await executePipeline(pool, [
29
+ * db.users.buildFindUnique({ where: { id: 1 } }),
30
+ * db.posts.buildCount({ where: { orgId: 1 } }),
31
+ * db.posts.buildFindMany({ where: { userId: 1 }, limit: 10 }),
32
+ * ]);
33
+ * ```
34
+ */
35
+ export declare function executePipeline<T extends readonly DeferredQuery<unknown>[]>(pool: pg.Pool, queries: T): Promise<PipelineResults<T>>;
36
+ /**
37
+ * Extract the result types from a tuple of DeferredQuery objects.
38
+ * If you pass [DeferredQuery<User>, DeferredQuery<number>, DeferredQuery<Post[]>],
39
+ * you get back [User, number, Post[]].
40
+ */
41
+ export type PipelineResults<T extends readonly DeferredQuery<unknown>[]> = {
42
+ [K in keyof T]: T[K] extends DeferredQuery<infer R> ? R : never;
43
+ };
44
+ //# sourceMappingURL=pipeline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAMhD;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,eAAe,CAAC,CAAC,SAAS,SAAS,aAAa,CAAC,OAAO,CAAC,EAAE,EAC/E,IAAI,EAAE,EAAE,CAAC,IAAI,EACb,OAAO,EAAE,CAAC,GACT,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAmC7B;AAMD;;;;GAIG;AACH,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,SAAS,aAAa,CAAC,OAAO,CAAC,EAAE,IAAI;KACxE,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,aAAa,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK;CAChE,CAAC"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * @batadata/turbine — Pipeline execution
3
+ *
4
+ * Pipelines batch multiple independent queries into a single database round-trip.
5
+ * Instead of N sequential awaits (N round-trips), you get 1 round-trip for all N queries.
6
+ *
7
+ * How it works:
8
+ * 1. Each query method (findUnique, count, etc.) can produce a DeferredQuery descriptor
9
+ * containing the SQL, params, and a transform function.
10
+ * 2. pipeline() collects these descriptors, executes them in a single Postgres
11
+ * pipeline/transaction, and maps each result through its transform.
12
+ *
13
+ * In the production Turbine engine, this would go through the Rust proxy which uses
14
+ * actual Postgres pipeline protocol (libpq PQpipelineEnter). For the TS SDK prototype,
15
+ * we simulate it by running queries concurrently on a single connection or via
16
+ * a multi-statement batch.
17
+ */
18
+ // ---------------------------------------------------------------------------
19
+ // Pipeline executor
20
+ // ---------------------------------------------------------------------------
21
+ /**
22
+ * Execute multiple deferred queries in a single batch.
23
+ *
24
+ * Uses a single connection from the pool and runs all queries within
25
+ * a transaction to guarantee consistency and minimize round-trips.
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * const [user, count, posts] = await executePipeline(pool, [
30
+ * db.users.buildFindUnique({ where: { id: 1 } }),
31
+ * db.posts.buildCount({ where: { orgId: 1 } }),
32
+ * db.posts.buildFindMany({ where: { userId: 1 }, limit: 10 }),
33
+ * ]);
34
+ * ```
35
+ */
36
+ export async function executePipeline(pool, queries) {
37
+ if (queries.length === 0) {
38
+ return [];
39
+ }
40
+ // Acquire a single connection for the entire batch
41
+ const client = await pool.connect();
42
+ try {
43
+ // Wrap in a transaction for consistency
44
+ await client.query('BEGIN');
45
+ // Execute all queries on the same connection — in sequence on a single
46
+ // connection this avoids pool checkout overhead, and the Postgres server
47
+ // processes them as a tight batch.
48
+ //
49
+ // Execute queries sequentially on the same connection to avoid the
50
+ // "already executing a query" deprecation in pg@8. This is still faster
51
+ // than separate pool checkouts because we skip N-1 acquire/release cycles.
52
+ // Future: use actual Postgres pipeline protocol for true pipelining.
53
+ const results = [];
54
+ for (const q of queries) {
55
+ const raw = await client.query(q.sql, q.params);
56
+ results.push(q.transform(raw));
57
+ }
58
+ await client.query('COMMIT');
59
+ return results;
60
+ }
61
+ catch (err) {
62
+ await client.query('ROLLBACK');
63
+ throw err;
64
+ }
65
+ finally {
66
+ client.release();
67
+ }
68
+ }
69
+ //# sourceMappingURL=pipeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../src/pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAKH,8EAA8E;AAC9E,oBAAoB;AACpB,8EAA8E;AAE9E;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,IAAa,EACb,OAAU;IAEV,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,EAAmC,CAAC;IAC7C,CAAC;IAED,mDAAmD;IACnD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;IAEpC,IAAI,CAAC;QACH,wCAAwC;QACxC,MAAM,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAE5B,uEAAuE;QACvE,yEAAyE;QACzE,mCAAmC;QACnC,EAAE;QACF,mEAAmE;QACnE,wEAAwE;QACxE,2EAA2E;QAC3E,qEAAqE;QACrE,MAAM,OAAO,GAAc,EAAE,CAAC;QAC9B,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;YAChD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;QACjC,CAAC;QAED,MAAM,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAE7B,OAAO,OAA6B,CAAC;IACvC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAC/B,MAAM,GAAG,CAAC;IACZ,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,OAAO,EAAE,CAAC;IACnB,CAAC;AACH,CAAC"}