@arcote.tech/arc 0.0.11 → 0.0.12

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.
@@ -31,7 +31,9 @@ declare class ArcCollection<Name extends string, Id extends ArcIdAny, Schema ext
31
31
  commandContext(transaction: ReadTransaction, changes: CollectionChange[], getDraft: GetDraft<any>): {
32
32
  one: (id: util.GetType<Id>) => Deserialize<Id, Schema>;
33
33
  remove: (id: util.GetType<Id>) => Promise<any>;
34
- add: (data: objectUtil.addQuestionMarks<util.FirstArgument<Schema["serialize"]>>) => Promise<any>;
34
+ add: (data: objectUtil.addQuestionMarks<util.FirstArgument<Schema["serialize"]>>) => Promise<{
35
+ id: util.GetType<Id>;
36
+ }>;
35
37
  set: (id: util.GetType<Id>, data: util.FirstArgument<Schema["serialize"]>) => Promise<any>;
36
38
  };
37
39
  applyChange(transaction: ReadWriteTransaction, change: CollectionChange, events: CollectionChange[]): Promise<void>;
@@ -7,7 +7,7 @@ export interface ReadWriteTransaction extends ReadTransaction {
7
7
  commit(): Promise<void>;
8
8
  }
9
9
  export interface ReadTransaction {
10
- findById<C extends ArcCollectionAny>(collection: C, id: util.GetType<C["id"]>): Promise<util.CollectionItemWithId<C>>;
10
+ findById<C extends ArcCollectionAny>(collection: C, id: util.GetType<C["id"]>): Promise<util.CollectionItemWithId<C> | undefined>;
11
11
  findByIndex<C extends ArcIndexedCollectionAny>(collection: C, index: string, data: any): Promise<util.CollectionItemWithId<C>[]>;
12
12
  findAll<C extends ArcCollectionAny>(collection: C): Promise<util.CollectionItemWithId<C>[]>;
13
13
  }
@@ -0,0 +1,10 @@
1
+ import type { ArcCollectionAny } from "../collection";
2
+ import type { DatabaseAdapter, ReadTransaction, ReadWriteTransaction } from "../collection/db";
3
+ export declare class InMemoryDatabaseProxyAdapter implements DatabaseAdapter {
4
+ private parentAdapter;
5
+ private local;
6
+ constructor(parentAdapter: DatabaseAdapter);
7
+ readWriteTransaction(collections: ArcCollectionAny[]): ReadWriteTransaction;
8
+ readTransaction(collections: ArcCollectionAny[]): ReadTransaction;
9
+ clearLocal(): void;
10
+ }
@@ -12,7 +12,7 @@ export declare abstract class ArcCollectionQuery<Collection extends ArcCollectio
12
12
  getLastResult(): Response;
13
13
  run(db: DatabaseAdapter, changes$: Subject<CollectionChange>): Promise<void>;
14
14
  protected abstract onChange(change: CollectionChange): Response | false;
15
- protected abstract fetch(transaction: ReadTransaction): Promise<Response> | undefined;
15
+ protected abstract fetch(transaction: ReadTransaction): Promise<Response | undefined> | undefined;
16
16
  private changeHandler;
17
17
  unsubscribe(): void;
18
18
  private nextResult;
@@ -7,5 +7,5 @@ export declare class ArcOneItemQuery<Collection extends ArcCollectionAny> extend
7
7
  private id;
8
8
  constructor(collection: Collection, id: util.GetType<Collection["id"]>);
9
9
  protected onChange(change: CollectionChange): any;
10
- protected fetch(transaction: ReadTransaction): Promise<ReturnType<Collection["deserialize"]>> | undefined;
10
+ protected fetch(transaction: ReadTransaction): Promise<ReturnType<Collection["deserialize"]> | undefined> | undefined;
11
11
  }
package/dist/index.js CHANGED
@@ -713,7 +713,7 @@ class ArcModel {
713
713
  const result = await command(context3, ...args);
714
714
  const changes = await finalize();
715
715
  await this.applyChangesForTransaction(transaction, changes);
716
- this.rtc.commandExecuted(command.name, changes);
716
+ this.rtc.changesExecuted(changes);
717
717
  return { changes, result };
718
718
  }
719
719
  async applyChangesForTransaction(transaction, changes) {
@@ -736,6 +736,147 @@ class ArcModel {
736
736
  return this.context.collectionsMap[name];
737
737
  }
738
738
  }
739
+ // model/submodel.ts
740
+ import { Subject as Subject3 } from "rxjs";
741
+
742
+ // collection/in-memory-db-proxy.ts
743
+ class InMemoryTransaction {
744
+ parentTransaction;
745
+ local;
746
+ constructor(parentTransaction, local) {
747
+ this.parentTransaction = parentTransaction;
748
+ this.local = local;
749
+ }
750
+ async set(collection3, data) {
751
+ let collectionLocal = this.local.get(collection3.name);
752
+ if (!collectionLocal) {
753
+ collectionLocal = new Map;
754
+ this.local.set(collection3.name, collectionLocal);
755
+ }
756
+ collectionLocal.set(data._id, data);
757
+ }
758
+ async remove(collection3, id3) {
759
+ let collectionLocal = this.local.get(collection3.name);
760
+ if (!collectionLocal) {
761
+ collectionLocal = new Map;
762
+ this.local.set(collection3.name, collectionLocal);
763
+ }
764
+ collectionLocal.set(id3, null);
765
+ }
766
+ async findById(collection3, id3) {
767
+ const localItem = this.local.get(collection3.name)?.get(id3);
768
+ if (localItem !== undefined) {
769
+ return localItem === null ? undefined : localItem;
770
+ }
771
+ return this.parentTransaction.findById(collection3, id3);
772
+ }
773
+ async findByIndex(collection3, index, data) {
774
+ const parentResults = await this.parentTransaction.findByIndex(collection3, index, data);
775
+ const localResults = Array.from(this.local.get(collection3.name)?.values() || []).filter((item) => item !== null && this.matchesIndex(item, index, data));
776
+ return this.mergeResults(parentResults, localResults);
777
+ }
778
+ async findAll(collection3) {
779
+ const parentResults = await this.parentTransaction.findAll(collection3);
780
+ const localResults = Array.from(this.local.get(collection3.name)?.values() || []).filter((item) => item !== null);
781
+ return this.mergeResults(parentResults, localResults);
782
+ }
783
+ async commit() {
784
+ }
785
+ matchesIndex(item, index, data) {
786
+ return Object.entries(data).every(([key, value]) => item[key] === value);
787
+ }
788
+ mergeResults(parentResults, localResults) {
789
+ const mergedMap = new Map;
790
+ parentResults.forEach((item) => mergedMap.set(item._id, item));
791
+ localResults.forEach((item) => mergedMap.set(item._id, item));
792
+ return Array.from(mergedMap.values());
793
+ }
794
+ }
795
+
796
+ class InMemoryDatabaseProxyAdapter {
797
+ parentAdapter;
798
+ local = new Map;
799
+ constructor(parentAdapter) {
800
+ this.parentAdapter = parentAdapter;
801
+ }
802
+ readWriteTransaction(collections) {
803
+ const parentTransaction = this.parentAdapter.readWriteTransaction(collections);
804
+ return new InMemoryTransaction(parentTransaction, this.local);
805
+ }
806
+ readTransaction(collections) {
807
+ const parentTransaction = this.parentAdapter.readTransaction(collections);
808
+ return new InMemoryTransaction(parentTransaction, this.local);
809
+ }
810
+ clearLocal() {
811
+ this.local.clear();
812
+ }
813
+ }
814
+
815
+ // model/submodel.ts
816
+ class ArcSubModel {
817
+ parentModel;
818
+ changes$ = new Subject3;
819
+ proxyAdapterPromise;
820
+ uncommitedChanges = [];
821
+ constructor(parentModel) {
822
+ this.parentModel = parentModel;
823
+ this.parentModel.changes$.subscribe(this.changes$);
824
+ this.proxyAdapterPromise = this.parentModel.dbAdapterPromise.then((dbAdapter) => new InMemoryDatabaseProxyAdapter(dbAdapter));
825
+ }
826
+ query(queryFactory) {
827
+ const queryBuilder = this.context.queryBuilder();
828
+ const query = queryFactory(queryBuilder).toQuery();
829
+ this.runQuery(query);
830
+ return query;
831
+ }
832
+ async runQuery(query) {
833
+ const proxyAdapter = await this.proxyAdapterPromise;
834
+ query.run(proxyAdapter, this.changes$);
835
+ }
836
+ commands() {
837
+ return new Proxy({}, {
838
+ get: (target, name) => {
839
+ if (name in this.parentModel.context.commands) {
840
+ return async (...args) => {
841
+ const { result } = await this.executeCommand(this.parentModel.context.commands[name], ...args);
842
+ return result;
843
+ };
844
+ }
845
+ console.warn(`Command '${name}' not found in the context.`);
846
+ return;
847
+ }
848
+ });
849
+ }
850
+ async executeCommand(command, ...args) {
851
+ const proxyAdapter = await this.proxyAdapterPromise;
852
+ const transaction = proxyAdapter.readWriteTransaction(this.parentModel.context.collections);
853
+ const { context: context3, finalize } = await this.parentModel.context.commandContext(transaction);
854
+ const result = await command(context3, ...args);
855
+ const changes = await finalize();
856
+ const events = [];
857
+ for (const change of changes) {
858
+ await this.context.applyChange(transaction, change, events);
859
+ }
860
+ this.uncommitedChanges.push(...changes);
861
+ events.forEach((change) => this.changes$.next(change));
862
+ return { changes, result };
863
+ }
864
+ getCollection(name) {
865
+ return this.parentModel.getCollection(name);
866
+ }
867
+ async applyChanges(changes) {
868
+ const proxyAdapter = await this.proxyAdapterPromise;
869
+ const transaction = proxyAdapter.readWriteTransaction(this.parentModel.context.collections);
870
+ await this.parentModel.applyChangesForTransaction(transaction, changes);
871
+ }
872
+ get context() {
873
+ return this.parentModel.context;
874
+ }
875
+ async commitChanges() {
876
+ this.parentModel.applyChanges(this.uncommitedChanges);
877
+ this.parentModel.rtc.changesExecuted(this.uncommitedChanges);
878
+ }
879
+ }
739
880
  // rtc/deserializeChanges.ts
740
881
  function deserializeChanges(changes, getCollection) {
741
882
  return changes.map((change) => {
@@ -807,10 +948,9 @@ class RTCClient {
807
948
  console.error("Max reconnect attempts reached. Giving up.");
808
949
  }
809
950
  }
810
- commandExecuted(command, changes) {
951
+ changesExecuted(changes) {
811
952
  return this.sendMessage({
812
- type: "command-executed",
813
- command,
953
+ type: "changes-executed",
814
954
  changes
815
955
  });
816
956
  }
@@ -874,6 +1014,7 @@ export {
874
1014
  collection,
875
1015
  boolean,
876
1016
  array,
1017
+ ArcSubModel,
877
1018
  ArcStringEnum,
878
1019
  ArcString,
879
1020
  ArcOptional,
@@ -1,3 +1,4 @@
1
1
  export * from "./model";
2
2
  export * from "./query-builder";
3
3
  export * from "./rtc";
4
+ export * from "./submodel";
@@ -1,16 +1,24 @@
1
1
  import { Subject } from "rxjs";
2
2
  import type { ArcCollectionAny, ArcIndexedCollectionAny } from "../collection";
3
3
  import type { CollectionChange } from "../collection/collection-change";
4
- import type { DBAdapterFactory } from "../collection/db";
4
+ import type { DatabaseAdapter, DBAdapterFactory, ReadWriteTransaction } from "../collection/db";
5
5
  import type { CommandsClient } from "../context/commands";
6
6
  import { type ArcContextAny, type ArcContextWithCommandsAny } from "../context/context";
7
7
  import type { ArcQuery } from "../context/query";
8
8
  import type { QueryFactoryFunction } from "./query-builder";
9
- import type { RealTimeCommunicationAdapterFactory } from "./rtc";
10
- export declare class ArcModel<C extends ArcContextWithCommandsAny> {
9
+ import type { RealTimeCommunicationAdapter, RealTimeCommunicationAdapterFactory } from "./rtc";
10
+ export interface IArcModel<C extends ArcContextWithCommandsAny> {
11
11
  readonly context: C;
12
- private rtc;
13
- private dbAdapterPromise;
12
+ changes$: Subject<CollectionChange>;
13
+ query(queryFactory: QueryFactoryFunction<C>): ArcQuery;
14
+ commands(): CommandsClient<C["commands"]>;
15
+ getCollection(name: string): ArcCollectionAny | ArcIndexedCollectionAny;
16
+ applyChanges(changes: CollectionChange[]): Promise<void>;
17
+ }
18
+ export declare class ArcModel<C extends ArcContextWithCommandsAny> implements IArcModel<C> {
19
+ readonly context: C;
20
+ rtc: RealTimeCommunicationAdapter;
21
+ dbAdapterPromise: Promise<DatabaseAdapter>;
14
22
  changes$: Subject<CollectionChange>;
15
23
  constructor(context: C, dbAdapterFactory: DBAdapterFactory, rtcAdapterFactory: RealTimeCommunicationAdapterFactory);
16
24
  query(queryFactory: QueryFactoryFunction<C>): ArcQuery;
@@ -20,7 +28,7 @@ export declare class ArcModel<C extends ArcContextWithCommandsAny> {
20
28
  changes: CollectionChange[];
21
29
  result: any;
22
30
  }>;
23
- private applyChangesForTransaction;
31
+ applyChangesForTransaction(transaction: ReadWriteTransaction, changes: CollectionChange[]): Promise<void>;
24
32
  private notifyChange;
25
33
  applyChanges(changes: CollectionChange[]): Promise<void>;
26
34
  getCollection(name: string): ArcCollectionAny | ArcIndexedCollectionAny;
@@ -1,6 +1,6 @@
1
1
  import type { CollectionChange } from "../collection/collection-change";
2
2
  import type { ArcModelAny } from "./model";
3
3
  export interface RealTimeCommunicationAdapter {
4
- commandExecuted(command: string, changes: CollectionChange[]): void;
4
+ changesExecuted(changes: CollectionChange[]): void;
5
5
  }
6
6
  export type RealTimeCommunicationAdapterFactory = (model: ArcModelAny) => RealTimeCommunicationAdapter;
@@ -0,0 +1,23 @@
1
+ import { Subject } from "rxjs";
2
+ import type { ArcCollectionAny, ArcIndexedCollectionAny } from "../collection";
3
+ import type { CollectionChange } from "../collection/collection-change";
4
+ import type { CommandsClient } from "../context/commands";
5
+ import type { ArcContextWithCommandsAny } from "../context/context";
6
+ import type { ArcQuery } from "../context/query";
7
+ import { ArcModel, type IArcModel } from "./model";
8
+ import type { QueryFactoryFunction } from "./query-builder";
9
+ export declare class ArcSubModel<C extends ArcContextWithCommandsAny> implements IArcModel<C> {
10
+ private parentModel;
11
+ changes$: Subject<CollectionChange>;
12
+ private proxyAdapterPromise;
13
+ private uncommitedChanges;
14
+ constructor(parentModel: ArcModel<C>);
15
+ query(queryFactory: QueryFactoryFunction<C>): ArcQuery;
16
+ private runQuery;
17
+ commands(): CommandsClient<C["commands"]>;
18
+ private executeCommand;
19
+ getCollection(name: string): ArcCollectionAny | ArcIndexedCollectionAny;
20
+ applyChanges(changes: CollectionChange[]): Promise<void>;
21
+ get context(): C;
22
+ commitChanges(): Promise<void>;
23
+ }
@@ -3,8 +3,7 @@ export type MessageClientToHost = {
3
3
  type: "sync";
4
4
  lastDate: string | null;
5
5
  } | {
6
- type: "command-executed";
7
- command: string;
6
+ type: "changes-executed";
8
7
  changes: CollectionChange[];
9
8
  };
10
9
  export type MessageHostToClient = {
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
7
- "version": "0.0.11",
7
+ "version": "0.0.12",
8
8
  "private": false,
9
9
  "author": "Przemysław Krasiński [arcote.tech]",
10
10
  "description": "Arc is a framework designed to align code closely with business logic, streamlining development and enhancing productivity.",
@@ -13,7 +13,6 @@
13
13
  "build:declaration": "tsc --emitDeclarationOnly --project tsconfig.types.json",
14
14
  "postbuild": "rimraf tsconfig.types.tsbuildinfo",
15
15
  "type-check": "tsc",
16
- "publish": "bun run build && npm publish --access=public",
17
16
  "dev": "nodemon --ignore dist -e ts,tsx --exec 'bun run build'"
18
17
  },
19
18
  "dependencies": {