axiodb
Version:
The Pure JavaScript Alternative to SQLite. Embedded NoSQL database for Node.js with MongoDB-style queries, zero native dependencies, built-in InMemoryCache, and web GUI. Perfect for desktop apps, CLI tools, and embedded systems. No compilation, no platfor
231 lines • 12.8 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.IndexManager = void 0;
const Keys_1 = require("../../config/Keys/Keys");
const FileManager_1 = __importDefault(require("../../engine/Filesystem/FileManager"));
const FolderManager_1 = __importDefault(require("../../engine/Filesystem/FolderManager"));
const Converter_helper_1 = __importDefault(require("../../Helper/Converter.helper"));
const response_helper_1 = __importDefault(require("../../Helper/response.helper"));
class IndexManager {
constructor(path) {
this.path = path;
this.indexFolderPath = `${this.path}/indexes`;
this.indexMetaPath = `${this.indexFolderPath}/index.meta.json`;
this.fileManager = new FileManager_1.default();
this.folderManager = new FolderManager_1.default();
this.converter = new Converter_helper_1.default();
this.ResponseHelper = new response_helper_1.default();
}
/**
* Create one or more index files and register them in the index metadata.
*
* For each supplied field name this method:
* 1. Determines the index file path as `${indexName}.axiodb` inside the configured index folder.
* 2. Checks whether the index file already exists. If it does not, creates the file with an empty
* index structure ({ fieldName, indexEntries: [] }).
* 3. Reads the index metadata file (index.meta.json), parses it, and if an entry for the index
* field does not already exist, appends a metadata record `{ indexFieldName, fileName, path }`
* and writes the metadata file back.
*
* Side effects:
* - Writes new index files to disk via `fileManager.WriteFile`.
* - Reads and updates the index metadata file via `fileManager.ReadFile` / `WriteFile`.
* - Uses the configured `converter` to serialize/deserialize index and metadata content.
*
* Notes:
* - The operation is not atomic: some indexes may be created while others fail. The method will
* collect created and failed index names and include them in the returned response.
* - A failure is recorded for a field when the index file already exists, when the index already
* exists in the metadata, or when reading/writing the metadata file fails.
* - The method relies on `indexFolderPath`, `indexMetaPath`, `fileManager`, and `converter`
* being correctly configured and available on the instance.
*
* @param fieldNames - One or more field names for which to create indexes.
* @returns A promise that resolves to either:
* - SuccessInterface: indicates which indexes were created and which already existed / failed,
* typically containing a human-readable message listing affected and existing indexes.
* - ErrorInterface: returned when underlying file/IO operations fail in a way that prevents
* producing the expected success response.
*
* @example
* // Create a single index
* await service.createIndex('email');
*
* @example
* // Create multiple indexes
* await service.createIndex('email', 'username', 'createdAt');
*/
createIndex(...fieldNames) {
return __awaiter(this, void 0, void 0, function* () {
const EffectedIndexes = [];
const FailedIndexes = [];
for (const fieldName of fieldNames) {
const indexName = fieldName;
const indexFilePath = `${this.indexFolderPath}/${indexName}${Keys_1.General.DBMS_File_EXT}`;
const DemoIndexHash = {
fieldName: indexName,
indexEntries: {},
};
const exists = yield this.fileManager.FileExists(indexFilePath);
if (!exists.status) {
// create empty index file
yield this.fileManager.WriteFile(indexFilePath, this.converter.ToString(DemoIndexHash));
// Update index.meta.json
const indexMetaContent = yield this.fileManager.ReadFile(this.indexMetaPath);
if (indexMetaContent.status) {
const indexMeta = this.converter.ToObject(indexMetaContent.data);
// check if index already exists in meta
const indexExists = indexMeta.find((index) => index.indexFieldName === indexName);
if (!indexExists) {
indexMeta.push({
indexFieldName: indexName,
fileName: `${indexName}${Keys_1.General.DBMS_File_EXT}`,
path: indexFilePath,
});
yield this.fileManager.WriteFile(this.indexMetaPath, this.converter.ToString(indexMeta));
EffectedIndexes.push(indexName);
return this.ResponseHelper.Success(`Indexes: ${EffectedIndexes.join(", ")} created Indexes: ${FailedIndexes.join(", ")}`);
}
else {
FailedIndexes.push(indexName);
}
}
}
}
});
}
/**
* Deletes an index file and removes its entry from the index metadata.
*
* This asynchronous method attempts to delete the index file located at
* `${this.indexFolderPath}/${indexName}.axiodb`. If the file exists it is removed,
* and the index metadata file at `this.indexMetaPath` is read and updated by
* filtering out the metadata entry whose `indexFieldName` matches `indexName`.
* The metadata update is performed only if the metadata file can be read successfully.
*
* @param indexName - The name of the index to delete (without extension).
* @returns A Promise that resolves to a SuccessInterface when the index was deleted
* (and metadata updated when possible), or an ErrorInterface when the
* specified index does not exist.
*
* @async
* @remarks
* - Side effects: removes a file from the file system and may modify the index metadata file.
* - Uses injected helpers: `fileManager` for filesystem operations, `converter` for
* (de)serialization of metadata, and `ResponseHelper` to construct the returned result.
* - If the metadata file cannot be read, the method still succeeds after deleting the index file.
*
* @throws {Error} May propagate errors from underlying file operations if those utilities throw.
*/
dropIndex(indexName) {
return __awaiter(this, void 0, void 0, function* () {
const indexFilePath = `${this.indexFolderPath}/${indexName}${Keys_1.General.DBMS_File_EXT}`;
// check if index file exists
const exists = yield this.fileManager.FileExists(indexFilePath);
if (exists.status === true) {
// delete index file
yield this.fileManager.DeleteFile(indexFilePath);
// update index.meta.json
const indexMetaContent = yield this.fileManager.ReadFile(this.indexMetaPath);
if (indexMetaContent.status) {
let indexMeta = this.converter.ToObject(indexMetaContent.data);
indexMeta = indexMeta.filter((index) => index.indexFieldName !== indexName);
yield this.fileManager.WriteFile(this.indexMetaPath, this.converter.ToString(indexMeta));
}
return this.ResponseHelper.Success(`Index: ${indexName} deleted successfully`);
}
else {
return this.ResponseHelper.Error(`Index: ${indexName} does not exist`);
}
});
}
/**
* Ensures the index folder and the index metadata file exist, creating them if necessary.
*
* This asynchronous method performs the following steps:
* 1. Checks whether the index folder at `this.indexFolderPath` exists; if not, creates it.
* 2. Checks whether the index metadata file at `this.indexMetaPath` exists; if not:
* a. Constructs a default index metadata entry for a unique "documentId" index:
* - indexFieldName: "documentId"
* - fileName: "documentId.axiodb"
* - path: `${this.indexFolderPath}/documentId.axiodb`
* - unique: true
* b. Calls `this.createIndex("documentId")` to create the underlying index file/structure.
* c. Writes the metadata array to `this.indexMetaPath` using `this.converter.ToString(...)`.
*
* The operation is idempotent: if the folder or metadata file already exist, no changes are made.
*
* @remarks
* - This method performs filesystem modifications via `folderManager` and `fileManager`.
* - Any errors thrown by `folderManager`, `fileManager`, `converter`, or `createIndex` will propagate to the caller.
* - Callers should `await` this method to ensure the initialization is complete before proceeding.
*
* @returns A Promise that resolves when initialization is complete.
*
* @throws Will reject if directory creation, file checks/writes, conversion, or index creation fails.
*
* @example
* // Ensure index folder and metadata exist before using the index service
* await indexService.generateIndexMeta();
*/
generateIndexMeta() {
return __awaiter(this, void 0, void 0, function* () {
// check is index.meta.json exists or not
const folderExists = yield this.folderManager.DirectoryExists(this.indexFolderPath);
if (!folderExists.status) {
yield this.folderManager.CreateDirectory(this.indexFolderPath);
}
const exists = yield this.fileManager.FileExists(this.indexMetaPath);
if (!exists.status) {
// create index.meta.json
const indexMeta = [
{
indexFieldName: "documentId",
path: `${this.indexFolderPath}/documentId${Keys_1.General.DBMS_File_EXT}`,
fileName: `documentId${Keys_1.General.DBMS_File_EXT}`
}
];
yield this.createIndex("documentId");
yield this.fileManager.WriteFile(this.indexMetaPath, this.converter.ToString(indexMeta));
}
});
}
/**
* Finds index metadata entries that correspond to properties present on the provided document.
*
* Reads the index metadata file at `this.indexMetaPath`, converts its content into an object,
* and returns the subset of metadata entries whose `indexFieldName` is an own property of `doc`.
*
* @param doc - The document to check for matching index fields. The function tests own properties
* (via `Object.prototype.hasOwnProperty.call`) rather than inherited properties.
* @returns A Promise that resolves to an array of matching index metadata entries, or `undefined`
* if the index metadata file could not be successfully read. The array may be empty if
* no metadata entries match.
*
* @throws May propagate errors from `fileManager.ReadFile` or `converter.ToObject` if those
* operations throw or reject.
*/
findMatchingIndexMeta(doc) {
return __awaiter(this, void 0, void 0, function* () {
const indexMetaContent = yield this.fileManager.ReadFile(this.indexMetaPath);
if (indexMetaContent.status) {
const indexMeta = this.converter.ToObject(indexMetaContent.data);
return indexMeta.filter((meta) => Object.prototype.hasOwnProperty.call(doc, meta.indexFieldName));
}
});
}
}
exports.IndexManager = IndexManager;
//# sourceMappingURL=Index.service.js.map