From 239497b25400ea31795e313c422a03763adfcea1 Mon Sep 17 00:00:00 2001 From: Neal Beeken Date: Wed, 17 Feb 2021 11:01:37 -0500 Subject: [PATCH] refactor: remove enums in favor of const objects Changes remaining enums to const objects and exports all user relevant "enums" from index.ts. Enums are frozen to ensure they remain static. Added a lint rule to prevent further enums. Corrected mistake in sourcemap emit settings. --- .eslintrc.json | 10 ++++++- src/cmap/message_stream.ts | 5 ++-- src/cmap/wire_protocol/compression.ts | 14 +++++---- src/connection_string.ts | 4 +-- src/db.ts | 24 +++++++-------- src/deps.ts | 19 +++++++----- src/index.ts | 42 +++++++++++++++------------ src/logger.ts | 35 +++++++++++++--------- src/mongo_client.ts | 15 ++-------- src/operations/set_profiling_level.ts | 21 ++++++++------ src/sdam/common.ts | 42 +++++++++++++++------------ src/sdam/server_description.ts | 10 +++---- src/sdam/topology_description.ts | 38 +++++++++++++----------- src/sessions.ts | 10 +++++-- src/transactions.ts | 35 ++++++++++++---------- tsconfig.json | 4 +-- 16 files changed, 183 insertions(+), 145 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index bda3d7eae3..90b4d1186e 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -32,7 +32,15 @@ "strict": ["error", "global"], "promise/no-native": "error", - "@typescript-eslint/no-explicit-any": "off" + "@typescript-eslint/no-explicit-any": "off", + + "no-restricted-syntax": [ + "error", + { + "selector": "TSEnumDeclaration", + "message": "Don't declare enums" + } + ] }, "overrides": [{ "files": ["*.d.ts"], diff --git a/src/cmap/message_stream.ts b/src/cmap/message_stream.ts index c8c8d3c124..7785710028 100644 --- a/src/cmap/message_stream.ts +++ b/src/cmap/message_stream.ts @@ -7,7 +7,8 @@ import { decompress, uncompressibleCommands, Compressor, - CompressorName + CompressorName, + CompressorId } from './wire_protocol/compression'; import type { Document, BSONSerializeOptions } from '../bson'; import { BufferPool, Callback } from '../utils'; @@ -177,7 +178,7 @@ function processIncomingData(stream: MessageStream, callback: Callback) messageHeader.fromCompressed = true; messageHeader.opCode = message.readInt32LE(MESSAGE_HEADER_SIZE); messageHeader.length = message.readInt32LE(MESSAGE_HEADER_SIZE + 4); - const compressorID = message[MESSAGE_HEADER_SIZE + 8]; + const compressorID: CompressorId = message[MESSAGE_HEADER_SIZE + 8] as CompressorId; const compressedBuffer = message.slice(MESSAGE_HEADER_SIZE + 9); // recalculate based on wrapped opcode diff --git a/src/cmap/wire_protocol/compression.ts b/src/cmap/wire_protocol/compression.ts index 6ac225d8e7..47276dbd58 100644 --- a/src/cmap/wire_protocol/compression.ts +++ b/src/cmap/wire_protocol/compression.ts @@ -5,11 +5,13 @@ import type { OperationDescription } from '../message_stream'; import { Snappy } from '../../deps'; /** @public */ -export enum Compressor { - none = 0, - snappy = 1, - zlib = 2 -} +export const Compressor = Object.freeze({ + none: 0, + snappy: 1, + zlib: 2 +} as const); + +export type CompressorId = typeof Compressor[keyof typeof Compressor]; /** @public */ export type CompressorName = keyof typeof Compressor; @@ -59,7 +61,7 @@ export function compress( // Decompress a message using the given compressor export function decompress( - compressorID: Compressor, + compressorID: CompressorId, compressedData: Buffer, callback: Callback ): void { diff --git a/src/connection_string.ts b/src/connection_string.ts index 133b7b8940..23cd5723a3 100644 --- a/src/connection_string.ts +++ b/src/connection_string.ts @@ -25,7 +25,7 @@ import { } from './mongo_client'; import { MongoCredentials } from './cmap/auth/mongo_credentials'; import type { TagSet } from './sdam/server_description'; -import { Logger, LoggerLevel } from './logger'; +import { Logger, LoggerLevelId } from './logger'; import { PromiseProvider } from './promise_provider'; import { createAutoEncrypter } from './operations/connect'; @@ -714,7 +714,7 @@ export const OPTIONS = { loggerLevel: { target: 'logger', transform({ values: [value] }) { - return new Logger('MongoClient', { loggerLevel: value as LoggerLevel }); + return new Logger('MongoClient', { loggerLevel: value as LoggerLevelId }); } }, maxIdleTimeMS: { diff --git a/src/db.ts b/src/db.ts index 1948228c82..8c1be9e33f 100644 --- a/src/db.ts +++ b/src/db.ts @@ -44,8 +44,8 @@ import { RemoveUserOperation, RemoveUserOptions } from './operations/remove_user import { RenameOperation, RenameOptions } from './operations/rename'; import { SetProfilingLevelOperation, - ProfilingLevel, - SetProfilingLevelOptions + SetProfilingLevelOptions, + ProfilingLevelId } from './operations/set_profiling_level'; import { executeOperation } from './operations/execute_operation'; import { EvalOperation, EvalOptions } from './operations/eval'; @@ -639,22 +639,22 @@ export class Db { * @param options - Optional settings for the command * @param callback - An optional callback, a Promise will be returned if none is provided */ - setProfilingLevel(level: ProfilingLevel): Promise; - setProfilingLevel(level: ProfilingLevel, callback: Callback): void; + setProfilingLevel(level: ProfilingLevelId): Promise; + setProfilingLevel(level: ProfilingLevelId, callback: Callback): void; setProfilingLevel( - level: ProfilingLevel, + level: ProfilingLevelId, options: SetProfilingLevelOptions - ): Promise; + ): Promise; setProfilingLevel( - level: ProfilingLevel, + level: ProfilingLevelId, options: SetProfilingLevelOptions, - callback: Callback + callback: Callback ): void; setProfilingLevel( - level: ProfilingLevel, - options?: SetProfilingLevelOptions | Callback, - callback?: Callback - ): Promise | void { + level: ProfilingLevelId, + options?: SetProfilingLevelOptions | Callback, + callback?: Callback + ): Promise | void { if (typeof options === 'function') (callback = options), (options = {}); return executeOperation( diff --git a/src/deps.ts b/src/deps.ts index 570ca14a31..30fed6d375 100644 --- a/src/deps.ts +++ b/src/deps.ts @@ -68,13 +68,16 @@ try { } catch {} // eslint-disable-line /** @public */ -export const enum AutoEncryptionLoggerLevels { - FatalError = 0, - Error = 1, - Warning = 2, - Info = 3, - Trace = 4 -} +export const AutoEncryptionLoggerLevel = Object.freeze({ + FatalError: 0, + Error: 1, + Warning: 2, + Info: 3, + Trace: 4 +} as const); + +/** @public */ +export type AutoEncryptionLoggerLevelId = typeof AutoEncryptionLoggerLevel[keyof typeof AutoEncryptionLoggerLevel]; /** @public */ export interface AutoEncryptionOptions { @@ -146,7 +149,7 @@ export interface AutoEncryptionOptions { bypassAutoEncryption?: boolean; options?: { /** An optional hook to catch logging messages from the underlying encryption engine */ - logger?: (level: AutoEncryptionLoggerLevels, message: string) => void; + logger?: (level: AutoEncryptionLoggerLevelId, message: string) => void; }; extraOptions?: { /** diff --git a/src/index.ts b/src/index.ts index 798c223d5d..6688cca10a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -73,6 +73,20 @@ export { GridFSBucket }; +// enums +export { ProfilingLevel } from './operations/set_profiling_level'; +export { ServerType, TopologyType } from './sdam/common'; +export { LoggerLevel } from './logger'; +export { AutoEncryptionLoggerLevel } from './deps'; +export { BatchType } from './bulk/common'; +export { AuthMechanism } from './cmap/auth/defaultAuthProviders'; +export { CURSOR_FLAGS } from './cursor/abstract_cursor'; +export { Compressor } from './cmap/wire_protocol/compression'; +export { ExplainVerbosity } from './explain'; +export { ReadConcernLevel } from './read_concern'; +export { ReadPreferenceMode } from './read_preference'; + +// type only exports below, these are removed from emitted JS export type { AdminPrivate } from './admin'; export type { Instrumentation } from './apm'; export type { Document, BSONSerializeOptions } from './bson'; @@ -99,7 +113,7 @@ export type { OperationTime, ResumeOptions } from './change_stream'; -export type { AuthMechanism, AuthMechanismId } from './cmap/auth/defaultAuthProviders'; +export type { AuthMechanismId } from './cmap/auth/defaultAuthProviders'; export type { MongoCredentials, MongoCredentialsOptions } from './cmap/auth/mongo_credentials'; export type { WriteProtocolMessageType, @@ -132,20 +146,19 @@ export type { MessageStreamOptions } from './cmap/message_stream'; export type { StreamDescription, StreamDescriptionOptions } from './cmap/stream_description'; -export type { CompressorName, Compressor } from './cmap/wire_protocol/compression'; +export type { CompressorName } from './cmap/wire_protocol/compression'; export type { CollectionPrivate, CollectionOptions } from './collection'; export type { AggregationCursorOptions } from './cursor/aggregation_cursor'; export type { CursorCloseOptions, CursorStreamOptions, AbstractCursorOptions, - CURSOR_FLAGS, CursorFlag } from './cursor/abstract_cursor'; export type { DbPrivate, DbOptions } from './db'; -export type { AutoEncryptionOptions, AutoEncryptionLoggerLevels, AutoEncrypter } from './deps'; +export type { AutoEncryptionOptions, AutoEncryptionLoggerLevelId, AutoEncrypter } from './deps'; export type { AnyError, ErrorDescription } from './error'; -export type { Explain, ExplainOptions, ExplainVerbosity, ExplainVerbosityLike } from './explain'; +export type { Explain, ExplainOptions, ExplainVerbosityLike } from './explain'; export type { GridFSBucketReadStream, GridFSBucketReadStreamOptions, @@ -159,14 +172,12 @@ export type { TFileId, GridFSBucketWriteStream } from './gridfs-stream/upload'; -export type { LoggerOptions, LoggerFunction, LoggerLevel } from './logger'; +export type { LoggerOptions, LoggerFunction, LoggerLevelId } from './logger'; export type { MongoClientPrivate, MongoClientOptions, WithSessionCallback, PkFactory, - LogLevel, - LogLevelId, Auth, DriverInfo, MongoOptions, @@ -221,7 +232,7 @@ export type { ProfilingLevelOptions } from './operations/profiling_level'; export type { RemoveUserOptions } from './operations/remove_user'; export type { RenameOptions } from './operations/rename'; export type { RunCommandOptions } from './operations/run_command'; -export type { ProfilingLevel, SetProfilingLevelOptions } from './operations/set_profiling_level'; +export type { ProfilingLevelId, SetProfilingLevelOptions } from './operations/set_profiling_level'; export type { CollStatsOptions, DbStatsOptions } from './operations/stats'; export type { UpdateResult, @@ -230,22 +241,16 @@ export type { UpdateStatement } from './operations/update'; export type { ValidateCollectionOptions } from './operations/validate_collection'; -export type { - ReadConcern, - ReadConcernLike, - ReadConcernLevel, - ReadConcernLevelId -} from './read_concern'; +export type { ReadConcern, ReadConcernLike, ReadConcernLevelId } from './read_concern'; export type { ReadPreferenceLike, ReadPreferenceModeId, - ReadPreferenceMode, ReadPreferenceOptions, ReadPreferenceLikeOptions, ReadPreferenceFromOptions, HedgeOptions } from './read_preference'; -export type { ClusterTime, ServerType, TimerQueue, TopologyType } from './sdam/common'; +export type { ClusterTime, ServerTypeId, TimerQueue, TopologyTypeId } from './sdam/common'; export type { TopologyDescriptionChangedEvent } from './sdam/events'; export type { Monitor, @@ -282,7 +287,7 @@ export type { ServerSessionId, WithTransactionCallback } from './sessions'; -export type { TransactionOptions, Transaction, TxnState } from './transactions'; +export type { TransactionOptions, Transaction, TxnState, TxnStateId } from './transactions'; export type { Callback, ClientMetadata, @@ -298,7 +303,6 @@ export type { InternalAbstractCursorOptions } from './cursor/abstract_cursor'; export type { BulkOperationBase, BulkOperationPrivate, - BatchType, BatchTypeId, FindOperators, Batch diff --git a/src/logger.ts b/src/logger.ts index 5856df870d..c7c55cfea9 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -1,10 +1,10 @@ -import { format as f } from 'util'; +import { format } from 'util'; import { MongoError } from './error'; // Filters for classes const classFilters: any = {}; let filteredClasses: any = {}; -let level: LoggerLevel; +let level: LoggerLevelId; // Save the process id const pid = process.pid; @@ -13,12 +13,19 @@ const pid = process.pid; let currentLogger: LoggerFunction = console.warn; /** @public */ -export enum LoggerLevel { - ERROR = 'error', - WARN = 'warn', - INFO = 'info', - DEBUG = 'debug' -} +export const LoggerLevel = Object.freeze({ + ERROR: 'error', + WARN: 'warn', + INFO: 'info', + DEBUG: 'debug', + error: 'error', + warn: 'warn', + info: 'info', + debug: 'debug' +} as const); + +/** @public */ +export type LoggerLevelId = typeof LoggerLevel[keyof typeof LoggerLevel]; /** @public */ export type LoggerFunction = (message?: any, ...optionalParams: any[]) => void; @@ -26,7 +33,7 @@ export type LoggerFunction = (message?: any, ...optionalParams: any[]) => void; /** @public */ export interface LoggerOptions { logger?: LoggerFunction; - loggerLevel?: LoggerLevel; + loggerLevel?: LoggerLevelId; } /** @@ -76,7 +83,7 @@ export class Logger { (Object.keys(filteredClasses).length === 0 && classFilters[this.className])) ) { const dateTime = new Date().getTime(); - const msg = f('[%s-%s:%s] %s %s', 'DEBUG', this.className, pid, dateTime, message); + const msg = format('[%s-%s:%s] %s %s', 'DEBUG', this.className, pid, dateTime, message); const state = { type: LoggerLevel.DEBUG, message, @@ -103,7 +110,7 @@ export class Logger { (Object.keys(filteredClasses).length === 0 && classFilters[this.className])) ) { const dateTime = new Date().getTime(); - const msg = f('[%s-%s:%s] %s %s', 'WARN', this.className, pid, dateTime, message); + const msg = format('[%s-%s:%s] %s %s', 'WARN', this.className, pid, dateTime, message); const state = { type: LoggerLevel.WARN, message, @@ -130,7 +137,7 @@ export class Logger { (Object.keys(filteredClasses).length === 0 && classFilters[this.className])) ) { const dateTime = new Date().getTime(); - const msg = f('[%s-%s:%s] %s %s', 'INFO', this.className, pid, dateTime, message); + const msg = format('[%s-%s:%s] %s %s', 'INFO', this.className, pid, dateTime, message); const state = { type: LoggerLevel.INFO, message, @@ -157,7 +164,7 @@ export class Logger { (Object.keys(filteredClasses).length === 0 && classFilters[this.className])) ) { const dateTime = new Date().getTime(); - const msg = f('[%s-%s:%s] %s %s', 'ERROR', this.className, pid, dateTime, message); + const msg = format('[%s-%s:%s] %s %s', 'ERROR', this.className, pid, dateTime, message); const state = { type: LoggerLevel.ERROR, message, @@ -238,7 +245,7 @@ export class Logger { * * @param newLevel - Set current log level (debug, warn, info, error) */ - static setLevel(newLevel: LoggerLevel): void { + static setLevel(newLevel: LoggerLevelId): void { if ( newLevel !== LoggerLevel.INFO && newLevel !== LoggerLevel.ERROR && diff --git a/src/mongo_client.ts b/src/mongo_client.ts index 458dd219ff..b5fbefdbdf 100644 --- a/src/mongo_client.ts +++ b/src/mongo_client.ts @@ -16,7 +16,7 @@ import { import { deprecate } from 'util'; import { connect } from './operations/connect'; import { PromiseProvider } from './promise_provider'; -import type { Logger } from './logger'; +import type { Logger, LoggerLevelId } from './logger'; import type { ReadConcern, ReadConcernLevelId, ReadConcernLike } from './read_concern'; import { BSONSerializeOptions, Document, resolveBSONOptions } from './bson'; import type { AutoEncrypter, AutoEncryptionOptions } from './deps'; @@ -33,17 +33,6 @@ import type { SrvPoller } from './sdam/srv_polling'; import type { Connection } from './cmap/connection'; import type { LEGAL_TLS_SOCKET_OPTIONS, LEGAL_TCP_SOCKET_OPTIONS } from './cmap/connect'; -/** @public */ -export const LogLevel = { - error: 'error', - warn: 'warn', - info: 'info', - debug: 'debug' -} as const; - -/** @public */ -export type LogLevelId = typeof LogLevel[keyof typeof LogLevel]; - /** @public */ export interface DriverInfo { name?: string; @@ -205,7 +194,7 @@ export interface MongoClientOptions extends BSONSerializeOptions, SupportedNodeC /** A Promise library class the application wishes to use such as Bluebird, must be ES6 compatible */ promiseLibrary?: any; /** The logging level */ - loggerLevel?: LogLevelId; + loggerLevel?: LoggerLevelId; /** Custom logger object */ logger?: Logger; /** Enable command monitoring for this client */ diff --git a/src/operations/set_profiling_level.ts b/src/operations/set_profiling_level.ts index 98bb0c1b3f..9f160fb4b7 100644 --- a/src/operations/set_profiling_level.ts +++ b/src/operations/set_profiling_level.ts @@ -6,22 +6,25 @@ import type { ClientSession } from '../sessions'; const levelValues = new Set(['off', 'slow_only', 'all']); /** @public */ -export enum ProfilingLevel { - off = 'off', - slowOnly = 'slow_only', - all = 'all' -} +export const ProfilingLevel = Object.freeze({ + off: 'off', + slowOnly: 'slow_only', + all: 'all' +} as const); + +/** @public */ +export type ProfilingLevelId = typeof ProfilingLevel[keyof typeof ProfilingLevel]; /** @public */ export type SetProfilingLevelOptions = CommandOperationOptions; /** @internal */ -export class SetProfilingLevelOperation extends CommandOperation { +export class SetProfilingLevelOperation extends CommandOperation { options: SetProfilingLevelOptions; - level: ProfilingLevel; + level: ProfilingLevelId; profile: 0 | 1 | 2; - constructor(db: Db, level: ProfilingLevel, options: SetProfilingLevelOptions) { + constructor(db: Db, level: ProfilingLevelId, options: SetProfilingLevelOptions) { super(db, options); this.options = options; switch (level) { @@ -42,7 +45,7 @@ export class SetProfilingLevelOperation extends CommandOperation this.level = level; } - execute(server: Server, session: ClientSession, callback: Callback): void { + execute(server: Server, session: ClientSession, callback: Callback): void { const level = this.level; if (!levelValues.has(level)) { diff --git a/src/sdam/common.ts b/src/sdam/common.ts index 490706678d..b3147d38e0 100644 --- a/src/sdam/common.ts +++ b/src/sdam/common.ts @@ -12,29 +12,35 @@ export const STATE_CONNECTED = 'connected'; * An enumeration of topology types we know about * @public */ -export enum TopologyType { - Single = 'Single', - ReplicaSetNoPrimary = 'ReplicaSetNoPrimary', - ReplicaSetWithPrimary = 'ReplicaSetWithPrimary', - Sharded = 'Sharded', - Unknown = 'Unknown' -} +export const TopologyType = Object.freeze({ + Single: 'Single', + ReplicaSetNoPrimary: 'ReplicaSetNoPrimary', + ReplicaSetWithPrimary: 'ReplicaSetWithPrimary', + Sharded: 'Sharded', + Unknown: 'Unknown' +} as const); + +/** @public */ +export type TopologyTypeId = typeof TopologyType[keyof typeof TopologyType]; /** * An enumeration of server types we know about * @public */ -export enum ServerType { - Standalone = 'Standalone', - Mongos = 'Mongos', - PossiblePrimary = 'PossiblePrimary', - RSPrimary = 'RSPrimary', - RSSecondary = 'RSSecondary', - RSArbiter = 'RSArbiter', - RSOther = 'RSOther', - RSGhost = 'RSGhost', - Unknown = 'Unknown' -} +export const ServerType = Object.freeze({ + Standalone: 'Standalone', + Mongos: 'Mongos', + PossiblePrimary: 'PossiblePrimary', + RSPrimary: 'RSPrimary', + RSSecondary: 'RSSecondary', + RSArbiter: 'RSArbiter', + RSOther: 'RSOther', + RSGhost: 'RSGhost', + Unknown: 'Unknown' +} as const); + +/** @public */ +export type ServerTypeId = typeof ServerType[keyof typeof ServerType]; /** @internal */ export type TimerQueue = Set; diff --git a/src/sdam/server_description.ts b/src/sdam/server_description.ts index b98086b435..4fd9248ca6 100644 --- a/src/sdam/server_description.ts +++ b/src/sdam/server_description.ts @@ -1,15 +1,15 @@ import { arrayStrictEqual, errorStrictEqual, now, HostAddress } from '../utils'; -import { ServerType } from './common'; +import { ServerType, ServerTypeId } from './common'; import type { ObjectId, Long, Document } from '../bson'; import type { ClusterTime } from './common'; -const WRITABLE_SERVER_TYPES = new Set([ +const WRITABLE_SERVER_TYPES = new Set([ ServerType.RSPrimary, ServerType.Standalone, ServerType.Mongos ]); -const DATA_BEARING_SERVER_TYPES = new Set([ +const DATA_BEARING_SERVER_TYPES = new Set([ ServerType.RSPrimary, ServerType.RSSecondary, ServerType.Mongos, @@ -46,7 +46,7 @@ export interface ServerDescriptionOptions { export class ServerDescription { private _hostAddress: HostAddress; address: string; - type: ServerType; + type: ServerTypeId; hosts: string[]; passives: string[]; arbiters: string[]; @@ -205,7 +205,7 @@ export class ServerDescription { } // Parses an `ismaster` message and determines the server type -export function parseServerType(ismaster?: Document): ServerType { +export function parseServerType(ismaster?: Document): ServerTypeId { if (!ismaster || !ismaster.ok) { return ServerType.Unknown; } diff --git a/src/sdam/topology_description.ts b/src/sdam/topology_description.ts index c17920eb57..225d07770b 100644 --- a/src/sdam/topology_description.ts +++ b/src/sdam/topology_description.ts @@ -1,6 +1,6 @@ import { ServerDescription } from './server_description'; import * as WIRE_CONSTANTS from '../cmap/wire_protocol/constants'; -import { TopologyType, ServerType } from './common'; +import { TopologyType, ServerType, TopologyTypeId, ServerTypeId } from './common'; import type { ObjectId, Document } from '../bson'; import type { SrvPollingEvent } from './srv_polling'; @@ -10,6 +10,14 @@ const MAX_SUPPORTED_SERVER_VERSION = WIRE_CONSTANTS.MAX_SUPPORTED_SERVER_VERSION const MIN_SUPPORTED_WIRE_VERSION = WIRE_CONSTANTS.MIN_SUPPORTED_WIRE_VERSION; const MAX_SUPPORTED_WIRE_VERSION = WIRE_CONSTANTS.MAX_SUPPORTED_WIRE_VERSION; +const MONGOS_OR_UNKNOWN = new Set([ServerType.Mongos, ServerType.Unknown]); +const MONGOS_OR_STANDALONE = new Set([ServerType.Mongos, ServerType.Standalone]); +const NON_PRIMARY_RS_MEMBERS = new Set([ + ServerType.RSSecondary, + ServerType.RSArbiter, + ServerType.RSOther +]); + /** @public */ export interface TopologyDescriptionOptions { heartbeatFrequencyMS?: number; @@ -21,7 +29,7 @@ export interface TopologyDescriptionOptions { * @public */ export class TopologyDescription { - type: TopologyType; + type: TopologyTypeId; setName?: string; maxSetVersion?: number; maxElectionId?: ObjectId; @@ -38,7 +46,7 @@ export class TopologyDescription { * Create a TopologyDescription */ constructor( - topologyType: TopologyType, + topologyType: TopologyTypeId, serverDescriptions?: Map, setName?: string, maxSetVersion?: number, @@ -209,13 +217,13 @@ export class TopologyDescription { } if (topologyType === TopologyType.Sharded) { - if ([ServerType.Mongos, ServerType.Unknown].indexOf(serverType) === -1) { + if (!MONGOS_OR_UNKNOWN.has(serverType)) { serverDescriptions.delete(address); } } if (topologyType === TopologyType.ReplicaSetNoPrimary) { - if ([ServerType.Standalone, ServerType.Mongos].indexOf(serverType) >= 0) { + if (MONGOS_OR_STANDALONE.has(serverType)) { serverDescriptions.delete(address); } @@ -232,9 +240,7 @@ export class TopologyDescription { setName = result[1]; maxSetVersion = result[2]; maxElectionId = result[3]; - } else if ( - [ServerType.RSSecondary, ServerType.RSArbiter, ServerType.RSOther].indexOf(serverType) >= 0 - ) { + } else if (NON_PRIMARY_RS_MEMBERS.has(serverType)) { const result = updateRsNoPrimaryFromMember(serverDescriptions, serverDescription, setName); topologyType = result[0]; setName = result[1]; @@ -242,7 +248,7 @@ export class TopologyDescription { } if (topologyType === TopologyType.ReplicaSetWithPrimary) { - if ([ServerType.Standalone, ServerType.Mongos].indexOf(serverType) >= 0) { + if (MONGOS_OR_STANDALONE.has(serverType)) { serverDescriptions.delete(address); topologyType = checkHasPrimary(serverDescriptions); } else if (serverType === ServerType.RSPrimary) { @@ -258,9 +264,7 @@ export class TopologyDescription { setName = result[1]; maxSetVersion = result[2]; maxElectionId = result[3]; - } else if ( - [ServerType.RSSecondary, ServerType.RSArbiter, ServerType.RSOther].indexOf(serverType) >= 0 - ) { + } else if (NON_PRIMARY_RS_MEMBERS.has(serverType)) { topologyType = updateRsWithPrimaryFromMember( serverDescriptions, serverDescription, @@ -316,7 +320,7 @@ export class TopologyDescription { } } -function topologyTypeForServerType(serverType: ServerType): TopologyType { +function topologyTypeForServerType(serverType: ServerTypeId): TopologyTypeId { switch (serverType) { case ServerType.Standalone: return TopologyType.Single; @@ -359,7 +363,7 @@ function updateRsFromPrimary( setName?: string, maxSetVersion?: number, maxElectionId?: ObjectId -): [TopologyType, string?, number?, ObjectId?] { +): [TopologyTypeId, string?, number?, ObjectId?] { setName = setName || serverDescription.setName; if (setName !== serverDescription.setName) { serverDescriptions.delete(serverDescription.address); @@ -427,7 +431,7 @@ function updateRsWithPrimaryFromMember( serverDescriptions: Map, serverDescription: ServerDescription, setName?: string -): TopologyType { +): TopologyTypeId { if (setName == null) { throw new TypeError('setName is required'); } @@ -446,7 +450,7 @@ function updateRsNoPrimaryFromMember( serverDescriptions: Map, serverDescription: ServerDescription, setName?: string -): [TopologyType, string?] { +): [TopologyTypeId, string?] { const topologyType = TopologyType.ReplicaSetNoPrimary; setName = setName || serverDescription.setName; if (setName !== serverDescription.setName) { @@ -467,7 +471,7 @@ function updateRsNoPrimaryFromMember( return [topologyType, setName]; } -function checkHasPrimary(serverDescriptions: Map): TopologyType { +function checkHasPrimary(serverDescriptions: Map): TopologyTypeId { for (const serverDescription of serverDescriptions.values()) { if (serverDescription.type === ServerType.RSPrimary) { return TopologyType.ReplicaSetWithPrimary; diff --git a/src/sessions.ts b/src/sessions.ts index 237065634f..799495dc7e 100644 --- a/src/sessions.ts +++ b/src/sessions.ts @@ -2,7 +2,13 @@ import { PromiseProvider } from './promise_provider'; import { EventEmitter } from 'events'; import { Binary, Long, Timestamp, Document } from './bson'; import { ReadPreference } from './read_preference'; -import { isTransactionCommand, TxnState, Transaction, TransactionOptions } from './transactions'; +import { + isTransactionCommand, + TxnState, + Transaction, + TransactionOptions, + TxnStateId +} from './transactions'; import { resolveClusterTime, ClusterTime } from './sdam/common'; import { isSharded } from './cmap/wire_protocol/shared'; import { MongoError, isRetryableError, MongoNetworkError, MongoWriteConcernError } from './error'; @@ -374,7 +380,7 @@ function attemptTransactionCommit( }); } -const USER_EXPLICIT_TXN_END_STATES = new Set([ +const USER_EXPLICIT_TXN_END_STATES = new Set([ TxnState.NO_TRANSACTION, TxnState.TRANSACTION_COMMITTED, TxnState.TRANSACTION_ABORTED diff --git a/src/transactions.ts b/src/transactions.ts index 7830049030..05908f1601 100644 --- a/src/transactions.ts +++ b/src/transactions.ts @@ -7,16 +7,19 @@ import type { CommandOperationOptions } from './operations/command'; import type { Document } from './bson'; /** @internal */ -export enum TxnState { - NO_TRANSACTION = 'NO_TRANSACTION', - STARTING_TRANSACTION = 'STARTING_TRANSACTION', - TRANSACTION_IN_PROGRESS = 'TRANSACTION_IN_PROGRESS', - TRANSACTION_COMMITTED = 'TRANSACTION_COMMITTED', - TRANSACTION_COMMITTED_EMPTY = 'TRANSACTION_COMMITTED_EMPTY', - TRANSACTION_ABORTED = 'TRANSACTION_ABORTED' -} +export const TxnState = Object.freeze({ + NO_TRANSACTION: 'NO_TRANSACTION', + STARTING_TRANSACTION: 'STARTING_TRANSACTION', + TRANSACTION_IN_PROGRESS: 'TRANSACTION_IN_PROGRESS', + TRANSACTION_COMMITTED: 'TRANSACTION_COMMITTED', + TRANSACTION_COMMITTED_EMPTY: 'TRANSACTION_COMMITTED_EMPTY', + TRANSACTION_ABORTED: 'TRANSACTION_ABORTED' +} as const); + +/** @internal */ +export type TxnStateId = typeof TxnState[keyof typeof TxnState]; -const stateMachine = { +const stateMachine: { [state in TxnStateId]: TxnStateId[] } = { [TxnState.NO_TRANSACTION]: [TxnState.NO_TRANSACTION, TxnState.STARTING_TRANSACTION], [TxnState.STARTING_TRANSACTION]: [ TxnState.TRANSACTION_IN_PROGRESS, @@ -63,7 +66,7 @@ export interface TransactionOptions extends CommandOperationOptions { */ export class Transaction { /** @internal */ - state: TxnState; + state: TxnStateId; options: TransactionOptions; _pinnedServer?: Server; _recoveryToken?: Document; @@ -117,9 +120,11 @@ export class Transaction { * @returns Whether this session is presently in a transaction */ get isActive(): boolean { - return ( - [TxnState.STARTING_TRANSACTION, TxnState.TRANSACTION_IN_PROGRESS].indexOf(this.state) !== -1 - ); + const activeStates: TxnStateId[] = [ + TxnState.STARTING_TRANSACTION, + TxnState.TRANSACTION_IN_PROGRESS + ]; + return activeStates.includes(this.state); } /** @@ -127,9 +132,9 @@ export class Transaction { * @internal * @param nextState - The new state to transition to */ - transition(nextState: TxnState): void { + transition(nextState: TxnStateId): void { const nextStates = stateMachine[this.state]; - if (nextStates && nextStates.indexOf(nextState) !== -1) { + if (nextStates && nextStates.includes(nextState)) { this.state = nextState; if (this.state === TxnState.NO_TRANSACTION || this.state === TxnState.STARTING_TRANSACTION) { this.unpinServer(); diff --git a/tsconfig.json b/tsconfig.json index 624720f417..90089e86eb 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -21,8 +21,8 @@ // API-Extractor uses declaration maps to report problems in source, no need to distribute "declaration": true, "declarationMap": true, - // inline the source so the original content can be debugged - "inlineSources": true, + // we include sources in the release + "inlineSources": false, // Prevents web types from being suggested by vscode. "types": ["node"], "forceConsistentCasingInFileNames": true