Skip to content

Commit

Permalink
clean build, not errors, all tests passes
Browse files Browse the repository at this point in the history
  • Loading branch information
FridayCandour committed Oct 7, 2024
1 parent 20499a4 commit 08a9785
Show file tree
Hide file tree
Showing 8 changed files with 83 additions and 147 deletions.
4 changes: 1 addition & 3 deletions bun.all_tests.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,8 @@ describe("queries", () => {
});
it("large delete", async () => {
const users = await db.query(JSON.stringify({ table: "USER", many: true }));
console.log(users.length);

for (let i = 0; i < users.length; i++) {
db.query(JSON.stringify({ table: "USER", delete: users[i]._id }));
await db.query(JSON.stringify({ table: "USER", delete: users[i]._id }));
}
const deletedUsersCount = await db.query(
JSON.stringify({ table: "USER", count: true })
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "exabase",
"version": "0.0.0-rc-28",
"version": "0.0.0-rc-29",
"description": "A scaling focused distributed nosql database with surprising performance and strong data consistency.",
"main": "dist/index.js",
"type": "module",
Expand Down
5 changes: 2 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export class Exabase {
private dbDir: string;
schemas: ExaSchema<{}>[] = [];
constructor(init: ExabaseOptions = {}) {
GLOBAL_OBJECT._db = this;
GLOBAL_OBJECT.db = this;
//? [1] directories
this.dbDir = (init.name || "DB").trim();
// ? setting up memory allocation for RCT enabled cache managers
Expand All @@ -24,7 +24,6 @@ export class Exabase {
}
console.log("Exabase: running!");
}

//? this is a function that creates/updates schemas also adjusting RCT memory
public async induce(schema: ExaSchema<any>) {
if (!(schema instanceof ExaSchema)) {
Expand All @@ -39,7 +38,7 @@ export class Exabase {
exabaseDirectory: this.dbDir,
schemas: this.schemas,
});
await GLOBAL_OBJECT.EXABASE_MANAGERS[schema?.table!]._synchronize();
await GLOBAL_OBJECT.EXABASE_MANAGERS[schema?.table!].synchronize();
//? update query makers and RCT level per manager
const rct_level = Math.round(150 / this.schemas.length);
GLOBAL_OBJECT.rct_level = rct_level > 5 ? rct_level : 5;
Expand Down
121 changes: 55 additions & 66 deletions src/primitives/classes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import {
bucketSort,
populateForeignKeys,
setPopulateOptions,
intersect,
getFileSize,
deepMerge,
ExaId,
Expand All @@ -42,7 +41,7 @@ export class GLOBAL_OBJECT {
static RCT: Record<string, Record<string, Msgs | undefined> | boolean> = {
none: false, //? none is default for use with identifiers that has no need to cache
};
static _db: any;
static db: any;
static rct_level: number;
}

Expand Down Expand Up @@ -114,10 +113,10 @@ export class ExaSchema<Model> {
} else {
throw new ExaError("No table name provided!");
}
if (!GLOBAL_OBJECT._db) {
if (!GLOBAL_OBJECT.db) {
throw new ExaError("database has not yet been created!");
}
GLOBAL_OBJECT._db.induce(this);
GLOBAL_OBJECT.db.induce(this);
}
}

Expand Down Expand Up @@ -158,7 +157,7 @@ export class Manager {
}
}
constructRelationships() {
const allSchemas: ExaSchema<{}>[] = GLOBAL_OBJECT._db.schemas;
const allSchemas: ExaSchema<{}>[] = GLOBAL_OBJECT.db.schemas;
if (this.schema.table) {
//? keep a easy track of relationships
if (this.schema.relationship) {
Expand Down Expand Up @@ -195,7 +194,7 @@ export class Manager {
}
this.isRelatedConstructed = true;
}
async _synchronize() {
async synchronize() {
try {
const dir = await opendir(this.tableDir!);
const logFiles: string[] = [];
Expand Down Expand Up @@ -229,8 +228,7 @@ export class Manager {
for (const filename in this.LogFiles) {
const logFile = this.LogFiles[filename];
//? size check is for inserts
// //? 3142656
if (logFile.size < 124 /*3mb*/) {
if (logFile.size < 3142656 /*3mb*/) {
return filename;
}
}
Expand Down Expand Up @@ -280,7 +278,7 @@ export class Manager {
} else {
// ? update search index
if (flag === "d") {
await this.xIndex.removeIndex(message, file);
await this.xIndex.removeIndex(message, file, true);
} else {
await this.xIndex.createIndex(message);
}
Expand Down Expand Up @@ -318,44 +316,33 @@ export class Manager {
}
return RCTied;
}
const file = this.xIndex.log_search(id as string) || "LOG-1";
const file = this.xIndex.log_search(id);
let RCTied = this.RCT[file];
if (!RCTied) {
RCTied = await loadLog(this.tableDir + file);
this.RCT[file] = RCTied;
}
return RCTied;
}
async _find(query: QueryType<Record<string, any>>) {
async find(query: QueryType<Record<string, any>>) {
let RCTied = await this.getLog(query.one);
if (query.many) {
// ? skip results
if (query.skip && query.skip < RCTied.length) {
RCTied = RCTied.slice(query.skip);
}
const skip = query.skip || 0;
const take = query.take || 1000;
if (RCTied.length > take) {
RCTied = RCTied.slice(0);
} else {
const logsCount = Object.keys(this.LogFiles).length;
let log = 2;
for (; RCTied.length < take; ) {
// ? break an endless loop.
if (log > logsCount) {
break;
}
const RCTied2 = await this.getLog(undefined, log);
Array.prototype.push.apply(RCTied, RCTied2);
if (query.skip && query.skip < RCTied.length) {
RCTied = RCTied.slice(query.skip);
let result: any[] = [];
for (let log = 1; log <= Object.keys(this.LogFiles).length; log++) {
const RCTied = await this.getLog(
log === 1 ? query.one : undefined,
log
);
for (let i = 0; i < RCTied.length && result.length < take; i++) {
if (i >= skip) {
result.push(RCTied[i]);
}
log += 1;
}
if (RCTied.length > take) {
RCTied = RCTied.slice(0);
}
if (result.length >= take) break;
}
// ? cutdown results
RCTied = result;
// ? sort results using bucketed merge.sort algorithm
if (query.sort) {
const key = Object.keys(query.sort)[0] as "_id";
Expand Down Expand Up @@ -388,14 +375,14 @@ export class Manager {
}
async runner(query: QueryType<Msg>): Promise<Msg | Msgs | number | void> {
if (query.many || query.one) {
return this._find(query);
return this.find(query);
}
if (query["search"]) {
const indexes = this.xIndex.search(query.search as Msg, query.take);
const searches = await Promise.all(
indexes.map(
(_id: string) =>
this._find({
this.find({
one: _id,
populate: query.populate,
sort: query.sort,
Expand Down Expand Up @@ -455,6 +442,12 @@ export class Manager {
const file = this.xIndex.log_search(message._id);
if (typeof file !== "string")
throw new ExaError("item to update not found");
const oldMessage = (await this.find({ one: query.update._id })) as Msg;
if (!oldMessage) {
throw new ExaError("item to update not found");
} else {
await this.xIndex.removeIndex(oldMessage, file, false);
}
// ? conserve foreign relationships
await conserveForeignKeys(message, this.schema.foreign_field);
return this.queue(file, message, "u");
Expand All @@ -473,8 +466,7 @@ export class Manager {
if (typeof file !== "string")
throw new ExaError("item to delete not found");

const message = (await this._find({ one: query.delete })) as Msg;

const message = (await this.find({ one: query.delete })) as Msg;
if (!message) {
throw new ExaError("item to delete not found");
}
Expand Down Expand Up @@ -516,30 +508,28 @@ export class XTree {
this.indexTable = init.indexTable;
}
search(search: Msg, take: number = Infinity) {
let idx: string[] = [];
const Indexes: number[][] = [];
// ? get the search keys
for (const key in search) {
if (!this.indexTable[key]) continue;
if (this.tree[key]) {
const index = this.tree[key].map[search[key as "_id"]];
if (!index || index?.length === 0) continue;
Indexes.push(index);
if (idx.length >= take) break;
}
const index = this.tree[key]?.map[search[key as "_id"]];
if (index?.length) Indexes.push(index);
}
// ? get return the keys if the length is 1
if (Indexes.length === 1) {
return Indexes[0].map((idx) => this.keys[idx]);
if (Indexes.length === 0) return [];
const result = new Set<number>();
const smallestIndex = Indexes.reduce((a, b) =>
a.length < b.length ? a : b
);
for (const id of smallestIndex) {
if (Indexes.every((index) => index.includes(id))) {
result.add(id);
if (result.size >= take) break;
}
}
// ? get return the keys if the length is more than one
return intersect(Indexes).map((idx) => this.keys[idx]);
return Array.from(result).map((idx) => this.keys[idx]);
}
// ? for keep _id indexes and possibly unique indexes on the XTree algorithm
log_search(id: string) {
// ? remove log tree index
log_search(id: string = "") {
const logKey = this.tree["_exa_log_index"].map?.[id];
if (logKey) return this.logKeys[logKey[0]];
return " LOG-1";
}
count(search: Msg) {
let resultsCount: number = 0;
Expand All @@ -557,15 +547,10 @@ export class XTree {
let logKey = this.logKeys.indexOf(logFile);
if (logKey === -1) {
logKey = this.logKeys.push(logFile) - 1;
if (!this.tree["_exa_log_index"]) {
this.tree["_exa_log_index"] = new XNode();
}
}
// ? index it log file
this.tree["_exa_log_index"].create(data._id, logKey);
}
//
//
// ? retrieve msg key index
let idk = this.keys.indexOf(data._id);
if (idk === -1) {
Expand All @@ -581,19 +566,20 @@ export class XTree {
}
return this.persist();
}
removeIndex(data: Msg, logFile: string) {
removeIndex(data: Msg, logFile: string, drop: boolean) {
// ? remove other attributes indexes
let idk = this.keys.indexOf(data._id);
if (idk === -1) return;
for (const key in data) {
if (!this.tree[key]) continue;
this.tree[key].drop(data[key as "_id"], idk);
}

this.keys.splice(idk, 1);
// ? remove log tree index
const logKey = this.logKeys.indexOf(logFile);
this.tree["_exa_log_index"].drop(data._id, logKey);
if (drop) {
this.keys.splice(idk, 1);
// ? remove log tree index
const logKey = this.logKeys.indexOf(logFile);
this.tree["_exa_log_index"].drop(data._id, logKey);
}

return this.persist();
}
Expand Down Expand Up @@ -631,5 +617,8 @@ export class XTree {
this.tree[key] = new XNode(tree[key]);
}
}
if (!this.tree["_exa_log_index"]) {
this.tree["_exa_log_index"] = new XNode();
}
}
}
Loading

0 comments on commit 08a9785

Please sign in to comment.