diff --git a/Enterprise/package.json b/Enterprise/package.json new file mode 100644 index 0000000..3dbc1ca --- /dev/null +++ b/Enterprise/package.json @@ -0,0 +1,3 @@ +{ + "type": "module" +} diff --git a/Enterprise/static/404.html b/Enterprise/static/404.html new file mode 100644 index 0000000..586632d --- /dev/null +++ b/Enterprise/static/404.html @@ -0,0 +1,11 @@ + + + + + Error 404: File not found + + + +

File not found

+ + diff --git a/Enterprise/static/application.js b/Enterprise/static/application.js new file mode 100644 index 0000000..116e39c --- /dev/null +++ b/Enterprise/static/application.js @@ -0,0 +1,68 @@ +import { Database } from './database.js'; +import { UserRepository, UserService } from './user.js'; + +class Logger { + #output; + + constructor(outputId) { + this.#output = document.getElementById(outputId); + } + + log(...args) { + const lines = args.map(Logger.#serialize); + this.#output.textContent += lines.join(' ') + '\n'; + this.#output.scrollTop = this.#output.scrollHeight; + } + + static #serialize(x) { + return typeof x === 'object' ? JSON.stringify(x, null, 2) : x; + } +} + +const logger = new Logger('output'); + +const action = (id, handler) => { + const element = document.getElementById(id); + if (element) element.onclick = handler; +}; + +const db = new Database('EnterpriseApplication', 1, (db) => { + if (!db.objectStoreNames.contains('user')) { + db.createObjectStore('user', { keyPath: 'id', autoIncrement: true }); + } +}); +await db.connect(); +const userRepository = new UserRepository(db, 'user'); +const userService = new UserService(userRepository); + +action('add', async () => { + const name = prompt('Enter user name:'); + const age = parseInt(prompt('Enter age:'), 10); + if (!name || !Number.isInteger(age)) return; + const user = await userService.createUser(name, age); + logger.log('Added:', user); +}); + +action('get', async () => { + const users = await userRepository.getAll(); + logger.log('Users:', users); +}); + +action('update', async () => { + try { + const user = await userService.incrementAge(1); + logger.log('Updated:', user); + } catch (err) { + logger.log(err.message); + } +}); + +action('delete', async () => { + await userRepository.delete(2); + logger.log('Deleted user with id=2'); +}); + +action('adults', async () => { + const adults = await userService.findAdults(); + logger.log('Adults:', adults); +}); diff --git a/Enterprise/static/core.js b/Enterprise/static/core.js new file mode 100644 index 0000000..90bdce7 --- /dev/null +++ b/Enterprise/static/core.js @@ -0,0 +1,50 @@ +export class Repository { + constructor(database, storeName) { + this.db = database; + this.storeName = storeName; + } + + insert(record) { + return this.db.exec(this.storeName, 'readwrite', (store) => + store.add(record), + ); + } + + getAll() { + return this.db.exec(this.storeName, 'readonly', (store) => { + const req = store.getAll(); + return new Promise((resolve, reject) => { + req.onsuccess = () => resolve(req.result); + req.onerror = () => reject(req.error); + }); + }); + } + + get(id) { + return this.db.exec(this.storeName, 'readonly', (store) => { + const req = store.get(id); + return new Promise((resolve, reject) => { + req.onsuccess = () => resolve(req.result); + req.onerror = () => reject(req.error); + }); + }); + } + + update(record) { + return this.db.exec(this.storeName, 'readwrite', (store) => + store.put(record), + ); + } + + delete(id) { + return this.db.exec(this.storeName, 'readwrite', (store) => + store.delete(id), + ); + } +} + +export class Service { + constructor(repository) { + this.repository = repository; + } +} diff --git a/Enterprise/static/database.js b/Enterprise/static/database.js new file mode 100644 index 0000000..ebc1a6b --- /dev/null +++ b/Enterprise/static/database.js @@ -0,0 +1,46 @@ +export class Database { + #db; + + constructor(name, version = 1, upgradeCallback) { + this.name = name; + this.version = version; + this.upgradeCallback = upgradeCallback; + } + + async connect() { + return new Promise((resolve, reject) => { + const request = indexedDB.open(this.name, this.version); + + request.onupgradeneeded = (event) => { + const db = event.target.result; + if (this.upgradeCallback) this.upgradeCallback(db); + }; + + request.onsuccess = () => { + this.#db = request.result; + resolve(); + }; + + request.onerror = () => reject(request.error); + }); + } + + transaction(storeName, mode = 'readonly') { + const tx = this.#db.transaction(storeName, mode); + return tx.objectStore(storeName); + } + + exec(storeName, mode, operation) { + return new Promise((resolve, reject) => { + try { + const tx = this.#db.transaction(storeName, mode); + const store = tx.objectStore(storeName); + const result = operation(store); + tx.oncomplete = () => resolve(result); + tx.onerror = () => reject(tx.error); + } catch (err) { + reject(err); + } + }); + } +} diff --git a/Enterprise/static/favicon.ico b/Enterprise/static/favicon.ico new file mode 100644 index 0000000..1b75888 Binary files /dev/null and b/Enterprise/static/favicon.ico differ diff --git a/Enterprise/static/index.html b/Enterprise/static/index.html new file mode 100644 index 0000000..bd10db2 --- /dev/null +++ b/Enterprise/static/index.html @@ -0,0 +1,20 @@ + + + + + IndexedDB Exampe + + + +

IndexedDB Repository Example

+
+ + + + + +
+

+  
+
+
diff --git a/Enterprise/static/styles.css b/Enterprise/static/styles.css
new file mode 100644
index 0000000..194793e
--- /dev/null
+++ b/Enterprise/static/styles.css
@@ -0,0 +1,37 @@
+body {
+  font-family: system-ui, sans-serif;
+  padding: 1rem;
+  background: #f4f4f4;
+  color: #222;
+}
+
+h1 {
+  margin-bottom: 1rem;
+}
+
+.controls {
+  margin-bottom: 1rem;
+}
+
+button {
+  margin-right: 0.5rem;
+  padding: 0.5rem 1rem;
+  font-size: 1rem;
+  cursor: pointer;
+}
+
+pre#output {
+  position: fixed;
+  top: 10rem;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  overflow: auto;
+  margin: 0;
+  padding: 1rem;
+  background: #111;
+  color: #0f0;
+  font-family: monospace;
+  font-size: 0.9rem;
+  white-space: pre-wrap;
+}
diff --git a/Enterprise/static/user.js b/Enterprise/static/user.js
new file mode 100644
index 0000000..5ef9126
--- /dev/null
+++ b/Enterprise/static/user.js
@@ -0,0 +1,41 @@
+import { Repository, Service } from './core.js';
+
+export class UserModel {
+  constructor(name, age) {
+    if (typeof name !== 'string' || name.trim().length === 0) {
+      throw new Error('Invalid name');
+    }
+    if (!Number.isInteger(age) || age < 0) {
+      throw new Error('Invalid age');
+    }
+    this.name = name.trim();
+    this.age = age;
+  }
+}
+
+export class UserRepository extends Repository {
+  constructor(database) {
+    super(database, 'user');
+  }
+}
+
+export class UserService extends Service {
+  async createUser(name, age) {
+    const user = new UserModel(name, age);
+    await this.repository.insert(user);
+    return user;
+  }
+
+  async incrementAge(id) {
+    const user = await this.repository.get(id);
+    if (!user) throw new Error('User with id=1 not found');
+    user.age += 1;
+    await this.repository.update(user);
+    return user;
+  }
+
+  async findAdults() {
+    const users = await this.repository.getAll();
+    return users.filter((user) => user.age >= 18);
+  }
+}
diff --git a/Enterprise/test/core.js b/Enterprise/test/core.js
new file mode 100644
index 0000000..c716dc6
--- /dev/null
+++ b/Enterprise/test/core.js
@@ -0,0 +1,41 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import 'fake-indexeddb/auto';
+import { Database } from '../static/database.js';
+import { Repository, Service } from '../static/core.js';
+
+test('Enterprise: Repository', async () => {
+  const db = new Database('RepoTestDB', 1, (db) => {
+    db.createObjectStore('items', { keyPath: 'id', autoIncrement: true });
+  });
+  await db.connect();
+
+  const repo = new Repository(db, 'items');
+
+  const item = { name: 'Item1' };
+  await repo.insert(item);
+
+  const items = await repo.getAll();
+  assert.equal(items.length, 1);
+  assert.equal(items[0].name, 'Item1');
+
+  const id = items[0].id;
+  const one = await repo.get(id);
+  assert.equal(one.name, 'Item1');
+
+  one.name = 'Item1Updated';
+  await repo.update(one);
+
+  const updated = await repo.get(id);
+  assert.equal(updated.name, 'Item1Updated');
+
+  await repo.delete(id);
+  const afterDelete = await repo.getAll();
+  assert.equal(afterDelete.length, 0);
+});
+
+test('Enterprise: Service', () => {
+  const fakeRepo = { insert: () => {}, get: () => {} };
+  const service = new Service(fakeRepo);
+  assert.equal(service.repository, fakeRepo);
+});
diff --git a/Enterprise/test/database.js b/Enterprise/test/database.js
new file mode 100644
index 0000000..c0e22e7
--- /dev/null
+++ b/Enterprise/test/database.js
@@ -0,0 +1,34 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import 'fake-indexeddb/auto';
+import { Database } from '../static/database.js';
+import { Repository, Service } from '../static/core.js';
+import { UserModel, UserRepository, UserService } from '../static/user.js';
+
+test('Enterprise: Database CRUD + queries', async () => {
+  const db = new Database('TestDB', 1, (db) => {
+    if (!db.objectStoreNames.contains('user')) {
+      db.createObjectStore('user', { keyPath: 'id', autoIncrement: true });
+    }
+  });
+  await db.connect();
+
+  const repo = new Repository(db, 'user');
+  const marcus = new UserModel('Marcus', 28);
+
+  await repo.insert(marcus);
+  const allUsers = await repo.getAll();
+  assert.equal(allUsers.length, 1);
+  assert.equal(allUsers[0].name, 'Marcus');
+
+  const user = await repo.get(1);
+  user.age = 29;
+  await repo.update(user);
+
+  const updated = await repo.get(1);
+  assert.equal(updated.age, 29);
+
+  await repo.delete(1);
+  const empty = await repo.getAll();
+  assert.equal(empty.length, 0);
+});
diff --git a/Enterprise/test/user.js b/Enterprise/test/user.js
new file mode 100644
index 0000000..bacdd92
--- /dev/null
+++ b/Enterprise/test/user.js
@@ -0,0 +1,42 @@
+import test from 'node:test';
+import assert from 'node:assert/strict';
+import 'fake-indexeddb/auto';
+import { Database } from '../static/database.js';
+import { Repository, Service } from '../static/core.js';
+import { UserModel, UserRepository, UserService } from '../static/user.js';
+
+test('Enterprise: UserModel validation', async () => {
+  assert.throws(() => new UserModel('', 25), /Invalid name/);
+  assert.throws(() => new UserModel('Faustina', -1), /Invalid age/);
+  assert.throws(() => new UserModel('Lucius', 3.14), /Invalid age/);
+
+  const user = new UserModel('Titus', 42);
+  assert.ok(user instanceof UserModel);
+  assert.strictEqual(user.name, 'Titus');
+  assert.strictEqual(user.age, 42);
+});
+
+test('Enterprise: UserService, UserRepository', async () => {
+  const db = new Database('ServiceTestDB', 1, (db) => {
+    if (!db.objectStoreNames.contains('user')) {
+      db.createObjectStore('user', { keyPath: 'id', autoIncrement: true });
+    }
+  });
+  await db.connect();
+
+  const userRepo = new UserRepository(db, 'user');
+  const userService = new UserService(userRepo);
+
+  await userService.createUser('Lucius', 17);
+  await userService.createUser('Antoninus', 33);
+  await userService.createUser('Faustina', 18);
+
+  const adults = await userService.findAdults();
+  assert.equal(adults.length, 2);
+  assert.ok(adults.some((user) => user.name === 'Antoninus'));
+
+  const updatedUser = await userService.incrementAge(2);
+  assert.equal(updatedUser.age, 34);
+
+  await assert.rejects(() => userService.incrementAge(999), /User with id=1 not found/);
+});
diff --git a/Native/package.json b/Native/package.json
new file mode 100644
index 0000000..3dbc1ca
--- /dev/null
+++ b/Native/package.json
@@ -0,0 +1,3 @@
+{
+  "type": "module"
+}
diff --git a/Native/static/404.html b/Native/static/404.html
new file mode 100644
index 0000000..586632d
--- /dev/null
+++ b/Native/static/404.html
@@ -0,0 +1,11 @@
+
+
+  
+    
+    Error 404: File not found
+    
+  
+  
+    

File not found

+ + diff --git a/Native/static/application.js b/Native/static/application.js new file mode 100644 index 0000000..e8735bb --- /dev/null +++ b/Native/static/application.js @@ -0,0 +1,92 @@ +class Logger { + #output; + + constructor(outputId) { + this.#output = document.getElementById(outputId); + } + + log(...args) { + const lines = args.map(Logger.#serialize); + this.#output.textContent += lines.join(' ') + '\n'; + this.#output.scrollTop = this.#output.scrollHeight; + } + + static #serialize(x) { + return typeof x === 'object' ? JSON.stringify(x, null, 2) : x; + } +} + +const logger = new Logger('output'); + +const db = await new Promise((resolve, reject) => { + const request = indexedDB.open('Example', 1); + request.onupgradeneeded = () => { + const db = request.result; + if (!db.objectStoreNames.contains('user')) { + db.createObjectStore('user', { keyPath: 'id', autoIncrement: true }); + } + }; + request.onsuccess = () => resolve(request.result); + request.onerror = () => reject(request.error); +}); + +document.getElementById('add').onclick = () => { + const name = prompt('Enter user name:'); + if (!name) return; + const age = parseInt(prompt('Enter age:'), 10); + if (!Number.isInteger(age)) return; + const tx = db.transaction('user', 'readwrite'); + tx.objectStore('user').add({ name, age }); + tx.oncomplete = () => logger.log('Added:', { name, age }); + tx.onerror = () => logger.log('Add failed'); +}; + +document.getElementById('get').onclick = () => { + const tx = db.transaction('user', 'readonly'); + const store = tx.objectStore('user'); + const req = store.getAll(); + req.onsuccess = () => logger.log('Users:', req.result); + req.onerror = () => logger.log('Get failed'); +}; + +document.getElementById('update').onclick = () => { + const tx = db.transaction('user', 'readwrite'); + const store = tx.objectStore('user'); + const req = store.get(1); + req.onsuccess = () => { + const user = req.result; + if (!user) { + logger.log('User with id=1 not found'); + return; + } + user.age += 1; + store.put(user); + tx.oncomplete = () => logger.log('Updatued:', user); + }; + req.onerror = () => logger.log('Update failed'); +}; + +document.getElementById('delete').onclick = () => { + const tx = db.transaction('user', 'readwrite'); + tx.objectStore('user').delete(2); + tx.oncomplete = () => logger.log('Deleted user with id=2'); + tx.onerror = () => logger.log('Delete failed'); +}; + +document.getElementById('adults').onclick = () => { + const tx = db.transaction('user', 'readonly'); + const store = tx.objectStore('user'); + const req = store.openCursor(); + const adults = []; + req.onsuccess = (event) => { + const cursor = event.target.result; + if (!cursor) { + logger.log('Adults:', adults); + return; + } + const user = cursor.value; + if (user.age >= 18) adults.push(user); + cursor.continue(); + }; + req.onerror = () => logger.log('Adult query failed'); +}; diff --git a/Native/static/favicon.ico b/Native/static/favicon.ico new file mode 100644 index 0000000..1b75888 Binary files /dev/null and b/Native/static/favicon.ico differ diff --git a/Native/static/index.html b/Native/static/index.html new file mode 100644 index 0000000..bd10db2 --- /dev/null +++ b/Native/static/index.html @@ -0,0 +1,20 @@ + + + + + IndexedDB Exampe + + + +

IndexedDB Repository Example

+
+ + + + + +
+

+  
+
+
diff --git a/Native/static/styles.css b/Native/static/styles.css
new file mode 100644
index 0000000..194793e
--- /dev/null
+++ b/Native/static/styles.css
@@ -0,0 +1,37 @@
+body {
+  font-family: system-ui, sans-serif;
+  padding: 1rem;
+  background: #f4f4f4;
+  color: #222;
+}
+
+h1 {
+  margin-bottom: 1rem;
+}
+
+.controls {
+  margin-bottom: 1rem;
+}
+
+button {
+  margin-right: 0.5rem;
+  padding: 0.5rem 1rem;
+  font-size: 1rem;
+  cursor: pointer;
+}
+
+pre#output {
+  position: fixed;
+  top: 10rem;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  overflow: auto;
+  margin: 0;
+  padding: 1rem;
+  background: #111;
+  color: #0f0;
+  font-family: monospace;
+  font-size: 0.9rem;
+  white-space: pre-wrap;
+}
diff --git a/Pragmatic/static/application.js b/Pragmatic/static/application.js
index c5e0372..3ee086b 100644
--- a/Pragmatic/static/application.js
+++ b/Pragmatic/static/application.js
@@ -31,20 +31,20 @@ const actions = {
     const age = parseInt(prompt('Enter age:'), 10);
     if (!Number.isInteger(age)) return;
     const user = { name, age };
-    await db.insert('user', user);
+    await db.insert({ store: 'user', record: user });
     logger.log('Added:', user);
   },
 
   get: async () => {
-    const users = await db.select('user');
+    const users = await db.select({ store: 'user' });
     logger.log('Users:', users);
   },
 
   update: async () => {
-    const user = await db.get('user', { id: 1 });
+    const user = await db.get({ store: 'user', id: 1 });
     if (user) {
       user.age += 1;
-      await db.update('user', user);
+      await db.update({ store: 'user', record: user });
       logger.log('Updated:', user);
     } else {
       logger.log('User with id=1 not found');
@@ -52,14 +52,15 @@ const actions = {
   },
 
   delete: async () => {
-    await db.delete('user', { id: 2 });
+    await db.delete({ store: 'user', id: 2 });
     logger.log('Deleted user with id=2');
   },
 
   adults: async () => {
-    const users = await db.select('user', {
+    const users = await db.select({
+      store: 'user',
       filter: (user) => user.age >= 18,
-      order: 'name asc',
+      order: { name: 'asc' },
       limit: 10,
     });
     logger.log('Adults:', users);
diff --git a/Pragmatic/static/storage.js b/Pragmatic/static/storage.js
index be5f884..dc24382 100644
--- a/Pragmatic/static/storage.js
+++ b/Pragmatic/static/storage.js
@@ -1,14 +1,14 @@
 class Database {
   #name;
-  #version = 1;
-  #schemas = null;
+  #version;
+  #schemas;
   #instance = null;
   #active = false;
 
-  constructor(name, { version, schemas }) {
+  constructor(name, { version = 1, schemas = {} } = {}) {
     this.#name = name;
-    if (version) this.#version = version;
-    if (schemas) this.#schemas = schemas;
+    this.#version = version;
+    this.#schemas = schemas;
     return this.#open();
   }
 
@@ -17,14 +17,15 @@ class Database {
       const request = indexedDB.open(this.#name, this.#version);
       request.onupgradeneeded = (event) => this.#upgrade(event.target.result);
       request.onsuccess = (event) => {
-        this.#active = true;
         this.#instance = event.target.result;
+        this.#active = true;
         resolve();
       };
       request.onerror = (event) => {
-        let { error } = event.target;
-        if (!error) error = new Error(`IndexedDB: can't open ${this.#name}`);
-        reject(error);
+        reject(
+          event.target.error ??
+            new Error(`IndexedDB: can't open ${this.#name}`),
+        );
       };
     });
     return this;
@@ -34,79 +35,80 @@ class Database {
     for (const [name, schema] of Object.entries(this.#schemas)) {
       if (!db.objectStoreNames.contains(name)) {
         const store = db.createObjectStore(name, schema);
-        const indexes = schema.indexes || [];
-        for (const index of Object.entries(indexes)) {
-          store.createIndex(index.name, index.keyPath, index.options);
+        const indexes = schema.indexes ?? [];
+        for (const { name: idxName, keyPath, options } of indexes) {
+          store.createIndex(idxName, keyPath, options);
         }
       }
     }
   }
 
-  #exec(entity, operation, mode = 'readwrite') {
+  #exec(store, operation, mode = 'readwrite') {
     if (!this.#active) {
       return Promise.reject(new Error('Database not connected'));
     }
     return new Promise((resolve, reject) => {
       try {
-        const tx = this.#instance.transaction(entity, mode);
-        const store = tx.objectStore(entity);
-        const result = operation(store);
+        const tx = this.#instance.transaction(store, mode);
+        const objectStore = tx.objectStore(store);
+        const result = operation(objectStore);
         tx.oncomplete = () => resolve(result);
-        tx.onerror = () => reject(tx.error || new Error('Transaction error'));
+        tx.onerror = () => reject(tx.error ?? new Error('Transaction error'));
       } catch (error) {
         reject(error);
       }
     });
   }
 
-  async insert(entity, record) {
-    return this.#exec(entity, (store) => store.add(record));
+  insert({ store, record }) {
+    return this.#exec(store, (s) => s.add(record));
   }
 
-  async update(entity, record) {
-    return this.#exec(entity, (store) => store.put(record));
+  update({ store, record }) {
+    return this.#exec(store, (s) => s.put(record));
   }
 
-  async delete(entity, { id }) {
-    return this.#exec(entity, (store) => store.delete(id));
+  delete({ store, id }) {
+    return this.#exec(store, (s) => s.delete(id));
   }
 
-  async get(entity, { id }) {
+  get({ store, id }) {
     return this.#exec(
-      entity,
-      (store) => {
-        const req = store.get(id);
+      store,
+      (s) => {
+        const req = s.get(id);
         return new Promise((resolve, reject) => {
           req.onsuccess = () => resolve(req.result);
-          req.onerror = () => reject(req.error || new Error(`Can't get ${id}`));
+          req.onerror = () => reject(req.error ?? new Error(`Can't get ${id}`));
         });
       },
       'readonly',
     );
   }
 
-  async select(entity, { where, limit, offset, order, filter, sort } = {}) {
+  select({ store, where, limit, offset, order, filter, sort }) {
     return this.#exec(
-      entity,
-      (store) => {
+      store,
+      (s) => {
         const results = [];
         let skipped = 0;
         return new Promise((resolve, reject) => {
-          const req = store.openCursor();
+          const req = s.openCursor();
           req.onerror = () => reject(req.error);
           req.onsuccess = (event) => {
             const cursor = event.target.result;
             if (!cursor) {
               const filtered = filter ? results.filter(filter) : results;
-              const sorted = sort
-                ? filtered.toSorted(sort)
-                : Database.#order(filtered, order);
-              return void resolve(sorted);
+              return void resolve(
+                sort
+                  ? filtered.toSorted(sort)
+                  : Database.#order(filtered, order),
+              );
             }
             const record = cursor.value;
             const match =
               !where ||
-              Object.entries(where).every(([key, val]) => record[key] === val);
+              Object.entries(where).every(([k, v]) => record[k] === v);
             if (match) {
               if (!offset || skipped >= offset) {
                 results.push(record);
@@ -127,7 +129,7 @@ class Database {
 
   static #order(arr, order) {
     if (!order || typeof order !== 'object') return arr;
-    const [[field, dir]] = Object.entries(order);
+    const [[field, dir = 'asc']] = Object.entries(order);
     const sign = dir === 'desc' ? -1 : 1;
     return [...arr].sort((a, b) => {
       if (a[field] === b[field]) return 0;
diff --git a/Pragmatic/test/database.js b/Pragmatic/test/database.js
index 3abe1fd..396e534 100644
--- a/Pragmatic/test/database.js
+++ b/Pragmatic/test/database.js
@@ -3,28 +3,72 @@ import assert from 'node:assert/strict';
 import 'fake-indexeddb/auto';
 import { Database } from '../static/storage.js';
 
-test('Database basic CRUD', async () => {
-  const schemas = {
-    user: { keyPath: 'id', autoIncrement: true },
-  };
-  const db = await new Database('TestDatabase', { version: 1, schemas });
+test('Pragmatic: Database CRUD + DSL', async () => {
+  const db = await new Database('TestDB', {
+    version: 1,
+    schemas: {
+      user: { keyPath: 'id', autoIncrement: true },
+    },
+  });
 
-  await db.insert('user', { name: 'Marcus', age: 30 });
-  await db.insert('user', { name: 'Lucius', age: 20 });
+  // Insert
+  await db.insert({ store: 'user', record: { name: 'Marcus', age: 20 } });
+  await db.insert({ store: 'user', record: { name: 'Lucius', age: 20 } });
+  await db.insert({ store: 'user', record: { name: 'Antoninus', age: 40 } });
 
-  const users = await db.select('user');
-  assert.equal(users.length, 2);
+  // Select all
+  const allUsers = await db.select({ store: 'user' });
+  assert.equal(allUsers.length, 3);
 
-  const record = await db.get('user', { id: 1 });
-  assert.equal(record.name, 'Marcus');
+  // Get
+  const marcus = await db.get({ store: 'user', id: 1 });
+  assert.equal(marcus.name, 'Marcus');
 
-  record.age++;
-  await db.update('user', record);
-
-  const updated = await db.get('user', { id: 1 });
+  // Update
+  marcus.age = 31;
+  await db.update({ store: 'user', record: marcus });
+  const updated = await db.get({ store: 'user', id: 1 });
   assert.equal(updated.age, 31);
 
-  await db.delete('user', { id: 2 });
-  const remaining = await db.select('user');
-  assert.equal(remaining.length, 1);
+  // Delete
+  await db.delete({ store: 'user', id: 2 });
+  const afterDelete = await db.select({ store: 'user' });
+  assert.equal(afterDelete.length, 2);
+
+  // Select with where
+  const list = await db.select({ store: 'user', where: { name: 'Marcus' } });
+  assert.equal(list.length, 1);
+  assert.equal(list[0].age, 31);
+
+  // Select with filter
+  const adults = await db.select({
+    store: 'user',
+    filter: (u) => u.age >= 30,
+  });
+  assert.equal(adults.length, 2);
+  assert.equal(adults[0].name, 'Marcus');
+
+  // Select with order
+  const ordered = await db.select({
+    store: 'user',
+    order: { age: 'desc' },
+  });
+  assert.equal(ordered[0].name, 'Antoninus');
+  assert.equal(ordered[1].name, 'Marcus');
+
+  // Select with offset
+  const skipped = await db.select({
+    store: 'user',
+    offset: 1,
+    order: { name: 'asc' },
+  });
+  assert.equal(skipped.length, 1);
+  assert.equal(skipped[0].name, 'Antoninus');
+
+  // Select with limit
+  const limited = await db.select({
+    store: 'user',
+    limit: 1,
+  });
+  assert.equal(limited.length, 1);
 });
diff --git a/eslint.config.js b/eslint.config.js
index 4275f34..e970e96 100644
--- a/eslint.config.js
+++ b/eslint.config.js
@@ -6,7 +6,7 @@ module.exports = init;
 module.exports = [
   ...init,
   {
-    files: ['Pragmatic/**/*.js'],
+    files: ['Enterprise/**/*.js', 'Native/**/*.js', 'Pragmatic/**/*.js'],
     languageOptions: {
       sourceType: 'module',
       globals: {