@holo-js/db-mysql 0.5.6 → 0.6.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.
@@ -1 +1 @@
1
- 5fb7be0c0ef79c9df7421b90e37490117b12bfb84074b9564528264f47cedf37
1
+ d9288909e973717eb5503c3b7a4c8b7765d69e777a183e1417a35a042834ca0d
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { PoolOptions, Connection } from 'mysql2/promise';
2
- import { DriverAdapter, DriverQueryResult, DriverExecutionResult, DatabaseDriverFactory } from '@holo-js/db';
1
+ import { DriverAdapter, holoRuntimeInternals, DriverQueryResult, DriverExecutionResult, DatabaseDriverFactory } from '@holo-js/db';
3
2
  export { DriverAdapter, DriverExecutionResult, DriverQueryResult } from '@holo-js/db';
3
+ import { PoolOptions, Connection } from 'mysql2/promise';
4
4
 
5
5
  interface MySQLQueryableLike {
6
6
  query(sql: string, bindings?: readonly unknown[]): Promise<readonly [unknown, unknown]>;
@@ -29,11 +29,13 @@ declare class MySQLAdapter<TConfig extends PoolOptions = PoolOptions> implements
29
29
  private readonly config;
30
30
  private connected;
31
31
  private readonly transactionClients;
32
+ private readonly managedPool;
32
33
  constructor(options?: MySQLAdapterOptions<TConfig>);
33
34
  initialize(): Promise<void>;
34
35
  isDatabaseMissingError(error: unknown): boolean;
35
36
  disconnect(): Promise<void>;
36
37
  isConnected(): boolean;
38
+ get [holoRuntimeInternals.databaseSessionCacheEligibleKey](): boolean;
37
39
  runWithTransactionScope<T>(callback: () => Promise<T>): Promise<T>;
38
40
  query<TRow extends Record<string, unknown> = Record<string, unknown>>(sql: string, bindings?: readonly unknown[]): Promise<DriverQueryResult<TRow>>;
39
41
  introspect<TRow extends Record<string, unknown> = Record<string, unknown>>(sql: string, bindings?: readonly unknown[]): Promise<DriverQueryResult<TRow>>;
package/dist/index.mjs CHANGED
@@ -1,13 +1,13 @@
1
1
  // src/index.ts
2
2
  import { holoRuntimeInternals } from "@holo-js/db";
3
3
  import mysql from "mysql2/promise";
4
- var { formatWallClock, parseCalendarDate, parseWallClockTimestamp } = holoRuntimeInternals;
4
+ var { SERVER_WALL_CLOCK_AMBIGUITY, formatWallClockSeconds, parseCalendarDate, parseWallClockTimestamp } = holoRuntimeInternals;
5
5
  var TransactionError = class extends Error {
6
6
  };
7
7
  var ZERO_DATE_PART = /-00(?:-|\s|$)/;
8
8
  function toDriverBinding(value, timeZone) {
9
9
  if (!(value instanceof Date)) return value;
10
- return Number.isNaN(value.getTime()) ? null : formatWallClock(value, timeZone);
10
+ return Number.isNaN(value.getTime()) ? null : formatWallClockSeconds(value, timeZone);
11
11
  }
12
12
  function toDriverBindings(bindings) {
13
13
  const timeZone = holoRuntimeInternals.getApplicationTimezone();
@@ -23,10 +23,26 @@ function dateStringTypes(config) {
23
23
  if (Array.isArray(option)) return new Set(option.map((type) => String(type).toLowerCase()));
24
24
  return /* @__PURE__ */ new Set();
25
25
  }
26
+ function uriFlag(value) {
27
+ try {
28
+ return Boolean(JSON.parse(value));
29
+ } catch {
30
+ return value.length > 0;
31
+ }
32
+ }
33
+ function readsJsonAsText(config) {
34
+ const uriOption = typeof config.uri === "string" ? new URL(config.uri).searchParams.get("jsonStrings") : null;
35
+ return Boolean(config.jsonStrings) || uriOption !== null && uriFlag(uriOption);
36
+ }
26
37
  function applicationTypeCast(config) {
27
38
  const fallback = typeof config.typeCast === "function" ? config.typeCast : config.typeCast === false ? rawTypeCast : void 0;
28
39
  const stringTypes = dateStringTypes(config);
40
+ const jsonText = readsJsonAsText(config);
29
41
  return (field, next) => {
42
+ if ((field.type === "JSON" || field.extendedFormat === "json") && !fallback && !jsonText) {
43
+ const text = field.type === "JSON" ? field.string("utf8") : field.string();
44
+ return text === null ? null : JSON.parse(text);
45
+ }
30
46
  if (field.type !== "DATE" && field.type !== "DATETIME" && field.type !== "TIMESTAMP") {
31
47
  return fallback ? fallback(field, next) : next();
32
48
  }
@@ -35,7 +51,7 @@ function applicationTypeCast(config) {
35
51
  if (stringTypes.has(field.type.toLowerCase()) || ZERO_DATE_PART.test(value)) return value;
36
52
  const timeZone = holoRuntimeInternals.getApplicationTimezone();
37
53
  if (field.type === "DATE") return parseCalendarDate(value, timeZone) ?? value;
38
- return parseWallClockTimestamp(value, timeZone, "earlier") ?? value;
54
+ return parseWallClockTimestamp(value, timeZone, SERVER_WALL_CLOCK_AMBIGUITY.mysql) ?? value;
39
55
  };
40
56
  }
41
57
  function sessionTimeZone(timeZone) {
@@ -114,10 +130,19 @@ function wrapMySQLPool(pool) {
114
130
  };
115
131
  }
116
132
  var DEFAULT_MAX_PREPARED_STATEMENTS = 256;
133
+ var BIG_NUMBER_OPTIONS = ["supportBigNumbers", "bigNumberStrings"];
134
+ function resolveBigNumberOptions(config) {
135
+ const defaults = { supportBigNumbers: true, bigNumberStrings: false };
136
+ if (typeof config.uri !== "string") return { ...defaults, ...config };
137
+ const uri = new URL(config.uri);
138
+ const fromUri = BIG_NUMBER_OPTIONS.some((option) => uri.searchParams.has(option)) ? Object.fromEntries(BIG_NUMBER_OPTIONS.map((option) => [option, uriFlag(uri.searchParams.get(option) ?? "")])) : defaults;
139
+ for (const option of BIG_NUMBER_OPTIONS) uri.searchParams.delete(option);
140
+ return { ...fromUri, ...config, uri: uri.toString() };
141
+ }
117
142
  function createNativeMySQLPool(config) {
118
143
  const pool = mysql.createPool({
119
144
  maxPreparedStatements: DEFAULT_MAX_PREPARED_STATEMENTS,
120
- ...config,
145
+ ...resolveBigNumberOptions(config),
121
146
  timezone: config.timezone ?? "Z",
122
147
  typeCast: applicationTypeCast(config)
123
148
  });
@@ -141,7 +166,9 @@ var MySQLAdapter = class {
141
166
  config;
142
167
  connected;
143
168
  transactionClients;
169
+ managedPool;
144
170
  constructor(options = {}) {
171
+ this.managedPool = !options.client && !options.pool && !options.createPool;
145
172
  this.supportsConcurrentTransactionScopes = !options.client;
146
173
  this.directClient = options.client;
147
174
  this.pool = options.pool;
@@ -191,6 +218,9 @@ var MySQLAdapter = class {
191
218
  isConnected() {
192
219
  return this.connected;
193
220
  }
221
+ get [holoRuntimeInternals.databaseSessionCacheEligibleKey]() {
222
+ return this.managedPool && !this.transactionClients.current;
223
+ }
194
224
  runWithTransactionScope(callback) {
195
225
  return this.transactionClients.run(callback);
196
226
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@holo-js/db-mysql",
3
- "version": "0.5.6",
3
+ "version": "0.6.0",
4
4
  "description": "Holo-JS Framework - MySQL database adapter",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -30,13 +30,13 @@
30
30
  "test:integration": "HOLO_MYSQL_INTEGRATION=1 vitest --run tests/mysql.test.ts"
31
31
  },
32
32
  "peerDependencies": {
33
- "@holo-js/db": "^0.5.6"
33
+ "@holo-js/db": "^0.6.0"
34
34
  },
35
35
  "dependencies": {
36
36
  "mysql2": "^3.24.6"
37
37
  },
38
38
  "devDependencies": {
39
- "@holo-js/db": "^0.5.6",
39
+ "@holo-js/db": "^0.6.0",
40
40
  "tsup": "^9.0.0",
41
41
  "typescript": "^6.0.3",
42
42
  "vitest": "^5.0.5"