@travetto/model-mysql 3.0.0-rc.9 → 3.0.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/README.md CHANGED
@@ -6,6 +6,10 @@
6
6
  **Install: @travetto/model-mysql**
7
7
  ```bash
8
8
  npm install @travetto/model-mysql
9
+
10
+ # or
11
+
12
+ yarn add @travetto/model-mysql
9
13
  ```
10
14
 
11
15
  This module provides a [MySQL](https://www.mysql.com/)-based implementation for the [Data Modeling Support](https://github.com/travetto/travetto/tree/main/module/model#readme "Datastore abstraction for core operations.") module. This source allows the [Data Modeling Support](https://github.com/travetto/travetto/tree/main/module/model#readme "Datastore abstraction for core operations.") module to read, write and query against [SQL](https://en.wikipedia.org/wiki/SQL) databases. In development mode, the [SQLModelService](https://github.com/travetto/travetto/tree/main/module/model-sql/src/service.ts#L38) will also modify the database schema in real time to minimize impact to development.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/model-mysql",
3
- "version": "3.0.0-rc.9",
3
+ "version": "3.0.0",
4
4
  "description": "MySQL backing for the travetto model module, with real-time modeling support for SQL schemas.",
5
5
  "keywords": [
6
6
  "sql",
@@ -27,16 +27,16 @@
27
27
  "directory": "module/model-mysql"
28
28
  },
29
29
  "dependencies": {
30
- "@travetto/config": "^3.0.0-rc.9",
31
- "@travetto/context": "^3.0.0-rc.9",
32
- "@travetto/model": "^3.0.0-rc.9",
33
- "@travetto/model-query": "^3.0.0-rc.9",
34
- "@travetto/model-sql": "^3.0.0-rc.9",
30
+ "@travetto/config": "^3.0.0",
31
+ "@travetto/context": "^3.0.0",
32
+ "@travetto/model": "^3.0.0",
33
+ "@travetto/model-query": "^3.0.0",
34
+ "@travetto/model-sql": "^3.0.0",
35
35
  "@types/mysql": "^2.15.21",
36
- "mysql": "^2.18.1"
36
+ "mysql2": "^3.1.2"
37
37
  },
38
38
  "peerDependencies": {
39
- "@travetto/command": "^3.0.0-rc.7"
39
+ "@travetto/command": "^3.0.0"
40
40
  },
41
41
  "peerDependenciesMeta": {
42
42
  "@travetto/command": {
package/src/connection.ts CHANGED
@@ -1,10 +1,16 @@
1
- import mysql from 'mysql';
1
+ import mysql, { OkPacket, ResultSetHeader } from 'mysql2';
2
2
 
3
3
  import { ShutdownManager } from '@travetto/base';
4
4
  import { AsyncContext } from '@travetto/context';
5
5
  import { ExistsError } from '@travetto/model';
6
6
  import { Connection, SQLModelConfig } from '@travetto/model-sql';
7
7
 
8
+ function isSimplePacket(o: unknown): o is OkPacket | ResultSetHeader {
9
+ return o !== null && o !== undefined && typeof o === 'object' && 'constructor' in o && (
10
+ o.constructor.name === 'OkPacket' || o.constructor.name === 'ResultSetHeader'
11
+ );
12
+ }
13
+
8
14
  /**
9
15
  * Connection support for mysql
10
16
  */
@@ -28,7 +34,7 @@ export class MySQLConnection extends Connection<mysql.PoolConnection> {
28
34
  database: this.#config.database,
29
35
  host: this.#config.host,
30
36
  port: this.#config.port,
31
- timezone: 'utc',
37
+ timezone: '+00:00',
32
38
  typeCast: this.typeCast.bind(this),
33
39
  ...(this.#config.options || {})
34
40
  });
@@ -40,9 +46,9 @@ export class MySQLConnection extends Connection<mysql.PoolConnection> {
40
46
  /**
41
47
  * Support some basic type support for JSON data
42
48
  */
43
- typeCast(field: Parameters<Exclude<mysql.TypeCast, boolean>>[0], next: () => unknown): unknown {
49
+ typeCast(field: unknown, next: () => unknown): unknown {
44
50
  const res = next();
45
- if (typeof res === 'string' && (field.type === 'JSON' || field.type === 'BLOB')) {
51
+ if (typeof res === 'string' && (field && typeof field === 'object' && 'type' in field) && (field.type === 'JSON' || field.type === 'BLOB')) {
46
52
  if (res.charAt(0) === '{' && res.charAt(res.length - 1) === '}') {
47
53
  try {
48
54
  return JSON.parse(res);
@@ -58,14 +64,22 @@ export class MySQLConnection extends Connection<mysql.PoolConnection> {
58
64
  conn.query(query, (err, results, fields) => {
59
65
  if (err) {
60
66
  console.debug('Failed query', { error: err, query });
61
- if (err.message.startsWith('ER_DUP_ENTRY')) {
67
+ if (err.message.startsWith('Duplicate entry')) {
62
68
  rej(new ExistsError('query', query));
63
69
  } else {
64
70
  rej(err);
65
71
  }
66
72
  } else {
67
- const records: T[] = Array.isArray(results) ? [...results].map(v => ({ ...v })) : [{ ...results }];
68
- res({ records, count: results.affectedRows });
73
+ if (isSimplePacket(results)) {
74
+ return res({ records: [], count: results.affectedRows });
75
+ } else {
76
+ if (isSimplePacket(results[0])) {
77
+ return res({ records: [], count: results[0].affectedRows });
78
+ }
79
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
80
+ const records: T[] = [...results].map(v => ({ ...v }) as T);
81
+ return res({ records, count: records.length });
82
+ }
69
83
  }
70
84
  });
71
85
  });
package/src/dialect.ts CHANGED
@@ -16,18 +16,12 @@ import { MySQLConnection } from './connection';
16
16
  export class MySQLDialect extends SQLDialect {
17
17
 
18
18
  conn: MySQLConnection;
19
- tablePostfix = "COLLATE='utf8mb4_unicode_ci' ENGINE=InnoDB";
19
+ tablePostfix = 'COLLATE=utf8mb4_bin ENGINE=InnoDB';
20
20
 
21
21
  constructor(context: AsyncContext, public config: SQLModelConfig) {
22
22
  super(config.namespace);
23
23
  this.conn = new MySQLConnection(context, config);
24
24
 
25
- // Customer operators
26
- Object.assign(this.SQL_OPS, {
27
- $regex: 'REGEXP BINARY',
28
- $iregex: 'REGEXP'
29
- });
30
-
31
25
  // Custom types
32
26
  Object.assign(this.COLUMN_TYPES, {
33
27
  TIMESTAMP: 'DATETIME(3)',
@@ -35,7 +29,6 @@ export class MySQLDialect extends SQLDialect {
35
29
  });
36
30
 
37
31
  // Word boundary
38
- this.regexWordBoundary = '([[:<:]]|[[:>:]])';
39
32
  // Field maxlength
40
33
  this.idField.minlength = this.idField.maxlength = { n: this.KEY_LEN };
41
34
 
@@ -44,6 +37,25 @@ export class MySQLDialect extends SQLDialect {
44
37
  */
45
38
  if (/^5[.][56]/.test(this.config.version)) {
46
39
  this.DEFAULT_STRING_LEN = 191; // Mysql limitation with utf8 and keys
40
+ } else {
41
+ this.DEFAULT_STRING_LEN = 3072 / 4 - 1;
42
+ }
43
+
44
+ if (/^5[.].*/.test(this.config.version)) {
45
+ // Customer operators
46
+ Object.assign(this.SQL_OPS, {
47
+ $regex: 'REGEXP BINARY',
48
+ $iregex: 'REGEXP'
49
+ });
50
+
51
+ this.regexWordBoundary = '([[:<:]]|[[:>:]])';
52
+ } else {
53
+ // Customer operators
54
+ Object.assign(this.SQL_OPS, {
55
+ $regex: 'REGEXP',
56
+ });
57
+ // Double escape
58
+ this.regexWordBoundary = '\\\\b';
47
59
  }
48
60
  }
49
61
 
@@ -1,9 +1,9 @@
1
1
  import { Env } from '@travetto/base';
2
- import type { Service } from '@travetto/command/support/bin/service';
2
+ import type { CommandService } from '@travetto/command';
3
3
 
4
- const version = Env.get('MYSQL_VERSION', '5.6');
4
+ const version = Env.get('MYSQL_VERSION', '8.0');
5
5
 
6
- export const service: Service = {
6
+ export const service: CommandService = {
7
7
  name: 'mysql',
8
8
  version,
9
9
  image: `mysql:${version}`,