UNPKG

@deepkit/framework

Version:

475 lines 22.6 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.OrmBrowserController = void 0; /*@ts-ignore*/ const { __ΩFakerTypes } = require('@deepkit/orm-browser-api'); /*@ts-ignore*/ const { __ΩHttpQuery } = require('@deepkit/http'); /*@ts-ignore*/ const { __ΩQueryResult } = require('@deepkit/orm-browser-api'); /*@ts-ignore*/ const { __ΩDatabaseCommit } = require('@deepkit/orm-browser-api'); function __assignType(fn, args) { fn.__type = args; return fn; } const core_1 = require("@deepkit/core"); const orm_1 = require("@deepkit/orm"); const orm_browser_api_1 = require("@deepkit/orm-browser-api"); const rpc_1 = require("@deepkit/rpc"); const sql_1 = require("@deepkit/sql"); const logger_1 = require("@deepkit/logger"); const perf_hooks_1 = require("perf_hooks"); const http_1 = require("@deepkit/http"); const type_1 = require("@deepkit/type"); let OrmBrowserController = class OrmBrowserController { constructor(databases) { this.databases = databases; } registerDatabase(...databases) { this.databases.push(...databases); } extractDatabaseInfo(db) { return new orm_browser_api_1.DatabaseInfo(db.name, db.adapter.getName(), db.entityRegistry.all().map(__assignType(v => v.serializeType(), ['v', '', 'P"2!"/"']))); } getDb(dbName) { for (const db of this.databases) { if (db.name === dbName) return db; } throw new Error(`No database ${dbName} found`); } getDbEntity(dbName, entityName) { for (const db of this.databases) { if (db.name === dbName) { for (const entity of db.entityRegistry.all()) { if (entity.name === entityName) return [db, entity]; } } } throw new Error(`No entity ${entityName} for in database ${dbName}`); } getDatabases() { const databases = []; for (const db of this.databases) { databases.push(this.extractDatabaseInfo(db)); } return databases; } getDatabase(name) { for (const db of this.databases) { if (db.name === name) return this.extractDatabaseInfo(db); } throw new Error(`No database ${name} found`); } findDatabase(name) { for (const db of this.databases) { if (db.name === name) return db; } throw new Error(`No database ${name} found`); } async migrate(name) { const db = this.findDatabase(name); await db.migrate(); } async resetAllTables(name) { const db = this.findDatabase(name); if (db.adapter instanceof sql_1.SQLDatabaseAdapter) { await db.adapter.createTables(db.entityRegistry); } } async getFakerTypes() { const res = {}; const faker = require('faker'); for (const fn of orm_browser_api_1.fakerFunctions) { const [p1, p2] = fn.split('.'); try { const example = p2 ? faker[p1][p2]() : faker[p1](); res[fn] = { example: example, type: (0, orm_browser_api_1.getType)(example) }; } catch (error) { console.log(`warning: faker function not available ${fn}: ${error}`); } } return res; } async getMigrations(name) { const db = this.findDatabase(name); if (db.adapter instanceof sql_1.SQLDatabaseAdapter) { return db.adapter.getMigrations(new orm_1.MigrateOptions(), db.entityRegistry); } return {}; } async seed(dbName, seed) { var _a, _b; const db = this.getDb(dbName); const oldLevel = db.logger.level; db.logger.level = logger_1.LoggerLevel.debug; try { const session = db.createSession(); const added = {}; const assignReference = []; const faker = require('faker'); function fakerValue(path, fakerName) { const [p1, p2] = fakerName.split('.'); try { return p2 ? faker[p1][p2]() : faker[p1](); } catch (error) { console.warn(`Could not fake ${path} via faker's ${fakerName}: ${error}`); } } fakerValue.__type = ['path', 'fakerName', 'fakerValue', 'P&2!&2""/#']; function fake(path, property, propSeed, callback) { if (!propSeed.fake) { if (propSeed.value !== undefined) callback(propSeed.value); return; } if ((0, type_1.isReferenceType)(property)) { // if (property.type !== 'class') throw new Error(`${path}: only class properties can be references`); assignReference.push({ path, entity: (0, type_1.resolveClassType)(property).getName(), reference: propSeed.reference, properties: propSeed.properties, callback }); return; } else if (property.kind === type_1.ReflectionKind.array) { const res = []; if (!propSeed.array) return res; const range = propSeed.array.max - propSeed.array.min; for (let i = 0; i < Math.ceil(Math.random() * range); i++) { fake(path + '.' + i, property.type, propSeed.array.seed, __assignType((v) => { res.push(v); }, ['v', '', 'P"2!"/"'])); } return callback(res); } else if (property.kind === type_1.ReflectionKind.class || property.kind === type_1.ReflectionKind.objectLiteral) { const schema = type_1.ReflectionClass.from(property); const item = schema.createDefaultObject(); for (const prop of schema.getProperties()) { if (!propSeed.properties[prop.name]) continue; fake(path + '.' + prop.name, prop.type, propSeed.properties[prop.name], __assignType((v) => { item[prop.name] = v; }, ['v', '', 'P"2!"/"'])); } return callback(item); } else if (property.kind === type_1.ReflectionKind.boolean) { callback(Math.random() > 0.5); } else if (property.kind === type_1.ReflectionKind.enum) { const values = property.values; callback(values[values.length * Math.random() | 0]); } else { return callback(fakerValue(path, propSeed.faker)); } } fake.__type = ['path', 'Type', 'property', () => orm_browser_api_1.EntityPropertySeed, 'propSeed', 'v', '', 'callback', 'fake', 'P&2!"w"2#P7$2%P"2&"/\'2("/)']; function create(entity, properties) { if (!added[entity.getName()]) added[entity.getName()] = []; const item = entity.createDefaultObject(); for (const [propName, propSeed] of Object.entries(properties)) { const property = entity.getProperty(propName); fake(entity.getClassName() + '.' + propName, property.type, propSeed, __assignType((v) => { item[property.name] = v; }, ['v', '', 'P"2!"/"'])); } for (const reference of entity.getReferences()) { if (reference.isArray()) continue; if (reference.isBackReference()) continue; item[reference.name] = db.getReference(reference.getResolvedReflectionClass(), item[reference.name]); } session.add(item); added[entity.getName()].push(item); return item; } create.__type = [() => type_1.ReflectionClass, 'entity', () => orm_browser_api_1.EntityPropertySeed, 'properties', 'create', 'PP"7!2"P&P7#LM2$"/%']; for (const [entityName, entitySeed] of Object.entries(seed.entities)) { if (!entitySeed || !entitySeed.active) continue; const entity = db.getEntity(entityName); if (entitySeed.truncate) { await db.query(entity).deleteMany(); } for (let i = 0; i < entitySeed.amount; i++) { create(entity, entitySeed.properties); } } //assign references const dbCandidates = {}; for (const ref of assignReference) { const entity = db.getEntity(ref.entity); let candidates = added[_a = ref.entity] || (added[_a] = []); if (ref.reference === 'random') { //note: I know there are faster ways, but this gets the job done for now candidates = dbCandidates[_b = ref.entity] || (dbCandidates[_b] = await db.query(entity).limit(1000).find()); } if (!candidates.length) { if (ref.reference === 'random') { throw new Error(`Entity ${ref.entity} has no items in the database. Used in ${ref.path}.`); } if (ref.reference === 'random-seed') { throw new Error(`Entity ${ref.entity} has no seeded items. Used in ${ref.path}.`); } } if (ref.reference === 'create') { ref.callback(create(entity, ref.properties)); } else { ref.callback(candidates[candidates.length * Math.random() | 0]); } } await session.commit(); } finally { db.logger.level = oldLevel; } } async httpQuery(dbName, entityName, query) { const [, entity] = this.getDbEntity(dbName, entityName); const res = await this.query(dbName, entityName, query); if ((0, core_1.isArray)(res.result)) { const partial = (0, type_1.getPartialSerializeFunction)(entity.type, type_1.serializer.deserializeRegistry); res.result = res.result.map(__assignType(v => partial(v), ['v', '', 'P"2!"/"'])); } return res; } async query(dbName, entityName, query) { const res = { executionTime: 0, log: [], result: undefined }; const [db, entity] = this.getDbEntity(dbName, entityName); const oldLogger = db.logger; const loggerTransport = new logger_1.MemoryLoggerTransport; db.setLogger(new logger_1.Logger([loggerTransport])); try { const fn = new Function(`return function(database, ${entity.getClassName()}) {return ${query}}`)(); const start = perf_hooks_1.performance.now(); res.result = await fn(db, entity); res.executionTime = perf_hooks_1.performance.now() - start; } catch (error) { res.error = String(error); } finally { res.log = loggerTransport.messageStrings; if (oldLogger) db.setLogger(oldLogger); } return res; } async getCount(dbName, entityName, filter) { const [db, entity] = this.getDbEntity(dbName, entityName); return await db.query(entity).filter(filter).count(); } async getItems(dbName, entityName, filter, sort, limit, skip) { const [db, entity] = this.getDbEntity(dbName, entityName); const start = perf_hooks_1.performance.now(); const items = await db.query(entity).filter(filter).sort(sort).limit(limit).skip(skip).find(); return { items, executionTime: perf_hooks_1.performance.now() - start }; } async create(dbName, entityName) { const [db, entity] = this.getDbEntity(dbName, entityName); return entity.createDefaultObject(); } async commit(commit) { // console.log(inspect(commit, false, 2133)); function isNewIdWrapper(value) { return (0, core_1.isObject)(value) && '$___newId' in value; } isNewIdWrapper.__type = ['value', 'isNewIdWrapper', 'P"2!!/"']; for (const [dbName, c] of Object.entries(commit)) { const db = this.getDb(dbName); const session = db.createSession(); try { const updates = []; for (const [entityName, removes] of Object.entries(c.removed)) { const entity = db.getEntity(entityName); const query = session.query(entity); for (const remove of removes) { updates.push(query.filter(db.getReference(entity, remove)).deleteOne()); } } const addedItems = (Map.Ω = [['\''], ['"']], new Map()); for (const [entityName, added] of Object.entries(c.added)) { const entity = db.getEntity(entityName); const addedIds = c.addedIds[entityName]; for (let i = 0; i < added.length; i++) { addedItems.set(addedIds[i], (0, type_1.cast)(added[i], undefined, undefined, undefined, entity.type)); } } for (const [entityName, ids] of Object.entries(c.addedIds)) { const entity = db.getEntity(entityName); const added = c.added[entityName]; for (let i = 0; i < added.length; i++) { const id = ids[i]; const add = added[i]; const item = addedItems.get(id); for (const reference of entity.getReferences()) { if (reference.isBackReference()) continue; //note, we need to operate on `added` from commit // since `item` from addedItems got already converted and $___newId is lost. const v = add[reference.name]; if (reference.isArray()) { } else { if (isNewIdWrapper(v)) { //reference to not-yet existing record, //so place the actual item in it, so the UoW accordingly saves item[reference.name] = addedItems.get(v.$___newId); } else { //regular reference to already existing record, //so convert to reference item[reference.name] = db.getReference(reference.getResolvedReflectionClass(), item[reference.name]); } } } session.add(item); } } await session.commit(); for (const [entityName, changes] of Object.entries(c.changed)) { const entity = db.getEntity(entityName); const query = session.query(entity); for (const change of changes) { //todo: convert $set from json to class const $set = change.changes.$set; if (!$set) continue; for (const reference of entity.getReferences()) { if (reference.isBackReference()) continue; const v = $set[reference.name]; if (v === undefined) continue; if (isNewIdWrapper(v)) { $set[reference.name] = addedItems.get(v.$___newId); } else { $set[reference.name] = db.getReference(reference.getResolvedReflectionClass(), $set[reference.name]); } } updates.push(query.filter(db.getReference(entity, change.pk)).patchOne(change.changes)); } } await Promise.all(updates); } catch (error) { //todo: rollback throw error; } } } }; exports.OrmBrowserController = OrmBrowserController; OrmBrowserController.__type = [() => orm_1.Database, 'databases', 'constructor', () => orm_1.Database, 'registerDatabase', () => orm_1.Database, 'db', () => orm_browser_api_1.DatabaseInfo, 'extractDatabaseInfo', 'dbName', () => orm_1.Database, 'getDb', 'entityName', () => orm_1.Database, () => type_1.ReflectionClass, 'getDbEntity', () => orm_browser_api_1.DatabaseInfo, 'getDatabases', 'name', () => orm_browser_api_1.DatabaseInfo, 'getDatabase', () => orm_1.Database, 'findDatabase', 'migrate', 'resetAllTables', () => __ΩFakerTypes, 'getFakerTypes', 'sql', 'diff', 'getMigrations', () => orm_browser_api_1.SeedDatabase, 'seed', () => __ΩHttpQuery, () => __ΩHttpQuery, () => __ΩHttpQuery, 'query', () => __ΩQueryResult, 'httpQuery', () => __ΩQueryResult, 'filter', 'getCount', 'sort', 'limit', 'skip', 'items', 'executionTime', 'getItems', 'create', () => __ΩDatabaseCommit, 'commit', 'OrmBrowserController', 'PP7!F2"<"0#PP7$@2""0%PP7&2\'P7(0)<P&2*P7+0,<P&2*&2-PP7.P"7/G00<PP71F02P&23P7405P&23P7607<P&23$`08P&23$`09Pn:`0;P&23P&P&F4<&4=MLM`0>P&2*P7?2@$`0@P&oA"2*&oB"2-&oC"2DnE`0FP&2*&2-&2DnG`0DP&2*&2-P&"LM2H\'`0IP&2*&2-P&"LM2HP&"LM2J\'2K\'2LP"F4M\'4NM`0OP&2*&2-"`0PPnQ2R"0R5!x"wS']; __decorate([ rpc_1.rpc.action(), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", Array) ], OrmBrowserController.prototype, "getDatabases", null); __decorate([ rpc_1.rpc.action(), __metadata("design:type", Function), __metadata("design:paramtypes", [String]), __metadata("design:returntype", orm_browser_api_1.DatabaseInfo) ], OrmBrowserController.prototype, "getDatabase", null); __decorate([ rpc_1.rpc.action(), __metadata("design:type", Function), __metadata("design:paramtypes", [String]), __metadata("design:returntype", Promise) ], OrmBrowserController.prototype, "migrate", null); __decorate([ rpc_1.rpc.action(), __metadata("design:type", Function), __metadata("design:paramtypes", [String]), __metadata("design:returntype", Promise) ], OrmBrowserController.prototype, "resetAllTables", null); __decorate([ rpc_1.rpc.action(), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", Promise) ], OrmBrowserController.prototype, "getFakerTypes", null); __decorate([ rpc_1.rpc.action(), __metadata("design:type", Function), __metadata("design:paramtypes", [String]), __metadata("design:returntype", Promise) ], OrmBrowserController.prototype, "getMigrations", null); __decorate([ rpc_1.rpc.action(), __metadata("design:type", Function), __metadata("design:paramtypes", [String, orm_browser_api_1.SeedDatabase]), __metadata("design:returntype", Promise) ], OrmBrowserController.prototype, "seed", null); __decorate([ http_1.http.GET('_orm-browser/query'), __metadata("design:type", Function), __metadata("design:paramtypes", [Object, Object, Object]), __metadata("design:returntype", Promise) ], OrmBrowserController.prototype, "httpQuery", null); __decorate([ rpc_1.rpc.action(), __metadata("design:type", Function), __metadata("design:paramtypes", [String, String, String]), __metadata("design:returntype", Promise) ], OrmBrowserController.prototype, "query", null); __decorate([ rpc_1.rpc.action(), __metadata("design:type", Function), __metadata("design:paramtypes", [String, String, Object]), __metadata("design:returntype", Promise) ], OrmBrowserController.prototype, "getCount", null); __decorate([ rpc_1.rpc.action(), __metadata("design:type", Function), __metadata("design:paramtypes", [String, String, Object, Object, Number, Number]), __metadata("design:returntype", Promise) ], OrmBrowserController.prototype, "getItems", null); __decorate([ rpc_1.rpc.action(), __metadata("design:type", Function), __metadata("design:paramtypes", [String, String]), __metadata("design:returntype", Promise) ], OrmBrowserController.prototype, "create", null); __decorate([ rpc_1.rpc.action(), __metadata("design:type", Function), __metadata("design:paramtypes", [Object]), __metadata("design:returntype", Promise) ], OrmBrowserController.prototype, "commit", null); exports.OrmBrowserController = OrmBrowserController = __decorate([ rpc_1.rpc.controller(orm_browser_api_1.BrowserControllerInterface), __metadata("design:paramtypes", [Array]) ], OrmBrowserController); //# sourceMappingURL=controller.js.map