diff --git a/examples/client/index.html b/examples/client/index.html
index caedefd2..23fb0859 100644
--- a/examples/client/index.html
+++ b/examples/client/index.html
@@ -19,7 +19,7 @@
db.fields().then((fields) => {
fields.map((field) => {
dbFields.add(field.fieldName);
- fieldTypes[field.fieldName] = field.fieldType;
+ fieldTypes[field.fieldName] = db.decodeType(field.fieldType);
});
document.getElementById("fields").innerHTML = JSON.stringify(
@@ -88,8 +88,34 @@
return "Error: 'value' in 'where' clause is missing.";
}
- // todo: find out how to decode bigint field types. i.e. what is a 34n?
- // assert `where` type
+ const allowedRanks = fieldTypes[whereNode.key];
+
+ let valueRank;
+ let valueType;
+
+ if (whereNode.value === null) {
+ valueRank = 1;
+ valueType = "null";
+ }
+ if (typeof whereNode.value === "boolean") {
+ valueRank = 2;
+ valueType = "boolean";
+ }
+ if (
+ typeof whereNode.value === "number" ||
+ typeof whereNode.value === "bigint"
+ ) {
+ valueRank = 3;
+ valueType = "number or bigint";
+ }
+ if (typeof whereNode.value === "string") {
+ valueRank = 4;
+ valueType = "string";
+ }
+
+ if (!allowedRanks.has(valueRank)) {
+ return `Error: 'key: ${whereNode.key} does not have type: ${valueType}.`;
+ }
}
if (query.orderBy) {
diff --git a/src/database.ts b/src/database.ts
index eeefe6ed..2f7af0ab 100644
--- a/src/database.ts
+++ b/src/database.ts
@@ -21,6 +21,16 @@ export type Query = {
orderBy?: OrderBy[];
};
+// This record maps from fieldRank -> Bitmask
+export const typeRankToBits: Record = {
+ 4: BigInt(1), // FieldTypeString = 1 << 0
+ 3: BigInt(2), // FieldTypeNumber = 1 << 1
+ //'Object': BigInt(4), // FieldTypeObject = 1 << 2
+ //'Array': BigInt(8), // FieldTypeArray = 1 << 3
+ 2: BigInt(16), // FieldTypeBoolean = 1 << 4
+ 1: BigInt(32), // FieldTypeNull = 1 << 5
+};
+
function parseIgnoringSuffix(x: string) {
// TODO: implement a proper parser.
try {
@@ -203,4 +213,17 @@ export class Database {
}
}
}
+
+ // given a bitmask, we decode and return the types
+ decodeType(bitmask: bigint): Set {
+ let decodedRanks = new Set();
+
+ for (const [fieldRank, bitValue] of Object.entries(typeRankToBits)) {
+ if ((bitmask & bitValue) !== BigInt(0)) {
+ decodedRanks.add(Number(fieldRank));
+ }
+ }
+
+ return decodedRanks;
+ }
}
diff --git a/src/tests/database.test.ts b/src/tests/database.test.ts
index e6a787e0..266d0815 100644
--- a/src/tests/database.test.ts
+++ b/src/tests/database.test.ts
@@ -94,3 +94,43 @@ describe("test query relation", () => {
expect(results).toEqual([25]);
});
});
+
+describe("test type bitmask decoding", () => {
+ let mockDataFile: jest.Mocked;
+ let mockIndexFile: jest.Mocked>;
+ let database: Database;
+ beforeEach(() => {
+ (DataFile.forUrl as jest.Mock).mockReturnValue({
+ get: jest.fn().mockResolvedValue("mocked response"),
+ });
+ mockDataFile = DataFile.forUrl(
+ "http://example.com/data"
+ ) as jest.Mocked;
+
+ mockIndexFile = {
+ indexFileHeader: jest.fn(),
+ indexHeaders: jest.fn(),
+ indexRecord: jest.fn(),
+ dataRecord: jest.fn(),
+ } as jest.Mocked>;
+
+ // instantiate a Database object with given mocked data file and index file
+ database = Database.forDataFileAndIndexFile(mockDataFile, mockIndexFile);
+ });
+
+ it("it should return the correct field rank from fieldtype", async () => {
+ const testCases = [
+ { fieldType: BigInt(34), expected: new Set([1, 3]) },
+ { fieldType: BigInt(1), expected: new Set([4]) },
+ { fieldType: BigInt(2), expected: new Set([3]) },
+ { fieldType: BigInt(16), expected: new Set([2]) },
+ { fieldType: BigInt(32), expected: new Set([1]) },
+ { fieldType: BigInt(33), expected: new Set([1, 4]) },
+ ];
+
+ testCases.forEach(({ fieldType, expected }) => {
+ const result = database.decodeType(fieldType);
+ expect(result).toEqual(expected);
+ });
+ });
+});