@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.
- package/dist/collection/collection.d.ts +3 -1
- package/dist/collection/db.d.ts +1 -1
- package/dist/collection/in-memory-db-proxy.d.ts +10 -0
- package/dist/collection/queries/abstract-collection-query.d.ts +1 -1
- package/dist/collection/queries/one-item.d.ts +1 -1
- package/dist/index.js +145 -4
- package/dist/model/index.d.ts +1 -0
- package/dist/model/model.d.ts +14 -6
- package/dist/model/rtc.d.ts +1 -1
- package/dist/model/submodel.d.ts +23 -0
- package/dist/rtc/messages.d.ts +1 -2
- package/package.json +1 -2
|
@@ -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<
|
|
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>;
|
package/dist/collection/db.d.ts
CHANGED
|
@@ -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"]
|
|
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.
|
|
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
|
-
|
|
951
|
+
changesExecuted(changes) {
|
|
811
952
|
return this.sendMessage({
|
|
812
|
-
type: "
|
|
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,
|
package/dist/model/index.d.ts
CHANGED
package/dist/model/model.d.ts
CHANGED
|
@@ -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
|
|
9
|
+
import type { RealTimeCommunicationAdapter, RealTimeCommunicationAdapterFactory } from "./rtc";
|
|
10
|
+
export interface IArcModel<C extends ArcContextWithCommandsAny> {
|
|
11
11
|
readonly context: C;
|
|
12
|
-
|
|
13
|
-
|
|
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
|
-
|
|
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;
|
package/dist/model/rtc.d.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
+
}
|
package/dist/rtc/messages.d.ts
CHANGED
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.
|
|
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": {
|