Path: blob/main/core/models/DetachedJsPathCallsTable.ts
1028 views
import { Database as SqliteDatabase } from 'better-sqlite3';1import SqliteTable from '@secret-agent/commons/SqliteTable';2import IScriptInstanceMeta from '@secret-agent/interfaces/IScriptInstanceMeta';3import { IJsPathHistory } from '../lib/JsPath';45export default class DetachedJsPathCallsTable extends SqliteTable<IDetachedJsPathCallsRecord> {6private cacheByCallsiteKey: {7[entrypoint_callsitepath_key: string]: IDetachedJsPathCallsRecord;8} = {};910constructor(readonly db: SqliteDatabase) {11super(db, 'DetachedJsPathCalls', [12['scriptEntrypoint', 'TEXT'],13['callsitePath', 'TEXT'],14['execJsPathHistory', 'TEXT'],15['timestamp', 'INTEGER'],16['key', 'TEXT'],17]);18}1920public insert(21scriptMeta: IScriptInstanceMeta,22callsitePath: string,23execJsPathHistory: IJsPathHistory[],24timestamp: Date,25key = 'default',26): void {27if (!scriptMeta) return;28const { entrypoint: scriptEntrypoint } = scriptMeta;29const record = {30scriptEntrypoint,31callsitePath,32timestamp: timestamp.getTime(),33execJsPathHistory: JSON.stringify(execJsPathHistory),34key,35};36const existing = this.getCachedRecord(scriptMeta, callsitePath, key);37// already stored38if (existing?.execJsPathHistory === record.execJsPathHistory) return;3940this.insertNow([41record.scriptEntrypoint,42record.callsitePath,43record.execJsPathHistory,44record.timestamp,45record.key,46]);47this.cacheRecord(record);48}4950public find(51scriptMeta: IScriptInstanceMeta,52callsite: string,53key = 'default',54): IDetachedJsPathCallsRecord {55if (!scriptMeta) return null;5657const cached = this.getCachedRecord(scriptMeta, callsite, key);58if (cached) return cached;5960try {61const result = this.db62.prepare(63`select * from ${this.tableName} where scriptEntrypoint=? and callsitePath=? and key=? order by timestamp desc limit 1`,64)65.get(scriptMeta.entrypoint, callsite, key);6667if (result) this.cacheRecord(result);6869return result;70} catch (err) {71if (String(err).includes('no such table')) return;72throw err;73}74}7576private getCachedRecord(77scriptMeta: IScriptInstanceMeta,78callsite: string,79key: string,80): IDetachedJsPathCallsRecord {81const entrypoint = scriptMeta?.entrypoint ?? '';82const cacheKey = DetachedJsPathCallsTable.getCacheKey(entrypoint, callsite, key);83return this.cacheByCallsiteKey[cacheKey];84}8586private cacheRecord(record: IDetachedJsPathCallsRecord): void {87const cacheKey = DetachedJsPathCallsTable.getCacheKey(88record.scriptEntrypoint,89record.callsitePath,90record.key,91);92this.cacheByCallsiteKey[cacheKey] = record;93}9495private static getCacheKey(scriptEntrypoint: string, callsitePath: string, key: string): string {96return `${scriptEntrypoint}_${callsitePath}_${key}`;97}98}99100export interface IDetachedJsPathCallsRecord {101scriptEntrypoint: string;102callsitePath: string;103execJsPathHistory: string;104timestamp: number;105key: string;106}107108109