@atscript/db-mysql 0.1.134 → 0.1.136

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
@@ -168,8 +168,29 @@ const mysqlDialect = {
168
168
  },
169
169
  calendarBucket: mysqlCalendarBucket,
170
170
  bucketAliasInHaving: true,
171
+ jsonExtract: mysqlJsonExtract,
171
172
  createViewPrefix: "CREATE OR REPLACE VIEW"
172
173
  };
174
+ /** `JSON_TYPE()` names of JSON numbers (MariaDB reports only INTEGER / DOUBLE). */
175
+ const MYSQL_JSON_NUMBER_TYPES = "'INTEGER', 'UNSIGNED INTEGER', 'DOUBLE', 'DECIMAL'";
176
+ /**
177
+ * Typed read of a JSON leaf (`SqlDialect.jsonExtract`), MySQL and MariaDB:
178
+ * `JSON_TYPE()` guards the declared type, so a missing path, JSON `null` or
179
+ * another JSON type yields NULL (no coercion). Numbers convert with `+ 0`
180
+ * (a double) and booleans come back as 1/0 (the comparison's own result) —
181
+ * the view's boolean formatter converts them. Avoids `CAST(… AS DOUBLE)` (MySQL 8.0.17+) and
182
+ * `CAST(… AS JSON)` (not in MariaDB).
183
+ */
184
+ function mysqlJsonExtract(quotedCol, path, type) {
185
+ const e = `JSON_EXTRACT(${quotedCol}, ${(0, _atscript_db_sql_tools.jsonDollarPath)(path)})`;
186
+ const t = `JSON_TYPE(${e})`;
187
+ switch (type) {
188
+ case "string": return `CASE ${t} WHEN 'STRING' THEN JSON_UNQUOTE(${e}) END`;
189
+ case "number": return `CASE WHEN ${t} IN (${MYSQL_JSON_NUMBER_TYPES}) THEN ${e} + 0 END`;
190
+ case "boolean": return `CASE ${t} WHEN 'BOOLEAN' THEN JSON_UNQUOTE(${e}) = 'true' END`;
191
+ default: return type;
192
+ }
193
+ }
173
194
  /**
174
195
  * Whether a field is stored as a native MySQL `TIMESTAMP`: a `number` with
175
196
  * `@db.default.now`. The adapter writes such values as UTC
@@ -577,6 +598,10 @@ var MysqlAdapter = class MysqlAdapter extends _atscript_db.BaseDbAdapter {
577
598
  calendarBucketUnits() {
578
599
  return _atscript_db.ALL_BUCKET_UNITS;
579
600
  }
601
+ /** Every aggregate function, `countDistinct` included. */
602
+ aggregateFns() {
603
+ return _atscript_db.ALL_AGGREGATE_FNS;
604
+ }
580
605
  onBeforeFlatten(_type) {
581
606
  const meta = _type.metadata;
582
607
  const engine = meta.get("db.mysql.engine");
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { BaseDbAdapter, BucketUnit, DbQuery, DbSpace, FilterExpr, TColumnDiff, TDbDefaultFn, TDbDeleteResult, TDbFieldMeta, TDbInsertManyResult, TDbInsertResult, TDbObjectKind, TDbUpdateResult, TEnsureTableOptions, TExistingColumn, TExistingTableOption, TFieldOps, TPrimaryKeyChange, TReferencingForeignKey, TSearchIndexInfo, TSyncColumnResult, TTableOptionDiff, TValueFormatterPair } from "@atscript/db";
1
+ import { AggregateFn, BaseDbAdapter, BucketUnit, DbQuery, DbSpace, FilterExpr, TColumnDiff, TDbDefaultFn, TDbDeleteResult, TDbFieldMeta, TDbInsertManyResult, TDbInsertResult, TDbObjectKind, TDbUpdateResult, TEnsureTableOptions, TExistingColumn, TExistingTableOption, TFieldOps, TPrimaryKeyChange, TReferencingForeignKey, TSearchIndexInfo, TSyncColumnResult, TTableOptionDiff, TValueFormatterPair } from "@atscript/db";
2
2
  import { TMetadataMap } from "@atscript/typescript/utils";
3
3
  import { FilterExpr as FilterExpr$1 } from "@uniqu/core";
4
4
  import { TSqlFragment, TSqlFragment as TSqlFragment$1 } from "@atscript/db-sql-tools";
@@ -137,6 +137,8 @@ declare class MysqlAdapter extends BaseDbAdapter {
137
137
  * server's time zone tables (probed per zone in `aggregate()`).
138
138
  */
139
139
  calendarBucketUnits(): ReadonlySet<BucketUnit>;
140
+ /** Every aggregate function, `countDistinct` included. */
141
+ aggregateFns(): ReadonlySet<AggregateFn>;
140
142
  onBeforeFlatten(_type: unknown): void;
141
143
  onFieldScanned(field: string, _type: unknown, metadata: TMetadataMap<AtscriptMetadata>): void;
142
144
  getDesiredTableOptions(): TExistingTableOption[];
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { BaseDbAdapter, BucketUnit, DbQuery, DbSpace, FilterExpr, TColumnDiff, TDbDefaultFn, TDbDeleteResult, TDbFieldMeta, TDbInsertManyResult, TDbInsertResult, TDbObjectKind, TDbUpdateResult, TEnsureTableOptions, TExistingColumn, TExistingTableOption, TFieldOps, TPrimaryKeyChange, TReferencingForeignKey, TSearchIndexInfo, TSyncColumnResult, TTableOptionDiff, TValueFormatterPair } from "@atscript/db";
1
+ import { AggregateFn, BaseDbAdapter, BucketUnit, DbQuery, DbSpace, FilterExpr, TColumnDiff, TDbDefaultFn, TDbDeleteResult, TDbFieldMeta, TDbInsertManyResult, TDbInsertResult, TDbObjectKind, TDbUpdateResult, TEnsureTableOptions, TExistingColumn, TExistingTableOption, TFieldOps, TPrimaryKeyChange, TReferencingForeignKey, TSearchIndexInfo, TSyncColumnResult, TTableOptionDiff, TValueFormatterPair } from "@atscript/db";
2
2
  import { TSqlFragment, TSqlFragment as TSqlFragment$1 } from "@atscript/db-sql-tools";
3
3
  import { FilterExpr as FilterExpr$1 } from "@uniqu/core";
4
4
  import { TMetadataMap } from "@atscript/typescript/utils";
@@ -137,6 +137,8 @@ declare class MysqlAdapter extends BaseDbAdapter {
137
137
  * server's time zone tables (probed per zone in `aggregate()`).
138
138
  */
139
139
  calendarBucketUnits(): ReadonlySet<BucketUnit>;
140
+ /** Every aggregate function, `countDistinct` included. */
141
+ aggregateFns(): ReadonlySet<AggregateFn>;
140
142
  onBeforeFlatten(_type: unknown): void;
141
143
  onFieldScanned(field: string, _type: unknown, metadata: TMetadataMap<AtscriptMetadata>): void;
142
144
  getDesiredTableOptions(): TExistingTableOption[];
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
- import { ALL_BUCKET_UNITS, BaseDbAdapter, DbError, DbSpace, bucketTimeZoneUnavailable } from "@atscript/db";
1
+ import { ALL_AGGREGATE_FNS, ALL_BUCKET_UNITS, BaseDbAdapter, DbError, DbSpace, bucketTimeZoneUnavailable } from "@atscript/db";
2
2
  import { resolveAggregateSearch } from "@atscript/db/agg";
3
- import { buildAggregateCount, buildAggregateSelect, buildCreateView, buildDelete, buildGeoSearchCount, buildGeoSearchSelect, buildInsert, buildInsertMany, buildSelect, buildUpdate, buildWhere as buildWhere$1, defaultValueForType, defaultValueToSqlLiteral, fillReplacePayload, geoWindowFromControls, insertManyColumns, normalizeGeoPointValue, parseRegexString, refActionToSql, renameGeoDistance, replaceColumnsFor, sqlTimeZoneLiteral, toSqlValue } from "@atscript/db-sql-tools";
3
+ import { buildAggregateCount, buildAggregateSelect, buildCreateView, buildDelete, buildGeoSearchCount, buildGeoSearchSelect, buildInsert, buildInsertMany, buildSelect, buildUpdate, buildWhere as buildWhere$1, defaultValueForType, defaultValueToSqlLiteral, fillReplacePayload, geoWindowFromControls, insertManyColumns, jsonDollarPath, normalizeGeoPointValue, parseRegexString, refActionToSql, renameGeoDistance, replaceColumnsFor, sqlTimeZoneLiteral, toSqlValue } from "@atscript/db-sql-tools";
4
4
  import { BUCKET_MAX_INSTANT, BUCKET_MIN_INSTANT } from "@uniqu/core";
5
5
  //#region src/sql-builder.ts
6
6
  /** TEXT / BLOB families (`TINYTEXT` … `LONGBLOB`). */
@@ -167,8 +167,29 @@ const mysqlDialect = {
167
167
  },
168
168
  calendarBucket: mysqlCalendarBucket,
169
169
  bucketAliasInHaving: true,
170
+ jsonExtract: mysqlJsonExtract,
170
171
  createViewPrefix: "CREATE OR REPLACE VIEW"
171
172
  };
173
+ /** `JSON_TYPE()` names of JSON numbers (MariaDB reports only INTEGER / DOUBLE). */
174
+ const MYSQL_JSON_NUMBER_TYPES = "'INTEGER', 'UNSIGNED INTEGER', 'DOUBLE', 'DECIMAL'";
175
+ /**
176
+ * Typed read of a JSON leaf (`SqlDialect.jsonExtract`), MySQL and MariaDB:
177
+ * `JSON_TYPE()` guards the declared type, so a missing path, JSON `null` or
178
+ * another JSON type yields NULL (no coercion). Numbers convert with `+ 0`
179
+ * (a double) and booleans come back as 1/0 (the comparison's own result) —
180
+ * the view's boolean formatter converts them. Avoids `CAST(… AS DOUBLE)` (MySQL 8.0.17+) and
181
+ * `CAST(… AS JSON)` (not in MariaDB).
182
+ */
183
+ function mysqlJsonExtract(quotedCol, path, type) {
184
+ const e = `JSON_EXTRACT(${quotedCol}, ${jsonDollarPath(path)})`;
185
+ const t = `JSON_TYPE(${e})`;
186
+ switch (type) {
187
+ case "string": return `CASE ${t} WHEN 'STRING' THEN JSON_UNQUOTE(${e}) END`;
188
+ case "number": return `CASE WHEN ${t} IN (${MYSQL_JSON_NUMBER_TYPES}) THEN ${e} + 0 END`;
189
+ case "boolean": return `CASE ${t} WHEN 'BOOLEAN' THEN JSON_UNQUOTE(${e}) = 'true' END`;
190
+ default: return type;
191
+ }
192
+ }
172
193
  /**
173
194
  * Whether a field is stored as a native MySQL `TIMESTAMP`: a `number` with
174
195
  * `@db.default.now`. The adapter writes such values as UTC
@@ -576,6 +597,10 @@ var MysqlAdapter = class MysqlAdapter extends BaseDbAdapter {
576
597
  calendarBucketUnits() {
577
598
  return ALL_BUCKET_UNITS;
578
599
  }
600
+ /** Every aggregate function, `countDistinct` included. */
601
+ aggregateFns() {
602
+ return ALL_AGGREGATE_FNS;
603
+ }
579
604
  onBeforeFlatten(_type) {
580
605
  const meta = _type.metadata;
581
606
  const engine = meta.get("db.mysql.engine");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atscript/db-mysql",
3
- "version": "0.1.134",
3
+ "version": "0.1.136",
4
4
  "description": "MySQL adapter for @atscript/db with mysql2 driver support.",
5
5
  "keywords": [
6
6
  "atscript",
@@ -43,17 +43,17 @@
43
43
  "devDependencies": {
44
44
  "@atscript/core": "^0.1.92",
45
45
  "@atscript/typescript": "^0.1.92",
46
- "@uniqu/core": "^0.1.10",
46
+ "@uniqu/core": "^0.1.11",
47
47
  "mysql2": "^3.11.0",
48
48
  "unplugin-atscript": "^0.1.92"
49
49
  },
50
50
  "peerDependencies": {
51
51
  "@atscript/core": "^0.1.92",
52
52
  "@atscript/typescript": "^0.1.92",
53
- "@uniqu/core": "^0.1.10",
53
+ "@uniqu/core": "^0.1.11",
54
54
  "mysql2": ">=3.0.0",
55
- "@atscript/db-sql-tools": "^0.1.134",
56
- "@atscript/db": "^0.1.134"
55
+ "@atscript/db": "^0.1.136",
56
+ "@atscript/db-sql-tools": "^0.1.136"
57
57
  },
58
58
  "peerDependenciesMeta": {
59
59
  "mysql2": {