Skip to content

feat(bedrock-project): SqliteDataSet<T> POC — sql.js-backed drop-in for DataSet<T>#339

Draft
Copilot wants to merge 2 commits intomainfrom
copilot/create-sqlite-dataset-poc
Draft

feat(bedrock-project): SqliteDataSet<T> POC — sql.js-backed drop-in for DataSet<T>#339
Copilot wants to merge 2 commits intomainfrom
copilot/create-sqlite-dataset-poc

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 26, 2026

Introduces a proof-of-concept SqliteDataSet<T> backed by sql.js (SQLite → WASM), enabling a future path to replace the in-memory Map-backed DataSet<T> with a queryable store that works on all platforms including vscode.dev.

Implementation

  • sqlite-data-set.tsSqliteDataSet<T> implements the same DataSetBase + IDataSet<T> interfaces as DataSet<T>; async factory SqliteDataSet.create(tableName, db?) handles sql.js init
  • Schema — one table per dataset: id TEXT PRIMARY KEY, uri TEXT NOT NULL, data TEXT NOT NULL + index on uri; full object stored as JSON in data
  • Efficient deletionsdeleteFile / deleteFolder use SQL WHERE uri = ? / WHERE uri LIKE ? || '%' instead of full-Map iteration
  • Shared DB support — optional db parameter allows multiple datasets to share a single in-memory Database instance
// Each pack type gets its own table; db is shared across all of them
const SQL = await initSqlJs();
const db = new SQL.Database();

const entities  = await SqliteDataSet.create<BpEntity>('bp_entities', db);
const functions = await SqliteDataSet.create<McFunction>('bp_functions', db);

entities.set(entity);
entities.deleteFolder('file:///workspace/bp/entities/mobs');

Package changes

  • packages/bedrock-project/package.json — adds sql.js ^1.12.0 (dep) and @types/sql.js ^1.4.9 (devDep)
  • packages/bedrock-project/src/types/index.ts — re-exports SqliteDataSet
  • packages/bedrock-project/src/types/sqlite-data-set.test.ts — Jest suite mirroring data-set.test.ts, covering all 11 operations plus shared-DB usage

DataSet<T>, BehaviorPack, and ProjectData are untouched — this is POC only.

Original prompt

Goal

Create a proof-of-concept (POC) for replacing the in-memory DataSet<T> (backed by Map<string, T> in packages/bedrock-project/src/types/data-set.ts) with a sql.js-backed SqliteDataSet<T> that:

  • Is a drop-in replacement — implements the same DataSetBase + IDataSet<T> interfaces
  • Uses sql.js (SQLite compiled to WASM) so it works on all platforms including vscode.dev (browser/web extension) with no native binaries
  • Has an async factory (SqliteDataSet.create(tableName)) since sql.js initialisation is async
  • Stores the full typed object as JSON in a data TEXT column, plus separate indexed columns for id TEXT and uri TEXT — making deleteFile and deleteFolder efficient SQL operations instead of full-Map iteration
  • Includes a Jest test suite (sqlite-data-set.test.ts) that mirrors data-set.test.ts and covers all operations

Location

All new files should live inside the existing package:

packages/bedrock-project/src/types/sqlite-data-set.ts        ← implementation
packages/bedrock-project/src/types/sqlite-data-set.test.ts   ← tests

Also update:

packages/bedrock-project/src/types/index.ts    ← export the new class
packages/bedrock-project/package.json          ← add sql.js + @types/sql.js deps

If packages/bedrock-project/src/types/index.ts does not exist, check packages/bedrock-project/src/types.ts or the barrel exports and add the export there appropriately.


Implementation details

SqliteDataSet<T extends Identifiable & Locatable>

import initSqlJs, { Database } from 'sql.js';
import { Identifiable, Locatable } from 'bc-minecraft-bedrock-shared';
import { DataSetBase } from './data-set';
import { IDataSet } from './i-data-set';

export class SqliteDataSet<T extends Identifiable & Locatable>
  implements DataSetBase, IDataSet<T>
{
  private _db: Database;
  private _table: string;

  /** Use SqliteDataSet.create() instead */
  private constructor(db: Database, table: string) { ... }

  /** Async factory — must be called once per dataset, e.g. await SqliteDataSet.create('bp_entities') */
  static async create<T extends Identifiable & Locatable>(
    tableName: string,
    db?: Database,   // optional: share a single DB instance across multiple datasets
  ): Promise<SqliteDataSet<T>> { ... }

  // --- DataSetBase ---
  clear(): void { ... }
  delete(key: string | Identifiable): boolean { ... }
  deleteFile(uri: string): boolean { ... }   // DELETE WHERE uri = ?
  deleteFolder(uri: string): boolean { ... } // DELETE WHERE uri LIKE ? || '%'  (prefix match)
  has(key: string | Identifiable): boolean { ... }

  // --- IDataSet<T> ---
  get(key: string | Identifiable): T | undefined { ... }
  forEach(callbackfn: (value: T) => void, thisArg?: any): void { ... }
  find(predicate: (value: T, key: string) => boolean): T | undefined { ... }

  // --- Extra (matches DataSet<T>) ---
  set(value: T | T[] | undefined): this { ... }  // INSERT OR REPLACE
  count(): number { ... }
}

Schema (per table)

CREATE TABLE IF NOT EXISTS <tableName> (
  id   TEXT PRIMARY KEY,
  uri  TEXT NOT NULL,
  data TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_<tableName>_uri ON <tableName>(uri);

Serialisation

  • set(value)JSON.stringify(value) into data
  • get(id)JSON.parse(row.data) back to T

deleteFolder semantics

Match the existing DataSet.deleteFolder behaviour: delete all rows where item.location.uri.startsWith(uri). Implement as: DELETE FROM <table> WHERE uri LIKE ? || '%' with the folder URI as the parameter — this is correct for URI prefix matching in practice (file URIs don't contain SQL wildcards).

static async create behaviour

static async create<T extends Identifiable & Locatable>(
  tableName: string,
  db?: Database,
): Promise<SqliteDataSet<T>> {
  if (!db) {
    const SQL = await initSqlJs();   // no locateFile needed for Node/Jest
    db = new SQL.Database();
  }
  // create table + index
  const instance = new SqliteDataSet<T>(db, tableName);
  return instance;
}

The caller is responsible for sharing/closing the Database instance if needed. For the POC, each SqliteDataSet owns its own in-memory DB unless one is passed in.


Test file (sqlite-data-set.test.ts)

Cover the following scenarios (use the same concrete fake type as data-set.test.ts uses, i.e. { id: string, location: { uri: string }, documentation: string }):

  1. set + get — round-trips a typed object through JSON
  2. has — returns true/false correctly
  3. delete — removes by id; returns true if deleted, false if not found
  4. deleteFile — removes all items with matching uri; returns true
  5. deleteFolder — removes all items whose uri starts with the folder path; returns true
  6. forEach — iterates all items
  7. find — finds item by predicate
  8. count — returns number of stored items
  9. clear —...

This pull request was created from Copilot chat.


📱 Kick off Copilot coding agent tasks wherever you are with GitHub Mobile, available on iOS and Android.

Copilot AI changed the title [WIP] Create proof-of-concept for SqliteDataSet implementation feat(bedrock-project): SqliteDataSet<T> POC — sql.js-backed drop-in for DataSet<T> Mar 26, 2026
Copilot AI requested a review from DaanV2 March 26, 2026 19:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants