@bunnykit/orm 0.1.18 → 0.1.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -20,6 +20,7 @@ export { ObserverRegistry, type ObserverContract } from "./model/Observer.js";
20
20
  export { MorphMap } from "./model/MorphMap.js";
21
21
  export { MorphTo, MorphOne, MorphMany, MorphToMany } from "./model/MorphRelations.js";
22
22
  export { BelongsToMany } from "./model/BelongsToMany.js";
23
+ export { IdentityMap } from "./model/IdentityMap.js";
23
24
  export { Migration } from "./migration/Migration.js";
24
25
  export { Migrator } from "./migration/Migrator.js";
25
26
  export type { MigrationEvent, MigrationEventListener, MigrationEventPayload } from "./migration/Migrator.js";
package/dist/src/index.js CHANGED
@@ -15,6 +15,7 @@ export { ObserverRegistry } from "./model/Observer.js";
15
15
  export { MorphMap } from "./model/MorphMap.js";
16
16
  export { MorphTo, MorphOne, MorphMany, MorphToMany } from "./model/MorphRelations.js";
17
17
  export { BelongsToMany } from "./model/BelongsToMany.js";
18
+ export { IdentityMap } from "./model/IdentityMap.js";
18
19
  export { Migration } from "./migration/Migration.js";
19
20
  export { Migrator } from "./migration/Migrator.js";
20
21
  export { MigrationCreator } from "./migration/MigrationCreator.js";
@@ -0,0 +1,8 @@
1
+ import type { Model } from "./Model.js";
2
+ export declare class IdentityMap {
3
+ static current(): Map<string, Model> | undefined;
4
+ static run<T>(callback: () => T | Promise<T>): Promise<T>;
5
+ static get(table: string, key: string | number): Model | undefined;
6
+ static set(table: string, key: string | number, model: Model): void;
7
+ static clear(): void;
8
+ }
@@ -0,0 +1,28 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ const storage = new AsyncLocalStorage();
3
+ export class IdentityMap {
4
+ static current() {
5
+ return storage.getStore();
6
+ }
7
+ static async run(callback) {
8
+ return await storage.run(new Map(), callback);
9
+ }
10
+ static get(table, key) {
11
+ const map = this.current();
12
+ if (!map)
13
+ return undefined;
14
+ return map.get(`${table}:${String(key)}`);
15
+ }
16
+ static set(table, key, model) {
17
+ const map = this.current();
18
+ if (!map)
19
+ return;
20
+ map.set(`${table}:${String(key)}`, model);
21
+ }
22
+ static clear() {
23
+ const map = this.current();
24
+ if (!map)
25
+ return;
26
+ map.clear();
27
+ }
28
+ }
@@ -115,6 +115,7 @@ export declare class Model<T extends Record<string, any> = Record<string, any>>
115
115
  static getTable(): string;
116
116
  static getConnection(): Connection;
117
117
  static setConnection(connection: Connection): void;
118
+ static useIdentityMap<T>(callback: () => T | Promise<T>): Promise<T>;
118
119
  static on<M extends ModelConstructor>(this: M, connection: string | Connection): Builder<InstanceType<M>>;
119
120
  static forTenant<M extends ModelConstructor>(this: M, tenantId: string): Builder<InstanceType<M>>;
120
121
  static query<M extends ModelConstructor>(this: M): Builder<InstanceType<M>>;
@@ -7,6 +7,7 @@ import { Schema } from "../schema/Schema.js";
7
7
  import { ModelNotFoundError } from "./ModelNotFoundError.js";
8
8
  import { ConnectionManager } from "../connection/ConnectionManager.js";
9
9
  import { TenantContext } from "../connection/TenantContext.js";
10
+ import { IdentityMap } from "./IdentityMap.js";
10
11
  const globalScopes = new WeakMap();
11
12
  function getGlobalScopes(model) {
12
13
  const scopes = new Map();
@@ -353,6 +354,9 @@ export class Model {
353
354
  this.connection = connection;
354
355
  ConnectionManager.setDefault(connection);
355
356
  }
357
+ static useIdentityMap(callback) {
358
+ return IdentityMap.run(callback);
359
+ }
356
360
  static on(connection) {
357
361
  const resolved = typeof connection === "string" ? ConnectionManager.require(connection) : connection;
358
362
  const builder = new Builder(resolved, resolved.qualifyTable(this.getTable()));
@@ -813,6 +817,13 @@ export class Model {
813
817
  await ObserverRegistry.dispatch("created", this);
814
818
  await ObserverRegistry.dispatch("saved", this);
815
819
  }
820
+ const identityMap = IdentityMap.current();
821
+ if (identityMap) {
822
+ const pk = this.getAttribute(constructor.primaryKey);
823
+ if (pk !== null && pk !== undefined && pk !== "") {
824
+ IdentityMap.set(constructor.getTable(), pk, this);
825
+ }
826
+ }
816
827
  return this;
817
828
  }
818
829
  updateTimestamps() {
@@ -1,4 +1,5 @@
1
1
  import { ModelNotFoundError } from "../model/ModelNotFoundError.js";
2
+ import { IdentityMap } from "../model/IdentityMap.js";
2
3
  export class Builder {
3
4
  connection;
4
5
  tableName;
@@ -589,13 +590,31 @@ export class Builder {
589
590
  const results = await this.connection.query(sql, this.bindings);
590
591
  const rows = Array.from(results);
591
592
  if (this.model) {
593
+ const identityMap = IdentityMap.current();
594
+ const table = this.model.getTable();
595
+ const primaryKey = this.model.primaryKey || "id";
592
596
  const models = rows.map((row) => {
597
+ if (identityMap) {
598
+ const pk = row[primaryKey];
599
+ if (pk !== null && pk !== undefined) {
600
+ const cached = IdentityMap.get(table, pk);
601
+ if (cached) {
602
+ return cached;
603
+ }
604
+ }
605
+ }
593
606
  const instance = new this.model(row);
594
607
  instance.$exists = true;
595
608
  instance.$original = { ...row };
596
609
  if (typeof instance.setConnection === "function") {
597
610
  instance.setConnection(this.connection);
598
611
  }
612
+ if (identityMap) {
613
+ const pk = row[primaryKey];
614
+ if (pk !== null && pk !== undefined) {
615
+ IdentityMap.set(table, pk, instance);
616
+ }
617
+ }
599
618
  return instance;
600
619
  });
601
620
  if (this.eagerLoads.length > 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bunnykit/orm",
3
- "version": "0.1.18",
3
+ "version": "0.1.19",
4
4
  "description": "An Eloquent-inspired ORM for Bun's native SQL client supporting SQLite, MySQL, and PostgreSQL.",
5
5
  "license": "MIT",
6
6
  "packageManager": "bun@1.3.12",