@malloydata/db-mysql 0.0.431 → 0.0.433

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.
@@ -62,6 +62,33 @@ class MySQLExecutor {
62
62
  }
63
63
  }
64
64
  exports.MySQLExecutor = MySQLExecutor;
65
+ /**
66
+ * MySQL renders a DECIMAL at its declared scale, so trailing zeros after the
67
+ * point are formatting rather than data and stripping them is lossless.
68
+ *
69
+ * This matters because every aggregate of an integer column comes back as a
70
+ * DECIMAL: SUM() of a BIGINT arrives as `18014398509481986.0000000000`, and
71
+ * Malloy reads a bigint-typed cell with BigInt(), which rejects any fractional
72
+ * spelling. A value with a real fraction is left alone.
73
+ *
74
+ * mysql2 delivers DECIMAL as a string, which is what preserves digits above
75
+ * 2^53 -- its `decimalNumbers` option parses them into a double instead, and
76
+ * must stay off. This hook is the last point at which a cell's MySQL type is
77
+ * known; by the time a row reaches Malloy it is gone.
78
+ */
79
+ function castMySQLValue(field, next) {
80
+ if (field.type === 'DECIMAL' || field.type === 'NEWDECIMAL') {
81
+ const digits = next();
82
+ if (typeof digits === 'string') {
83
+ const whole = digits.match(/^([+-]?\d+)\.0+$/);
84
+ if (whole) {
85
+ return whole[1];
86
+ }
87
+ }
88
+ return digits;
89
+ }
90
+ return next();
91
+ }
65
92
  class MySQLConnection extends connection_1.BaseConnection {
66
93
  get dialectName() {
67
94
  return this.dialect.name;
@@ -84,9 +111,10 @@ class MySQLConnection extends connection_1.BaseConnection {
84
111
  password: this.config.password,
85
112
  database: this.config.database,
86
113
  multipleStatements: true,
87
- decimalNumbers: true,
114
+ // A BIGINT too wide for a double arrives as an exact string.
88
115
  supportBigNumbers: true,
89
116
  timezone: '+00:00',
117
+ typeCast: castMySQLValue,
90
118
  });
91
119
  await this.connection.query(
92
120
  // LTNOTE: Need to make the group_concat_max_len configurable.
@@ -246,9 +274,9 @@ class MySQLConnection extends connection_1.BaseConnection {
246
274
  }
247
275
  fillStructDefFromTypeMap(structDef, typeMap) {
248
276
  for (const fieldName in typeMap) {
249
- let mySqlType = typeMap[fieldName].toLocaleLowerCase();
250
- mySqlType = mySqlType.trim().split('(')[0];
251
- const malloyType = this.dialect.sqlTypeToMalloyType(mySqlType);
277
+ // The dialect needs the full reported spelling: DECIMAL's parameters
278
+ // decide its Malloy type.
279
+ const malloyType = this.dialect.sqlTypeToMalloyType(typeMap[fieldName]);
252
280
  // no arrays or records exist in mysql
253
281
  structDef.fields.push({ ...malloyType, name: fieldName });
254
282
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@malloydata/db-mysql",
3
- "version": "0.0.431",
3
+ "version": "0.0.433",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -23,7 +23,7 @@
23
23
  "prepublishOnly": "npm run build"
24
24
  },
25
25
  "dependencies": {
26
- "@malloydata/malloy": "0.0.431",
26
+ "@malloydata/malloy": "0.0.433",
27
27
  "@types/node": "^22.20.0",
28
28
  "fastestsmallesttextencoderdecoder": "^1.0.22",
29
29
  "luxon": "^3.7.2",