longcelot-sheet-db
Version:
Google Sheets-backed staging database adapter for Node.js with schema-first design
91 lines • 4 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.SQLAdapterBase = void 0;
const PermissionError_1 = require("../../errors/PermissionError");
const SchemaError_1 = require("../../errors/SchemaError");
const accessControl_1 = require("../accessControl");
const sqlTableOperations_1 = require("./sqlTableOperations");
const fkResolver_1 = require("./fkResolver");
/**
* Shared DatabaseAdapter implementation for the Postgres/MySQL adapters (Phase 16.2) —
* withContext()/asActor()/table() mirror SheetAdapter's exactly (same actor/role and
* targetActor/targetRole normalization), minus the Sheets-only schema-version-check
* machinery, since SQL adapters never auto-sync schema at runtime (Phase 16 decision 5).
*/
class SQLAdapterBase {
constructor(connection, dialect, config = {}) {
this.connection = connection;
this.dialect = dialect;
this.schemas = new Map();
this.tenantColumn = config.tenantColumn ?? 'tenant_id';
this.permissions = config.permissions;
}
registerSchema(schema) {
this.schemas.set(schema.name, schema);
}
registerSchemas(schemas) {
schemas.forEach((schema) => this.registerSchema(schema));
}
withContext(context) {
let actorValue;
if (context.actor) {
actorValue = context.actor;
}
else if (context.role) {
console.warn('[lsdb] UserContext.role is deprecated — use actor instead. ' +
'See: https://github.com/longcelot/sheet-db#actors-vs-application-roles');
actorValue = context.role;
}
else {
throw new Error('[lsdb] withContext() requires either actor or role in UserContext');
}
let targetActorValue;
if (context.targetActor) {
targetActorValue = context.targetActor;
}
else if (context.targetRole) {
console.warn('[lsdb] UserContext.targetRole is deprecated — use targetActor instead. ' +
'See: https://github.com/longcelot/sheet-db#actors-vs-application-roles');
targetActorValue = context.targetRole;
}
const normalised = {
userId: context.userId,
actor: actorValue,
role: actorValue,
actorSheetId: context.actorSheetId,
targetActor: targetActorValue,
targetSheetId: context.targetSheetId,
};
const newAdapter = Object.create(this);
newAdapter.context = normalised;
return newAdapter;
}
asActor(targetActor, targetSheetId) {
if (!this.context) {
throw new PermissionError_1.PermissionError('Context required before calling asActor()', undefined);
}
return this.withContext({
userId: this.context.userId,
actor: this.context.actor,
actorSheetId: this.context.actorSheetId,
targetActor,
targetSheetId,
});
}
table(tableName) {
const schema = this.schemas.get(tableName);
if (!schema) {
throw new SchemaError_1.SchemaError(`Table ${tableName} is not registered`, tableName);
}
if (!(0, accessControl_1.hasPermission)(schema, this.context, this.permissions)) {
throw new PermissionError_1.PermissionError(`User does not have permission to access ${tableName}`, this.context?.role);
}
const tenant = schema.actor === 'admin'
? undefined
: { column: this.tenantColumn, value: (0, accessControl_1.resolveNonAdminTenantKey)(schema, this.context) };
const fkResolver = (0, fkResolver_1.createSQLFKResolver)(this.connection, this.dialect, this.schemas, this.tenantColumn, this.context);
return new sqlTableOperations_1.SQLTableOperations(this.connection, this.dialect, schema, tenant, fkResolver);
}
}
exports.SQLAdapterBase = SQLAdapterBase;
//# sourceMappingURL=sqlAdapterBase.js.map