Skip to content

Commit 08a9785

Browse files
committed
clean build, not errors, all tests passes
1 parent 20499a4 commit 08a9785

File tree

8 files changed

+83
-147
lines changed

8 files changed

+83
-147
lines changed

bun.all_tests.test.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,10 +130,8 @@ describe("queries", () => {
130130
});
131131
it("large delete", async () => {
132132
const users = await db.query(JSON.stringify({ table: "USER", many: true }));
133-
console.log(users.length);
134-
135133
for (let i = 0; i < users.length; i++) {
136-
db.query(JSON.stringify({ table: "USER", delete: users[i]._id }));
134+
await db.query(JSON.stringify({ table: "USER", delete: users[i]._id }));
137135
}
138136
const deletedUsersCount = await db.query(
139137
JSON.stringify({ table: "USER", count: true })

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "exabase",
3-
"version": "0.0.0-rc-28",
3+
"version": "0.0.0-rc-29",
44
"description": "A scaling focused distributed nosql database with surprising performance and strong data consistency.",
55
"main": "dist/index.js",
66
"type": "module",

src/index.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export class Exabase {
1111
private dbDir: string;
1212
schemas: ExaSchema<{}>[] = [];
1313
constructor(init: ExabaseOptions = {}) {
14-
GLOBAL_OBJECT._db = this;
14+
GLOBAL_OBJECT.db = this;
1515
//? [1] directories
1616
this.dbDir = (init.name || "DB").trim();
1717
// ? setting up memory allocation for RCT enabled cache managers
@@ -24,7 +24,6 @@ export class Exabase {
2424
}
2525
console.log("Exabase: running!");
2626
}
27-
2827
//? this is a function that creates/updates schemas also adjusting RCT memory
2928
public async induce(schema: ExaSchema<any>) {
3029
if (!(schema instanceof ExaSchema)) {
@@ -39,7 +38,7 @@ export class Exabase {
3938
exabaseDirectory: this.dbDir,
4039
schemas: this.schemas,
4140
});
42-
await GLOBAL_OBJECT.EXABASE_MANAGERS[schema?.table!]._synchronize();
41+
await GLOBAL_OBJECT.EXABASE_MANAGERS[schema?.table!].synchronize();
4342
//? update query makers and RCT level per manager
4443
const rct_level = Math.round(150 / this.schemas.length);
4544
GLOBAL_OBJECT.rct_level = rct_level > 5 ? rct_level : 5;

src/primitives/classes.ts

Lines changed: 55 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import {
2727
bucketSort,
2828
populateForeignKeys,
2929
setPopulateOptions,
30-
intersect,
3130
getFileSize,
3231
deepMerge,
3332
ExaId,
@@ -42,7 +41,7 @@ export class GLOBAL_OBJECT {
4241
static RCT: Record<string, Record<string, Msgs | undefined> | boolean> = {
4342
none: false, //? none is default for use with identifiers that has no need to cache
4443
};
45-
static _db: any;
44+
static db: any;
4645
static rct_level: number;
4746
}
4847

@@ -114,10 +113,10 @@ export class ExaSchema<Model> {
114113
} else {
115114
throw new ExaError("No table name provided!");
116115
}
117-
if (!GLOBAL_OBJECT._db) {
116+
if (!GLOBAL_OBJECT.db) {
118117
throw new ExaError("database has not yet been created!");
119118
}
120-
GLOBAL_OBJECT._db.induce(this);
119+
GLOBAL_OBJECT.db.induce(this);
121120
}
122121
}
123122

@@ -158,7 +157,7 @@ export class Manager {
158157
}
159158
}
160159
constructRelationships() {
161-
const allSchemas: ExaSchema<{}>[] = GLOBAL_OBJECT._db.schemas;
160+
const allSchemas: ExaSchema<{}>[] = GLOBAL_OBJECT.db.schemas;
162161
if (this.schema.table) {
163162
//? keep a easy track of relationships
164163
if (this.schema.relationship) {
@@ -195,7 +194,7 @@ export class Manager {
195194
}
196195
this.isRelatedConstructed = true;
197196
}
198-
async _synchronize() {
197+
async synchronize() {
199198
try {
200199
const dir = await opendir(this.tableDir!);
201200
const logFiles: string[] = [];
@@ -229,8 +228,7 @@ export class Manager {
229228
for (const filename in this.LogFiles) {
230229
const logFile = this.LogFiles[filename];
231230
//? size check is for inserts
232-
// //? 3142656
233-
if (logFile.size < 124 /*3mb*/) {
231+
if (logFile.size < 3142656 /*3mb*/) {
234232
return filename;
235233
}
236234
}
@@ -280,7 +278,7 @@ export class Manager {
280278
} else {
281279
// ? update search index
282280
if (flag === "d") {
283-
await this.xIndex.removeIndex(message, file);
281+
await this.xIndex.removeIndex(message, file, true);
284282
} else {
285283
await this.xIndex.createIndex(message);
286284
}
@@ -318,44 +316,33 @@ export class Manager {
318316
}
319317
return RCTied;
320318
}
321-
const file = this.xIndex.log_search(id as string) || "LOG-1";
319+
const file = this.xIndex.log_search(id);
322320
let RCTied = this.RCT[file];
323321
if (!RCTied) {
324322
RCTied = await loadLog(this.tableDir + file);
325323
this.RCT[file] = RCTied;
326324
}
327325
return RCTied;
328326
}
329-
async _find(query: QueryType<Record<string, any>>) {
327+
async find(query: QueryType<Record<string, any>>) {
330328
let RCTied = await this.getLog(query.one);
331329
if (query.many) {
332-
// ? skip results
333-
if (query.skip && query.skip < RCTied.length) {
334-
RCTied = RCTied.slice(query.skip);
335-
}
330+
const skip = query.skip || 0;
336331
const take = query.take || 1000;
337-
if (RCTied.length > take) {
338-
RCTied = RCTied.slice(0);
339-
} else {
340-
const logsCount = Object.keys(this.LogFiles).length;
341-
let log = 2;
342-
for (; RCTied.length < take; ) {
343-
// ? break an endless loop.
344-
if (log > logsCount) {
345-
break;
346-
}
347-
const RCTied2 = await this.getLog(undefined, log);
348-
Array.prototype.push.apply(RCTied, RCTied2);
349-
if (query.skip && query.skip < RCTied.length) {
350-
RCTied = RCTied.slice(query.skip);
332+
let result: any[] = [];
333+
for (let log = 1; log <= Object.keys(this.LogFiles).length; log++) {
334+
const RCTied = await this.getLog(
335+
log === 1 ? query.one : undefined,
336+
log
337+
);
338+
for (let i = 0; i < RCTied.length && result.length < take; i++) {
339+
if (i >= skip) {
340+
result.push(RCTied[i]);
351341
}
352-
log += 1;
353-
}
354-
if (RCTied.length > take) {
355-
RCTied = RCTied.slice(0);
356342
}
343+
if (result.length >= take) break;
357344
}
358-
// ? cutdown results
345+
RCTied = result;
359346
// ? sort results using bucketed merge.sort algorithm
360347
if (query.sort) {
361348
const key = Object.keys(query.sort)[0] as "_id";
@@ -388,14 +375,14 @@ export class Manager {
388375
}
389376
async runner(query: QueryType<Msg>): Promise<Msg | Msgs | number | void> {
390377
if (query.many || query.one) {
391-
return this._find(query);
378+
return this.find(query);
392379
}
393380
if (query["search"]) {
394381
const indexes = this.xIndex.search(query.search as Msg, query.take);
395382
const searches = await Promise.all(
396383
indexes.map(
397384
(_id: string) =>
398-
this._find({
385+
this.find({
399386
one: _id,
400387
populate: query.populate,
401388
sort: query.sort,
@@ -455,6 +442,12 @@ export class Manager {
455442
const file = this.xIndex.log_search(message._id);
456443
if (typeof file !== "string")
457444
throw new ExaError("item to update not found");
445+
const oldMessage = (await this.find({ one: query.update._id })) as Msg;
446+
if (!oldMessage) {
447+
throw new ExaError("item to update not found");
448+
} else {
449+
await this.xIndex.removeIndex(oldMessage, file, false);
450+
}
458451
// ? conserve foreign relationships
459452
await conserveForeignKeys(message, this.schema.foreign_field);
460453
return this.queue(file, message, "u");
@@ -473,8 +466,7 @@ export class Manager {
473466
if (typeof file !== "string")
474467
throw new ExaError("item to delete not found");
475468

476-
const message = (await this._find({ one: query.delete })) as Msg;
477-
469+
const message = (await this.find({ one: query.delete })) as Msg;
478470
if (!message) {
479471
throw new ExaError("item to delete not found");
480472
}
@@ -516,30 +508,28 @@ export class XTree {
516508
this.indexTable = init.indexTable;
517509
}
518510
search(search: Msg, take: number = Infinity) {
519-
let idx: string[] = [];
520511
const Indexes: number[][] = [];
521-
// ? get the search keys
522512
for (const key in search) {
523-
if (!this.indexTable[key]) continue;
524-
if (this.tree[key]) {
525-
const index = this.tree[key].map[search[key as "_id"]];
526-
if (!index || index?.length === 0) continue;
527-
Indexes.push(index);
528-
if (idx.length >= take) break;
529-
}
513+
const index = this.tree[key]?.map[search[key as "_id"]];
514+
if (index?.length) Indexes.push(index);
530515
}
531-
// ? get return the keys if the length is 1
532-
if (Indexes.length === 1) {
533-
return Indexes[0].map((idx) => this.keys[idx]);
516+
if (Indexes.length === 0) return [];
517+
const result = new Set<number>();
518+
const smallestIndex = Indexes.reduce((a, b) =>
519+
a.length < b.length ? a : b
520+
);
521+
for (const id of smallestIndex) {
522+
if (Indexes.every((index) => index.includes(id))) {
523+
result.add(id);
524+
if (result.size >= take) break;
525+
}
534526
}
535-
// ? get return the keys if the length is more than one
536-
return intersect(Indexes).map((idx) => this.keys[idx]);
527+
return Array.from(result).map((idx) => this.keys[idx]);
537528
}
538-
// ? for keep _id indexes and possibly unique indexes on the XTree algorithm
539-
log_search(id: string) {
540-
// ? remove log tree index
529+
log_search(id: string = "") {
541530
const logKey = this.tree["_exa_log_index"].map?.[id];
542531
if (logKey) return this.logKeys[logKey[0]];
532+
return " LOG-1";
543533
}
544534
count(search: Msg) {
545535
let resultsCount: number = 0;
@@ -557,15 +547,10 @@ export class XTree {
557547
let logKey = this.logKeys.indexOf(logFile);
558548
if (logKey === -1) {
559549
logKey = this.logKeys.push(logFile) - 1;
560-
if (!this.tree["_exa_log_index"]) {
561-
this.tree["_exa_log_index"] = new XNode();
562-
}
563550
}
564551
// ? index it log file
565552
this.tree["_exa_log_index"].create(data._id, logKey);
566553
}
567-
//
568-
//
569554
// ? retrieve msg key index
570555
let idk = this.keys.indexOf(data._id);
571556
if (idk === -1) {
@@ -581,19 +566,20 @@ export class XTree {
581566
}
582567
return this.persist();
583568
}
584-
removeIndex(data: Msg, logFile: string) {
569+
removeIndex(data: Msg, logFile: string, drop: boolean) {
585570
// ? remove other attributes indexes
586571
let idk = this.keys.indexOf(data._id);
587572
if (idk === -1) return;
588573
for (const key in data) {
589574
if (!this.tree[key]) continue;
590575
this.tree[key].drop(data[key as "_id"], idk);
591576
}
592-
593-
this.keys.splice(idk, 1);
594-
// ? remove log tree index
595-
const logKey = this.logKeys.indexOf(logFile);
596-
this.tree["_exa_log_index"].drop(data._id, logKey);
577+
if (drop) {
578+
this.keys.splice(idk, 1);
579+
// ? remove log tree index
580+
const logKey = this.logKeys.indexOf(logFile);
581+
this.tree["_exa_log_index"].drop(data._id, logKey);
582+
}
597583

598584
return this.persist();
599585
}
@@ -631,5 +617,8 @@ export class XTree {
631617
this.tree[key] = new XNode(tree[key]);
632618
}
633619
}
620+
if (!this.tree["_exa_log_index"]) {
621+
this.tree["_exa_log_index"] = new XNode();
622+
}
634623
}
635624
}

0 commit comments

Comments
 (0)