diff --git a/src/app/repo/sqlite.ts b/src/app/repo/sqlite.ts new file mode 100644 index 0000000..c138802 --- /dev/null +++ b/src/app/repo/sqlite.ts @@ -0,0 +1,35 @@ +import { Entity } from '../entity' +import { ErrEntityNotFound, ErrFoundNotUniqEntity, Repo } from '../repo' +import { StorageSQLite } from '../storage/sqlite' + +export abstract class RepoSQLite> extends Repo { + abstract Create(): Promise + + async Drop(): Promise { + const st = this._storage as StorageSQLite + await st?.db?.run(`DROP TABLE IF EXISTS ${this.Name()}`) + } + + async Recreate(): Promise { + await this.Drop() + await this.Create() + } + + async findById(id: string): Promise { + const uniqKey = this.Entity().data.uniqKey() + const cond = `${uniqKey} = ?` + const cursor = await this._storage.find(this.Name(), { [cond]: [id] }) + const entryList = await cursor.toArray() + if (entryList.length > 1) { + throw new ErrFoundNotUniqEntity( + `found few (${entryList.length}) entries in ${this.Name()} for id ${id}` + ) + } + + if (entryList.length === 0) { + throw new ErrEntityNotFound(`not found entry in [${this.Name()}] for id [${id}]`) + } + + return this._transformer(entryList[0]) + } +} diff --git a/src/app/storage/sqlite.ts b/src/app/storage/sqlite.ts index 746b4d8..12e5d7d 100644 --- a/src/app/storage/sqlite.ts +++ b/src/app/storage/sqlite.ts @@ -156,7 +156,7 @@ export class SQLiteCursor implements StorageCursor { } _buildSQL(): { query: string[]; params: (string | number)[] } { - const query = [`SELECT * FROM ${this._tableName}`] + const query = [`SELECT ROWID as '_id', * FROM ${this._tableName}`] const { where, params } = parseCriteria(this._criteria) if (where) { query.push(`WHERE ${where}`) diff --git a/src/tests/repository.test.ts b/src/tests/repo.test.ts similarity index 83% rename from src/tests/repository.test.ts rename to src/tests/repo.test.ts index 91b9586..cca6573 100644 --- a/src/tests/repository.test.ts +++ b/src/tests/repo.test.ts @@ -21,12 +21,12 @@ class Item extends Entity { return this._data.c } - _getRepo(storage: Storage): ItemRepository { - return new ItemRepository(storage) + _getRepo(storage: Storage): ItemRepo { + return new ItemRepo(storage) } } -class ItemRepository extends Repo { +class ItemRepo extends Repo { Name() { return 'items' } @@ -36,10 +36,10 @@ class ItemRepository extends Repo { } } -describe('ItemRepository', () => { +describe('ItemRepo', () => { describe('map storage save', () => { const storage = new MapStorage('') - const repo = new ItemRepository(storage) + const repo = new ItemRepo(storage) it('should return entity', async () => { const dt = Data.assign(new ItemData(), { a: 1, b: 2, c: { d: 3 } }) diff --git a/src/tests/repo/sqlite.test.ts b/src/tests/repo/sqlite.test.ts new file mode 100644 index 0000000..4012e8d --- /dev/null +++ b/src/tests/repo/sqlite.test.ts @@ -0,0 +1,74 @@ +import { Data } from '../../app/data' +import { Entity } from '../../app/entity' +import { Storage } from '../../app/storage' +import { Repo } from '../../app/repo' +import { RepoSQLite } from '../../app/repo/sqlite' +import { StorageSQLite } from '../../app/storage/sqlite' +import { assert } from 'chai' + +class ItemData extends Data { + uniqKey(): string { + return 'uid' + } + + uid: string + title: string +} +class ItemEntity extends Entity { + _getRepo(storage: Storage): Repo> { + return undefined + } + + _getVO(): ItemData { + return new ItemData() + } +} +class ItemsRepo extends RepoSQLite { + Entity(): ItemEntity { + return new ItemEntity() + } + + Name(): string { + return 'items' + } + + async Create(): Promise { + const st = this._storage as StorageSQLite + await st?.db?.run(` + create table if not exists ${this.Name()} ( + uid varchar(255) not null unique, + title text null + ) + `) + } +} + +describe('ItemsRepoSQLite', () => { + const dsn = __dirname + `/sqlite.test.db` + let storage: StorageSQLite + let repo: ItemsRepo + + beforeAll(async () => { + storage = new StorageSQLite({ dsn }) + await storage.connect() + storage.db.on('trace', (data: string) => { + console.log(data) + }) + repo = new ItemsRepo(storage) + await repo.Recreate() + for (const uid of ['foo', 'bar', 'pew', 'baz', 'fox']) { + const d = new ItemData() + d.uid = uid + const e = new ItemEntity(d) + await repo.save(e) + } + }) + + describe('#findById', () => { + it('should return persisted entity', async () => { + const e = await repo.findById('foo') + assert.isTrue(e.isPersisted()) + assert.isDefined(e._id) + }) + }) +})