Skip to content

Commit

Permalink
feat: CommonDao DBM no longer extends Saved<BM>
Browse files Browse the repository at this point in the history
Basically, DBM no longer requires non-optional id/created/updated.
This simplifies generics definition of CommonDao, so DBM
is now less dependent on BM.
It's a trade-off, but hopefully with net-negative complexity result.
  • Loading branch information
kirillgroshkov committed Jan 19, 2024
1 parent d58783e commit 16742f2
Show file tree
Hide file tree
Showing 17 changed files with 228 additions and 194 deletions.
4 changes: 2 additions & 2 deletions src/adapter/cachedb/cache.db.model.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CommonLogger, ObjectWithId } from '@naturalcycles/js-lib'
import { CommonLogger, PartialObjectWithId } from '@naturalcycles/js-lib'
import { CommonDB } from '../../common.db'
import {
CommonDBCreateOptions,
Expand Down Expand Up @@ -62,7 +62,7 @@ export interface CacheDBOptions extends CommonDBOptions {
onlyCache?: boolean
}

export interface CacheDBSaveOptions<ROW extends Partial<ObjectWithId>>
export interface CacheDBSaveOptions<ROW extends PartialObjectWithId>
extends CacheDBOptions,
CommonDBSaveOptions<ROW> {}

Expand Down
34 changes: 18 additions & 16 deletions src/adapter/cachedb/cache.db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ import {
_isTruthy,
JsonSchemaObject,
JsonSchemaRootObject,
ObjectWithId,
PartialObjectWithId,
Saved,
StringMap,
} from '@naturalcycles/js-lib'
import { ReadableTyped } from '@naturalcycles/nodejs-lib'
import { BaseCommonDB } from '../../base.common.db'
import { CommonDB, commonDBFullSupport, CommonDBSupport } from '../../common.db'
import { DBPatch, RunQueryResult } from '../../db.model'
Expand Down Expand Up @@ -57,13 +59,13 @@ export class CacheDB extends BaseCommonDB implements CommonDB {
return await this.cfg.downstreamDB.getTables()
}

override async getTableSchema<ROW extends ObjectWithId>(
override async getTableSchema<ROW extends PartialObjectWithId>(
table: string,
): Promise<JsonSchemaRootObject<ROW>> {
return await this.cfg.downstreamDB.getTableSchema<ROW>(table)
}

override async createTable<ROW extends ObjectWithId>(
override async createTable<ROW extends PartialObjectWithId>(
table: string,
schema: JsonSchemaObject<ROW>,
opt: CacheDBCreateOptions = {},
Expand All @@ -77,13 +79,13 @@ export class CacheDB extends BaseCommonDB implements CommonDB {
}
}

override async getByIds<ROW extends ObjectWithId>(
override async getByIds<ROW extends PartialObjectWithId>(
table: string,
ids: ROW['id'][],
ids: string[],
opt: CacheDBSaveOptions<ROW> = {},
): Promise<ROW[]> {
const resultMap: StringMap<ROW> = {}
const missingIds: ROW['id'][] = []
): Promise<Saved<ROW>[]> {
const resultMap: StringMap<Saved<ROW>> = {}
const missingIds: string[] = []

if (!opt.skipCache && !this.cfg.skipCache) {
const results = await this.cfg.cacheDB.getByIds<ROW>(table, ids, opt)
Expand Down Expand Up @@ -123,7 +125,7 @@ export class CacheDB extends BaseCommonDB implements CommonDB {
return ids.map(id => resultMap[id]).filter(_isTruthy)
}

override async saveBatch<ROW extends Partial<ObjectWithId>>(
override async saveBatch<ROW extends PartialObjectWithId>(
table: string,
rows: ROW[],
opt: CacheDBSaveOptions<ROW> = {},
Expand Down Expand Up @@ -152,10 +154,10 @@ export class CacheDB extends BaseCommonDB implements CommonDB {
}
}

override async runQuery<ROW extends ObjectWithId>(
override async runQuery<ROW extends PartialObjectWithId>(
q: DBQuery<ROW>,
opt: CacheDBSaveOptions<ROW> = {},
): Promise<RunQueryResult<ROW>> {
): Promise<RunQueryResult<Saved<ROW>>> {
if (!opt.onlyCache && !this.cfg.onlyCache) {
const { rows, ...queryResult } = await this.cfg.downstreamDB.runQuery(q, opt)

Expand All @@ -182,7 +184,7 @@ export class CacheDB extends BaseCommonDB implements CommonDB {
return { rows, ...queryResult }
}

override async runQueryCount<ROW extends ObjectWithId>(
override async runQueryCount<ROW extends PartialObjectWithId>(
q: DBQuery<ROW>,
opt: CacheDBOptions = {},
): Promise<number> {
Expand All @@ -199,10 +201,10 @@ export class CacheDB extends BaseCommonDB implements CommonDB {
return count
}

override streamQuery<ROW extends ObjectWithId>(
override streamQuery<ROW extends PartialObjectWithId>(
q: DBQuery<ROW>,
opt: CacheDBStreamOptions = {},
): Readable {
): ReadableTyped<Saved<ROW>> {
if (!opt.onlyCache && !this.cfg.onlyCache) {
const stream = this.cfg.downstreamDB.streamQuery<ROW>(q, opt)

Expand Down Expand Up @@ -238,7 +240,7 @@ export class CacheDB extends BaseCommonDB implements CommonDB {
return stream
}

override async deleteByQuery<ROW extends ObjectWithId>(
override async deleteByQuery<ROW extends PartialObjectWithId>(
q: DBQuery<ROW>,
opt: CacheDBOptions = {},
): Promise<number> {
Expand Down Expand Up @@ -270,7 +272,7 @@ export class CacheDB extends BaseCommonDB implements CommonDB {
return deletedIds
}

override async updateByQuery<ROW extends ObjectWithId>(
override async updateByQuery<ROW extends PartialObjectWithId>(
q: DBQuery<ROW>,
patch: DBPatch<ROW>,
opt: CacheDBOptions = {},
Expand Down
4 changes: 2 additions & 2 deletions src/adapter/file/file.db.model.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { CommonLogger, ObjectWithId } from '@naturalcycles/js-lib'
import { CommonLogger, PartialObjectWithId, Saved } from '@naturalcycles/js-lib'
import { DBSaveBatchOperation } from '../../db.model'
import type { DBQueryOrder } from '../../query/dbQuery'

export interface FileDBPersistencePlugin {
ping: () => Promise<void>
getTables: () => Promise<string[]>
loadFile: <ROW extends ObjectWithId>(table: string) => Promise<ROW[]>
loadFile: <ROW extends PartialObjectWithId>(table: string) => Promise<Saved<ROW>[]>
saveFiles: (ops: DBSaveBatchOperation<any>[]) => Promise<void>
}

Expand Down
32 changes: 17 additions & 15 deletions src/adapter/file/file.db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import {
_stringMapValues,
JsonSchemaRootObject,
_filterUndefinedValues,
ObjectWithId,
_assert,
Saved,
PartialObjectWithId,
} from '@naturalcycles/js-lib'
import { readableCreate, ReadableTyped, dimGrey } from '@naturalcycles/nodejs-lib'
import {
Expand Down Expand Up @@ -74,16 +74,16 @@ export class FileDB extends BaseCommonDB implements CommonDB {
return tables
}

override async getByIds<ROW extends ObjectWithId>(
override async getByIds<ROW extends PartialObjectWithId>(
table: string,
ids: ROW['id'][],
ids: string[],
_opt?: CommonDBOptions,
): Promise<ROW[]> {
): Promise<Saved<ROW>[]> {
const byId = _by(await this.loadFile<ROW>(table), r => r.id)
return ids.map(id => byId[id]!).filter(Boolean)
}

override async saveBatch<ROW extends Partial<ObjectWithId>>(
override async saveBatch<ROW extends PartialObjectWithId>(
table: string,
rows: ROW[],
_opt?: CommonDBSaveOptions<ROW>,
Expand Down Expand Up @@ -111,23 +111,23 @@ export class FileDB extends BaseCommonDB implements CommonDB {
}
}

override async runQuery<ROW extends ObjectWithId>(
override async runQuery<ROW extends PartialObjectWithId>(
q: DBQuery<ROW>,
_opt?: CommonDBOptions,
): Promise<RunQueryResult<ROW>> {
): Promise<RunQueryResult<Saved<ROW>>> {
return {
rows: queryInMemory(q, await this.loadFile<ROW>(q.table)),
}
}

override async runQueryCount<ROW extends ObjectWithId>(
override async runQueryCount<ROW extends PartialObjectWithId>(
q: DBQuery<ROW>,
_opt?: CommonDBOptions,
): Promise<number> {
return (await this.loadFile(q.table)).length
}

override streamQuery<ROW extends ObjectWithId>(
override streamQuery<ROW extends PartialObjectWithId>(
q: DBQuery<ROW>,
opt?: CommonDBStreamOptions,
): ReadableTyped<ROW> {
Expand All @@ -141,7 +141,7 @@ export class FileDB extends BaseCommonDB implements CommonDB {
return readable
}

override async deleteByQuery<ROW extends ObjectWithId>(
override async deleteByQuery<ROW extends PartialObjectWithId>(
q: DBQuery<ROW>,
_opt?: CommonDBOptions,
): Promise<number> {
Expand Down Expand Up @@ -181,7 +181,7 @@ export class FileDB extends BaseCommonDB implements CommonDB {
return deleted
}

override async getTableSchema<ROW extends ObjectWithId>(
override async getTableSchema<ROW extends PartialObjectWithId>(
table: string,
): Promise<JsonSchemaRootObject<ROW>> {
const rows = await this.loadFile(table)
Expand All @@ -192,15 +192,15 @@ export class FileDB extends BaseCommonDB implements CommonDB {
}

// wrapper, to handle logging
async loadFile<ROW extends ObjectWithId>(table: string): Promise<ROW[]> {
async loadFile<ROW extends PartialObjectWithId>(table: string): Promise<Saved<ROW>[]> {
const started = this.logStarted(`loadFile(${table})`)
const rows = await this.cfg.plugin.loadFile<ROW>(table)
this.logFinished(started, `loadFile(${table}) ${rows.length} row(s)`)
return rows
}

// wrapper, to handle logging, sorting rows before saving
async saveFile<ROW extends ObjectWithId>(table: string, _rows: ROW[]): Promise<void> {
async saveFile<ROW extends PartialObjectWithId>(table: string, _rows: ROW[]): Promise<void> {
// if (!_rows.length) return // NO, it should be able to save file with 0 rows!

// Sort the rows, if needed
Expand All @@ -212,7 +212,9 @@ export class FileDB extends BaseCommonDB implements CommonDB {
this.logFinished(started, op)
}

async saveFiles<ROW extends ObjectWithId>(ops: DBSaveBatchOperation<ROW>[]): Promise<void> {
async saveFiles<ROW extends PartialObjectWithId>(
ops: DBSaveBatchOperation<ROW>[],
): Promise<void> {
if (!ops.length) return
const op =
`saveFiles ${ops.length} op(s):\n` + ops.map(o => `${o.table} (${o.rows.length})`).join('\n')
Expand All @@ -225,7 +227,7 @@ export class FileDB extends BaseCommonDB implements CommonDB {
// return new FileDBTransaction(this)
// }

sortRows<ROW extends ObjectWithId>(rows: ROW[]): ROW[] {
sortRows<ROW extends PartialObjectWithId>(rows: ROW[]): ROW[] {
rows = rows.map(r => _filterUndefinedValues(r))

if (this.cfg.sortOnSave) {
Expand Down
8 changes: 4 additions & 4 deletions src/adapter/file/localFile.persistence.plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import fs from 'node:fs'
import fsp from 'node:fs/promises'
import { Readable } from 'node:stream'
import { createGzip, createUnzip } from 'node:zlib'
import { pMap, ObjectWithId } from '@naturalcycles/js-lib'
import { pMap, PartialObjectWithId, Saved } from '@naturalcycles/js-lib'
import {
transformJsonParse,
transformSplit,
Expand Down Expand Up @@ -48,7 +48,7 @@ export class LocalFilePersistencePlugin implements FileDBPersistencePlugin {
.map(f => f.split('.ndjson')[0]!)
}

async loadFile<ROW extends ObjectWithId>(table: string): Promise<ROW[]> {
async loadFile<ROW extends PartialObjectWithId>(table: string): Promise<Saved<ROW>[]> {
await fs2.ensureDirAsync(this.cfg.storagePath)
const ext = `ndjson${this.cfg.gzip ? '.gz' : ''}`
const filePath = `${this.cfg.storagePath}/${table}.${ext}`
Expand All @@ -57,7 +57,7 @@ export class LocalFilePersistencePlugin implements FileDBPersistencePlugin {

const transformUnzip = this.cfg.gzip ? [createUnzip()] : []

const rows: ROW[] = []
const rows: Saved<ROW>[] = []

await _pipeline([
fs.createReadStream(filePath),
Expand All @@ -74,7 +74,7 @@ export class LocalFilePersistencePlugin implements FileDBPersistencePlugin {
await pMap(ops, async op => await this.saveFile(op.table, op.rows), { concurrency: 16 })
}

async saveFile<ROW extends ObjectWithId>(table: string, rows: ROW[]): Promise<void> {
async saveFile<ROW extends PartialObjectWithId>(table: string, rows: ROW[]): Promise<void> {
await fs2.ensureDirAsync(this.cfg.storagePath)
const ext = `ndjson${this.cfg.gzip ? '.gz' : ''}`
const filePath = `${this.cfg.storagePath}/${table}.${ext}`
Expand Down
4 changes: 2 additions & 2 deletions src/adapter/file/noop.persistence.plugin.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ObjectWithId } from '@naturalcycles/js-lib'
import { PartialObjectWithId, Saved } from '@naturalcycles/js-lib'
import { DBSaveBatchOperation } from '../../db.model'
import { FileDBPersistencePlugin } from './file.db.model'

Expand All @@ -9,7 +9,7 @@ export class NoopPersistencePlugin implements FileDBPersistencePlugin {
return []
}

async loadFile<ROW extends ObjectWithId>(_table: string): Promise<ROW[]> {
async loadFile<ROW extends PartialObjectWithId>(_table: string): Promise<Saved<ROW>[]> {
return []
}

Expand Down
Loading

0 comments on commit 16742f2

Please sign in to comment.