ivanovna.orm/src/app/storage/mongo.ts

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()
}
}