@biref/scanner 0.1.0 → 0.2.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/dist/index.d.cts CHANGED
@@ -14,7 +14,7 @@
14
14
  * ```
15
15
  */
16
16
  interface MySQLClient {
17
- execute<TRow = unknown>(sql: string, params?: readonly unknown[]): Promise<[TRow[], unknown]>;
17
+ execute<TRow = unknown>(sql: string, params?: any[]): Promise<[TRow[], unknown]>;
18
18
  }
19
19
 
20
20
  /**
@@ -1004,6 +1004,21 @@ declare class QueryPlanExecutor {
1004
1004
  private static filterKeys;
1005
1005
  }
1006
1006
 
1007
+ /**
1008
+ * A single query that would be executed by `findMany` / `findFirst`.
1009
+ *
1010
+ * `sql` is the parameterized SQL string, `params` are the bound values,
1011
+ * and `entity` identifies which table the query targets. For include
1012
+ * trees the `includes` array contains one `ExplainedQuery` per nested
1013
+ * level, mirroring the execution order.
1014
+ */
1015
+ interface ExplainedQuery {
1016
+ readonly entity: string;
1017
+ readonly sql: string;
1018
+ readonly params: readonly unknown[];
1019
+ readonly includes: readonly ExplainedQuery[];
1020
+ }
1021
+
1007
1022
  /**
1008
1023
  * Runtime context threaded through every `ChainBuilder` instance.
1009
1024
  *
@@ -1071,6 +1086,22 @@ declare class ChainBuilder {
1071
1086
  include(relationName: string, build?: (q: ChainBuilder) => ChainBuilder): ChainBuilder;
1072
1087
  findMany(): Promise<readonly ParsedRecord[]>;
1073
1088
  findFirst(): Promise<ParsedRecord | null>;
1089
+ /**
1090
+ * Build and return every SQL query that `findMany` would execute,
1091
+ * without running them. Walks the full plan tree including nested
1092
+ * includes, returning the root query and one child per include level.
1093
+ *
1094
+ * Include children use placeholder `IN (?)` filters since the real
1095
+ * parent key values are only known at execution time.
1096
+ *
1097
+ * Accepts a `QueryEngine` to produce adapter-specific SQL. Pass the
1098
+ * adapter's engine for the dialect you want to inspect:
1099
+ *
1100
+ * const explained = chain.toSQL(biref.adapters.get('postgres').engine);
1101
+ */
1102
+ toSQL(engine: QueryEngine): ExplainedQuery;
1103
+ private static explainPlan;
1104
+ private static buildExplainChildPlan;
1074
1105
  /**
1075
1106
  * Escape hatch for advanced callers (tests, tooling): exposes the
1076
1107
  * accumulated plan without executing it. The typed builder's public
@@ -1350,6 +1381,16 @@ interface TypedChain<S extends BirefSchemaShape, Ns extends keyof S, E extends k
1350
1381
  }>;
1351
1382
  findMany(): Promise<readonly HydratedRow<Sel, Inc>[]>;
1352
1383
  findFirst(): Promise<HydratedRow<Sel, Inc> | null>;
1384
+ /**
1385
+ * Build and return every SQL query that `findMany` would execute,
1386
+ * without running them. Walks the full plan tree including nested
1387
+ * includes.
1388
+ *
1389
+ * Pass the adapter's engine for the dialect you want to inspect:
1390
+ *
1391
+ * chain.toSQL(biref.adapters.get('postgres').engine)
1392
+ */
1393
+ toSQL(engine: QueryEngine): ExplainedQuery;
1353
1394
  toPlan(): QueryPlan;
1354
1395
  }
1355
1396
  /**
@@ -1646,4 +1687,4 @@ type ApplySchemaOverrides<Raw extends BirefSchemaShape, Overrides extends BirefO
1646
1687
  };
1647
1688
  type ReplaceFieldTs<Field, NewTs> = Field extends SchemaFieldDescriptor<infer _OldTs, infer Nullable, infer Identifier, infer Category> ? SchemaFieldDescriptor<NewTs, Nullable, Identifier, Category> : Field;
1648
1689
 
1649
- export { type Adapter, type AdapterFactory, type AdapterName, AdapterRegistry, type ApplySchemaOverrides, Biref, BirefBuilder, type BirefOverridesShape, type BirefSchemaShape, type BuiltQuery, type BuiltQueryMetadata, type CardinalityOf, type CategoryOf, type CategoryOfField, ChainBuilder, type ChainBuilderContext, type Constraint, type ConstraintKind, CsvFormatter, type CsvFormatterOptions, DataModel, DefaultRecordParser, type DefaultSelect, type EngineKind, type Entity, type EntityRef, type Field, type FieldType, type FieldTypeCategory, type FieldsOf, type Filter, type FilterOperator, type Formatter, type HydratedRow, type IncludeMap, type Index, type IndexKind, type IntrospectOptions, type Introspector, JsonFormatter, type JsonFormatterOptions, type KnownAdapterName, MYSQL_ADAPTER_NAME, MYSQL_URL_SCHEMES, type MySQLAdapterName, type MySQLClient, MySQLIntrospector, MySQLQueryEngine, MySQLRecordParser, type NullaryOps, type OpsFor, type OrderBy, POSTGRES_ADAPTER_NAME, POSTGRES_URL_SCHEMES, type ParsedRecord, type ParsedValue, type PickSelect, type PostgresAdapterName, type PostgresClient, PostgresIntrospector, PostgresQueryEngine, PostgresRecordParser, type QueryEngine, type QueryInclude, type QueryPlan, QueryPlanExecutor, type QuerySpec, RawFormatter, type RawQueryRunner, type RecordParser, type Reference, type ReferentialAction, type RelationsOf, type RelationsOfEntity, type Relationship, type RelationshipDirection, Scanner, type SchemaEntityDescriptor, type SchemaFieldDescriptor, type SchemaFile, type SchemaNamespaceDescriptor, type SchemaRelationDescriptor, type Selection, type SerializeOptions, type Split, type TargetE, type TargetNs, type TypeOf, type TypedChain, type TypedQueryRoot, type UntypedQueryRoot, type ValueFor, type WrapForCardinality, generateSchema, generateSchemaFiles, isMySQLAdapter, isPostgresAdapter, mysqlAdapter, overridesScaffold, postgresAdapter, tsTypeFor };
1690
+ export { type Adapter, type AdapterFactory, type AdapterName, AdapterRegistry, type ApplySchemaOverrides, Biref, BirefBuilder, type BirefOverridesShape, type BirefSchemaShape, type BuiltQuery, type BuiltQueryMetadata, type CardinalityOf, type CategoryOf, type CategoryOfField, ChainBuilder, type ChainBuilderContext, type Constraint, type ConstraintKind, CsvFormatter, type CsvFormatterOptions, DataModel, DefaultRecordParser, type DefaultSelect, type EngineKind, type Entity, type EntityRef, type ExplainedQuery, type Field, type FieldType, type FieldTypeCategory, type FieldsOf, type Filter, type FilterOperator, type Formatter, type HydratedRow, type IncludeMap, type Index, type IndexKind, type IntrospectOptions, type Introspector, JsonFormatter, type JsonFormatterOptions, type KnownAdapterName, MYSQL_ADAPTER_NAME, MYSQL_URL_SCHEMES, type MySQLAdapterName, type MySQLClient, MySQLIntrospector, MySQLQueryEngine, MySQLRecordParser, type NullaryOps, type OpsFor, type OrderBy, POSTGRES_ADAPTER_NAME, POSTGRES_URL_SCHEMES, type ParsedRecord, type ParsedValue, type PickSelect, type PostgresAdapterName, type PostgresClient, PostgresIntrospector, PostgresQueryEngine, PostgresRecordParser, type QueryEngine, type QueryInclude, type QueryPlan, QueryPlanExecutor, type QuerySpec, RawFormatter, type RawQueryRunner, type RecordParser, type Reference, type ReferentialAction, type RelationsOf, type RelationsOfEntity, type Relationship, type RelationshipDirection, Scanner, type SchemaEntityDescriptor, type SchemaFieldDescriptor, type SchemaFile, type SchemaNamespaceDescriptor, type SchemaRelationDescriptor, type Selection, type SerializeOptions, type Split, type TargetE, type TargetNs, type TypeOf, type TypedChain, type TypedQueryRoot, type UntypedQueryRoot, type ValueFor, type WrapForCardinality, generateSchema, generateSchemaFiles, isMySQLAdapter, isPostgresAdapter, mysqlAdapter, overridesScaffold, postgresAdapter, tsTypeFor };
package/dist/index.d.ts CHANGED
@@ -14,7 +14,7 @@
14
14
  * ```
15
15
  */
16
16
  interface MySQLClient {
17
- execute<TRow = unknown>(sql: string, params?: readonly unknown[]): Promise<[TRow[], unknown]>;
17
+ execute<TRow = unknown>(sql: string, params?: any[]): Promise<[TRow[], unknown]>;
18
18
  }
19
19
 
20
20
  /**
@@ -1004,6 +1004,21 @@ declare class QueryPlanExecutor {
1004
1004
  private static filterKeys;
1005
1005
  }
1006
1006
 
1007
+ /**
1008
+ * A single query that would be executed by `findMany` / `findFirst`.
1009
+ *
1010
+ * `sql` is the parameterized SQL string, `params` are the bound values,
1011
+ * and `entity` identifies which table the query targets. For include
1012
+ * trees the `includes` array contains one `ExplainedQuery` per nested
1013
+ * level, mirroring the execution order.
1014
+ */
1015
+ interface ExplainedQuery {
1016
+ readonly entity: string;
1017
+ readonly sql: string;
1018
+ readonly params: readonly unknown[];
1019
+ readonly includes: readonly ExplainedQuery[];
1020
+ }
1021
+
1007
1022
  /**
1008
1023
  * Runtime context threaded through every `ChainBuilder` instance.
1009
1024
  *
@@ -1071,6 +1086,22 @@ declare class ChainBuilder {
1071
1086
  include(relationName: string, build?: (q: ChainBuilder) => ChainBuilder): ChainBuilder;
1072
1087
  findMany(): Promise<readonly ParsedRecord[]>;
1073
1088
  findFirst(): Promise<ParsedRecord | null>;
1089
+ /**
1090
+ * Build and return every SQL query that `findMany` would execute,
1091
+ * without running them. Walks the full plan tree including nested
1092
+ * includes, returning the root query and one child per include level.
1093
+ *
1094
+ * Include children use placeholder `IN (?)` filters since the real
1095
+ * parent key values are only known at execution time.
1096
+ *
1097
+ * Accepts a `QueryEngine` to produce adapter-specific SQL. Pass the
1098
+ * adapter's engine for the dialect you want to inspect:
1099
+ *
1100
+ * const explained = chain.toSQL(biref.adapters.get('postgres').engine);
1101
+ */
1102
+ toSQL(engine: QueryEngine): ExplainedQuery;
1103
+ private static explainPlan;
1104
+ private static buildExplainChildPlan;
1074
1105
  /**
1075
1106
  * Escape hatch for advanced callers (tests, tooling): exposes the
1076
1107
  * accumulated plan without executing it. The typed builder's public
@@ -1350,6 +1381,16 @@ interface TypedChain<S extends BirefSchemaShape, Ns extends keyof S, E extends k
1350
1381
  }>;
1351
1382
  findMany(): Promise<readonly HydratedRow<Sel, Inc>[]>;
1352
1383
  findFirst(): Promise<HydratedRow<Sel, Inc> | null>;
1384
+ /**
1385
+ * Build and return every SQL query that `findMany` would execute,
1386
+ * without running them. Walks the full plan tree including nested
1387
+ * includes.
1388
+ *
1389
+ * Pass the adapter's engine for the dialect you want to inspect:
1390
+ *
1391
+ * chain.toSQL(biref.adapters.get('postgres').engine)
1392
+ */
1393
+ toSQL(engine: QueryEngine): ExplainedQuery;
1353
1394
  toPlan(): QueryPlan;
1354
1395
  }
1355
1396
  /**
@@ -1646,4 +1687,4 @@ type ApplySchemaOverrides<Raw extends BirefSchemaShape, Overrides extends BirefO
1646
1687
  };
1647
1688
  type ReplaceFieldTs<Field, NewTs> = Field extends SchemaFieldDescriptor<infer _OldTs, infer Nullable, infer Identifier, infer Category> ? SchemaFieldDescriptor<NewTs, Nullable, Identifier, Category> : Field;
1648
1689
 
1649
- export { type Adapter, type AdapterFactory, type AdapterName, AdapterRegistry, type ApplySchemaOverrides, Biref, BirefBuilder, type BirefOverridesShape, type BirefSchemaShape, type BuiltQuery, type BuiltQueryMetadata, type CardinalityOf, type CategoryOf, type CategoryOfField, ChainBuilder, type ChainBuilderContext, type Constraint, type ConstraintKind, CsvFormatter, type CsvFormatterOptions, DataModel, DefaultRecordParser, type DefaultSelect, type EngineKind, type Entity, type EntityRef, type Field, type FieldType, type FieldTypeCategory, type FieldsOf, type Filter, type FilterOperator, type Formatter, type HydratedRow, type IncludeMap, type Index, type IndexKind, type IntrospectOptions, type Introspector, JsonFormatter, type JsonFormatterOptions, type KnownAdapterName, MYSQL_ADAPTER_NAME, MYSQL_URL_SCHEMES, type MySQLAdapterName, type MySQLClient, MySQLIntrospector, MySQLQueryEngine, MySQLRecordParser, type NullaryOps, type OpsFor, type OrderBy, POSTGRES_ADAPTER_NAME, POSTGRES_URL_SCHEMES, type ParsedRecord, type ParsedValue, type PickSelect, type PostgresAdapterName, type PostgresClient, PostgresIntrospector, PostgresQueryEngine, PostgresRecordParser, type QueryEngine, type QueryInclude, type QueryPlan, QueryPlanExecutor, type QuerySpec, RawFormatter, type RawQueryRunner, type RecordParser, type Reference, type ReferentialAction, type RelationsOf, type RelationsOfEntity, type Relationship, type RelationshipDirection, Scanner, type SchemaEntityDescriptor, type SchemaFieldDescriptor, type SchemaFile, type SchemaNamespaceDescriptor, type SchemaRelationDescriptor, type Selection, type SerializeOptions, type Split, type TargetE, type TargetNs, type TypeOf, type TypedChain, type TypedQueryRoot, type UntypedQueryRoot, type ValueFor, type WrapForCardinality, generateSchema, generateSchemaFiles, isMySQLAdapter, isPostgresAdapter, mysqlAdapter, overridesScaffold, postgresAdapter, tsTypeFor };
1690
+ export { type Adapter, type AdapterFactory, type AdapterName, AdapterRegistry, type ApplySchemaOverrides, Biref, BirefBuilder, type BirefOverridesShape, type BirefSchemaShape, type BuiltQuery, type BuiltQueryMetadata, type CardinalityOf, type CategoryOf, type CategoryOfField, ChainBuilder, type ChainBuilderContext, type Constraint, type ConstraintKind, CsvFormatter, type CsvFormatterOptions, DataModel, DefaultRecordParser, type DefaultSelect, type EngineKind, type Entity, type EntityRef, type ExplainedQuery, type Field, type FieldType, type FieldTypeCategory, type FieldsOf, type Filter, type FilterOperator, type Formatter, type HydratedRow, type IncludeMap, type Index, type IndexKind, type IntrospectOptions, type Introspector, JsonFormatter, type JsonFormatterOptions, type KnownAdapterName, MYSQL_ADAPTER_NAME, MYSQL_URL_SCHEMES, type MySQLAdapterName, type MySQLClient, MySQLIntrospector, MySQLQueryEngine, MySQLRecordParser, type NullaryOps, type OpsFor, type OrderBy, POSTGRES_ADAPTER_NAME, POSTGRES_URL_SCHEMES, type ParsedRecord, type ParsedValue, type PickSelect, type PostgresAdapterName, type PostgresClient, PostgresIntrospector, PostgresQueryEngine, PostgresRecordParser, type QueryEngine, type QueryInclude, type QueryPlan, QueryPlanExecutor, type QuerySpec, RawFormatter, type RawQueryRunner, type RecordParser, type Reference, type ReferentialAction, type RelationsOf, type RelationsOfEntity, type Relationship, type RelationshipDirection, Scanner, type SchemaEntityDescriptor, type SchemaFieldDescriptor, type SchemaFile, type SchemaNamespaceDescriptor, type SchemaRelationDescriptor, type Selection, type SerializeOptions, type Split, type TargetE, type TargetNs, type TypeOf, type TypedChain, type TypedQueryRoot, type UntypedQueryRoot, type ValueFor, type WrapForCardinality, generateSchema, generateSchemaFiles, isMySQLAdapter, isPostgresAdapter, mysqlAdapter, overridesScaffold, postgresAdapter, tsTypeFor };
package/dist/index.js CHANGED
@@ -933,10 +933,10 @@ var MySQLQueryEngine = class {
933
933
  sql += ` ORDER BY ${orderPieces.join(", ")}`;
934
934
  }
935
935
  if (spec.limit !== void 0) {
936
- sql += ` LIMIT ${params.add(spec.limit)}`;
936
+ sql += ` LIMIT ${Number(spec.limit)}`;
937
937
  }
938
938
  if (spec.offset !== void 0) {
939
- sql += ` OFFSET ${params.add(spec.offset)}`;
939
+ sql += ` OFFSET ${Number(spec.offset)}`;
940
940
  }
941
941
  return {
942
942
  command: sql,
@@ -2849,6 +2849,50 @@ var ChainBuilder = class _ChainBuilder {
2849
2849
  const rows = await this.ctx.executor.execute(limited, this.ctx.model);
2850
2850
  return rows[0] ?? null;
2851
2851
  }
2852
+ /**
2853
+ * Build and return every SQL query that `findMany` would execute,
2854
+ * without running them. Walks the full plan tree including nested
2855
+ * includes, returning the root query and one child per include level.
2856
+ *
2857
+ * Include children use placeholder `IN (?)` filters since the real
2858
+ * parent key values are only known at execution time.
2859
+ *
2860
+ * Accepts a `QueryEngine` to produce adapter-specific SQL. Pass the
2861
+ * adapter's engine for the dialect you want to inspect:
2862
+ *
2863
+ * const explained = chain.toSQL(biref.adapters.get('postgres').engine);
2864
+ */
2865
+ toSQL(engine) {
2866
+ return _ChainBuilder.explainPlan(this.plan, engine, this.ctx.model);
2867
+ }
2868
+ static explainPlan(plan, engine, model) {
2869
+ const built = engine.build(plan.spec, model);
2870
+ const childExplained = [];
2871
+ for (const include of plan.includes) {
2872
+ const childPlan = _ChainBuilder.buildExplainChildPlan(include);
2873
+ childExplained.push(_ChainBuilder.explainPlan(childPlan, engine, model));
2874
+ }
2875
+ return {
2876
+ entity: `${plan.spec.namespace}.${plan.spec.entity}`,
2877
+ sql: built.command,
2878
+ params: built.params,
2879
+ includes: childExplained
2880
+ };
2881
+ }
2882
+ static buildExplainChildPlan(include) {
2883
+ const filters = [...include.plan.spec.filters ?? []];
2884
+ for (const childKey of include.childKeys) {
2885
+ filters.push({
2886
+ field: childKey,
2887
+ operator: "in",
2888
+ value: ["?"]
2889
+ });
2890
+ }
2891
+ return {
2892
+ ...include.plan,
2893
+ spec: { ...include.plan.spec, filters }
2894
+ };
2895
+ }
2852
2896
  /**
2853
2897
  * Escape hatch for advanced callers (tests, tooling): exposes the
2854
2898
  * accumulated plan without executing it. The typed builder's public