107 lines
3.3 KiB
TypeScript
107 lines
3.3 KiB
TypeScript
import { ClientSession, MongoClient, TransactionOptions } from 'mongodb'
|
|
import { Storage, StorageCursor, StorageSession } from '../storage'
|
|
import { ErrEntityHasNoUniqKeyValue } from '../entity'
|
|
|
|
/** @public */
|
|
export class MongoStorage extends Storage {
|
|
private readonly _client: MongoClient
|
|
_session: ClientSession
|
|
|
|
constructor(dsn: string) {
|
|
super(dsn)
|
|
this._client = new MongoClient(dsn)
|
|
this._session = null
|
|
}
|
|
|
|
async init() {
|
|
await this._connect()
|
|
}
|
|
|
|
async _connect() {
|
|
await this._client.connect()
|
|
}
|
|
|
|
async find(collectionName: string, query: Record<string, unknown>): Promise<StorageCursor> {
|
|
await this._connect()
|
|
const coll = await this._client.db().collection(collectionName)
|
|
return coll.find(query)
|
|
}
|
|
|
|
async count(collectionName: string, query: Record<string, unknown>): Promise<number> {
|
|
await this._connect()
|
|
const coll = await this._client.db().collection(collectionName)
|
|
return coll.countDocuments(query)
|
|
}
|
|
|
|
async save(collectionName: string, uniqKey: string, data: Record<string, unknown>): Promise<string> {
|
|
await this._connect()
|
|
const id = data[uniqKey]
|
|
const coll = await this._client.db().collection(collectionName)
|
|
if (id !== null && id !== undefined) {
|
|
const filter = { [uniqKey]: id }
|
|
const result = await coll.findOneAndReplace(filter, data, { upsert: true })
|
|
if (result.lastErrorObject) {
|
|
if (result.lastErrorObject.updatedExisting) {
|
|
return result.value._id
|
|
}
|
|
|
|
return result.lastErrorObject.upserted
|
|
}
|
|
|
|
throw new TypeError(`can not save data to ${collectionName} with result ${result}`)
|
|
} else {
|
|
// Нельзя сохранить сущность без значения уникального ключа
|
|
// const result = await coll.insertOne(data)
|
|
// return result.insertedId._id.toHexString()
|
|
throw new ErrEntityHasNoUniqKeyValue()
|
|
}
|
|
}
|
|
|
|
async _getCollection(name: string) {
|
|
await this._connect()
|
|
return this._client.db().collection(name)
|
|
}
|
|
|
|
createSession(): MongoStorageSession {
|
|
return new MongoStorageSession(this._client)
|
|
}
|
|
|
|
get client(): MongoClient {
|
|
return this._client
|
|
}
|
|
|
|
async remove(collectionName: string, uniqKeyName: string, uniqKey: string): Promise<boolean> {
|
|
const coll = await this._client.db().collection(collectionName)
|
|
const result = await coll.deleteOne({ [uniqKeyName]: uniqKey })
|
|
return Promise.resolve(result.acknowledged)
|
|
}
|
|
}
|
|
|
|
export class MongoStorageSession extends StorageSession {
|
|
_client: MongoClient
|
|
_session: ClientSession
|
|
|
|
constructor(client: MongoClient) {
|
|
super()
|
|
this._client = client
|
|
}
|
|
|
|
async start() {
|
|
if (this._session) {
|
|
await this._session.endSession()
|
|
}
|
|
|
|
this._session = this._client.startSession()
|
|
}
|
|
|
|
async commit(fn, options?: TransactionOptions) {
|
|
try {
|
|
await this._session.withTransaction(fn, options)
|
|
} catch (error) {
|
|
throw error
|
|
}
|
|
|
|
await this._session.endSession()
|
|
}
|
|
}
|