Skip to content

Commit d30ac8b

Browse files
feat: add option type validation
1 parent 8f17a01 commit d30ac8b

File tree

4 files changed

+112
-36
lines changed

4 files changed

+112
-36
lines changed

src/constants.ts

Lines changed: 93 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,94 @@
1-
const CONSTANTS = {
2-
MIN_SUPPORTED_MYSQL: '8.0.20'
3-
}
1+
import { InternalServerOptions, OptionTypeChecks } from "../types";
2+
import { randomUUID } from "crypto";
3+
import {normalize as normalizePath} from 'path'
4+
import { tmpdir } from "os";
45

5-
export default CONSTANTS
6+
export const MIN_SUPPORTED_MYSQL = '8.0.20';
7+
8+
export const DEFAULT_OPTIONS: InternalServerOptions = {
9+
dbName: 'dbdata',
10+
logLevel: 'ERROR',
11+
portRetries: 10,
12+
downloadBinaryOnce: true,
13+
lockRetries: 1_000,
14+
lockRetryWait: 1_000,
15+
username: 'root',
16+
deleteDBAfterStopped: true,
17+
//mysqlmsn = MySQL Memory Server Node.js
18+
dbPath: normalizePath(`${tmpdir()}/mysqlmsn/dbs/${randomUUID().replace(/-/g, '')}`),
19+
ignoreUnsupportedSystemVersion: false,
20+
port: 0,
21+
xPort: 0,
22+
binaryDirectoryPath: `${tmpdir()}/mysqlmsn/binaries`,
23+
downloadRetries: 10,
24+
initSQLString: ''
25+
} as const;
26+
27+
export const LOG_LEVELS = {
28+
'LOG': 0,
29+
'WARN': 1,
30+
'ERROR': 2
31+
} as const;
32+
33+
export const OPTION_TYPE_CHECKS: OptionTypeChecks = {
34+
dbName: {
35+
check: (opt: any) => typeof opt === 'string' && opt.length <= 64,
36+
errorMessage: 'Option dbName must be a string and must not be longer than 64 characters.'
37+
},
38+
logLevel: {
39+
check: (opt: any) => Object.keys(LOG_LEVELS).includes(opt),
40+
errorMessage: 'Option logLevel must be either "LOG", "WARN", or "ERROR".'
41+
},
42+
portRetries: {
43+
check: (opt: any) => typeof opt === 'number' && opt >= 0,
44+
errorMessage: 'Option portRetries must be a positive number or 0.'
45+
},
46+
downloadBinaryOnce: {
47+
check: (opt: any) => typeof opt === 'boolean',
48+
errorMessage: 'Option downloadBinaryOnce must be a boolean.'
49+
},
50+
lockRetries: {
51+
check: (opt: any) => typeof opt === 'number' && opt >= 0,
52+
errorMessage: 'Option lockRetries must be a positive number or 0.'
53+
},
54+
lockRetryWait: {
55+
check: (opt: any) => typeof opt === 'number' && opt >= 0,
56+
errorMessage: 'Option lockRetryWait must be a positive number or 0.'
57+
},
58+
username: {
59+
check: (opt: any) => typeof opt === 'string' && opt.length <= 32,
60+
errorMessage: 'Option username must be a string and must not be longer than 32 characters.'
61+
},
62+
_DO_NOT_USE_deleteDBAfterStopped: {
63+
check: (opt: any) => typeof opt === 'boolean',
64+
errorMessage: 'Option _DO_NOT_USE_deleteDBAfterStopped must be a boolean.'
65+
},
66+
_DO_NOT_USE_dbPath: {
67+
check: (opt: any) => typeof opt === 'string',
68+
errorMessage: 'Option _DO_NOT_USE_dbPath must be a string.'
69+
},
70+
ignoreUnsupportedSystemVersion: {
71+
check: (opt: any) => typeof opt === 'boolean',
72+
errorMessage: 'Option ignoreUnsupportedSystemVersion must be a boolean.'
73+
},
74+
port: {
75+
check: (opt: any) => typeof opt === 'number' && opt >= 0 && opt <= 65535,
76+
errorMessage: 'Option port must be a number and between 0 and 65535 inclusive.'
77+
},
78+
xPort: {
79+
check: (opt: any) => typeof opt === 'number' && opt >= 0 && opt <= 65535,
80+
errorMessage: 'Option xPort must be a number and between 0 and 65535 inclusive.'
81+
},
82+
_DO_NOT_USE_binaryDirectoryPath: {
83+
check: (opt: any) => typeof opt === 'string',
84+
errorMessage: 'Option _DO_NOT_USE_binaryDirectoryPath must be a string.'
85+
},
86+
downloadRetries: {
87+
check: (opt: any) => typeof opt === 'number' && opt >= 0,
88+
errorMessage: 'Option downloadRetries must be a positive number or 0.'
89+
},
90+
initSQLString: {
91+
check: (opt: any) => typeof opt === 'string',
92+
errorMessage: 'Option initSQLString must be a string.'
93+
}
94+
} as const;

src/index.ts

Lines changed: 11 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,13 @@ import Logger from './libraries/Logger'
22
import * as os from 'node:os'
33
import Executor from "./libraries/Executor"
44
import { satisfies, lt } from "semver"
5-
import DBDestroySignal from "./libraries/AbortSignal"
65
import { BinaryInfo, InternalServerOptions, ServerOptions } from '../types'
76
import getBinaryURL from './libraries/Version'
87
import MySQLVersions from './versions.json'
98
import { downloadBinary } from './libraries/Downloader'
10-
import { randomUUID } from "crypto";
11-
import {normalize as normalizePath} from 'path'
12-
import CONSTANTS from './constants'
9+
import { MIN_SUPPORTED_MYSQL, DEFAULT_OPTIONS, OPTION_TYPE_CHECKS } from './constants'
1310

1411
export async function createDB(opts?: ServerOptions) {
15-
const defaultOptions: InternalServerOptions = {
16-
dbName: 'dbdata',
17-
logLevel: 'ERROR',
18-
portRetries: 10,
19-
downloadBinaryOnce: true,
20-
lockRetries: 1_000,
21-
lockRetryWait: 1_000,
22-
username: 'root',
23-
deleteDBAfterStopped: true,
24-
//mysqlmsn = MySQL Memory Server Node.js
25-
dbPath: normalizePath(`${os.tmpdir()}/mysqlmsn/dbs/${randomUUID().replace(/-/g, '')}`),
26-
ignoreUnsupportedSystemVersion: false,
27-
port: 0,
28-
xPort: 0,
29-
binaryDirectoryPath: `${os.tmpdir()}/mysqlmsn/binaries`,
30-
downloadRetries: 10,
31-
initSQLString: ''
32-
}
33-
3412
const suppliedOpts = opts || {};
3513
const suppliedOptsKeys = Object.keys(suppliedOpts);
3614
const internalOpts = ['_DO_NOT_USE_deleteDBAfterStopped', '_DO_NOT_USE_dbPath', '_DO_NOT_USE_binaryDirectoryPath'];
@@ -40,24 +18,31 @@ export async function createDB(opts?: ServerOptions) {
4018
console.warn(`[ mysql-memory-server - Options WARN ]: Creating MySQL database with option ${opt}. This is considered unstable and should not be used externally. Please consider removing this option.`)
4119
}
4220
}
21+
22+
for (const opt of suppliedOptsKeys) {
23+
if (suppliedOpts[opt] !== undefined && !OPTION_TYPE_CHECKS[opt].check(suppliedOpts[opt])) {
24+
//Supplied option failed the check
25+
throw OPTION_TYPE_CHECKS[opt].errorMessage
26+
}
27+
}
4328

44-
const options: InternalServerOptions = {...defaultOptions, ...opts}
29+
const options: InternalServerOptions = {...DEFAULT_OPTIONS, ...opts}
4530

4631
const logger = new Logger(options.logLevel)
4732

4833
const executor = new Executor(logger)
4934

5035
const version = await executor.getMySQLVersion(options.version)
5136

52-
const unsupportedMySQLIsInstalled = version && lt(version.version, CONSTANTS.MIN_SUPPORTED_MYSQL)
37+
const unsupportedMySQLIsInstalled = version && lt(version.version, MIN_SUPPORTED_MYSQL)
5338

5439
const throwUnsupportedError = unsupportedMySQLIsInstalled && !options.ignoreUnsupportedSystemVersion && !options.version
5540

5641
if (throwUnsupportedError) {
5742
throw `A version of MySQL is installed on your system that is not supported by this package. If you want to download a MySQL binary instead of getting this error, please set the option "ignoreUnsupportedSystemVersion" to true.`
5843
}
5944

60-
if (options.version && lt(options.version, CONSTANTS.MIN_SUPPORTED_MYSQL)) {
45+
if (options.version && lt(options.version, MIN_SUPPORTED_MYSQL)) {
6146
//The difference between the throw here and the throw above is this throw is because the selected "version" is not supported.
6247
//The throw above is because the system-installed MySQL is out of date and "ignoreUnsupportedSystemVersion" is not set to true.
6348
throw `The selected version of MySQL (${options.version}) is not currently supported by this package. Please choose a different version to use.`

src/libraries/Logger.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
import { LOG_LEVEL } from "../../types";
2-
3-
const LOG_LEVELS = {
4-
'LOG': 0,
5-
'WARN': 1,
6-
'ERROR': 2
7-
}
2+
import { LOG_LEVELS } from "../constants";
83

94
class Logger {
105
LOG_LEVEL: number;

types/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,11 @@ export type InstalledMySQLVersion = {
7676
export type BinaryInfo = {
7777
url: string,
7878
version: string
79+
}
80+
81+
export type OptionTypeChecks = {
82+
[key in keyof ServerOptions]: {
83+
check: (opt: any) => boolean,
84+
errorMessage: string
85+
}
7986
}

0 commit comments

Comments
 (0)