diff --git a/src/services/processors/commands/DatabaseCommand.ts b/src/services/processors/commands/DatabaseCommand.ts index 8fe089d..8c6916a 100644 --- a/src/services/processors/commands/DatabaseCommand.ts +++ b/src/services/processors/commands/DatabaseCommand.ts @@ -45,7 +45,7 @@ export abstract class BaseDatabaseCommand implements DatabaseCommand { abstract getDescription(): string; validate(): boolean { - return this.config && typeof this.config === "object"; + return this.config != null && typeof this.config === "object"; } /** @@ -64,6 +64,38 @@ export abstract class BaseDatabaseCommand implements DatabaseCommand { } } + /** + * Runtime type guard utilities to enforce stronger config structures. + * These do not replace compile-time types but provide robust validation + * at runtime to prevent misconfiguration from propagating. + */ + protected hasString(config: any, key: string): config is Record { + return ( + config && typeof config[key] === "string" && config[key].trim() !== "" + ); + } + + protected hasObject(config: any, key: string): boolean { + return ( + config && + typeof config[key] === "object" && + config[key] !== null && + !Array.isArray(config[key]) + ); + } + + protected ensureKeys( + config: any, + keys: Array<{ key: string; type: "string" | "object" }> + ): { ok: boolean; missing: string[] } { + const missing: string[] = []; + for (const { key, type } of keys) { + if (type === "string" && !this.hasString(config, key)) missing.push(key); + if (type === "object" && !this.hasObject(config, key)) missing.push(key); + } + return { ok: missing.length === 0, missing }; + } + /** * Helper method to create a standardized result */ diff --git a/src/services/processors/commands/DeleteCommand.ts b/src/services/processors/commands/DeleteCommand.ts index 4dc5c63..dc8d30e 100644 --- a/src/services/processors/commands/DeleteCommand.ts +++ b/src/services/processors/commands/DeleteCommand.ts @@ -69,6 +69,16 @@ export class DeleteCommand } validate(): boolean { - return super.validate() && (!!this.config.filter || !!this.config.where); + if (!super.validate()) return false; + const hasFilter = + this.hasObject(this.config, "filter") || + this.hasObject(this.config, "where"); + if (!hasFilter) { + console.warn( + "DeleteCommand validation failed. 'filter' or 'where' object is required." + ); + return false; + } + return true; } } diff --git a/src/services/processors/commands/InsertCommand.ts b/src/services/processors/commands/InsertCommand.ts index 9929124..7ee4e4c 100644 --- a/src/services/processors/commands/InsertCommand.ts +++ b/src/services/processors/commands/InsertCommand.ts @@ -66,6 +66,25 @@ export class InsertCommand } validate(): boolean { - return super.validate() && (!!this.config.document || !!this.config.record); + if (!super.validate()) return false; + // Accept either 'document' (object/JSON) or 'record' + const hasDoc = this.hasObject(this.config, "document"); + const hasRecord = this.hasObject(this.config, "record"); + if (!hasDoc && !hasRecord) { + console.warn( + "InsertCommand validation failed. Expected 'document' or 'record' object." + ); + return false; + } + // If SQL-like, ensure table/collection name is present + const requiresTable = !!( + (this.config as any).table || (this.config as any).collection + ); + if (!requiresTable) { + console.warn( + "InsertCommand validation warning: missing 'table' or 'collection'. Some connectors require it." + ); + } + return true; } } diff --git a/src/services/processors/commands/QueryCommand.ts b/src/services/processors/commands/QueryCommand.ts index c2ebaf6..6cfbfb8 100644 --- a/src/services/processors/commands/QueryCommand.ts +++ b/src/services/processors/commands/QueryCommand.ts @@ -30,6 +30,15 @@ export class QueryCommand } validate(): boolean { - return super.validate() && !!this.config.query; + if (!super.validate()) return false; + const { ok, missing } = this.ensureKeys(this.config, [ + { key: "query", type: "string" }, + ]); + if (!ok) { + console.warn( + `QueryCommand validation failed. Missing fields: ${missing.join(", ")}` + ); + } + return ok; } } diff --git a/src/services/processors/commands/UpdateCommand.ts b/src/services/processors/commands/UpdateCommand.ts index d817ee7..43eede5 100644 --- a/src/services/processors/commands/UpdateCommand.ts +++ b/src/services/processors/commands/UpdateCommand.ts @@ -84,10 +84,19 @@ export class UpdateCommand } validate(): boolean { - return ( - super.validate() && - (!!this.config.filter || !!this.config.where) && - (!!this.config.update || !!this.config.set) - ); + if (!super.validate()) return false; + const hasFilter = + this.hasObject(this.config, "filter") || + this.hasObject(this.config, "where"); + const hasUpdate = + this.hasObject(this.config, "update") || + this.hasObject(this.config, "set"); + if (!hasFilter || !hasUpdate) { + console.warn( + "UpdateCommand validation failed. 'filter/where' and 'update/set' objects are required." + ); + return false; + } + return true; } }