@query-doctor/core 0.8.6 → 0.8.7

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 (29) hide show
  1. package/dist/index.cjs +2 -0
  2. package/dist/index.d.cts +2 -1
  3. package/dist/index.d.mts +2 -1
  4. package/dist/index.mjs +2 -1
  5. package/dist/optimizer/dump.cjs.map +1 -1
  6. package/dist/optimizer/dump.d.cts.map +1 -1
  7. package/dist/optimizer/dump.d.mts.map +1 -1
  8. package/dist/optimizer/dump.mjs.map +1 -1
  9. package/dist/sql/display-query.cjs +174 -0
  10. package/dist/sql/display-query.cjs.map +1 -0
  11. package/dist/sql/display-query.d.cts +33 -0
  12. package/dist/sql/display-query.d.cts.map +1 -0
  13. package/dist/sql/display-query.d.mts +33 -0
  14. package/dist/sql/display-query.d.mts.map +1 -0
  15. package/dist/sql/display-query.mjs +174 -0
  16. package/dist/sql/display-query.mjs.map +1 -0
  17. package/package.json +1 -1
  18. package/dist/_virtual/_@oxc-project_runtime@0.122.0/helpers/defineProperty.cjs +0 -13
  19. package/dist/_virtual/_@oxc-project_runtime@0.122.0/helpers/defineProperty.mjs +0 -13
  20. package/dist/_virtual/_@oxc-project_runtime@0.122.0/helpers/toPrimitive.cjs +0 -15
  21. package/dist/_virtual/_@oxc-project_runtime@0.122.0/helpers/toPrimitive.mjs +0 -15
  22. package/dist/_virtual/_@oxc-project_runtime@0.122.0/helpers/toPropertyKey.cjs +0 -10
  23. package/dist/_virtual/_@oxc-project_runtime@0.122.0/helpers/toPropertyKey.mjs +0 -10
  24. package/dist/_virtual/_@oxc-project_runtime@0.122.0/helpers/typeof.cjs +0 -17
  25. package/dist/_virtual/_@oxc-project_runtime@0.122.0/helpers/typeof.mjs +0 -12
  26. package/dist/index.cjs.map +0 -1
  27. package/dist/index.d.cts.map +0 -1
  28. package/dist/index.d.mts.map +0 -1
  29. package/dist/index.mjs.map +0 -1
package/dist/index.cjs CHANGED
@@ -3,6 +3,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const require_nudges = require("./sql/nudges.cjs");
4
4
  const require_analyzer = require("./sql/analyzer.cjs");
5
5
  const require_database = require("./sql/database.cjs");
6
+ const require_display_query = require("./sql/display-query.cjs");
6
7
  const require_indexes = require("./sql/indexes.cjs");
7
8
  const require_builder = require("./sql/builder.cjs");
8
9
  const require_pg_identifier = require("./sql/pg-identifier.cjs");
@@ -35,6 +36,7 @@ exports.Statistics = require_statistics.Statistics;
35
36
  exports.StatisticsMode = require_statistics.StatisticsMode;
36
37
  exports.StatisticsSource = require_statistics.StatisticsSource;
37
38
  exports.combinedDumpSql = require_dump.combinedDumpSql;
39
+ exports.compactSelectList = require_display_query.compactSelectList;
38
40
  exports.deriveSentryEnvironment = require_sentry.deriveSentryEnvironment;
39
41
  exports.dropIndex = require_database.dropIndex;
40
42
  exports.dumpQueriesSql = require_dump.dumpQueriesSql;
package/dist/index.d.cts CHANGED
@@ -7,8 +7,9 @@ import { ColumnMetadata, ComputedColumnStats, ComputedReltuples, ComputedStats,
7
7
  import { IndexIdentifier, IndexOptimizer, IndexRecommendation, OptimizeResult, PROCEED, PermutedIndexCandidate, RootIndexCandidate, SKIP } from "./optimizer/genalgo.cjs";
8
8
  import { Nudge, parseNudges } from "./sql/nudges.cjs";
9
9
  import { AnalysisResult, Analyzer, DatabaseDriver, DiscoveredColumnReference, JsonbOperator, Parser, SQLCommenterExtraction, SQLCommenterTag, SortContext, StatementType, TableReference, ignoredIdentifier } from "./sql/analyzer.cjs";
10
+ import { CompactSelectListOptions, compactSelectList } from "./sql/display-query.cjs";
10
11
  import { isIndexProbablyDroppable, isIndexSupported } from "./sql/indexes.cjs";
11
12
  import { CombinedExport, ExportedQuery, QuerySource, combinedDumpSql, dumpQueriesSql } from "./optimizer/dump.cjs";
12
13
  import { PssRewriter } from "./optimizer/pss-rewriter.cjs";
13
14
  import { deriveSentryEnvironment } from "./sentry.cjs";
14
- export { AnalysisResult, Analyzer, ColumnMetadata, CombinedExport, ComputedColumnStats, ComputedReltuples, ComputedStats, DUMP_STATS_SQL, DatabaseDriver, DiscoveredColumnReference, ExportedQuery, ExportedStats, ExportedStatsColumns, ExportedStatsIndex, ExportedStatsStatistics, ExportedStatsV1, IndexIdentifier, IndexOptimizer, IndexOrder, IndexRecommendation, IndexedTable, JsonbOperator, Nudge, OptimizeResult, PROCEED, Parameter, Parser, Path, PermutedIndexCandidate, PgIdentifier, Postgres, PostgresConnectionInput, PostgresExplainResult, PostgresExplainStage, PostgresExplainStageCommon, PostgresExplainStageSchema, PostgresFactory, PostgresQueryBuilder, PostgresQueryBuilderCommand, PostgresStage, PostgresStageId, PostgresTransaction, PostgresVersion, PssRewriter, QuerySource, RootIndexCandidate, SKIP, SQLCommenterExtraction, SQLCommenterTag, SerializeResult, SortContext, StatementType, Statistics, StatisticsMode, StatisticsSource, TableMetadata, TableReference, TableStats, combinedDumpSql, deriveSentryEnvironment, dropIndex, dumpQueriesSql, ignoredIdentifier, isIndexProbablyDroppable, isIndexSupported, parseNudges };
15
+ export { AnalysisResult, Analyzer, ColumnMetadata, CombinedExport, CompactSelectListOptions, ComputedColumnStats, ComputedReltuples, ComputedStats, DUMP_STATS_SQL, DatabaseDriver, DiscoveredColumnReference, ExportedQuery, ExportedStats, ExportedStatsColumns, ExportedStatsIndex, ExportedStatsStatistics, ExportedStatsV1, IndexIdentifier, IndexOptimizer, IndexOrder, IndexRecommendation, IndexedTable, JsonbOperator, Nudge, OptimizeResult, PROCEED, Parameter, Parser, Path, PermutedIndexCandidate, PgIdentifier, Postgres, PostgresConnectionInput, PostgresExplainResult, PostgresExplainStage, PostgresExplainStageCommon, PostgresExplainStageSchema, PostgresFactory, PostgresQueryBuilder, PostgresQueryBuilderCommand, PostgresStage, PostgresStageId, PostgresTransaction, PostgresVersion, PssRewriter, QuerySource, RootIndexCandidate, SKIP, SQLCommenterExtraction, SQLCommenterTag, SerializeResult, SortContext, StatementType, Statistics, StatisticsMode, StatisticsSource, TableMetadata, TableReference, TableStats, combinedDumpSql, compactSelectList, deriveSentryEnvironment, dropIndex, dumpQueriesSql, ignoredIdentifier, isIndexProbablyDroppable, isIndexSupported, parseNudges };
package/dist/index.d.mts CHANGED
@@ -7,8 +7,9 @@ import { ColumnMetadata, ComputedColumnStats, ComputedReltuples, ComputedStats,
7
7
  import { IndexIdentifier, IndexOptimizer, IndexRecommendation, OptimizeResult, PROCEED, PermutedIndexCandidate, RootIndexCandidate, SKIP } from "./optimizer/genalgo.mjs";
8
8
  import { Nudge, parseNudges } from "./sql/nudges.mjs";
9
9
  import { AnalysisResult, Analyzer, DatabaseDriver, DiscoveredColumnReference, JsonbOperator, Parser, SQLCommenterExtraction, SQLCommenterTag, SortContext, StatementType, TableReference, ignoredIdentifier } from "./sql/analyzer.mjs";
10
+ import { CompactSelectListOptions, compactSelectList } from "./sql/display-query.mjs";
10
11
  import { isIndexProbablyDroppable, isIndexSupported } from "./sql/indexes.mjs";
11
12
  import { CombinedExport, ExportedQuery, QuerySource, combinedDumpSql, dumpQueriesSql } from "./optimizer/dump.mjs";
12
13
  import { PssRewriter } from "./optimizer/pss-rewriter.mjs";
13
14
  import { deriveSentryEnvironment } from "./sentry.mjs";
14
- export { AnalysisResult, Analyzer, ColumnMetadata, CombinedExport, ComputedColumnStats, ComputedReltuples, ComputedStats, DUMP_STATS_SQL, DatabaseDriver, DiscoveredColumnReference, ExportedQuery, ExportedStats, ExportedStatsColumns, ExportedStatsIndex, ExportedStatsStatistics, ExportedStatsV1, IndexIdentifier, IndexOptimizer, IndexOrder, IndexRecommendation, IndexedTable, JsonbOperator, Nudge, OptimizeResult, PROCEED, Parameter, Parser, Path, PermutedIndexCandidate, PgIdentifier, Postgres, PostgresConnectionInput, PostgresExplainResult, PostgresExplainStage, PostgresExplainStageCommon, PostgresExplainStageSchema, PostgresFactory, PostgresQueryBuilder, PostgresQueryBuilderCommand, PostgresStage, PostgresStageId, PostgresTransaction, PostgresVersion, PssRewriter, QuerySource, RootIndexCandidate, SKIP, SQLCommenterExtraction, SQLCommenterTag, SerializeResult, SortContext, StatementType, Statistics, StatisticsMode, StatisticsSource, TableMetadata, TableReference, TableStats, combinedDumpSql, deriveSentryEnvironment, dropIndex, dumpQueriesSql, ignoredIdentifier, isIndexProbablyDroppable, isIndexSupported, parseNudges };
15
+ export { AnalysisResult, Analyzer, ColumnMetadata, CombinedExport, CompactSelectListOptions, ComputedColumnStats, ComputedReltuples, ComputedStats, DUMP_STATS_SQL, DatabaseDriver, DiscoveredColumnReference, ExportedQuery, ExportedStats, ExportedStatsColumns, ExportedStatsIndex, ExportedStatsStatistics, ExportedStatsV1, IndexIdentifier, IndexOptimizer, IndexOrder, IndexRecommendation, IndexedTable, JsonbOperator, Nudge, OptimizeResult, PROCEED, Parameter, Parser, Path, PermutedIndexCandidate, PgIdentifier, Postgres, PostgresConnectionInput, PostgresExplainResult, PostgresExplainStage, PostgresExplainStageCommon, PostgresExplainStageSchema, PostgresFactory, PostgresQueryBuilder, PostgresQueryBuilderCommand, PostgresStage, PostgresStageId, PostgresTransaction, PostgresVersion, PssRewriter, QuerySource, RootIndexCandidate, SKIP, SQLCommenterExtraction, SQLCommenterTag, SerializeResult, SortContext, StatementType, Statistics, StatisticsMode, StatisticsSource, TableMetadata, TableReference, TableStats, combinedDumpSql, compactSelectList, deriveSentryEnvironment, dropIndex, dumpQueriesSql, ignoredIdentifier, isIndexProbablyDroppable, isIndexSupported, parseNudges };
package/dist/index.mjs CHANGED
@@ -2,6 +2,7 @@
2
2
  import { parseNudges } from "./sql/nudges.mjs";
3
3
  import { Analyzer, ignoredIdentifier } from "./sql/analyzer.mjs";
4
4
  import { PostgresExplainStageSchema, PostgresVersion, dropIndex } from "./sql/database.mjs";
5
+ import { compactSelectList } from "./sql/display-query.mjs";
5
6
  import { isIndexProbablyDroppable, isIndexSupported } from "./sql/indexes.mjs";
6
7
  import { PostgresQueryBuilder } from "./sql/builder.mjs";
7
8
  import { PgIdentifier } from "./sql/pg-identifier.mjs";
@@ -10,4 +11,4 @@ import { ComputedColumnStats, ComputedReltuples, ComputedStats, DUMP_STATS_SQL,
10
11
  import { CombinedExport, ExportedQuery, combinedDumpSql, dumpQueriesSql } from "./optimizer/dump.mjs";
11
12
  import { PssRewriter } from "./optimizer/pss-rewriter.mjs";
12
13
  import { deriveSentryEnvironment } from "./sentry.mjs";
13
- export { Analyzer, CombinedExport, ComputedColumnStats, ComputedReltuples, ComputedStats, DUMP_STATS_SQL, ExportedQuery, ExportedStats, ExportedStatsColumns, ExportedStatsIndex, ExportedStatsStatistics, ExportedStatsV1, IndexOptimizer, PROCEED, PgIdentifier, PostgresExplainStageSchema, PostgresQueryBuilder, PostgresVersion, PssRewriter, SKIP, Statistics, StatisticsMode, StatisticsSource, combinedDumpSql, deriveSentryEnvironment, dropIndex, dumpQueriesSql, ignoredIdentifier, isIndexProbablyDroppable, isIndexSupported, parseNudges };
14
+ export { Analyzer, CombinedExport, ComputedColumnStats, ComputedReltuples, ComputedStats, DUMP_STATS_SQL, ExportedQuery, ExportedStats, ExportedStatsColumns, ExportedStatsIndex, ExportedStatsStatistics, ExportedStatsV1, IndexOptimizer, PROCEED, PgIdentifier, PostgresExplainStageSchema, PostgresQueryBuilder, PostgresVersion, PssRewriter, SKIP, Statistics, StatisticsMode, StatisticsSource, combinedDumpSql, compactSelectList, deriveSentryEnvironment, dropIndex, dumpQueriesSql, ignoredIdentifier, isIndexProbablyDroppable, isIndexSupported, parseNudges };
@@ -1 +1 @@
1
- {"version":3,"file":"dump.cjs","names":["z","ExportedStats","PgIdentifier","DUMP_STATS_SQL"],"sources":["../../src/optimizer/dump.ts"],"sourcesContent":["import dedent from \"dedent\";\nimport { z } from \"zod\";\nimport { PgIdentifier } from \"../sql/pg-identifier.js\";\nimport { DUMP_STATS_SQL, ExportedStats } from \"./statistics.js\";\n\nexport const ExportedQuery = z.object({\n username: z.string(),\n query: z.string(),\n meanTime: z.number(),\n calls: z.coerce.string(),\n rows: z.coerce.string(),\n topLevel: z.boolean(),\n});\n\nexport type ExportedQuery = z.infer<typeof ExportedQuery>;\n\nexport const CombinedExport = z.object({\n queries: z.array(ExportedQuery).nullable().transform((v) => v ?? []),\n stats: z.array(ExportedStats),\n});\n\nexport type CombinedExport = z.infer<typeof CombinedExport>;\n\nexport type QuerySource = \"pg_stat_statements\" | \"pg_stat_monitor\";\n\nfunction indent(sql: string, spaces: number): string {\n const pad = \" \".repeat(spaces);\n return sql\n .trim()\n .split(\"\\n\")\n .map((line) => pad + line)\n .join(\"\\n\");\n}\n\nexport function dumpQueriesSql(\n schema: string,\n source: QuerySource = \"pg_stat_statements\",\n): string {\n const quotedSchema = PgIdentifier.fromString(schema).toString();\n if (source === \"pg_stat_monitor\") {\n return dedent`\n SELECT\n COALESCE(username, 'unknown_user') as \"username\",\n query,\n mean_exec_time as \"meanTime\",\n calls,\n rows,\n toplevel as \"topLevel\"\n FROM ${quotedSchema}.pg_stat_monitor\n WHERE query NOT LIKE '%pg_stat_monitor%'\n AND query NOT LIKE '%@qd_introspection%'\n AND query NOT ILIKE 'explain%'\n `;\n }\n return dedent`\n SELECT\n 'unknown_user' as \"username\",\n query,\n mean_exec_time as \"meanTime\",\n calls,\n rows,\n toplevel as \"topLevel\"\n FROM ${quotedSchema}.pg_stat_statements\n WHERE query NOT LIKE '%pg_stat_statements%'\n AND query NOT LIKE '%@qd_introspection%'\n AND query != '<insufficient privilege>'\n AND query NOT ILIKE 'explain%'\n `;\n}\n\nexport function combinedDumpSql(\n schema: string,\n source: QuerySource = \"pg_stat_statements\",\n): string {\n const statsSql = indent(DUMP_STATS_SQL, 6);\n const queriesSql = indent(dumpQueriesSql(schema, source), 8);\n return [\n \"SELECT json_build_object(\",\n ` 'queries', (SELECT json_agg(q) FROM (`,\n queriesSql,\n ` ) q),`,\n ` 'stats', (`,\n statsSql,\n ` )`,\n `);`,\n ].join(\"\\n\");\n}\n"],"mappings":";;;;;;;;AAKA,MAAa,gBAAgBA,IAAAA,EAAE,OAAO;CACpC,UAAUA,IAAAA,EAAE,QAAQ;CACpB,OAAOA,IAAAA,EAAE,QAAQ;CACjB,UAAUA,IAAAA,EAAE,QAAQ;CACpB,OAAOA,IAAAA,EAAE,OAAO,QAAQ;CACxB,MAAMA,IAAAA,EAAE,OAAO,QAAQ;CACvB,UAAUA,IAAAA,EAAE,SAAS;CACtB,CAAC;AAIF,MAAa,iBAAiBA,IAAAA,EAAE,OAAO;CACrC,SAASA,IAAAA,EAAE,MAAM,cAAc,CAAC,UAAU,CAAC,WAAW,MAAM,KAAK,EAAE,CAAC;CACpE,OAAOA,IAAAA,EAAE,MAAMC,mBAAAA,cAAc;CAC9B,CAAC;AAMF,SAAS,OAAO,KAAa,QAAwB;CACnD,MAAM,MAAM,IAAI,OAAO,OAAO;AAC9B,QAAO,IACJ,MAAM,CACN,MAAM,KAAK,CACX,KAAK,SAAS,MAAM,KAAK,CACzB,KAAK,KAAK;;AAGf,SAAgB,eACd,QACA,SAAsB,sBACd;CACR,MAAM,eAAeC,sBAAAA,aAAa,WAAW,OAAO,CAAC,UAAU;AAC/D,KAAI,WAAW,kBACb,QAAO,OAAA,OAAM;;;;;;;;aAQJ,aAAa;;;;;AAMxB,QAAO,OAAA,OAAM;;;;;;;;WAQJ,aAAa;;;;;;;AAQxB,SAAgB,gBACd,QACA,SAAsB,sBACd;CACR,MAAM,WAAW,OAAOC,mBAAAA,gBAAgB,EAAE;AAE1C,QAAO;EACL;EACA;EAHiB,OAAO,eAAe,QAAQ,OAAO,EAAE,EAAE;EAK1D;EACA;EACA;EACA;EACA;EACD,CAAC,KAAK,KAAK"}
1
+ {"version":3,"file":"dump.cjs","names":["z","ExportedStats","PgIdentifier","DUMP_STATS_SQL"],"sources":["../../src/optimizer/dump.ts"],"sourcesContent":["import dedent from \"dedent\";\nimport { z } from \"zod\";\nimport { PgIdentifier } from \"../sql/pg-identifier.js\";\nimport { DUMP_STATS_SQL, ExportedStats } from \"./statistics.js\";\n\nexport const ExportedQuery = z.object({\n username: z.string(),\n query: z.string(),\n meanTime: z.number(),\n calls: z.coerce.string(),\n rows: z.coerce.string(),\n topLevel: z.boolean(),\n});\n\nexport type ExportedQuery = z.infer<typeof ExportedQuery>;\n\nexport const CombinedExport = z.object({\n queries: z\n .array(ExportedQuery)\n .nullable()\n .transform((v) => v ?? []),\n stats: z.array(ExportedStats),\n});\n\nexport type CombinedExport = z.infer<typeof CombinedExport>;\n\nexport type QuerySource = \"pg_stat_statements\" | \"pg_stat_monitor\";\n\nfunction indent(sql: string, spaces: number): string {\n const pad = \" \".repeat(spaces);\n return sql\n .trim()\n .split(\"\\n\")\n .map((line) => pad + line)\n .join(\"\\n\");\n}\n\nexport function dumpQueriesSql(\n schema: string,\n source: QuerySource = \"pg_stat_statements\",\n): string {\n const quotedSchema = PgIdentifier.fromString(schema).toString();\n if (source === \"pg_stat_monitor\") {\n return dedent`\n SELECT\n COALESCE(username, 'unknown_user') as \"username\",\n query,\n mean_exec_time as \"meanTime\",\n calls,\n rows,\n toplevel as \"topLevel\"\n FROM ${quotedSchema}.pg_stat_monitor\n WHERE query NOT LIKE '%pg_stat_monitor%'\n AND query NOT LIKE '%@qd_introspection%'\n AND query NOT ILIKE 'explain%'\n `;\n }\n return dedent`\n SELECT\n 'unknown_user' as \"username\",\n query,\n mean_exec_time as \"meanTime\",\n calls,\n rows,\n toplevel as \"topLevel\"\n FROM ${quotedSchema}.pg_stat_statements\n WHERE query NOT LIKE '%pg_stat_statements%'\n AND query NOT LIKE '%@qd_introspection%'\n AND query != '<insufficient privilege>'\n AND query NOT ILIKE 'explain%'\n `;\n}\n\nexport function combinedDumpSql(\n schema: string,\n source: QuerySource = \"pg_stat_statements\",\n): string {\n const statsSql = indent(DUMP_STATS_SQL, 6);\n const queriesSql = indent(dumpQueriesSql(schema, source), 8);\n return [\n \"SELECT json_build_object(\",\n ` 'queries', (SELECT json_agg(q) FROM (`,\n queriesSql,\n ` ) q),`,\n ` 'stats', (`,\n statsSql,\n ` )`,\n `);`,\n ].join(\"\\n\");\n}\n"],"mappings":";;;;;;;;AAKA,MAAa,gBAAgBA,IAAAA,EAAE,OAAO;CACpC,UAAUA,IAAAA,EAAE,QAAQ;CACpB,OAAOA,IAAAA,EAAE,QAAQ;CACjB,UAAUA,IAAAA,EAAE,QAAQ;CACpB,OAAOA,IAAAA,EAAE,OAAO,QAAQ;CACxB,MAAMA,IAAAA,EAAE,OAAO,QAAQ;CACvB,UAAUA,IAAAA,EAAE,SAAS;CACtB,CAAC;AAIF,MAAa,iBAAiBA,IAAAA,EAAE,OAAO;CACrC,SAASA,IAAAA,EACN,MAAM,cAAc,CACpB,UAAU,CACV,WAAW,MAAM,KAAK,EAAE,CAAC;CAC5B,OAAOA,IAAAA,EAAE,MAAMC,mBAAAA,cAAc;CAC9B,CAAC;AAMF,SAAS,OAAO,KAAa,QAAwB;CACnD,MAAM,MAAM,IAAI,OAAO,OAAO;AAC9B,QAAO,IACJ,MAAM,CACN,MAAM,KAAK,CACX,KAAK,SAAS,MAAM,KAAK,CACzB,KAAK,KAAK;;AAGf,SAAgB,eACd,QACA,SAAsB,sBACd;CACR,MAAM,eAAeC,sBAAAA,aAAa,WAAW,OAAO,CAAC,UAAU;AAC/D,KAAI,WAAW,kBACb,QAAO,OAAA,OAAM;;;;;;;;aAQJ,aAAa;;;;;AAMxB,QAAO,OAAA,OAAM;;;;;;;;WAQJ,aAAa;;;;;;;AAQxB,SAAgB,gBACd,QACA,SAAsB,sBACd;CACR,MAAM,WAAW,OAAOC,mBAAAA,gBAAgB,EAAE;AAE1C,QAAO;EACL;EACA;EAHiB,OAAO,eAAe,QAAQ,OAAO,EAAE,EAAE;EAK1D;EACA;EACA;EACA;EACA;EACD,CAAC,KAAK,KAAK"}
@@ -1 +1 @@
1
- {"version":3,"file":"dump.d.cts","names":[],"sources":["../../src/optimizer/dump.ts"],"mappings":";;;;;cAKa,aAAA,EAAa,CAAA,CAAA,SAAA;;;;;;;;KASd,aAAA,GAAgB,CAAA,CAAE,KAAA,QAAa,aAAA;AAAA,cAE9B,cAAA,EAAc,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAKf,cAAA,GAAiB,CAAA,CAAE,KAAA,QAAa,cAAA;AAAA,KAEhC,WAAA;AAAA,iBAWI,cAAA,CACd,MAAA,UACA,MAAA,GAAQ,WAAA;AAAA,iBAkCM,eAAA,CACd,MAAA,UACA,MAAA,GAAQ,WAAA"}
1
+ {"version":3,"file":"dump.d.cts","names":[],"sources":["../../src/optimizer/dump.ts"],"mappings":";;;;;cAKa,aAAA,EAAa,CAAA,CAAA,SAAA;;;;;;;;KASd,aAAA,GAAgB,CAAA,CAAE,KAAA,QAAa,aAAA;AAAA,cAE9B,cAAA,EAAc,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAQf,cAAA,GAAiB,CAAA,CAAE,KAAA,QAAa,cAAA;AAAA,KAEhC,WAAA;AAAA,iBAWI,cAAA,CACd,MAAA,UACA,MAAA,GAAQ,WAAA;AAAA,iBAkCM,eAAA,CACd,MAAA,UACA,MAAA,GAAQ,WAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"dump.d.mts","names":[],"sources":["../../src/optimizer/dump.ts"],"mappings":";;;;;cAKa,aAAA,EAAa,CAAA,CAAA,SAAA;;;;;;;;KASd,aAAA,GAAgB,CAAA,CAAE,KAAA,QAAa,aAAA;AAAA,cAE9B,cAAA,EAAc,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAKf,cAAA,GAAiB,CAAA,CAAE,KAAA,QAAa,cAAA;AAAA,KAEhC,WAAA;AAAA,iBAWI,cAAA,CACd,MAAA,UACA,MAAA,GAAQ,WAAA;AAAA,iBAkCM,eAAA,CACd,MAAA,UACA,MAAA,GAAQ,WAAA"}
1
+ {"version":3,"file":"dump.d.mts","names":[],"sources":["../../src/optimizer/dump.ts"],"mappings":";;;;;cAKa,aAAA,EAAa,CAAA,CAAA,SAAA;;;;;;;;KASd,aAAA,GAAgB,CAAA,CAAE,KAAA,QAAa,aAAA;AAAA,cAE9B,cAAA,EAAc,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAQf,cAAA,GAAiB,CAAA,CAAE,KAAA,QAAa,cAAA;AAAA,KAEhC,WAAA;AAAA,iBAWI,cAAA,CACd,MAAA,UACA,MAAA,GAAQ,WAAA;AAAA,iBAkCM,eAAA,CACd,MAAA,UACA,MAAA,GAAQ,WAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"dump.mjs","names":[],"sources":["../../src/optimizer/dump.ts"],"sourcesContent":["import dedent from \"dedent\";\nimport { z } from \"zod\";\nimport { PgIdentifier } from \"../sql/pg-identifier.js\";\nimport { DUMP_STATS_SQL, ExportedStats } from \"./statistics.js\";\n\nexport const ExportedQuery = z.object({\n username: z.string(),\n query: z.string(),\n meanTime: z.number(),\n calls: z.coerce.string(),\n rows: z.coerce.string(),\n topLevel: z.boolean(),\n});\n\nexport type ExportedQuery = z.infer<typeof ExportedQuery>;\n\nexport const CombinedExport = z.object({\n queries: z.array(ExportedQuery).nullable().transform((v) => v ?? []),\n stats: z.array(ExportedStats),\n});\n\nexport type CombinedExport = z.infer<typeof CombinedExport>;\n\nexport type QuerySource = \"pg_stat_statements\" | \"pg_stat_monitor\";\n\nfunction indent(sql: string, spaces: number): string {\n const pad = \" \".repeat(spaces);\n return sql\n .trim()\n .split(\"\\n\")\n .map((line) => pad + line)\n .join(\"\\n\");\n}\n\nexport function dumpQueriesSql(\n schema: string,\n source: QuerySource = \"pg_stat_statements\",\n): string {\n const quotedSchema = PgIdentifier.fromString(schema).toString();\n if (source === \"pg_stat_monitor\") {\n return dedent`\n SELECT\n COALESCE(username, 'unknown_user') as \"username\",\n query,\n mean_exec_time as \"meanTime\",\n calls,\n rows,\n toplevel as \"topLevel\"\n FROM ${quotedSchema}.pg_stat_monitor\n WHERE query NOT LIKE '%pg_stat_monitor%'\n AND query NOT LIKE '%@qd_introspection%'\n AND query NOT ILIKE 'explain%'\n `;\n }\n return dedent`\n SELECT\n 'unknown_user' as \"username\",\n query,\n mean_exec_time as \"meanTime\",\n calls,\n rows,\n toplevel as \"topLevel\"\n FROM ${quotedSchema}.pg_stat_statements\n WHERE query NOT LIKE '%pg_stat_statements%'\n AND query NOT LIKE '%@qd_introspection%'\n AND query != '<insufficient privilege>'\n AND query NOT ILIKE 'explain%'\n `;\n}\n\nexport function combinedDumpSql(\n schema: string,\n source: QuerySource = \"pg_stat_statements\",\n): string {\n const statsSql = indent(DUMP_STATS_SQL, 6);\n const queriesSql = indent(dumpQueriesSql(schema, source), 8);\n return [\n \"SELECT json_build_object(\",\n ` 'queries', (SELECT json_agg(q) FROM (`,\n queriesSql,\n ` ) q),`,\n ` 'stats', (`,\n statsSql,\n ` )`,\n `);`,\n ].join(\"\\n\");\n}\n"],"mappings":";;;;;;AAKA,MAAa,gBAAgB,EAAE,OAAO;CACpC,UAAU,EAAE,QAAQ;CACpB,OAAO,EAAE,QAAQ;CACjB,UAAU,EAAE,QAAQ;CACpB,OAAO,EAAE,OAAO,QAAQ;CACxB,MAAM,EAAE,OAAO,QAAQ;CACvB,UAAU,EAAE,SAAS;CACtB,CAAC;AAIF,MAAa,iBAAiB,EAAE,OAAO;CACrC,SAAS,EAAE,MAAM,cAAc,CAAC,UAAU,CAAC,WAAW,MAAM,KAAK,EAAE,CAAC;CACpE,OAAO,EAAE,MAAM,cAAc;CAC9B,CAAC;AAMF,SAAS,OAAO,KAAa,QAAwB;CACnD,MAAM,MAAM,IAAI,OAAO,OAAO;AAC9B,QAAO,IACJ,MAAM,CACN,MAAM,KAAK,CACX,KAAK,SAAS,MAAM,KAAK,CACzB,KAAK,KAAK;;AAGf,SAAgB,eACd,QACA,SAAsB,sBACd;CACR,MAAM,eAAe,aAAa,WAAW,OAAO,CAAC,UAAU;AAC/D,KAAI,WAAW,kBACb,QAAO,MAAM;;;;;;;;aAQJ,aAAa;;;;;AAMxB,QAAO,MAAM;;;;;;;;WAQJ,aAAa;;;;;;;AAQxB,SAAgB,gBACd,QACA,SAAsB,sBACd;CACR,MAAM,WAAW,OAAO,gBAAgB,EAAE;AAE1C,QAAO;EACL;EACA;EAHiB,OAAO,eAAe,QAAQ,OAAO,EAAE,EAAE;EAK1D;EACA;EACA;EACA;EACA;EACD,CAAC,KAAK,KAAK"}
1
+ {"version":3,"file":"dump.mjs","names":[],"sources":["../../src/optimizer/dump.ts"],"sourcesContent":["import dedent from \"dedent\";\nimport { z } from \"zod\";\nimport { PgIdentifier } from \"../sql/pg-identifier.js\";\nimport { DUMP_STATS_SQL, ExportedStats } from \"./statistics.js\";\n\nexport const ExportedQuery = z.object({\n username: z.string(),\n query: z.string(),\n meanTime: z.number(),\n calls: z.coerce.string(),\n rows: z.coerce.string(),\n topLevel: z.boolean(),\n});\n\nexport type ExportedQuery = z.infer<typeof ExportedQuery>;\n\nexport const CombinedExport = z.object({\n queries: z\n .array(ExportedQuery)\n .nullable()\n .transform((v) => v ?? []),\n stats: z.array(ExportedStats),\n});\n\nexport type CombinedExport = z.infer<typeof CombinedExport>;\n\nexport type QuerySource = \"pg_stat_statements\" | \"pg_stat_monitor\";\n\nfunction indent(sql: string, spaces: number): string {\n const pad = \" \".repeat(spaces);\n return sql\n .trim()\n .split(\"\\n\")\n .map((line) => pad + line)\n .join(\"\\n\");\n}\n\nexport function dumpQueriesSql(\n schema: string,\n source: QuerySource = \"pg_stat_statements\",\n): string {\n const quotedSchema = PgIdentifier.fromString(schema).toString();\n if (source === \"pg_stat_monitor\") {\n return dedent`\n SELECT\n COALESCE(username, 'unknown_user') as \"username\",\n query,\n mean_exec_time as \"meanTime\",\n calls,\n rows,\n toplevel as \"topLevel\"\n FROM ${quotedSchema}.pg_stat_monitor\n WHERE query NOT LIKE '%pg_stat_monitor%'\n AND query NOT LIKE '%@qd_introspection%'\n AND query NOT ILIKE 'explain%'\n `;\n }\n return dedent`\n SELECT\n 'unknown_user' as \"username\",\n query,\n mean_exec_time as \"meanTime\",\n calls,\n rows,\n toplevel as \"topLevel\"\n FROM ${quotedSchema}.pg_stat_statements\n WHERE query NOT LIKE '%pg_stat_statements%'\n AND query NOT LIKE '%@qd_introspection%'\n AND query != '<insufficient privilege>'\n AND query NOT ILIKE 'explain%'\n `;\n}\n\nexport function combinedDumpSql(\n schema: string,\n source: QuerySource = \"pg_stat_statements\",\n): string {\n const statsSql = indent(DUMP_STATS_SQL, 6);\n const queriesSql = indent(dumpQueriesSql(schema, source), 8);\n return [\n \"SELECT json_build_object(\",\n ` 'queries', (SELECT json_agg(q) FROM (`,\n queriesSql,\n ` ) q),`,\n ` 'stats', (`,\n statsSql,\n ` )`,\n `);`,\n ].join(\"\\n\");\n}\n"],"mappings":";;;;;;AAKA,MAAa,gBAAgB,EAAE,OAAO;CACpC,UAAU,EAAE,QAAQ;CACpB,OAAO,EAAE,QAAQ;CACjB,UAAU,EAAE,QAAQ;CACpB,OAAO,EAAE,OAAO,QAAQ;CACxB,MAAM,EAAE,OAAO,QAAQ;CACvB,UAAU,EAAE,SAAS;CACtB,CAAC;AAIF,MAAa,iBAAiB,EAAE,OAAO;CACrC,SAAS,EACN,MAAM,cAAc,CACpB,UAAU,CACV,WAAW,MAAM,KAAK,EAAE,CAAC;CAC5B,OAAO,EAAE,MAAM,cAAc;CAC9B,CAAC;AAMF,SAAS,OAAO,KAAa,QAAwB;CACnD,MAAM,MAAM,IAAI,OAAO,OAAO;AAC9B,QAAO,IACJ,MAAM,CACN,MAAM,KAAK,CACX,KAAK,SAAS,MAAM,KAAK,CACzB,KAAK,KAAK;;AAGf,SAAgB,eACd,QACA,SAAsB,sBACd;CACR,MAAM,eAAe,aAAa,WAAW,OAAO,CAAC,UAAU;AAC/D,KAAI,WAAW,kBACb,QAAO,MAAM;;;;;;;;aAQJ,aAAa;;;;;AAMxB,QAAO,MAAM;;;;;;;;WAQJ,aAAa;;;;;;;AAQxB,SAAgB,gBACd,QACA,SAAsB,sBACd;CACR,MAAM,WAAW,OAAO,gBAAgB,EAAE;AAE1C,QAAO;EACL;EACA;EAHiB,OAAO,eAAe,QAAQ,OAAO,EAAE,EAAE;EAK1D;EACA;EACA;EACA;EACA;EACD,CAAC,KAAK,KAAK"}
@@ -0,0 +1,174 @@
1
+ "use client";
2
+ const require_ast_utils = require("./ast-utils.cjs");
3
+ //#region src/sql/display-query.ts
4
+ const DEFAULTS = {
5
+ minTargets: 2,
6
+ minSliceBytes: 40
7
+ };
8
+ const ENCODER = new TextEncoder();
9
+ const DECODER = new TextDecoder();
10
+ /**
11
+ * Returns `query` with the top-level SELECT target list replaced by `...`,
12
+ * e.g. `SELECT ... FROM users WHERE id = $1`. Returns `undefined` when the
13
+ * query shouldn't be compacted: parse failure, not a plain SELECT,
14
+ * UNION/INTERSECT/EXCEPT, no FROM clause, or below the configured threshold.
15
+ *
16
+ * NOT VALID SQL — never parse or execute the result. Display-only.
17
+ *
18
+ * Caller passes the AST (already parsed via `@pgsql/parser`) so this module
19
+ * stays free of a parser runtime dependency, mirroring how `Analyzer`
20
+ * accepts an injected parser.
21
+ */
22
+ function compactSelectList(query, ast, options = {}) {
23
+ const { minTargets, minSliceBytes } = {
24
+ ...DEFAULTS,
25
+ ...options
26
+ };
27
+ const stmt = ast.stmts?.[0]?.stmt;
28
+ if (!stmt || !require_ast_utils.is(stmt, "SelectStmt")) return void 0;
29
+ const select = stmt.SelectStmt;
30
+ if (select.op && select.op !== "SETOP_NONE") return void 0;
31
+ const targetList = select.targetList;
32
+ if (!targetList || targetList.length < minTargets + 1) {
33
+ if (!targetList || targetList.length === 0) return void 0;
34
+ }
35
+ const fromClause = select.fromClause;
36
+ if (!fromClause || fromClause.length === 0) return void 0;
37
+ const firstTarget = targetList[0];
38
+ if (!require_ast_utils.is(firstTarget, "ResTarget")) return void 0;
39
+ const startByte = firstTarget.ResTarget.location;
40
+ if (typeof startByte !== "number") return void 0;
41
+ const fromItemByte = locationOf(fromClause[0]);
42
+ if (typeof fromItemByte !== "number") return void 0;
43
+ const queryBytes = ENCODER.encode(query);
44
+ const fromKeywordByte = findFromKeyword(queryBytes, startByte, fromItemByte);
45
+ if (fromKeywordByte === void 0) return void 0;
46
+ const sliceBytes = fromKeywordByte - startByte;
47
+ if (!(targetList.length > minTargets) && !(sliceBytes > minSliceBytes)) return void 0;
48
+ return `${DECODER.decode(queryBytes.slice(0, startByte))}... ${DECODER.decode(queryBytes.slice(fromKeywordByte))}`;
49
+ }
50
+ /** Best-effort byte offset for common from-clause node kinds. */
51
+ function locationOf(node) {
52
+ if (require_ast_utils.is(node, "RangeVar")) return node.RangeVar.location;
53
+ if (require_ast_utils.is(node, "RangeSubselect")) return node.RangeSubselect.location;
54
+ if (require_ast_utils.is(node, "RangeFunction")) return node.RangeFunction.location;
55
+ if (require_ast_utils.is(node, "JoinExpr")) return node.JoinExpr.larg ? locationOf(node.JoinExpr.larg) : void 0;
56
+ }
57
+ const BYTE_F = 70;
58
+ const BYTE_f = 102;
59
+ const BYTE_R = 82;
60
+ const BYTE_r = 114;
61
+ const BYTE_O = 79;
62
+ const BYTE_o = 111;
63
+ const BYTE_M = 77;
64
+ const BYTE_m = 109;
65
+ const BYTE_LPAREN = 40;
66
+ const BYTE_RPAREN = 41;
67
+ const BYTE_SQUOTE = 39;
68
+ const BYTE_DQUOTE = 34;
69
+ const BYTE_DASH = 45;
70
+ const BYTE_SLASH = 47;
71
+ const BYTE_STAR = 42;
72
+ const BYTE_LF = 10;
73
+ /**
74
+ * Scan forward in `bytes` starting at `from` (inclusive) up to `until`
75
+ * (exclusive) for the first `FROM` keyword that is at parenthesis depth 0
76
+ * and not inside a string or comment. Case-insensitive, requires word
77
+ * boundaries on both sides. Returns the byte offset of the matching `F`.
78
+ */
79
+ function findFromKeyword(bytes, from, until) {
80
+ let i = from;
81
+ let depth = 0;
82
+ let inLineComment = false;
83
+ let inBlockComment = false;
84
+ let inSingleQuote = false;
85
+ let inDoubleQuote = false;
86
+ while (i < until) {
87
+ const c = bytes[i];
88
+ if (inLineComment) {
89
+ if (c === BYTE_LF) inLineComment = false;
90
+ i++;
91
+ continue;
92
+ }
93
+ if (inBlockComment) {
94
+ if (c === BYTE_STAR && bytes[i + 1] === BYTE_SLASH) {
95
+ inBlockComment = false;
96
+ i += 2;
97
+ continue;
98
+ }
99
+ i++;
100
+ continue;
101
+ }
102
+ if (inSingleQuote) {
103
+ if (c === BYTE_SQUOTE) {
104
+ if (bytes[i + 1] === BYTE_SQUOTE) {
105
+ i += 2;
106
+ continue;
107
+ }
108
+ inSingleQuote = false;
109
+ }
110
+ i++;
111
+ continue;
112
+ }
113
+ if (inDoubleQuote) {
114
+ if (c === BYTE_DQUOTE) {
115
+ if (bytes[i + 1] === BYTE_DQUOTE) {
116
+ i += 2;
117
+ continue;
118
+ }
119
+ inDoubleQuote = false;
120
+ }
121
+ i++;
122
+ continue;
123
+ }
124
+ if (c === BYTE_DASH && bytes[i + 1] === BYTE_DASH) {
125
+ inLineComment = true;
126
+ i += 2;
127
+ continue;
128
+ }
129
+ if (c === BYTE_SLASH && bytes[i + 1] === BYTE_STAR) {
130
+ inBlockComment = true;
131
+ i += 2;
132
+ continue;
133
+ }
134
+ if (c === BYTE_SQUOTE) {
135
+ inSingleQuote = true;
136
+ i++;
137
+ continue;
138
+ }
139
+ if (c === BYTE_DQUOTE) {
140
+ inDoubleQuote = true;
141
+ i++;
142
+ continue;
143
+ }
144
+ if (c === BYTE_LPAREN) {
145
+ depth++;
146
+ i++;
147
+ continue;
148
+ }
149
+ if (c === BYTE_RPAREN) {
150
+ depth--;
151
+ i++;
152
+ continue;
153
+ }
154
+ if (depth === 0 && (c === BYTE_F || c === BYTE_f) && isFromKeywordAt(bytes, i)) return i;
155
+ i++;
156
+ }
157
+ }
158
+ function isFromKeywordAt(bytes, pos) {
159
+ const r = bytes[pos + 1];
160
+ const o = bytes[pos + 2];
161
+ const m = bytes[pos + 3];
162
+ if (!((r === BYTE_R || r === BYTE_r) && (o === BYTE_O || o === BYTE_o) && (m === BYTE_M || m === BYTE_m))) return false;
163
+ if (pos > 0 && isWordByte(bytes[pos - 1])) return false;
164
+ const next = bytes[pos + 4];
165
+ if (next !== void 0 && isWordByte(next)) return false;
166
+ return true;
167
+ }
168
+ function isWordByte(c) {
169
+ return c >= 48 && c <= 57 || c >= 65 && c <= 90 || c >= 97 && c <= 122 || c === 95;
170
+ }
171
+ //#endregion
172
+ exports.compactSelectList = compactSelectList;
173
+
174
+ //# sourceMappingURL=display-query.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"display-query.cjs","names":["is"],"sources":["../../src/sql/display-query.ts"],"sourcesContent":["import type { Node, ParseResult } from \"@pgsql/types\";\nimport { is } from \"./ast-utils.js\";\n\nexport interface CompactSelectListOptions {\n /**\n * Compact only when the SELECT has more than this many target-list entries.\n * Default: 2.\n */\n minTargets?: number;\n /**\n * Compact only when the target-list slice (from first target to FROM)\n * exceeds this many bytes. Default: 40.\n */\n minSliceBytes?: number;\n}\n\nconst DEFAULTS: Required<CompactSelectListOptions> = {\n minTargets: 2,\n minSliceBytes: 40,\n};\n\nconst ENCODER = new TextEncoder();\nconst DECODER = new TextDecoder();\n\n/**\n * Returns `query` with the top-level SELECT target list replaced by `...`,\n * e.g. `SELECT ... FROM users WHERE id = $1`. Returns `undefined` when the\n * query shouldn't be compacted: parse failure, not a plain SELECT,\n * UNION/INTERSECT/EXCEPT, no FROM clause, or below the configured threshold.\n *\n * NOT VALID SQL — never parse or execute the result. Display-only.\n *\n * Caller passes the AST (already parsed via `@pgsql/parser`) so this module\n * stays free of a parser runtime dependency, mirroring how `Analyzer`\n * accepts an injected parser.\n */\nexport function compactSelectList(\n query: string,\n ast: ParseResult,\n options: CompactSelectListOptions = {},\n): string | undefined {\n const { minTargets, minSliceBytes } = { ...DEFAULTS, ...options };\n\n const stmt = ast.stmts?.[0]?.stmt;\n if (!stmt || !is(stmt, \"SelectStmt\")) return undefined;\n\n const select = stmt.SelectStmt;\n\n // Skip set-operations — ambiguous which arm to compact.\n if (select.op && select.op !== \"SETOP_NONE\") return undefined;\n\n const targetList = select.targetList;\n if (!targetList || targetList.length < minTargets + 1) {\n // Below the target-count threshold — but the slice may still be long.\n // Fall through to the byte threshold check after computing the slice.\n if (!targetList || targetList.length === 0) return undefined;\n }\n\n const fromClause = select.fromClause;\n if (!fromClause || fromClause.length === 0) return undefined;\n\n const firstTarget = targetList[0];\n if (!is(firstTarget, \"ResTarget\")) return undefined;\n const startByte = firstTarget.ResTarget.location;\n if (typeof startByte !== \"number\") return undefined;\n\n const fromItemByte = locationOf(fromClause[0]);\n if (typeof fromItemByte !== \"number\") return undefined;\n\n const queryBytes = ENCODER.encode(query);\n\n const fromKeywordByte = findFromKeyword(queryBytes, startByte, fromItemByte);\n if (fromKeywordByte === undefined) return undefined;\n\n const sliceBytes = fromKeywordByte - startByte;\n const enoughTargets = targetList.length > minTargets;\n const enoughBytes = sliceBytes > minSliceBytes;\n if (!enoughTargets && !enoughBytes) return undefined;\n\n const before = DECODER.decode(queryBytes.slice(0, startByte));\n const after = DECODER.decode(queryBytes.slice(fromKeywordByte));\n return `${before}... ${after}`;\n}\n\n/** Best-effort byte offset for common from-clause node kinds. */\nfunction locationOf(node: Node): number | undefined {\n if (is(node, \"RangeVar\")) return node.RangeVar.location;\n if (is(node, \"RangeSubselect\")) return node.RangeSubselect.location;\n if (is(node, \"RangeFunction\")) return node.RangeFunction.location;\n if (is(node, \"JoinExpr\")) {\n return node.JoinExpr.larg ? locationOf(node.JoinExpr.larg) : undefined;\n }\n return undefined;\n}\n\nconst BYTE_F = 0x46;\nconst BYTE_f = 0x66;\nconst BYTE_R = 0x52;\nconst BYTE_r = 0x72;\nconst BYTE_O = 0x4f;\nconst BYTE_o = 0x6f;\nconst BYTE_M = 0x4d;\nconst BYTE_m = 0x6d;\nconst BYTE_LPAREN = 0x28;\nconst BYTE_RPAREN = 0x29;\nconst BYTE_SQUOTE = 0x27;\nconst BYTE_DQUOTE = 0x22;\nconst BYTE_DASH = 0x2d;\nconst BYTE_SLASH = 0x2f;\nconst BYTE_STAR = 0x2a;\nconst BYTE_LF = 0x0a;\n\n/**\n * Scan forward in `bytes` starting at `from` (inclusive) up to `until`\n * (exclusive) for the first `FROM` keyword that is at parenthesis depth 0\n * and not inside a string or comment. Case-insensitive, requires word\n * boundaries on both sides. Returns the byte offset of the matching `F`.\n */\nfunction findFromKeyword(\n bytes: Uint8Array,\n from: number,\n until: number,\n): number | undefined {\n let i = from;\n let depth = 0;\n let inLineComment = false;\n let inBlockComment = false;\n let inSingleQuote = false;\n let inDoubleQuote = false;\n\n while (i < until) {\n const c = bytes[i];\n\n if (inLineComment) {\n if (c === BYTE_LF) inLineComment = false;\n i++;\n continue;\n }\n if (inBlockComment) {\n if (c === BYTE_STAR && bytes[i + 1] === BYTE_SLASH) {\n inBlockComment = false;\n i += 2;\n continue;\n }\n i++;\n continue;\n }\n if (inSingleQuote) {\n if (c === BYTE_SQUOTE) {\n // '' is an escaped single quote inside a string literal.\n if (bytes[i + 1] === BYTE_SQUOTE) {\n i += 2;\n continue;\n }\n inSingleQuote = false;\n }\n i++;\n continue;\n }\n if (inDoubleQuote) {\n if (c === BYTE_DQUOTE) {\n if (bytes[i + 1] === BYTE_DQUOTE) {\n i += 2;\n continue;\n }\n inDoubleQuote = false;\n }\n i++;\n continue;\n }\n\n if (c === BYTE_DASH && bytes[i + 1] === BYTE_DASH) {\n inLineComment = true;\n i += 2;\n continue;\n }\n if (c === BYTE_SLASH && bytes[i + 1] === BYTE_STAR) {\n inBlockComment = true;\n i += 2;\n continue;\n }\n if (c === BYTE_SQUOTE) {\n inSingleQuote = true;\n i++;\n continue;\n }\n if (c === BYTE_DQUOTE) {\n inDoubleQuote = true;\n i++;\n continue;\n }\n if (c === BYTE_LPAREN) {\n depth++;\n i++;\n continue;\n }\n if (c === BYTE_RPAREN) {\n depth--;\n i++;\n continue;\n }\n\n if (\n depth === 0 &&\n (c === BYTE_F || c === BYTE_f) &&\n isFromKeywordAt(bytes, i)\n ) {\n return i;\n }\n i++;\n }\n return undefined;\n}\n\nfunction isFromKeywordAt(bytes: Uint8Array, pos: number): boolean {\n const r = bytes[pos + 1];\n const o = bytes[pos + 2];\n const m = bytes[pos + 3];\n if (\n !(\n (r === BYTE_R || r === BYTE_r) &&\n (o === BYTE_O || o === BYTE_o) &&\n (m === BYTE_M || m === BYTE_m)\n )\n ) {\n return false;\n }\n if (pos > 0 && isWordByte(bytes[pos - 1])) return false;\n const next = bytes[pos + 4];\n if (next !== undefined && isWordByte(next)) return false;\n return true;\n}\n\nfunction isWordByte(c: number): boolean {\n return (\n (c >= 0x30 && c <= 0x39) ||\n (c >= 0x41 && c <= 0x5a) ||\n (c >= 0x61 && c <= 0x7a) ||\n c === 0x5f\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ 'use client';
2
+
3
+ import { ParseResult } from "@pgsql/types";
4
+
5
+ //#region src/sql/display-query.d.ts
6
+ interface CompactSelectListOptions {
7
+ /**
8
+ * Compact only when the SELECT has more than this many target-list entries.
9
+ * Default: 2.
10
+ */
11
+ minTargets?: number;
12
+ /**
13
+ * Compact only when the target-list slice (from first target to FROM)
14
+ * exceeds this many bytes. Default: 40.
15
+ */
16
+ minSliceBytes?: number;
17
+ }
18
+ /**
19
+ * Returns `query` with the top-level SELECT target list replaced by `...`,
20
+ * e.g. `SELECT ... FROM users WHERE id = $1`. Returns `undefined` when the
21
+ * query shouldn't be compacted: parse failure, not a plain SELECT,
22
+ * UNION/INTERSECT/EXCEPT, no FROM clause, or below the configured threshold.
23
+ *
24
+ * NOT VALID SQL — never parse or execute the result. Display-only.
25
+ *
26
+ * Caller passes the AST (already parsed via `@pgsql/parser`) so this module
27
+ * stays free of a parser runtime dependency, mirroring how `Analyzer`
28
+ * accepts an injected parser.
29
+ */
30
+ declare function compactSelectList(query: string, ast: ParseResult, options?: CompactSelectListOptions): string | undefined;
31
+ //#endregion
32
+ export { CompactSelectListOptions, compactSelectList };
33
+ //# sourceMappingURL=display-query.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"display-query.d.cts","names":[],"sources":["../../src/sql/display-query.ts"],"mappings":";;;;;UAGiB,wBAAA;;;AAAjB;;EAKE,UAAA;EAAA;;AA4BF;;EAvBE,aAAA;AAAA;;;;;;;;;;;;;iBAuBc,iBAAA,CACd,KAAA,UACA,GAAA,EAAK,WAAA,EACL,OAAA,GAAS,wBAAA"}
@@ -0,0 +1,33 @@
1
+ 'use client';
2
+
3
+ import { ParseResult } from "@pgsql/types";
4
+
5
+ //#region src/sql/display-query.d.ts
6
+ interface CompactSelectListOptions {
7
+ /**
8
+ * Compact only when the SELECT has more than this many target-list entries.
9
+ * Default: 2.
10
+ */
11
+ minTargets?: number;
12
+ /**
13
+ * Compact only when the target-list slice (from first target to FROM)
14
+ * exceeds this many bytes. Default: 40.
15
+ */
16
+ minSliceBytes?: number;
17
+ }
18
+ /**
19
+ * Returns `query` with the top-level SELECT target list replaced by `...`,
20
+ * e.g. `SELECT ... FROM users WHERE id = $1`. Returns `undefined` when the
21
+ * query shouldn't be compacted: parse failure, not a plain SELECT,
22
+ * UNION/INTERSECT/EXCEPT, no FROM clause, or below the configured threshold.
23
+ *
24
+ * NOT VALID SQL — never parse or execute the result. Display-only.
25
+ *
26
+ * Caller passes the AST (already parsed via `@pgsql/parser`) so this module
27
+ * stays free of a parser runtime dependency, mirroring how `Analyzer`
28
+ * accepts an injected parser.
29
+ */
30
+ declare function compactSelectList(query: string, ast: ParseResult, options?: CompactSelectListOptions): string | undefined;
31
+ //#endregion
32
+ export { CompactSelectListOptions, compactSelectList };
33
+ //# sourceMappingURL=display-query.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"display-query.d.mts","names":[],"sources":["../../src/sql/display-query.ts"],"mappings":";;;;;UAGiB,wBAAA;;;AAAjB;;EAKE,UAAA;EAAA;;AA4BF;;EAvBE,aAAA;AAAA;;;;;;;;;;;;;iBAuBc,iBAAA,CACd,KAAA,UACA,GAAA,EAAK,WAAA,EACL,OAAA,GAAS,wBAAA"}
@@ -0,0 +1,174 @@
1
+ "use client";
2
+ import { is } from "./ast-utils.mjs";
3
+ //#region src/sql/display-query.ts
4
+ const DEFAULTS = {
5
+ minTargets: 2,
6
+ minSliceBytes: 40
7
+ };
8
+ const ENCODER = new TextEncoder();
9
+ const DECODER = new TextDecoder();
10
+ /**
11
+ * Returns `query` with the top-level SELECT target list replaced by `...`,
12
+ * e.g. `SELECT ... FROM users WHERE id = $1`. Returns `undefined` when the
13
+ * query shouldn't be compacted: parse failure, not a plain SELECT,
14
+ * UNION/INTERSECT/EXCEPT, no FROM clause, or below the configured threshold.
15
+ *
16
+ * NOT VALID SQL — never parse or execute the result. Display-only.
17
+ *
18
+ * Caller passes the AST (already parsed via `@pgsql/parser`) so this module
19
+ * stays free of a parser runtime dependency, mirroring how `Analyzer`
20
+ * accepts an injected parser.
21
+ */
22
+ function compactSelectList(query, ast, options = {}) {
23
+ const { minTargets, minSliceBytes } = {
24
+ ...DEFAULTS,
25
+ ...options
26
+ };
27
+ const stmt = ast.stmts?.[0]?.stmt;
28
+ if (!stmt || !is(stmt, "SelectStmt")) return void 0;
29
+ const select = stmt.SelectStmt;
30
+ if (select.op && select.op !== "SETOP_NONE") return void 0;
31
+ const targetList = select.targetList;
32
+ if (!targetList || targetList.length < minTargets + 1) {
33
+ if (!targetList || targetList.length === 0) return void 0;
34
+ }
35
+ const fromClause = select.fromClause;
36
+ if (!fromClause || fromClause.length === 0) return void 0;
37
+ const firstTarget = targetList[0];
38
+ if (!is(firstTarget, "ResTarget")) return void 0;
39
+ const startByte = firstTarget.ResTarget.location;
40
+ if (typeof startByte !== "number") return void 0;
41
+ const fromItemByte = locationOf(fromClause[0]);
42
+ if (typeof fromItemByte !== "number") return void 0;
43
+ const queryBytes = ENCODER.encode(query);
44
+ const fromKeywordByte = findFromKeyword(queryBytes, startByte, fromItemByte);
45
+ if (fromKeywordByte === void 0) return void 0;
46
+ const sliceBytes = fromKeywordByte - startByte;
47
+ if (!(targetList.length > minTargets) && !(sliceBytes > minSliceBytes)) return void 0;
48
+ return `${DECODER.decode(queryBytes.slice(0, startByte))}... ${DECODER.decode(queryBytes.slice(fromKeywordByte))}`;
49
+ }
50
+ /** Best-effort byte offset for common from-clause node kinds. */
51
+ function locationOf(node) {
52
+ if (is(node, "RangeVar")) return node.RangeVar.location;
53
+ if (is(node, "RangeSubselect")) return node.RangeSubselect.location;
54
+ if (is(node, "RangeFunction")) return node.RangeFunction.location;
55
+ if (is(node, "JoinExpr")) return node.JoinExpr.larg ? locationOf(node.JoinExpr.larg) : void 0;
56
+ }
57
+ const BYTE_F = 70;
58
+ const BYTE_f = 102;
59
+ const BYTE_R = 82;
60
+ const BYTE_r = 114;
61
+ const BYTE_O = 79;
62
+ const BYTE_o = 111;
63
+ const BYTE_M = 77;
64
+ const BYTE_m = 109;
65
+ const BYTE_LPAREN = 40;
66
+ const BYTE_RPAREN = 41;
67
+ const BYTE_SQUOTE = 39;
68
+ const BYTE_DQUOTE = 34;
69
+ const BYTE_DASH = 45;
70
+ const BYTE_SLASH = 47;
71
+ const BYTE_STAR = 42;
72
+ const BYTE_LF = 10;
73
+ /**
74
+ * Scan forward in `bytes` starting at `from` (inclusive) up to `until`
75
+ * (exclusive) for the first `FROM` keyword that is at parenthesis depth 0
76
+ * and not inside a string or comment. Case-insensitive, requires word
77
+ * boundaries on both sides. Returns the byte offset of the matching `F`.
78
+ */
79
+ function findFromKeyword(bytes, from, until) {
80
+ let i = from;
81
+ let depth = 0;
82
+ let inLineComment = false;
83
+ let inBlockComment = false;
84
+ let inSingleQuote = false;
85
+ let inDoubleQuote = false;
86
+ while (i < until) {
87
+ const c = bytes[i];
88
+ if (inLineComment) {
89
+ if (c === BYTE_LF) inLineComment = false;
90
+ i++;
91
+ continue;
92
+ }
93
+ if (inBlockComment) {
94
+ if (c === BYTE_STAR && bytes[i + 1] === BYTE_SLASH) {
95
+ inBlockComment = false;
96
+ i += 2;
97
+ continue;
98
+ }
99
+ i++;
100
+ continue;
101
+ }
102
+ if (inSingleQuote) {
103
+ if (c === BYTE_SQUOTE) {
104
+ if (bytes[i + 1] === BYTE_SQUOTE) {
105
+ i += 2;
106
+ continue;
107
+ }
108
+ inSingleQuote = false;
109
+ }
110
+ i++;
111
+ continue;
112
+ }
113
+ if (inDoubleQuote) {
114
+ if (c === BYTE_DQUOTE) {
115
+ if (bytes[i + 1] === BYTE_DQUOTE) {
116
+ i += 2;
117
+ continue;
118
+ }
119
+ inDoubleQuote = false;
120
+ }
121
+ i++;
122
+ continue;
123
+ }
124
+ if (c === BYTE_DASH && bytes[i + 1] === BYTE_DASH) {
125
+ inLineComment = true;
126
+ i += 2;
127
+ continue;
128
+ }
129
+ if (c === BYTE_SLASH && bytes[i + 1] === BYTE_STAR) {
130
+ inBlockComment = true;
131
+ i += 2;
132
+ continue;
133
+ }
134
+ if (c === BYTE_SQUOTE) {
135
+ inSingleQuote = true;
136
+ i++;
137
+ continue;
138
+ }
139
+ if (c === BYTE_DQUOTE) {
140
+ inDoubleQuote = true;
141
+ i++;
142
+ continue;
143
+ }
144
+ if (c === BYTE_LPAREN) {
145
+ depth++;
146
+ i++;
147
+ continue;
148
+ }
149
+ if (c === BYTE_RPAREN) {
150
+ depth--;
151
+ i++;
152
+ continue;
153
+ }
154
+ if (depth === 0 && (c === BYTE_F || c === BYTE_f) && isFromKeywordAt(bytes, i)) return i;
155
+ i++;
156
+ }
157
+ }
158
+ function isFromKeywordAt(bytes, pos) {
159
+ const r = bytes[pos + 1];
160
+ const o = bytes[pos + 2];
161
+ const m = bytes[pos + 3];
162
+ if (!((r === BYTE_R || r === BYTE_r) && (o === BYTE_O || o === BYTE_o) && (m === BYTE_M || m === BYTE_m))) return false;
163
+ if (pos > 0 && isWordByte(bytes[pos - 1])) return false;
164
+ const next = bytes[pos + 4];
165
+ if (next !== void 0 && isWordByte(next)) return false;
166
+ return true;
167
+ }
168
+ function isWordByte(c) {
169
+ return c >= 48 && c <= 57 || c >= 65 && c <= 90 || c >= 97 && c <= 122 || c === 95;
170
+ }
171
+ //#endregion
172
+ export { compactSelectList };
173
+
174
+ //# sourceMappingURL=display-query.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"display-query.mjs","names":[],"sources":["../../src/sql/display-query.ts"],"sourcesContent":["import type { Node, ParseResult } from \"@pgsql/types\";\nimport { is } from \"./ast-utils.js\";\n\nexport interface CompactSelectListOptions {\n /**\n * Compact only when the SELECT has more than this many target-list entries.\n * Default: 2.\n */\n minTargets?: number;\n /**\n * Compact only when the target-list slice (from first target to FROM)\n * exceeds this many bytes. Default: 40.\n */\n minSliceBytes?: number;\n}\n\nconst DEFAULTS: Required<CompactSelectListOptions> = {\n minTargets: 2,\n minSliceBytes: 40,\n};\n\nconst ENCODER = new TextEncoder();\nconst DECODER = new TextDecoder();\n\n/**\n * Returns `query` with the top-level SELECT target list replaced by `...`,\n * e.g. `SELECT ... FROM users WHERE id = $1`. Returns `undefined` when the\n * query shouldn't be compacted: parse failure, not a plain SELECT,\n * UNION/INTERSECT/EXCEPT, no FROM clause, or below the configured threshold.\n *\n * NOT VALID SQL — never parse or execute the result. Display-only.\n *\n * Caller passes the AST (already parsed via `@pgsql/parser`) so this module\n * stays free of a parser runtime dependency, mirroring how `Analyzer`\n * accepts an injected parser.\n */\nexport function compactSelectList(\n query: string,\n ast: ParseResult,\n options: CompactSelectListOptions = {},\n): string | undefined {\n const { minTargets, minSliceBytes } = { ...DEFAULTS, ...options };\n\n const stmt = ast.stmts?.[0]?.stmt;\n if (!stmt || !is(stmt, \"SelectStmt\")) return undefined;\n\n const select = stmt.SelectStmt;\n\n // Skip set-operations — ambiguous which arm to compact.\n if (select.op && select.op !== \"SETOP_NONE\") return undefined;\n\n const targetList = select.targetList;\n if (!targetList || targetList.length < minTargets + 1) {\n // Below the target-count threshold — but the slice may still be long.\n // Fall through to the byte threshold check after computing the slice.\n if (!targetList || targetList.length === 0) return undefined;\n }\n\n const fromClause = select.fromClause;\n if (!fromClause || fromClause.length === 0) return undefined;\n\n const firstTarget = targetList[0];\n if (!is(firstTarget, \"ResTarget\")) return undefined;\n const startByte = firstTarget.ResTarget.location;\n if (typeof startByte !== \"number\") return undefined;\n\n const fromItemByte = locationOf(fromClause[0]);\n if (typeof fromItemByte !== \"number\") return undefined;\n\n const queryBytes = ENCODER.encode(query);\n\n const fromKeywordByte = findFromKeyword(queryBytes, startByte, fromItemByte);\n if (fromKeywordByte === undefined) return undefined;\n\n const sliceBytes = fromKeywordByte - startByte;\n const enoughTargets = targetList.length > minTargets;\n const enoughBytes = sliceBytes > minSliceBytes;\n if (!enoughTargets && !enoughBytes) return undefined;\n\n const before = DECODER.decode(queryBytes.slice(0, startByte));\n const after = DECODER.decode(queryBytes.slice(fromKeywordByte));\n return `${before}... ${after}`;\n}\n\n/** Best-effort byte offset for common from-clause node kinds. */\nfunction locationOf(node: Node): number | undefined {\n if (is(node, \"RangeVar\")) return node.RangeVar.location;\n if (is(node, \"RangeSubselect\")) return node.RangeSubselect.location;\n if (is(node, \"RangeFunction\")) return node.RangeFunction.location;\n if (is(node, \"JoinExpr\")) {\n return node.JoinExpr.larg ? locationOf(node.JoinExpr.larg) : undefined;\n }\n return undefined;\n}\n\nconst BYTE_F = 0x46;\nconst BYTE_f = 0x66;\nconst BYTE_R = 0x52;\nconst BYTE_r = 0x72;\nconst BYTE_O = 0x4f;\nconst BYTE_o = 0x6f;\nconst BYTE_M = 0x4d;\nconst BYTE_m = 0x6d;\nconst BYTE_LPAREN = 0x28;\nconst BYTE_RPAREN = 0x29;\nconst BYTE_SQUOTE = 0x27;\nconst BYTE_DQUOTE = 0x22;\nconst BYTE_DASH = 0x2d;\nconst BYTE_SLASH = 0x2f;\nconst BYTE_STAR = 0x2a;\nconst BYTE_LF = 0x0a;\n\n/**\n * Scan forward in `bytes` starting at `from` (inclusive) up to `until`\n * (exclusive) for the first `FROM` keyword that is at parenthesis depth 0\n * and not inside a string or comment. Case-insensitive, requires word\n * boundaries on both sides. Returns the byte offset of the matching `F`.\n */\nfunction findFromKeyword(\n bytes: Uint8Array,\n from: number,\n until: number,\n): number | undefined {\n let i = from;\n let depth = 0;\n let inLineComment = false;\n let inBlockComment = false;\n let inSingleQuote = false;\n let inDoubleQuote = false;\n\n while (i < until) {\n const c = bytes[i];\n\n if (inLineComment) {\n if (c === BYTE_LF) inLineComment = false;\n i++;\n continue;\n }\n if (inBlockComment) {\n if (c === BYTE_STAR && bytes[i + 1] === BYTE_SLASH) {\n inBlockComment = false;\n i += 2;\n continue;\n }\n i++;\n continue;\n }\n if (inSingleQuote) {\n if (c === BYTE_SQUOTE) {\n // '' is an escaped single quote inside a string literal.\n if (bytes[i + 1] === BYTE_SQUOTE) {\n i += 2;\n continue;\n }\n inSingleQuote = false;\n }\n i++;\n continue;\n }\n if (inDoubleQuote) {\n if (c === BYTE_DQUOTE) {\n if (bytes[i + 1] === BYTE_DQUOTE) {\n i += 2;\n continue;\n }\n inDoubleQuote = false;\n }\n i++;\n continue;\n }\n\n if (c === BYTE_DASH && bytes[i + 1] === BYTE_DASH) {\n inLineComment = true;\n i += 2;\n continue;\n }\n if (c === BYTE_SLASH && bytes[i + 1] === BYTE_STAR) {\n inBlockComment = true;\n i += 2;\n continue;\n }\n if (c === BYTE_SQUOTE) {\n inSingleQuote = true;\n i++;\n continue;\n }\n if (c === BYTE_DQUOTE) {\n inDoubleQuote = true;\n i++;\n continue;\n }\n if (c === BYTE_LPAREN) {\n depth++;\n i++;\n continue;\n }\n if (c === BYTE_RPAREN) {\n depth--;\n i++;\n continue;\n }\n\n if (\n depth === 0 &&\n (c === BYTE_F || c === BYTE_f) &&\n isFromKeywordAt(bytes, i)\n ) {\n return i;\n }\n i++;\n }\n return undefined;\n}\n\nfunction isFromKeywordAt(bytes: Uint8Array, pos: number): boolean {\n const r = bytes[pos + 1];\n const o = bytes[pos + 2];\n const m = bytes[pos + 3];\n if (\n !(\n (r === BYTE_R || r === BYTE_r) &&\n (o === BYTE_O || o === BYTE_o) &&\n (m === BYTE_M || m === BYTE_m)\n )\n ) {\n return false;\n }\n if (pos > 0 && isWordByte(bytes[pos - 1])) return false;\n const next = bytes[pos + 4];\n if (next !== undefined && isWordByte(next)) return false;\n return true;\n}\n\nfunction isWordByte(c: number): boolean {\n return (\n (c >= 0x30 && c <= 0x39) ||\n (c >= 0x41 && c <= 0x5a) ||\n (c >= 0x61 && c <= 0x7a) ||\n c === 0x5f\n );\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@query-doctor/core",
3
- "version": "0.8.6",
3
+ "version": "0.8.7",
4
4
  "private": false,
5
5
  "description": "Core logic for Query Doctor",
6
6
  "license": "",
@@ -1,13 +0,0 @@
1
- "use client";
2
- const require_toPropertyKey = require("./toPropertyKey.cjs");
3
- //#region \0@oxc-project+runtime@0.122.0/helpers/defineProperty.js
4
- function _defineProperty(e, r, t) {
5
- return (r = require_toPropertyKey.toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
6
- value: t,
7
- enumerable: !0,
8
- configurable: !0,
9
- writable: !0
10
- }) : e[r] = t, e;
11
- }
12
- //#endregion
13
- exports._defineProperty = _defineProperty;
@@ -1,13 +0,0 @@
1
- "use client";
2
- import { toPropertyKey } from "./toPropertyKey.mjs";
3
- //#region \0@oxc-project+runtime@0.122.0/helpers/defineProperty.js
4
- function _defineProperty(e, r, t) {
5
- return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
6
- value: t,
7
- enumerable: !0,
8
- configurable: !0,
9
- writable: !0
10
- }) : e[r] = t, e;
11
- }
12
- //#endregion
13
- export { _defineProperty };
@@ -1,15 +0,0 @@
1
- "use client";
2
- const require_typeof = require("./typeof.cjs");
3
- //#region \0@oxc-project+runtime@0.122.0/helpers/toPrimitive.js
4
- function toPrimitive(t, r) {
5
- if ("object" != require_typeof._typeof(t) || !t) return t;
6
- var e = t[Symbol.toPrimitive];
7
- if (void 0 !== e) {
8
- var i = e.call(t, r || "default");
9
- if ("object" != require_typeof._typeof(i)) return i;
10
- throw new TypeError("@@toPrimitive must return a primitive value.");
11
- }
12
- return ("string" === r ? String : Number)(t);
13
- }
14
- //#endregion
15
- exports.toPrimitive = toPrimitive;