@atscript/db-sql-tools 0.1.154 → 0.1.155

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
@@ -1470,6 +1470,19 @@ function buildProjection(dialect, select, qualifier) {
1470
1470
  }
1471
1471
  return sql || `${prefix}*`;
1472
1472
  }
1473
+ /**
1474
+ * One query counting the rows of `quotedTable` that `columns` cannot hold as
1475
+ * a primary key: rows with a NULL in one of them, plus every row of a group
1476
+ * sharing the same values. Schema sync asks it before rebuilding the key of
1477
+ * a populated table (result column `violations`).
1478
+ * @since 0.1.155
1479
+ */
1480
+ function buildKeyViolationCount(dialect, quotedTable, columns) {
1481
+ const cols = columns.map((c) => dialect.quoteIdentifier(c));
1482
+ const anyNull = cols.map((c) => `${c} IS NULL`).join(" OR ");
1483
+ const noNull = cols.map((c) => `${c} IS NOT NULL`).join(" AND ");
1484
+ return `SELECT (SELECT COUNT(*) FROM ${quotedTable} WHERE ${anyNull}) + (SELECT COALESCE(SUM(${dialect.quoteIdentifier("n")}), 0) FROM (SELECT COUNT(*) AS ${dialect.quoteIdentifier("n")} FROM ${quotedTable} WHERE ${noNull} GROUP BY ${cols.join(", ")} HAVING COUNT(*) > 1) ${dialect.quoteIdentifier("d")}) AS ` + dialect.quoteIdentifier("violations");
1485
+ }
1473
1486
  //#endregion
1474
1487
  //#region src/geo.ts
1475
1488
  /**
@@ -1748,6 +1761,41 @@ function viewReadSource(dialect, readable, tableName, query, kind, partitionBy)
1748
1761
  return source;
1749
1762
  }
1750
1763
  //#endregion
1764
+ //#region src/json-copy.ts
1765
+ /**
1766
+ * `UPDATE` copying the JSON values of the text column `source` into
1767
+ * `targets` (`BaseDbAdapter.copyFromJsonColumn`, since 0.1.155): each target
1768
+ * reads its path with the dialect's {@link SqlDialect.jsonExtractText} (a
1769
+ * `boolean` target with `jsonExtract(…, "boolean")`, a `json` one with
1770
+ * {@link SqlDialect.jsonExtractValue}), passed through `cast` (the
1771
+ * adapter's conversion to the column type). Only rows where `source` holds
1772
+ * a value and every target is NULL are touched, so a re-run never
1773
+ * overwrites values written since.
1774
+ */
1775
+ function buildJsonColumnCopy(dialect, table, source, targets, cast = (expr) => expr) {
1776
+ if (!dialect.jsonExtractText || !dialect.jsonExtractValue || !dialect.jsonExtract) throw new Error("Copying JSON values into columns is not supported by this adapter");
1777
+ const src = dialect.quoteIdentifier(source);
1778
+ const sets = [];
1779
+ const empty = [];
1780
+ for (const target of targets) {
1781
+ const col = dialect.quoteIdentifier(target.column);
1782
+ const expr = target.kind === "json" ? dialect.jsonExtractValue(src, target.path) : target.kind === "boolean" ? dialect.jsonExtract(src, target.path, "boolean") : dialect.jsonExtractText(src, target.path);
1783
+ sets.push(`${col} = ${cast(expr, target)}`);
1784
+ empty.push(`${col} IS NULL`);
1785
+ }
1786
+ return `UPDATE ${dialect.quoteTable(table)} SET ${sets.join(", ")} WHERE ${src} IS NOT NULL AND ${empty.join(" AND ")}`;
1787
+ }
1788
+ /**
1789
+ * `UPDATE` rewriting the text column `column` as JSON text
1790
+ * (`BaseDbAdapter.jsonifyTextColumn`, since 0.1.155): valid JSON stays, other
1791
+ * text becomes a JSON string — see {@link SqlDialect.jsonFromText}.
1792
+ */
1793
+ function buildJsonifyText(dialect, table, column) {
1794
+ if (!dialect.jsonFromText) throw new Error("Converting text values to JSON is not supported by this adapter");
1795
+ const col = dialect.quoteIdentifier(column);
1796
+ return `UPDATE ${dialect.quoteTable(table)} SET ${col} = ${dialect.jsonFromText(col)} WHERE ${col} IS NOT NULL`;
1797
+ }
1798
+ //#endregion
1751
1799
  exports.AGG_FN_SQL = AGG_FN_SQL;
1752
1800
  exports.EMPTY_AND = EMPTY_AND;
1753
1801
  exports.EMPTY_OR = EMPTY_OR;
@@ -1766,6 +1814,9 @@ exports.buildGeoSearchCount = buildGeoSearchCount;
1766
1814
  exports.buildGeoSearchSelect = buildGeoSearchSelect;
1767
1815
  exports.buildInsert = buildInsert;
1768
1816
  exports.buildInsertMany = buildInsertMany;
1817
+ exports.buildJsonColumnCopy = buildJsonColumnCopy;
1818
+ exports.buildJsonifyText = buildJsonifyText;
1819
+ exports.buildKeyViolationCount = buildKeyViolationCount;
1769
1820
  exports.buildPartitionedSelect = buildPartitionedSelect;
1770
1821
  exports.buildProjection = buildProjection;
1771
1822
  exports.buildSelect = buildSelect;
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { AtscriptExprNode, AtscriptQueryFieldRef, AtscriptQueryNode, DbControls, DbError, DbQuery, TDbDefaultFn, TDbFieldMeta, TDbForeignKey, TDbReferentialAction, TFieldOps, TReadColumnsKind, TResolvedBucket, TViewColumnMapping, TViewJsonType, TViewPlan, UniquSelect } from "@atscript/db";
1
+ import { AtscriptExprNode, AtscriptQueryFieldRef, AtscriptQueryNode, DbControls, DbError, DbQuery, TDbDefaultFn, TDbFieldMeta, TDbForeignKey, TDbReferentialAction, TFieldOps, TJsonCopyTarget, TReadColumnsKind, TResolvedBucket, TViewColumnMapping, TViewJsonType, TViewPlan, UniquSelect } from "@atscript/db";
2
2
  import { FilterExpr, FilterVisitor, NullsPlacement } from "@uniqu/core";
3
3
  import { TDbAggregateFn } from "@atscript/db/agg";
4
4
 
@@ -100,6 +100,29 @@ interface SqlDialect {
100
100
  * @since 0.1.136
101
101
  */
102
102
  jsonExtract?(quotedCol: string, path: readonly string[], type: TViewJsonType): string;
103
+ /**
104
+ * Schema sync's copy out of a JSON text column ({@link buildJsonColumnCopy},
105
+ * since 0.1.155): the value at `path` as text — a JSON string unquoted, a
106
+ * number / boolean as its JSON text (SQLite: as the SQL value), an object
107
+ * or array as JSON text; NULL when the path is missing or the value is JSON
108
+ * `null`. A malformed JSON column value makes the statement fail.
109
+ * Parameter-free; dialects without it cannot run that copy.
110
+ * @since 0.1.155
111
+ */
112
+ jsonExtractText?(quotedCol: string, path: readonly string[]): string;
113
+ /**
114
+ * The value at `path` as JSON (for a JSON column), NULL when missing or
115
+ * JSON `null` — see {@link jsonExtractText}.
116
+ * @since 0.1.155
117
+ */
118
+ jsonExtractValue?(quotedCol: string, path: readonly string[]): string;
119
+ /**
120
+ * A text column's value as JSON text ({@link buildJsonifyText}, since
121
+ * 0.1.155): a valid JSON value is kept, any other text becomes a JSON
122
+ * string (`abc` → `"abc"`). Parameter-free.
123
+ * @since 0.1.155
124
+ */
125
+ jsonFromText?(quotedCol: string): string;
103
126
  /**
104
127
  * `expr` cast to an IEEE double — how a computed view column
105
128
  * (`@db.compute`) evaluates every field / literal leaf, so `7 / 2 = 3.5`
@@ -642,6 +665,14 @@ declare function derivedColumnExpr(dialect: SqlDialect, field: TDbFieldMeta): st
642
665
  * or aliased source such as the geo / vector search subqueries (since 0.1.143).
643
666
  */
644
667
  declare function buildProjection(dialect: SqlDialect, select?: UniquSelect, qualifier?: string): string;
668
+ /**
669
+ * One query counting the rows of `quotedTable` that `columns` cannot hold as
670
+ * a primary key: rows with a NULL in one of them, plus every row of a group
671
+ * sharing the same values. Schema sync asks it before rebuilding the key of
672
+ * a populated table (result column `violations`).
673
+ * @since 0.1.155
674
+ */
675
+ declare function buildKeyViolationCount(dialect: SqlDialect, quotedTable: string, columns: readonly string[]): string;
645
676
  //#endregion
646
677
  //#region src/common.d.ts
647
678
  /** Formats a string value as a SQL literal with single-quote escaping. */
@@ -775,4 +806,23 @@ interface TReadableLike {
775
806
  */
776
807
  declare function viewReadSource(dialect: SqlDialect, readable: TReadableLike, tableName: string, query: DbQuery, kind: TReadColumnsKind, partitionBy?: readonly string[]): TSqlFromSource;
777
808
  //#endregion
778
- export { AGG_FN_SQL, EMPTY_AND, EMPTY_OR, GEO_DISTANCE_ALIAS, InsertSqlCache, PARTITION_ROW_NUMBER_ALIAS, SEARCH_SOURCE_ALIAS, SQL_DEFAULT, type SqlDialect, type TArithFailure, type TFilterVisitorOptions, type TGeoCircle, type TGeoSearchControls, type TGeoWindow, type TReplaceColumn, type TSqlDerivedSource, type TSqlFragment, type TSqlFromSource, VECTOR_DISTANCE_ALIAS, arithOverflowError, buildAggregateCount, buildAggregateSelect, buildCreateView, buildDelete, buildGeoSearchCount, buildGeoSearchSelect, buildInsert, buildInsertMany, buildPartitionedSelect, buildProjection, buildSelect, buildUpdate, buildVectorSearchCount, buildVectorSearchSelect, buildViewSelect, buildWhere, chunkInsertRows, createFilterVisitor, defaultValueForType, defaultValueToSqlLiteral, derivedColumnExpr, fillReplacePayload, finalizeParams, foreignKeySql, fromSourceHint, fromSourceSql, geoWindowFromControls, groupKeySql, insertManyColumns, jsonDollarPath, mapQueryErrors, normalizeGeoPointValue, nullsOrderSql, nullsPlacementOf, numericOutOfRangeError, orFragment, orderByList, orderKeySql, parseRegexString, queryNodeToSql, queryOpToSql, quotedJsonPathSegments, refActionToSql, renameGeoDistance, renderArith, replaceColumnsFor, sqlStringLiteral, sqlTimeZoneLiteral, stripPartitionRowNumber, toSqlValue, vectorDistanceSource, viewReadSource };
809
+ //#region src/json-copy.d.ts
810
+ /**
811
+ * `UPDATE` copying the JSON values of the text column `source` into
812
+ * `targets` (`BaseDbAdapter.copyFromJsonColumn`, since 0.1.155): each target
813
+ * reads its path with the dialect's {@link SqlDialect.jsonExtractText} (a
814
+ * `boolean` target with `jsonExtract(…, "boolean")`, a `json` one with
815
+ * {@link SqlDialect.jsonExtractValue}), passed through `cast` (the
816
+ * adapter's conversion to the column type). Only rows where `source` holds
817
+ * a value and every target is NULL are touched, so a re-run never
818
+ * overwrites values written since.
819
+ */
820
+ declare function buildJsonColumnCopy(dialect: SqlDialect, table: string, source: string, targets: readonly TJsonCopyTarget[], cast?: (expr: string, target: TJsonCopyTarget) => string): string;
821
+ /**
822
+ * `UPDATE` rewriting the text column `column` as JSON text
823
+ * (`BaseDbAdapter.jsonifyTextColumn`, since 0.1.155): valid JSON stays, other
824
+ * text becomes a JSON string — see {@link SqlDialect.jsonFromText}.
825
+ */
826
+ declare function buildJsonifyText(dialect: SqlDialect, table: string, column: string): string;
827
+ //#endregion
828
+ export { AGG_FN_SQL, EMPTY_AND, EMPTY_OR, GEO_DISTANCE_ALIAS, InsertSqlCache, PARTITION_ROW_NUMBER_ALIAS, SEARCH_SOURCE_ALIAS, SQL_DEFAULT, type SqlDialect, type TArithFailure, type TFilterVisitorOptions, type TGeoCircle, type TGeoSearchControls, type TGeoWindow, type TReplaceColumn, type TSqlDerivedSource, type TSqlFragment, type TSqlFromSource, VECTOR_DISTANCE_ALIAS, arithOverflowError, buildAggregateCount, buildAggregateSelect, buildCreateView, buildDelete, buildGeoSearchCount, buildGeoSearchSelect, buildInsert, buildInsertMany, buildJsonColumnCopy, buildJsonifyText, buildKeyViolationCount, buildPartitionedSelect, buildProjection, buildSelect, buildUpdate, buildVectorSearchCount, buildVectorSearchSelect, buildViewSelect, buildWhere, chunkInsertRows, createFilterVisitor, defaultValueForType, defaultValueToSqlLiteral, derivedColumnExpr, fillReplacePayload, finalizeParams, foreignKeySql, fromSourceHint, fromSourceSql, geoWindowFromControls, groupKeySql, insertManyColumns, jsonDollarPath, mapQueryErrors, normalizeGeoPointValue, nullsOrderSql, nullsPlacementOf, numericOutOfRangeError, orFragment, orderByList, orderKeySql, parseRegexString, queryNodeToSql, queryOpToSql, quotedJsonPathSegments, refActionToSql, renameGeoDistance, renderArith, replaceColumnsFor, sqlStringLiteral, sqlTimeZoneLiteral, stripPartitionRowNumber, toSqlValue, vectorDistanceSource, viewReadSource };
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { AtscriptExprNode, AtscriptQueryFieldRef, AtscriptQueryNode, DbControls, DbError, DbQuery, TDbDefaultFn, TDbFieldMeta, TDbForeignKey, TDbReferentialAction, TFieldOps, TReadColumnsKind, TResolvedBucket, TViewColumnMapping, TViewJsonType, TViewPlan, UniquSelect } from "@atscript/db";
1
+ import { AtscriptExprNode, AtscriptQueryFieldRef, AtscriptQueryNode, DbControls, DbError, DbQuery, TDbDefaultFn, TDbFieldMeta, TDbForeignKey, TDbReferentialAction, TFieldOps, TJsonCopyTarget, TReadColumnsKind, TResolvedBucket, TViewColumnMapping, TViewJsonType, TViewPlan, UniquSelect } from "@atscript/db";
2
2
  import { FilterExpr, FilterVisitor, NullsPlacement } from "@uniqu/core";
3
3
  import { TDbAggregateFn } from "@atscript/db/agg";
4
4
 
@@ -100,6 +100,29 @@ interface SqlDialect {
100
100
  * @since 0.1.136
101
101
  */
102
102
  jsonExtract?(quotedCol: string, path: readonly string[], type: TViewJsonType): string;
103
+ /**
104
+ * Schema sync's copy out of a JSON text column ({@link buildJsonColumnCopy},
105
+ * since 0.1.155): the value at `path` as text — a JSON string unquoted, a
106
+ * number / boolean as its JSON text (SQLite: as the SQL value), an object
107
+ * or array as JSON text; NULL when the path is missing or the value is JSON
108
+ * `null`. A malformed JSON column value makes the statement fail.
109
+ * Parameter-free; dialects without it cannot run that copy.
110
+ * @since 0.1.155
111
+ */
112
+ jsonExtractText?(quotedCol: string, path: readonly string[]): string;
113
+ /**
114
+ * The value at `path` as JSON (for a JSON column), NULL when missing or
115
+ * JSON `null` — see {@link jsonExtractText}.
116
+ * @since 0.1.155
117
+ */
118
+ jsonExtractValue?(quotedCol: string, path: readonly string[]): string;
119
+ /**
120
+ * A text column's value as JSON text ({@link buildJsonifyText}, since
121
+ * 0.1.155): a valid JSON value is kept, any other text becomes a JSON
122
+ * string (`abc` → `"abc"`). Parameter-free.
123
+ * @since 0.1.155
124
+ */
125
+ jsonFromText?(quotedCol: string): string;
103
126
  /**
104
127
  * `expr` cast to an IEEE double — how a computed view column
105
128
  * (`@db.compute`) evaluates every field / literal leaf, so `7 / 2 = 3.5`
@@ -642,6 +665,14 @@ declare function derivedColumnExpr(dialect: SqlDialect, field: TDbFieldMeta): st
642
665
  * or aliased source such as the geo / vector search subqueries (since 0.1.143).
643
666
  */
644
667
  declare function buildProjection(dialect: SqlDialect, select?: UniquSelect, qualifier?: string): string;
668
+ /**
669
+ * One query counting the rows of `quotedTable` that `columns` cannot hold as
670
+ * a primary key: rows with a NULL in one of them, plus every row of a group
671
+ * sharing the same values. Schema sync asks it before rebuilding the key of
672
+ * a populated table (result column `violations`).
673
+ * @since 0.1.155
674
+ */
675
+ declare function buildKeyViolationCount(dialect: SqlDialect, quotedTable: string, columns: readonly string[]): string;
645
676
  //#endregion
646
677
  //#region src/common.d.ts
647
678
  /** Formats a string value as a SQL literal with single-quote escaping. */
@@ -775,4 +806,23 @@ interface TReadableLike {
775
806
  */
776
807
  declare function viewReadSource(dialect: SqlDialect, readable: TReadableLike, tableName: string, query: DbQuery, kind: TReadColumnsKind, partitionBy?: readonly string[]): TSqlFromSource;
777
808
  //#endregion
778
- export { AGG_FN_SQL, EMPTY_AND, EMPTY_OR, GEO_DISTANCE_ALIAS, InsertSqlCache, PARTITION_ROW_NUMBER_ALIAS, SEARCH_SOURCE_ALIAS, SQL_DEFAULT, type SqlDialect, type TArithFailure, type TFilterVisitorOptions, type TGeoCircle, type TGeoSearchControls, type TGeoWindow, type TReplaceColumn, type TSqlDerivedSource, type TSqlFragment, type TSqlFromSource, VECTOR_DISTANCE_ALIAS, arithOverflowError, buildAggregateCount, buildAggregateSelect, buildCreateView, buildDelete, buildGeoSearchCount, buildGeoSearchSelect, buildInsert, buildInsertMany, buildPartitionedSelect, buildProjection, buildSelect, buildUpdate, buildVectorSearchCount, buildVectorSearchSelect, buildViewSelect, buildWhere, chunkInsertRows, createFilterVisitor, defaultValueForType, defaultValueToSqlLiteral, derivedColumnExpr, fillReplacePayload, finalizeParams, foreignKeySql, fromSourceHint, fromSourceSql, geoWindowFromControls, groupKeySql, insertManyColumns, jsonDollarPath, mapQueryErrors, normalizeGeoPointValue, nullsOrderSql, nullsPlacementOf, numericOutOfRangeError, orFragment, orderByList, orderKeySql, parseRegexString, queryNodeToSql, queryOpToSql, quotedJsonPathSegments, refActionToSql, renameGeoDistance, renderArith, replaceColumnsFor, sqlStringLiteral, sqlTimeZoneLiteral, stripPartitionRowNumber, toSqlValue, vectorDistanceSource, viewReadSource };
809
+ //#region src/json-copy.d.ts
810
+ /**
811
+ * `UPDATE` copying the JSON values of the text column `source` into
812
+ * `targets` (`BaseDbAdapter.copyFromJsonColumn`, since 0.1.155): each target
813
+ * reads its path with the dialect's {@link SqlDialect.jsonExtractText} (a
814
+ * `boolean` target with `jsonExtract(…, "boolean")`, a `json` one with
815
+ * {@link SqlDialect.jsonExtractValue}), passed through `cast` (the
816
+ * adapter's conversion to the column type). Only rows where `source` holds
817
+ * a value and every target is NULL are touched, so a re-run never
818
+ * overwrites values written since.
819
+ */
820
+ declare function buildJsonColumnCopy(dialect: SqlDialect, table: string, source: string, targets: readonly TJsonCopyTarget[], cast?: (expr: string, target: TJsonCopyTarget) => string): string;
821
+ /**
822
+ * `UPDATE` rewriting the text column `column` as JSON text
823
+ * (`BaseDbAdapter.jsonifyTextColumn`, since 0.1.155): valid JSON stays, other
824
+ * text becomes a JSON string — see {@link SqlDialect.jsonFromText}.
825
+ */
826
+ declare function buildJsonifyText(dialect: SqlDialect, table: string, column: string): string;
827
+ //#endregion
828
+ export { AGG_FN_SQL, EMPTY_AND, EMPTY_OR, GEO_DISTANCE_ALIAS, InsertSqlCache, PARTITION_ROW_NUMBER_ALIAS, SEARCH_SOURCE_ALIAS, SQL_DEFAULT, type SqlDialect, type TArithFailure, type TFilterVisitorOptions, type TGeoCircle, type TGeoSearchControls, type TGeoWindow, type TReplaceColumn, type TSqlDerivedSource, type TSqlFragment, type TSqlFromSource, VECTOR_DISTANCE_ALIAS, arithOverflowError, buildAggregateCount, buildAggregateSelect, buildCreateView, buildDelete, buildGeoSearchCount, buildGeoSearchSelect, buildInsert, buildInsertMany, buildJsonColumnCopy, buildJsonifyText, buildKeyViolationCount, buildPartitionedSelect, buildProjection, buildSelect, buildUpdate, buildVectorSearchCount, buildVectorSearchSelect, buildViewSelect, buildWhere, chunkInsertRows, createFilterVisitor, defaultValueForType, defaultValueToSqlLiteral, derivedColumnExpr, fillReplacePayload, finalizeParams, foreignKeySql, fromSourceHint, fromSourceSql, geoWindowFromControls, groupKeySql, insertManyColumns, jsonDollarPath, mapQueryErrors, normalizeGeoPointValue, nullsOrderSql, nullsPlacementOf, numericOutOfRangeError, orFragment, orderByList, orderKeySql, parseRegexString, queryNodeToSql, queryOpToSql, quotedJsonPathSegments, refActionToSql, renameGeoDistance, renderArith, replaceColumnsFor, sqlStringLiteral, sqlTimeZoneLiteral, stripPartitionRowNumber, toSqlValue, vectorDistanceSource, viewReadSource };
package/dist/index.mjs CHANGED
@@ -1469,6 +1469,19 @@ function buildProjection(dialect, select, qualifier) {
1469
1469
  }
1470
1470
  return sql || `${prefix}*`;
1471
1471
  }
1472
+ /**
1473
+ * One query counting the rows of `quotedTable` that `columns` cannot hold as
1474
+ * a primary key: rows with a NULL in one of them, plus every row of a group
1475
+ * sharing the same values. Schema sync asks it before rebuilding the key of
1476
+ * a populated table (result column `violations`).
1477
+ * @since 0.1.155
1478
+ */
1479
+ function buildKeyViolationCount(dialect, quotedTable, columns) {
1480
+ const cols = columns.map((c) => dialect.quoteIdentifier(c));
1481
+ const anyNull = cols.map((c) => `${c} IS NULL`).join(" OR ");
1482
+ const noNull = cols.map((c) => `${c} IS NOT NULL`).join(" AND ");
1483
+ return `SELECT (SELECT COUNT(*) FROM ${quotedTable} WHERE ${anyNull}) + (SELECT COALESCE(SUM(${dialect.quoteIdentifier("n")}), 0) FROM (SELECT COUNT(*) AS ${dialect.quoteIdentifier("n")} FROM ${quotedTable} WHERE ${noNull} GROUP BY ${cols.join(", ")} HAVING COUNT(*) > 1) ${dialect.quoteIdentifier("d")}) AS ` + dialect.quoteIdentifier("violations");
1484
+ }
1472
1485
  //#endregion
1473
1486
  //#region src/geo.ts
1474
1487
  /**
@@ -1747,4 +1760,39 @@ function viewReadSource(dialect, readable, tableName, query, kind, partitionBy)
1747
1760
  return source;
1748
1761
  }
1749
1762
  //#endregion
1750
- export { AGG_FN_SQL, EMPTY_AND, EMPTY_OR, GEO_DISTANCE_ALIAS, InsertSqlCache, PARTITION_ROW_NUMBER_ALIAS, SEARCH_SOURCE_ALIAS, SQL_DEFAULT, VECTOR_DISTANCE_ALIAS, arithOverflowError, buildAggregateCount, buildAggregateSelect, buildCreateView, buildDelete, buildGeoSearchCount, buildGeoSearchSelect, buildInsert, buildInsertMany, buildPartitionedSelect, buildProjection, buildSelect, buildUpdate, buildVectorSearchCount, buildVectorSearchSelect, buildViewSelect, buildWhere, chunkInsertRows, createFilterVisitor, defaultValueForType, defaultValueToSqlLiteral, derivedColumnExpr, fillReplacePayload, finalizeParams, foreignKeySql, fromSourceHint, fromSourceSql, geoWindowFromControls, groupKeySql, insertManyColumns, jsonDollarPath, mapQueryErrors, normalizeGeoPointValue, nullsOrderSql, nullsPlacementOf, numericOutOfRangeError, orFragment, orderByList, orderKeySql, parseRegexString, queryNodeToSql, queryOpToSql, quotedJsonPathSegments, refActionToSql, renameGeoDistance, renderArith, replaceColumnsFor, sqlStringLiteral, sqlTimeZoneLiteral, stripPartitionRowNumber, toSqlValue, vectorDistanceSource, viewReadSource };
1763
+ //#region src/json-copy.ts
1764
+ /**
1765
+ * `UPDATE` copying the JSON values of the text column `source` into
1766
+ * `targets` (`BaseDbAdapter.copyFromJsonColumn`, since 0.1.155): each target
1767
+ * reads its path with the dialect's {@link SqlDialect.jsonExtractText} (a
1768
+ * `boolean` target with `jsonExtract(…, "boolean")`, a `json` one with
1769
+ * {@link SqlDialect.jsonExtractValue}), passed through `cast` (the
1770
+ * adapter's conversion to the column type). Only rows where `source` holds
1771
+ * a value and every target is NULL are touched, so a re-run never
1772
+ * overwrites values written since.
1773
+ */
1774
+ function buildJsonColumnCopy(dialect, table, source, targets, cast = (expr) => expr) {
1775
+ if (!dialect.jsonExtractText || !dialect.jsonExtractValue || !dialect.jsonExtract) throw new Error("Copying JSON values into columns is not supported by this adapter");
1776
+ const src = dialect.quoteIdentifier(source);
1777
+ const sets = [];
1778
+ const empty = [];
1779
+ for (const target of targets) {
1780
+ const col = dialect.quoteIdentifier(target.column);
1781
+ const expr = target.kind === "json" ? dialect.jsonExtractValue(src, target.path) : target.kind === "boolean" ? dialect.jsonExtract(src, target.path, "boolean") : dialect.jsonExtractText(src, target.path);
1782
+ sets.push(`${col} = ${cast(expr, target)}`);
1783
+ empty.push(`${col} IS NULL`);
1784
+ }
1785
+ return `UPDATE ${dialect.quoteTable(table)} SET ${sets.join(", ")} WHERE ${src} IS NOT NULL AND ${empty.join(" AND ")}`;
1786
+ }
1787
+ /**
1788
+ * `UPDATE` rewriting the text column `column` as JSON text
1789
+ * (`BaseDbAdapter.jsonifyTextColumn`, since 0.1.155): valid JSON stays, other
1790
+ * text becomes a JSON string — see {@link SqlDialect.jsonFromText}.
1791
+ */
1792
+ function buildJsonifyText(dialect, table, column) {
1793
+ if (!dialect.jsonFromText) throw new Error("Converting text values to JSON is not supported by this adapter");
1794
+ const col = dialect.quoteIdentifier(column);
1795
+ return `UPDATE ${dialect.quoteTable(table)} SET ${col} = ${dialect.jsonFromText(col)} WHERE ${col} IS NOT NULL`;
1796
+ }
1797
+ //#endregion
1798
+ export { AGG_FN_SQL, EMPTY_AND, EMPTY_OR, GEO_DISTANCE_ALIAS, InsertSqlCache, PARTITION_ROW_NUMBER_ALIAS, SEARCH_SOURCE_ALIAS, SQL_DEFAULT, VECTOR_DISTANCE_ALIAS, arithOverflowError, buildAggregateCount, buildAggregateSelect, buildCreateView, buildDelete, buildGeoSearchCount, buildGeoSearchSelect, buildInsert, buildInsertMany, buildJsonColumnCopy, buildJsonifyText, buildKeyViolationCount, buildPartitionedSelect, buildProjection, buildSelect, buildUpdate, buildVectorSearchCount, buildVectorSearchSelect, buildViewSelect, buildWhere, chunkInsertRows, createFilterVisitor, defaultValueForType, defaultValueToSqlLiteral, derivedColumnExpr, fillReplacePayload, finalizeParams, foreignKeySql, fromSourceHint, fromSourceSql, geoWindowFromControls, groupKeySql, insertManyColumns, jsonDollarPath, mapQueryErrors, normalizeGeoPointValue, nullsOrderSql, nullsPlacementOf, numericOutOfRangeError, orFragment, orderByList, orderKeySql, parseRegexString, queryNodeToSql, queryOpToSql, quotedJsonPathSegments, refActionToSql, renameGeoDistance, renderArith, replaceColumnsFor, sqlStringLiteral, sqlTimeZoneLiteral, stripPartitionRowNumber, toSqlValue, vectorDistanceSource, viewReadSource };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atscript/db-sql-tools",
3
- "version": "0.1.154",
3
+ "version": "0.1.155",
4
4
  "description": "Shared SQL builder utilities for @atscript database adapters.",
5
5
  "keywords": [
6
6
  "atscript",
@@ -38,11 +38,11 @@
38
38
  },
39
39
  "devDependencies": {
40
40
  "@uniqu/core": "^0.1.15",
41
- "unplugin-atscript": "^0.1.103"
41
+ "unplugin-atscript": "^0.1.105"
42
42
  },
43
43
  "peerDependencies": {
44
44
  "@uniqu/core": "^0.1.15",
45
- "@atscript/db": "^0.1.154"
45
+ "@atscript/db": "^0.1.155"
46
46
  },
47
47
  "scripts": {
48
48
  "build": "vp pack",