@codecks/fetch 0.0.2 → 0.0.4

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/README.md CHANGED
@@ -3,9 +3,9 @@
3
3
  ## Usage
4
4
 
5
5
  ```ts
6
- import {buildFetchers} from "@codecks/fetch";
6
+ import {buildFetchersWithSimpleLoader} from "@codecks/fetch";
7
7
 
8
- const {fetchFromRoot, fetchInstance} = buildFetchers({
8
+ const {fetchFromRoot, fetchInstance} = buildFetchersWithSimpleLoader({
9
9
  baseUrl: "https://api.codecks.io/",
10
10
  subdomain: "my-org",
11
11
  });
package/dist/index.d.ts CHANGED
@@ -2716,7 +2716,7 @@ declare const modelMap: {
2716
2716
  };
2717
2717
  //#endregion
2718
2718
  //#region src/has-many-filter-type.d.ts
2719
- type ModelMap$2 = Record<string, AnyDesc>;
2719
+ type ModelMap$3 = Record<string, AnyDesc>;
2720
2720
  type OneOrArray<T> = T | T[];
2721
2721
  type NormalAndNegatedKeys<T> = T & { [K in keyof T & string as `!${K}`]: T[K] };
2722
2722
  type OrderString<T extends string> = `${T}` | `-${T}`;
@@ -2745,20 +2745,20 @@ type Operators<T> = {
2745
2745
  value: El[];
2746
2746
  } : never);
2747
2747
  type FieldQuery<T extends AnyDesc> = { [K in keyof T["fields"]]?: null | OneOrArray<InferFieldType<T["fields"][K]>> | Operators<InferFieldType<T["fields"][K]>> };
2748
- type RelationQuery<T extends AnyDesc, TMap extends ModelMap$2> = NormalAndNegatedKeys<{ [K in keyof T["relations"]]?: SimpleFilter<TMap[T["relations"][K]["relName"]], TMap> }>;
2749
- type SimpleFilter<T extends AnyDesc, TMap extends ModelMap$2> = FieldQuery<T> | RelationQuery<T, TMap>;
2750
- type Filter<T extends AnyDesc, TMap extends ModelMap$2> = SimpleFilter<T, TMap> & {
2748
+ type RelationQuery<T extends AnyDesc, TMap extends ModelMap$3> = NormalAndNegatedKeys<{ [K in keyof T["relations"]]?: SimpleFilter<TMap[T["relations"][K]["relName"]], TMap> }>;
2749
+ type SimpleFilter<T extends AnyDesc, TMap extends ModelMap$3> = FieldQuery<T> | RelationQuery<T, TMap>;
2750
+ type Filter<T extends AnyDesc, TMap extends ModelMap$3> = SimpleFilter<T, TMap> & {
2751
2751
  $and?: Filter<T, TMap>[];
2752
2752
  $or?: Filter<T, TMap>[];
2753
2753
  };
2754
2754
  //#endregion
2755
2755
  //#region src/query-type.d.ts
2756
- type ModelMap$1 = Record<string, AnyDesc>;
2757
- interface ModelQuery<T extends AnyDesc, TMap extends ModelMap$1> {
2756
+ type ModelMap$2 = Record<string, AnyDesc>;
2757
+ interface ModelQuery<T extends AnyDesc, TMap extends ModelMap$2> {
2758
2758
  fields?: (keyof T["fields"])[];
2759
2759
  relations?: RelQuery<T, TMap>;
2760
2760
  }
2761
- interface SimpleHasManyQuery<T extends AnyDesc, TMap extends ModelMap$1> extends ModelQuery<T, TMap> {
2761
+ interface SimpleHasManyQuery<T extends AnyDesc, TMap extends ModelMap$2> extends ModelQuery<T, TMap> {
2762
2762
  type?: "query";
2763
2763
  orderBy?: Order<T>;
2764
2764
  limit?: number;
@@ -2766,20 +2766,20 @@ interface SimpleHasManyQuery<T extends AnyDesc, TMap extends ModelMap$1> extends
2766
2766
  filter?: Filter<T, TMap>;
2767
2767
  as?: string;
2768
2768
  }
2769
- interface CountOrExistQuery<T extends AnyDesc, TMap extends ModelMap$1> {
2769
+ interface CountOrExistQuery<T extends AnyDesc, TMap extends ModelMap$2> {
2770
2770
  type: "count" | "exists";
2771
2771
  filter?: Filter<T, TMap>;
2772
2772
  as: string;
2773
2773
  fields?: never;
2774
2774
  relations?: never;
2775
2775
  }
2776
- interface FirstOrLastQuery<T extends AnyDesc, TMap extends ModelMap$1> extends ModelQuery<T, TMap> {
2776
+ interface FirstOrLastQuery<T extends AnyDesc, TMap extends ModelMap$2> extends ModelQuery<T, TMap> {
2777
2777
  type: "first";
2778
2778
  filter?: Filter<T, TMap>;
2779
2779
  as: string;
2780
2780
  orderBy: Order<T>;
2781
2781
  }
2782
- type HasManyQuery<T extends AnyDesc, TMap extends ModelMap$1> = SimpleHasManyQuery<T, TMap> | CountOrExistQuery<T, TMap> | FirstOrLastQuery<T, TMap>;
2782
+ type HasManyQuery<T extends AnyDesc, TMap extends ModelMap$2> = SimpleHasManyQuery<T, TMap> | CountOrExistQuery<T, TMap> | FirstOrLastQuery<T, TMap>;
2783
2783
  type AbstractHasManyQuery = (ModelQuery<any, any> & {
2784
2784
  type?: "query" | "first";
2785
2785
  as?: string;
@@ -2787,57 +2787,57 @@ type AbstractHasManyQuery = (ModelQuery<any, any> & {
2787
2787
  type: "count" | "exists";
2788
2788
  as: string;
2789
2789
  };
2790
- type HasManyQueryWithAs<T extends AnyDesc, TMap extends ModelMap$1> = HasManyQuery<T, TMap> & {
2790
+ type HasManyQueryWithAs<T extends AnyDesc, TMap extends ModelMap$2> = HasManyQuery<T, TMap> & {
2791
2791
  as: string;
2792
2792
  };
2793
- type HasManyRelQueryEntry<T extends AnyDesc, TMap extends ModelMap$1, K extends keyof ExtractHasMany<T, TMap>> = HasManyQuery<TMap[T["relations"][K]["relName"]], TMap> | HasManyQueryWithAs<TMap[T["relations"][K]["relName"]], TMap>[];
2794
- type RelQueryEntry<T extends AnyDesc, TMap extends ModelMap$1, K extends keyof T["relations"]> = K extends keyof ExtractHasMany<T, TMap> ? HasManyRelQueryEntry<T, TMap, K> : ModelQuery<TMap[T["relations"][K]["relName"]], TMap>;
2793
+ type HasManyRelQueryEntry<T extends AnyDesc, TMap extends ModelMap$2, K extends keyof ExtractHasMany<T, TMap>> = HasManyQuery<TMap[T["relations"][K]["relName"]], TMap> | HasManyQueryWithAs<TMap[T["relations"][K]["relName"]], TMap>[];
2794
+ type RelQueryEntry<T extends AnyDesc, TMap extends ModelMap$2, K extends keyof T["relations"]> = K extends keyof ExtractHasMany<T, TMap> ? HasManyRelQueryEntry<T, TMap, K> : ModelQuery<TMap[T["relations"][K]["relName"]], TMap>;
2795
2795
  /**
2796
2796
  * examples for account:
2797
2797
  * {disabledBy: {fields: []}} // belongst
2798
2798
  * {cards: {fields: []}}
2799
2799
  * {cards: [{as: "myCards", fields: []}]}
2800
2800
  */
2801
- type RelQuery<T extends AnyDesc, TMap extends ModelMap$1> = { [K in keyof T["relations"]]?: RelQueryEntry<T, TMap, K> };
2801
+ type RelQuery<T extends AnyDesc, TMap extends ModelMap$2> = { [K in keyof T["relations"]]?: RelQueryEntry<T, TMap, K> };
2802
2802
  type EnsureModelQuery<T> = T extends ModelQuery<any, any> ? T : never;
2803
2803
  type EnsureHasManyQuery<T> = T extends AbstractHasManyQuery ? T : never;
2804
- type EnrichBelongsTo<M extends AnyDesc, TMap extends ModelMap$1> = FilterNeverKeys<{ [K in keyof M["relations"]]: M["relations"][K] extends RelationEntry<any, infer Opts> ? Opts extends BelongsToOpts<infer TFk> ? {
2804
+ type EnrichBelongsTo<M extends AnyDesc, TMap extends ModelMap$2> = FilterNeverKeys<{ [K in keyof M["relations"]]: M["relations"][K] extends RelationEntry<any, infer Opts> ? Opts extends BelongsToOpts<infer TFk> ? {
2805
2805
  model: TMap[M["relations"][K]["relName"]];
2806
2806
  fk: TFk;
2807
2807
  field: M["fields"][TFk] extends TypedField<"belongsTo", infer FieldType, infer FieldOpts> ? {
2808
2808
  type: FieldType;
2809
2809
  } & FieldOpts : never;
2810
2810
  } : never : never }>;
2811
- type ExtractHasMany<M extends AnyDesc, TMap extends ModelMap$1> = FilterNeverKeys<{ [K in keyof M["relations"]]: M["relations"][K] extends RelationEntry<infer RelName, {
2811
+ type ExtractHasMany<M extends AnyDesc, TMap extends ModelMap$2> = FilterNeverKeys<{ [K in keyof M["relations"]]: M["relations"][K] extends RelationEntry<infer RelName, {
2812
2812
  type: "hasMany";
2813
2813
  }> ? {
2814
2814
  model: TMap[RelName];
2815
2815
  } : never }>;
2816
- type ExtractHasOne<M extends AnyDesc, TMap extends ModelMap$1> = FilterNeverKeys<{ [K in keyof M["relations"]]: M["relations"][K] extends RelationEntry<infer RelName, {
2816
+ type ExtractHasOne<M extends AnyDesc, TMap extends ModelMap$2> = FilterNeverKeys<{ [K in keyof M["relations"]]: M["relations"][K] extends RelationEntry<infer RelName, {
2817
2817
  type: "hasOne";
2818
2818
  }> ? {
2819
2819
  model: TMap[RelName];
2820
2820
  } : never }>;
2821
- type InferModelQuery<M extends AnyDesc, Q extends ModelQuery<M, TMap>, TMap extends ModelMap$1> = (Q["fields"] extends (keyof M["fields"])[] ? { [K in Q["fields"][number]]: InferFieldType<M["fields"][K]> } : {}) & (Q["relations"] extends RelQuery<M, TMap> ? InferRelQuery<M, Q["relations"], TMap> : {}) & { [K in M["keys"][number] & string]: InferFieldType<M["fields"][K]> } & {
2821
+ type InferModelQuery<M extends AnyDesc, Q extends ModelQuery<M, TMap>, TMap extends ModelMap$2> = (Q["fields"] extends (keyof M["fields"])[] ? { [K in Q["fields"][number]]: InferFieldType<M["fields"][K]> } : {}) & (Q["relations"] extends RelQuery<M, TMap> ? InferRelQuery<M, Q["relations"], TMap> : {}) & { [K in M["keys"][number] & string]: InferFieldType<M["fields"][K]> } & {
2822
2822
  "~model": M["name"];
2823
2823
  "~key": string;
2824
2824
  };
2825
2825
  type IsOptional<T, Test> = Test extends true ? T | null : T;
2826
2826
  type EmptyObjIfNever<T> = [T] extends [never] ? {} : T;
2827
- type ExtractRelQueryArray<M extends AnyDesc, TMap extends ModelMap$1, Q extends RelQuery<M, TMap>> = { [K in keyof Q]: K extends keyof ExtractHasMany<M, TMap> ? Q[K] extends HasManyQueryWithAs<any, any>[] ? { [Item in Q[K][number] as Item["as"]]: InferHasMany<ExtractHasMany<M, TMap>[K]["model"], TMap, Item> } : never : never }[keyof Q];
2828
- type InferHasMany<M extends AnyDesc, TMap extends ModelMap$1, QM extends HasManyQuery<M, TMap>> = QM extends {
2827
+ type ExtractRelQueryArray<M extends AnyDesc, TMap extends ModelMap$2, Q extends RelQuery<M, TMap>> = { [K in keyof Q]: K extends keyof ExtractHasMany<M, TMap> ? Q[K] extends HasManyQueryWithAs<any, any>[] ? { [Item in Q[K][number] as Item["as"]]: InferHasMany<ExtractHasMany<M, TMap>[K]["model"], TMap, Item> } : never : never }[keyof Q];
2828
+ type InferHasMany<M extends AnyDesc, TMap extends ModelMap$2, QM extends HasManyQuery<M, TMap>> = QM extends {
2829
2829
  type: "count";
2830
2830
  } ? number : QM extends {
2831
2831
  type: "exist";
2832
2832
  } ? boolean : QM extends {
2833
2833
  type: "first";
2834
2834
  } ? InferModelQuery<M, EnsureModelQuery<QM>, TMap> | null : InferModelQuery<M, EnsureModelQuery<QM>, TMap>[];
2835
- type InferRelEntry<M extends AnyDesc, TMap extends ModelMap$1, Q extends RelQuery<any, any>, K extends keyof Q> = K extends keyof EnrichBelongsTo<M, TMap> ? IsOptional<InferModelQuery<EnrichBelongsTo<M, TMap>[K]["model"], EnsureModelQuery<Q[K]>, TMap>, EnrichBelongsTo<M, TMap>[K]["field"]["optional"]> : K extends keyof ExtractHasMany<M, TMap> ? InferHasMany<ExtractHasMany<M, TMap>[K]["model"], TMap, EnsureHasManyQuery<Q[K]>> : K extends keyof ExtractHasOne<M, TMap> ? InferModelQuery<ExtractHasOne<M, TMap>[K]["model"], EnsureModelQuery<Q[K]>, TMap> : never;
2835
+ type InferRelEntry<M extends AnyDesc, TMap extends ModelMap$2, Q extends RelQuery<any, any>, K extends keyof Q> = K extends keyof EnrichBelongsTo<M, TMap> ? IsOptional<InferModelQuery<EnrichBelongsTo<M, TMap>[K]["model"], EnsureModelQuery<Q[K]>, TMap>, EnrichBelongsTo<M, TMap>[K]["field"]["optional"]> : K extends keyof ExtractHasMany<M, TMap> ? InferHasMany<ExtractHasMany<M, TMap>[K]["model"], TMap, EnsureHasManyQuery<Q[K]>> : K extends keyof ExtractHasOne<M, TMap> ? InferModelQuery<ExtractHasOne<M, TMap>[K]["model"], EnsureModelQuery<Q[K]>, TMap> : never;
2836
2836
  type InferKeyName<Q extends RelQuery<any, any>, K extends keyof Q> = Q[K] extends Array<any> ? never : Q[K] extends {
2837
2837
  as: string;
2838
2838
  } ? K extends keyof ExtractHasMany<any, any> ? Q[K]["as"] : K : K;
2839
- type InferRelQuery<M extends AnyDesc, Q extends RelQuery<M, TMap>, TMap extends ModelMap$1> = EmptyObjIfNever<ExtractRelQueryArray<M, TMap, Q>> & EmptyObjIfNever<{ [K in keyof Q as InferKeyName<Q, K>]: InferRelEntry<M, TMap, Q, K> }>;
2840
- type Instance<M extends keyof ModelMap$1> = {
2839
+ type InferRelQuery<M extends AnyDesc, Q extends RelQuery<M, TMap>, TMap extends ModelMap$2> = EmptyObjIfNever<ExtractRelQueryArray<M, TMap, Q>> & EmptyObjIfNever<{ [K in keyof Q as InferKeyName<Q, K>]: InferRelEntry<M, TMap, Q, K> }>;
2840
+ type Instance<M extends keyof ModelMap$2> = {
2841
2841
  "~model": M;
2842
2842
  "~key": string;
2843
2843
  };
@@ -2873,16 +2873,13 @@ declare const _rootDesc: ModelDesc<"_root", {}, {
2873
2873
  }>;
2874
2874
  }, []>;
2875
2875
  //#endregion
2876
- //#region src/index.d.ts
2877
- type ModelMap = typeof modelMap;
2878
- type Fetchers = {
2879
- fetchFromRoot: <const Q extends RelQuery<typeof _rootDesc, ModelMap>>(q: Q) => Promise<InferRelQuery<typeof _rootDesc, Q, ModelMap>>;
2880
- fetchFromInstance: <M extends keyof ModelMap, const Q extends ModelQuery<ModelMap[M], ModelMap>>(instance: Instance<M>, q: Q) => Promise<InferModelQuery<ModelMap[M], Q, ModelMap>>;
2881
- fetchInstance: <K extends keyof ModelMap, const Q extends RelQuery<ModelMap[K], ModelMap>>(model: K, id: string, q: Q) => Promise<InferModelQuery<ModelMap[K], Q, ModelMap>>;
2882
- fetchInstances: <K extends keyof ModelMap, Id extends string, const Q extends RelQuery<ModelMap[K], ModelMap>>(model: K, id: Id[], q: Q) => Promise<Record<Id, InferModelQuery<ModelMap[K], Q, ModelMap>>>;
2876
+ //#region src/loader-utils.d.ts
2877
+ type ModelMap$1 = typeof modelMap;
2878
+ type DataLoader = {
2879
+ fetchModel: <K extends keyof ModelMap$1, Id extends string, const Q extends ModelQuery<ModelMap$1[K], ModelMap$1>>(model: K, id: Id[], q: Q) => Promise<Record<Id, InferModelQuery<ModelMap$1[K], Q, ModelMap$1>>>;
2883
2880
  };
2884
2881
  type FetchFunction = (url: string, init?: RequestInit) => Promise<Response>;
2885
- type FetcherOptions = {
2882
+ type FetchOptions = {
2886
2883
  fetch?: FetchFunction;
2887
2884
  accessToken?: string;
2888
2885
  subdomain?: string;
@@ -2890,6 +2887,19 @@ type FetcherOptions = {
2890
2887
  headers?: Record<string, string>;
2891
2888
  timeout?: number;
2892
2889
  };
2893
- declare const buildFetchers: (opts?: FetcherOptions) => Fetchers;
2894
2890
  //#endregion
2895
- export { buildFetchers };
2891
+ //#region src/simple-loader.d.ts
2892
+ type SimpleLoaderOptions = FetchOptions;
2893
+ //#endregion
2894
+ //#region src/index.d.ts
2895
+ type ModelMap = typeof modelMap;
2896
+ type Fetchers = {
2897
+ fetchFromRoot: <const Q extends RelQuery<typeof _rootDesc, ModelMap>>(q: Q) => Promise<InferRelQuery<typeof _rootDesc, Q, ModelMap>>;
2898
+ fetchFromInstance: <M extends keyof ModelMap, const Q extends ModelQuery<ModelMap[M], ModelMap>>(instance: Instance<M>, q: Q) => Promise<InferModelQuery<ModelMap[M], Q, ModelMap>>;
2899
+ fetchInstance: <K extends keyof ModelMap, const Q extends ModelQuery<ModelMap[K], ModelMap>>(model: K, id: string, q: Q) => Promise<InferModelQuery<ModelMap[K], Q, ModelMap>>;
2900
+ fetchInstances: <K extends keyof ModelMap, Id extends string, const Q extends ModelQuery<ModelMap[K], ModelMap>>(model: K, id: Id[], q: Q) => Promise<Record<Id, InferModelQuery<ModelMap[K], Q, ModelMap>>>;
2901
+ };
2902
+ declare const buildFetchersWithSimpleLoader: (opts: SimpleLoaderOptions) => Fetchers;
2903
+ declare const buildFetchers: (loader: DataLoader) => Fetchers;
2904
+ //#endregion
2905
+ export { buildFetchers, buildFetchersWithSimpleLoader };
package/dist/index.js CHANGED
@@ -1,13 +1,3 @@
1
- //#region src/collection-utils.ts
2
- const ensureMapValue = (map, key, fallback) => {
3
- const exist = map.get(key);
4
- if (exist) return exist;
5
- const newValue = fallback();
6
- map.set(key, newValue);
7
- return newValue;
8
- };
9
-
10
- //#endregion
11
1
  //#region src/models/_desc.ts
12
2
  const makeModel = (opts) => {
13
3
  return opts;
@@ -38,58 +28,6 @@ const _rootDesc = makeModel({
38
28
  keys: []
39
29
  });
40
30
 
41
- //#endregion
42
- //#region src/model-pool.ts
43
- const ROOT_ID = "";
44
- const dateStrToDay = (dateAsStr) => {
45
- const parts = dateAsStr.split("-");
46
- return {
47
- year: parseInt(parts[0], 10),
48
- month: parseInt(parts[1], 10),
49
- day: parseInt(parts[2], 10)
50
- };
51
- };
52
- const parseField = (v, field) => {
53
- if (!field) return v;
54
- switch (field.type) {
55
- case "date": return new Date(v);
56
- case "day": return dateStrToDay(v);
57
- default: return v;
58
- }
59
- };
60
- const transformData = (desc, data) => {
61
- return Object.fromEntries(Object.entries(data).map(([k, v]) => [k, parseField(v, desc.fields[k])]));
62
- };
63
- var ModelPool = class {
64
- data = new Map();
65
- modelMap;
66
- constructor(modelMap$1) {
67
- this.modelMap = modelMap$1;
68
- }
69
- addModelInstance(model, id$1, _data) {
70
- const instanceById = ensureMapValue(this.data, model, () => new Map());
71
- const exists = instanceById.get(id$1);
72
- const desc = this.modelMap[model];
73
- if (!desc) throw new Error(`Unknown model: ${model}`);
74
- const data = transformData(desc, _data);
75
- if (exists) Object.assign(exists, data);
76
- else instanceById.set(id$1, data);
77
- }
78
- add(data) {
79
- Object.entries(data).forEach(([modelName, payload]) => {
80
- if (modelName === _rootDesc.name) this.addModelInstance(modelName, ROOT_ID, payload);
81
- else Object.entries(payload).forEach(([id$1, payload$1]) => {
82
- this.addModelInstance(modelName, id$1, payload$1);
83
- });
84
- });
85
- }
86
- get(model, id$1) {
87
- const instances = this.data.get(model);
88
- if (!instances) return null;
89
- return instances.get(id$1) ?? null;
90
- }
91
- };
92
-
93
31
  //#endregion
94
32
  //#region src/models/_fields.ts
95
33
  const id = () => {
@@ -3013,6 +2951,84 @@ const modelMap = {
3013
2951
  workflowItem: workflowItemDesc
3014
2952
  };
3015
2953
 
2954
+ //#endregion
2955
+ //#region src/loader-utils.ts
2956
+ const configuredFetch = async (opts, url, init = {}) => {
2957
+ const fetchImpl = opts.fetch || globalThis.fetch;
2958
+ const headers = new Headers(init.headers);
2959
+ if (opts.accessToken) headers.set("X-Auth-Token", opts.accessToken);
2960
+ if (opts.subdomain) headers.set("X-Account", opts.subdomain);
2961
+ if (opts.headers) Object.entries(opts.headers).forEach(([key, value]) => {
2962
+ headers.set(key, value);
2963
+ });
2964
+ const fullUrl = opts.baseUrl ? `${opts.baseUrl}${url}` : url;
2965
+ return fetchImpl(fullUrl, {
2966
+ ...init,
2967
+ headers
2968
+ });
2969
+ };
2970
+
2971
+ //#endregion
2972
+ //#region src/collection-utils.ts
2973
+ const ensureMapValue = (map, key, fallback) => {
2974
+ const exist = map.get(key);
2975
+ if (exist) return exist;
2976
+ const newValue = fallback();
2977
+ map.set(key, newValue);
2978
+ return newValue;
2979
+ };
2980
+
2981
+ //#endregion
2982
+ //#region src/model-pool.ts
2983
+ const ROOT_ID = "";
2984
+ const dateStrToDay = (dateAsStr) => {
2985
+ const parts = dateAsStr.split("-");
2986
+ return {
2987
+ year: parseInt(parts[0], 10),
2988
+ month: parseInt(parts[1], 10),
2989
+ day: parseInt(parts[2], 10)
2990
+ };
2991
+ };
2992
+ const parseField = (v, field) => {
2993
+ if (!field) return v;
2994
+ switch (field.type) {
2995
+ case "date": return new Date(v);
2996
+ case "day": return dateStrToDay(v);
2997
+ default: return v;
2998
+ }
2999
+ };
3000
+ const transformData = (desc, data) => {
3001
+ return Object.fromEntries(Object.entries(data).map(([k, v]) => [k, parseField(v, desc.fields[k])]));
3002
+ };
3003
+ var ModelPool = class {
3004
+ data = new Map();
3005
+ modelMap;
3006
+ constructor(modelMap$1) {
3007
+ this.modelMap = modelMap$1;
3008
+ }
3009
+ addModelInstance(model, id$1, _data) {
3010
+ const instanceById = ensureMapValue(this.data, model, () => new Map());
3011
+ const exists = instanceById.get(id$1);
3012
+ const desc = this.modelMap[model];
3013
+ if (!desc) throw new Error(`Unknown model: ${model}`);
3014
+ const data = transformData(desc, _data);
3015
+ if (exists) Object.assign(exists, data);
3016
+ else instanceById.set(id$1, data);
3017
+ }
3018
+ add(data) {
3019
+ Object.entries(data).forEach(([modelName, payload]) => {
3020
+ if (modelName === _rootDesc.name) this.addModelInstance(modelName, ROOT_ID, payload);
3021
+ else Object.entries(payload).forEach(([id$1, payload$1]) => {
3022
+ this.addModelInstance(modelName, id$1, payload$1);
3023
+ });
3024
+ });
3025
+ }
3026
+ get(model, id$1) {
3027
+ const instances = this.data.get(model);
3028
+ return instances?.get(id$1) ?? null;
3029
+ }
3030
+ };
3031
+
3016
3032
  //#endregion
3017
3033
  //#region src/query-helpers.ts
3018
3034
  const getRelKey = (r, k) => {
@@ -3046,11 +3062,11 @@ const serializeModel = (q, modelDesc) => {
3046
3062
  rels.forEach((r) => {
3047
3063
  switch (r?.type) {
3048
3064
  case "count": {
3049
- list.push(`count(${getRelKey(r, k)})`);
3065
+ list.push(`count:${getRelKey(r, k)}`);
3050
3066
  break;
3051
3067
  }
3052
3068
  case "exists": {
3053
- list.push(`exists(${getRelKey(r, k)})`);
3069
+ list.push(`exists:${getRelKey(r, k)}`);
3054
3070
  break;
3055
3071
  }
3056
3072
  default:
@@ -3062,41 +3078,26 @@ const serializeModel = (q, modelDesc) => {
3062
3078
  if (Object.keys(relObj).length) list.push(relObj);
3063
3079
  return list;
3064
3080
  };
3065
- const serializeRelations = (q, modelDesc) => {
3066
- return Object.fromEntries(Object.entries(q).map(([k, v]) => [k, serializeModel(v, modelDesc.relations[k])]));
3067
- };
3068
- const serializeRootQuery = (q) => {
3069
- return { _root: [serializeRelations(q, _rootDesc)] };
3070
- };
3071
3081
  const serializeInstanceQuery = (q, instances, modelMap$1) => {
3072
3082
  return Object.fromEntries(instances.map((instance) => {
3073
3083
  const name = instance["~model"];
3074
- return [`${name}(${instance["~key"]})`, serializeModel(q, modelMap$1[name])];
3084
+ const getKey = () => {
3085
+ if (name === "_root") return "_root";
3086
+ return `${name}(${instance["~key"]})`;
3087
+ };
3088
+ return [getKey(), serializeModel(q, modelMap$1[name])];
3075
3089
  }));
3076
3090
  };
3077
3091
 
3078
3092
  //#endregion
3079
3093
  //#region src/reconcile-query.ts
3080
- const reconcileRootQuery = (query, response, pool) => {
3081
- const result = {};
3082
- const responsePart = response._root;
3083
- for (const [relName, modelFields] of Object.entries(query)) {
3084
- const relDesc = _rootDesc.relations[relName];
3085
- const id$1 = responsePart[relName];
3086
- if (!id$1) {
3087
- result[relName] = null;
3088
- continue;
3089
- } else result[relName] = reconcileInstanceQuery(modelFields, response, modelMap[relDesc.relName], `${id$1}`, pool);
3090
- }
3091
- return result;
3092
- };
3093
- const reconcileInstanceQuery = (query, response, instanceModel, key, pool) => {
3094
- const instance = pool.get(instanceModel.name, key);
3094
+ const reconcileInstanceQuery = (query, response, instanceModel, key, store) => {
3095
+ const instance = store.get(instanceModel.name, key);
3095
3096
  if (!instance) {
3096
3097
  console.warn(`no instance found in pool: [${instanceModel.name}, ${key}]`);
3097
3098
  return null;
3098
3099
  }
3099
- const result = {
3100
+ const result = instanceModel.name === "_root" ? {} : {
3100
3101
  "~model": instanceModel.name,
3101
3102
  "~key": key
3102
3103
  };
@@ -3112,11 +3113,11 @@ const reconcileInstanceQuery = (query, response, instanceModel, key, pool) => {
3112
3113
  switch (opts.type) {
3113
3114
  case "belongsTo":
3114
3115
  result[opts.fk] = instance[relName];
3115
- result[relName] = opts.fk ? reconcileInstanceQuery(relEntry, response, relModel, `${instance[relName]}`, pool) : null;
3116
+ result[relName] = opts.fk ? reconcileInstanceQuery(relEntry, response, relModel, `${instance[relName]}`, store) : null;
3116
3117
  break;
3117
3118
  case "hasOne":
3118
3119
  result[`~${relName}`] = instance[relName];
3119
- result[relName] = reconcileInstanceQuery(relEntry, response, relModel, `${instance[relName]}`, pool);
3120
+ result[relName] = reconcileInstanceQuery(relEntry, response, relModel, `${instance[relName]}`, store);
3120
3121
  break;
3121
3122
  case "hasMany":
3122
3123
  const asName = relEntry.as ?? relName;
@@ -3124,20 +3125,20 @@ const reconcileInstanceQuery = (query, response, instanceModel, key, pool) => {
3124
3125
  const val = instance[relKey];
3125
3126
  switch (relEntry.type) {
3126
3127
  case "count": {
3127
- result[asName] = instance[`count(${relKey})`];
3128
+ result[asName] = instance[`count:${relKey}`];
3128
3129
  break;
3129
3130
  }
3130
3131
  case "exists": {
3131
- result[asName] = instance[`exists(${relKey})`];
3132
+ result[asName] = instance[`exists:${relKey}`];
3132
3133
  break;
3133
3134
  }
3134
3135
  case "first":
3135
3136
  result[`~${asName}`] = val;
3136
- result[asName] = reconcileInstanceQuery(relEntry, response, relModel, `${val}`, pool);
3137
+ result[asName] = reconcileInstanceQuery(relEntry, response, relModel, `${val}`, store);
3137
3138
  break;
3138
3139
  default: {
3139
3140
  result[`~${asName}`] = val;
3140
- result[asName] = val.map((id$1) => reconcileInstanceQuery(relEntry, response, relModel, `${id$1}`, pool));
3141
+ result[asName] = val.map((id$1) => reconcileInstanceQuery(relEntry, response, relModel, `${id$1}`, store));
3141
3142
  }
3142
3143
  }
3143
3144
  break;
@@ -3148,24 +3149,10 @@ const reconcileInstanceQuery = (query, response, instanceModel, key, pool) => {
3148
3149
  };
3149
3150
 
3150
3151
  //#endregion
3151
- //#region src/index.ts
3152
- const buildFetchers = (opts = {}) => {
3153
- const fetchImpl = opts.fetch || globalThis.fetch;
3154
- const configuredFetch = async (url, init = {}) => {
3155
- const headers = new Headers(init.headers);
3156
- if (opts.accessToken) headers.set("X-Auth-Token", opts.accessToken);
3157
- if (opts.subdomain) headers.set("X-Account", opts.subdomain);
3158
- if (opts.headers) Object.entries(opts.headers).forEach(([key, value]) => {
3159
- headers.set(key, value);
3160
- });
3161
- const fullUrl = opts.baseUrl ? `${opts.baseUrl}${url}` : url;
3162
- return fetchImpl(fullUrl, {
3163
- ...init,
3164
- headers
3165
- });
3166
- };
3152
+ //#region src/simple-loader.ts
3153
+ const createSimpleLoader = (opts = {}) => {
3167
3154
  const fetchWithQuery = async (query) => {
3168
- const response = await configuredFetch("", {
3155
+ const response = await configuredFetch(opts, "", {
3169
3156
  method: "POST",
3170
3157
  headers: { "Content-Type": "application/json" },
3171
3158
  body: JSON.stringify({ query })
@@ -3176,40 +3163,43 @@ const buildFetchers = (opts = {}) => {
3176
3163
  });
3177
3164
  return response;
3178
3165
  };
3179
- const _fetchSingleInstance = async (instance, q) => {
3180
- const response = await fetchWithQuery(serializeInstanceQuery(q, [instance], modelMap));
3166
+ return { fetchModel: async (model, ids, q) => {
3167
+ const modelDesc = modelMap[model];
3168
+ const instances = ids.map((id$1) => ({
3169
+ "~model": model,
3170
+ "~key": id$1
3171
+ }));
3172
+ const response = await fetchWithQuery(serializeInstanceQuery(q, instances, modelMap));
3181
3173
  const pool = new ModelPool(modelMap);
3182
3174
  pool.add(response);
3183
- return reconcileInstanceQuery(q, response, modelMap[instance["~model"]], instance["~key"], pool);
3184
- };
3175
+ return Object.fromEntries(ids.map((id$1) => [id$1, reconcileInstanceQuery(q, response, modelDesc, id$1, pool)]));
3176
+ } };
3177
+ };
3178
+
3179
+ //#endregion
3180
+ //#region src/index.ts
3181
+ const buildFetchersWithSimpleLoader = (opts) => {
3182
+ const loader = createSimpleLoader(opts);
3183
+ return buildFetchers(loader);
3184
+ };
3185
+ const buildFetchers = (loader) => {
3185
3186
  return {
3186
3187
  fetchFromRoot: async (q) => {
3187
- const response = await fetchWithQuery(serializeRootQuery(q));
3188
- const pool = new ModelPool(modelMap);
3189
- pool.add(response);
3190
- return reconcileRootQuery(q, response, pool);
3188
+ const res = await loader.fetchModel("_root", [""], { relations: q });
3189
+ return res[""];
3191
3190
  },
3192
- fetchFromInstance: _fetchSingleInstance,
3193
- fetchInstance: async (key, id$1, q) => {
3194
- const instance = {
3195
- "~model": key,
3196
- "~key": id$1
3197
- };
3198
- return _fetchSingleInstance(instance, q);
3191
+ fetchFromInstance: async (instance, q) => {
3192
+ const key = instance["~key"];
3193
+ const res = await loader.fetchModel(instance["~model"], [key], q);
3194
+ return res[key];
3199
3195
  },
3200
- fetchInstances: async (key, ids, q) => {
3201
- const modelDesc = modelMap[key];
3202
- const instances = ids.map((id$1) => ({
3203
- "~model": key,
3204
- "~key": id$1
3205
- }));
3206
- const response = await fetchWithQuery(serializeInstanceQuery(q, instances, modelMap));
3207
- const pool = new ModelPool(modelMap);
3208
- pool.add(response);
3209
- return Object.fromEntries(ids.map((id$1) => [id$1, reconcileInstanceQuery(q, response, modelDesc, id$1, pool)]));
3210
- }
3196
+ fetchInstance: async (model, key, q) => {
3197
+ const res = await loader.fetchModel(model, [key], q);
3198
+ return res[key];
3199
+ },
3200
+ fetchInstances: loader.fetchModel
3211
3201
  };
3212
3202
  };
3213
3203
 
3214
3204
  //#endregion
3215
- export { buildFetchers };
3205
+ export { buildFetchers, buildFetchersWithSimpleLoader };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codecks/fetch",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "description": "Quickly create deeply nested queries for the Codecks API with advanced TypeScript support",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -32,8 +32,9 @@
32
32
  "check-format": "prettier --check .",
33
33
  "dev": "tsdown --watch",
34
34
  "test": "vitest",
35
+ "test:run": "vitest run",
35
36
  "typecheck": "tsc --noEmit",
36
- "ci": "npm run typecheck && npm run build && npm run check-format && npm run test",
37
+ "ci": "npm run typecheck && npm run build && npm run check-format && npm run test:run",
37
38
  "local-release": "changeset version && changeset publish",
38
39
  "prepublishOnly": "npm run ci"
39
40
  },