@smallwebco/tinypivot-server 1.0.61 → 1.0.62

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/index.cjs CHANGED
@@ -328,6 +328,8 @@ function createTinyPivotHandler(options = {}) {
328
328
  return handleListTables(connectionString, schemas, tableOptions, descriptions, onError);
329
329
  case "get-schema":
330
330
  return handleGetSchema(body.tables || [], connectionString, schemas, tableOptions, onError);
331
+ case "get-all-schemas":
332
+ return handleGetAllSchemas(connectionString, schemas, tableOptions, onError);
331
333
  case "query":
332
334
  return handleQuery(
333
335
  body.sql,
@@ -478,6 +480,89 @@ async function handleGetSchema(tables, connectionString, schemas, tableOptions,
478
480
  await pool.end();
479
481
  }
480
482
  }
483
+ async function handleGetAllSchemas(connectionString, schemas, tableOptions, onError) {
484
+ let Pool;
485
+ try {
486
+ const pg = await import("pg");
487
+ Pool = pg.Pool;
488
+ } catch {
489
+ return createErrorResponse(
490
+ "PostgreSQL driver (pg) is not installed. Install it with: pnpm add pg",
491
+ 500
492
+ );
493
+ }
494
+ if (!connectionString) {
495
+ return createErrorResponse(
496
+ "Database connection not configured. Set DATABASE_URL environment variable.",
497
+ 500
498
+ );
499
+ }
500
+ const pool = new Pool({ connectionString });
501
+ try {
502
+ const schemaPlaceholders = schemas.map((_, i) => `$${i + 1}`).join(", ");
503
+ const tablesResult = await pool.query(
504
+ `
505
+ SELECT table_name
506
+ FROM information_schema.tables
507
+ WHERE table_schema IN (${schemaPlaceholders})
508
+ AND table_type = 'BASE TABLE'
509
+ ORDER BY table_name
510
+ `,
511
+ schemas
512
+ );
513
+ let tableNames = tablesResult.rows.map((row) => row.table_name);
514
+ tableNames = filterTables(tableNames, tableOptions);
515
+ if (tableNames.length === 0) {
516
+ const response2 = { schemas: [] };
517
+ return new Response(JSON.stringify(response2), {
518
+ status: 200,
519
+ headers: { "Content-Type": "application/json" }
520
+ });
521
+ }
522
+ const tablePlaceholders = tableNames.map((_, i) => `$${i + 1}`).join(", ");
523
+ const columnsResult = await pool.query(
524
+ `
525
+ SELECT
526
+ table_name,
527
+ column_name,
528
+ data_type,
529
+ is_nullable
530
+ FROM information_schema.columns
531
+ WHERE table_name IN (${tablePlaceholders})
532
+ AND table_schema = ANY($${tableNames.length + 1}::text[])
533
+ ORDER BY table_name, ordinal_position
534
+ `,
535
+ [...tableNames, schemas]
536
+ );
537
+ const tableMap = /* @__PURE__ */ new Map();
538
+ for (const row of columnsResult.rows) {
539
+ const tableName = row.table_name;
540
+ if (!tableMap.has(tableName)) {
541
+ tableMap.set(tableName, []);
542
+ }
543
+ tableMap.get(tableName).push({
544
+ name: row.column_name,
545
+ type: PG_TYPE_MAP[row.data_type.toLowerCase()] || "unknown",
546
+ nullable: row.is_nullable === "YES"
547
+ });
548
+ }
549
+ const tableSchemas = [];
550
+ for (const [tableName, columns] of tableMap) {
551
+ tableSchemas.push({ table: tableName, columns });
552
+ }
553
+ const response = { schemas: tableSchemas };
554
+ return new Response(JSON.stringify(response), {
555
+ status: 200,
556
+ headers: { "Content-Type": "application/json" }
557
+ });
558
+ } catch (error) {
559
+ const err = error instanceof Error ? error : new Error(String(error));
560
+ onError?.(err);
561
+ return createErrorResponse(`Failed to get all schemas: ${err.message}`, 500);
562
+ } finally {
563
+ await pool.end();
564
+ }
565
+ }
481
566
  async function handleQuery(sql, table, connectionString, schemas, tableOptions, maxRows, timeout, onError) {
482
567
  if (!sql || typeof sql !== "string") {
483
568
  return createErrorResponse("Missing or invalid SQL query", 400);
package/dist/index.d.cts CHANGED
@@ -99,7 +99,7 @@ interface TinyPivotHandlerOptions {
99
99
  */
100
100
  interface TinyPivotRequest {
101
101
  /** Action to perform */
102
- action: 'list-tables' | 'get-schema' | 'query' | 'chat';
102
+ action: 'list-tables' | 'get-schema' | 'get-all-schemas' | 'query' | 'chat';
103
103
  tables?: string[];
104
104
  sql?: string;
105
105
  table?: string;
package/dist/index.d.ts CHANGED
@@ -99,7 +99,7 @@ interface TinyPivotHandlerOptions {
99
99
  */
100
100
  interface TinyPivotRequest {
101
101
  /** Action to perform */
102
- action: 'list-tables' | 'get-schema' | 'query' | 'chat';
102
+ action: 'list-tables' | 'get-schema' | 'get-all-schemas' | 'query' | 'chat';
103
103
  tables?: string[];
104
104
  sql?: string;
105
105
  table?: string;
package/dist/index.js CHANGED
@@ -288,6 +288,8 @@ function createTinyPivotHandler(options = {}) {
288
288
  return handleListTables(connectionString, schemas, tableOptions, descriptions, onError);
289
289
  case "get-schema":
290
290
  return handleGetSchema(body.tables || [], connectionString, schemas, tableOptions, onError);
291
+ case "get-all-schemas":
292
+ return handleGetAllSchemas(connectionString, schemas, tableOptions, onError);
291
293
  case "query":
292
294
  return handleQuery(
293
295
  body.sql,
@@ -438,6 +440,89 @@ async function handleGetSchema(tables, connectionString, schemas, tableOptions,
438
440
  await pool.end();
439
441
  }
440
442
  }
443
+ async function handleGetAllSchemas(connectionString, schemas, tableOptions, onError) {
444
+ let Pool;
445
+ try {
446
+ const pg = await import("pg");
447
+ Pool = pg.Pool;
448
+ } catch {
449
+ return createErrorResponse(
450
+ "PostgreSQL driver (pg) is not installed. Install it with: pnpm add pg",
451
+ 500
452
+ );
453
+ }
454
+ if (!connectionString) {
455
+ return createErrorResponse(
456
+ "Database connection not configured. Set DATABASE_URL environment variable.",
457
+ 500
458
+ );
459
+ }
460
+ const pool = new Pool({ connectionString });
461
+ try {
462
+ const schemaPlaceholders = schemas.map((_, i) => `$${i + 1}`).join(", ");
463
+ const tablesResult = await pool.query(
464
+ `
465
+ SELECT table_name
466
+ FROM information_schema.tables
467
+ WHERE table_schema IN (${schemaPlaceholders})
468
+ AND table_type = 'BASE TABLE'
469
+ ORDER BY table_name
470
+ `,
471
+ schemas
472
+ );
473
+ let tableNames = tablesResult.rows.map((row) => row.table_name);
474
+ tableNames = filterTables(tableNames, tableOptions);
475
+ if (tableNames.length === 0) {
476
+ const response2 = { schemas: [] };
477
+ return new Response(JSON.stringify(response2), {
478
+ status: 200,
479
+ headers: { "Content-Type": "application/json" }
480
+ });
481
+ }
482
+ const tablePlaceholders = tableNames.map((_, i) => `$${i + 1}`).join(", ");
483
+ const columnsResult = await pool.query(
484
+ `
485
+ SELECT
486
+ table_name,
487
+ column_name,
488
+ data_type,
489
+ is_nullable
490
+ FROM information_schema.columns
491
+ WHERE table_name IN (${tablePlaceholders})
492
+ AND table_schema = ANY($${tableNames.length + 1}::text[])
493
+ ORDER BY table_name, ordinal_position
494
+ `,
495
+ [...tableNames, schemas]
496
+ );
497
+ const tableMap = /* @__PURE__ */ new Map();
498
+ for (const row of columnsResult.rows) {
499
+ const tableName = row.table_name;
500
+ if (!tableMap.has(tableName)) {
501
+ tableMap.set(tableName, []);
502
+ }
503
+ tableMap.get(tableName).push({
504
+ name: row.column_name,
505
+ type: PG_TYPE_MAP[row.data_type.toLowerCase()] || "unknown",
506
+ nullable: row.is_nullable === "YES"
507
+ });
508
+ }
509
+ const tableSchemas = [];
510
+ for (const [tableName, columns] of tableMap) {
511
+ tableSchemas.push({ table: tableName, columns });
512
+ }
513
+ const response = { schemas: tableSchemas };
514
+ return new Response(JSON.stringify(response), {
515
+ status: 200,
516
+ headers: { "Content-Type": "application/json" }
517
+ });
518
+ } catch (error) {
519
+ const err = error instanceof Error ? error : new Error(String(error));
520
+ onError?.(err);
521
+ return createErrorResponse(`Failed to get all schemas: ${err.message}`, 500);
522
+ } finally {
523
+ await pool.end();
524
+ }
525
+ }
441
526
  async function handleQuery(sql, table, connectionString, schemas, tableOptions, maxRows, timeout, onError) {
442
527
  if (!sql || typeof sql !== "string") {
443
528
  return createErrorResponse("Missing or invalid SQL query", 400);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@smallwebco/tinypivot-server",
3
3
  "type": "module",
4
- "version": "1.0.61",
4
+ "version": "1.0.62",
5
5
  "description": "Server handlers for TinyPivot Embedded AI Data Analyst - PostgreSQL integration, AI chat proxy, and natural language to SQL",
6
6
  "license": "MIT",
7
7
  "homepage": "https://tiny-pivot.com",
@@ -49,7 +49,7 @@
49
49
  }
50
50
  },
51
51
  "dependencies": {
52
- "@smallwebco/tinypivot-core": "1.0.61"
52
+ "@smallwebco/tinypivot-core": "1.0.62"
53
53
  },
54
54
  "devDependencies": {
55
55
  "@types/pg": "^8.11.6",