UNPKG

@fizzyflow/suisql

Version:

SuiSQL is a library and set of tools for working with decentralized SQL databases on the Sui blockchain and Walrus protocol.

178 lines (177 loc) 6.93 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); var SuiSqliteBinaryView_exports = {}; __export(SuiSqliteBinaryView_exports, { default: () => SuiSqliteBinaryView }); module.exports = __toCommonJS(SuiSqliteBinaryView_exports); var import_SuiSqlUtils = require("./SuiSqlUtils.js"); var import_SuiSqlBinaryPatch = __toESM(require("./SuiSqlBinaryPatch.js")); class SuiSqliteBinaryView { constructor(params) { __publicField(this, "binary"); // private walrusClient?: WalrusClient; __publicField(this, "createdAt"); this.binary = Uint8Array.from(params.binary); this.createdAt = Date.now(); } async getPatched(binaryPatch) { const decompressed = await (0, import_SuiSqlUtils.decompress)(binaryPatch); const pageSize = this.getPageSize(); let maxPageNumber = this.getPagesCount() - 1; const pages = {}; let pos = 0; while (pos < decompressed.length) { const command = decompressed[pos]; if (command == 0) { pos++; const pageNumber = new DataView(decompressed.buffer, pos).getUint32(0, false); pos = pos + 4; const page = decompressed.slice(pos, pos + pageSize); pos = pos + pageSize; if (pageNumber > maxPageNumber) { maxPageNumber = pageNumber; } pages[pageNumber] = page; } else if (command == 1) { pos++; const pageNumber = new DataView(decompressed.buffer, pos).getUint32(0, false); pos = pos + 4; const patchSize = new DataView(decompressed.buffer, pos).getUint32(0, false); pos = pos + 4; const patch = decompressed.slice(pos, pos + patchSize); console.log(patch); const current = this.getPage(pageNumber); const patched = import_SuiSqlBinaryPatch.default.applyPatch(current, patch); pos = pos + patchSize; if (pageNumber > maxPageNumber) { maxPageNumber = pageNumber; } pages[pageNumber] = patched; } } const ret = []; for (let i = 0; i <= maxPageNumber; i++) { if (pages[i]) { ret.push(pages[i]); } else { ret.push(this.getPage(i)); } } return (0, import_SuiSqlUtils.concatUint8Arrays)(ret); } async getBinaryPatch(comparedTo) { const pageSize1 = comparedTo.getPageSize(); const pageSize2 = this.getPageSize(); if (pageSize1 != pageSize2) { return null; } const pageCount1 = comparedTo.getPagesCount(); const pageCount2 = this.getPagesCount(); const patchParts = []; for (let i = 0; i < pageCount2; i++) { if (pageCount1 <= i) { const page2 = this.getPage(i); patchParts.push(new Uint8Array([0])); patchParts.push((0, import_SuiSqlUtils.int32ToUint8ArrayBE)(i)); patchParts.push(page2); } else { const sha256_2 = await this.getPageSha256(i); const sha256_1 = await comparedTo.getPageSha256(i); if (sha256_1 != sha256_2) { const page1 = comparedTo.getPage(i); const page2 = this.getPage(i); const diff = import_SuiSqlBinaryPatch.default.binaryDiff(page1, page2); console.log("patch", diff); patchParts.push(new Uint8Array([1])); patchParts.push((0, import_SuiSqlUtils.int32ToUint8ArrayBE)(i)); patchParts.push((0, import_SuiSqlUtils.int32ToUint8ArrayBE)(diff.length)); patchParts.push(diff); } } } return await (0, import_SuiSqlUtils.compress)((0, import_SuiSqlUtils.concatUint8Arrays)(patchParts)); } /** * Returns binary of SqlLite format page. Little difference is that: * - page is 1-based, so first page * - page 0 is the header ( 100 bytes as per Sqlite format ) * - page 1 is the first page of the database, and its size is (page size - 100 bytes) size * @param pageNumber * @returns */ getPage(pageNumber) { if (pageNumber == 0) { return this.binary.subarray(0, 100); } const pageSize = this.getPageSize(); if (pageNumber == 1) { return this.binary.subarray(100, pageSize); } const offset = (pageNumber - 1) * pageSize; return this.binary.subarray(offset, offset + pageSize); } async getPageSha256(pageNumber) { const digest = await globalThis.crypto.subtle.digest("SHA-256", this.getPage(pageNumber)); return Array.from(new Uint8Array(digest)).map((byte) => byte.toString(16).padStart(2, "0")).join(""); } checkHeaderIsOk() { const header = this.binary.slice(0, 16); const expected = new TextEncoder().encode("SQLite format 3\0"); if (new TextDecoder().decode(header) == new TextDecoder().decode(expected)) { return true; } return false; } checkLooksValid() { if (this.binary.length == this.getPageSize() * (this.getPagesCount() - 1)) { return true; } return false; } getSize() { return this.binary.length; } getPageSize() { const data = this.binary.slice(16, 18); if (data[0] == 0 && data[1] == 1) { return 65536; } return data[0] * 256 + data[1]; } getPagesCount() { return new DataView(this.binary.buffer, 28).getUint32(0, false) + 1; } getFileChangeCounter() { return new DataView(this.binary.buffer, 24).getUint32(0, false); } } //# sourceMappingURL=SuiSqliteBinaryView.js.map