@bg-dev/nuxt-zenstack 0.0.2 → 0.0.3

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/module.d.mts CHANGED
@@ -1,7 +1,9 @@
1
1
  import * as _nuxt_schema from '@nuxt/schema';
2
+ import { FetchPolicy } from '../dist/runtime/composables/common.js';
2
3
 
3
4
  interface ModuleOptions {
4
5
  apiPath: string;
6
+ fetchPolicy: FetchPolicy;
5
7
  }
6
8
  declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
7
9
 
package/dist/module.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bg-dev/nuxt-zenstack",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "configKey": "zenstack",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
package/dist/module.mjs CHANGED
@@ -3,7 +3,7 @@ import { joinURL } from 'ufo';
3
3
  import { defu } from 'defu';
4
4
 
5
5
  const name = "@bg-dev/nuxt-zenstack";
6
- const version = "0.0.2";
6
+ const version = "0.0.3";
7
7
 
8
8
  const module$1 = defineNuxtModule({
9
9
  meta: {
@@ -13,12 +13,14 @@ const module$1 = defineNuxtModule({
13
13
  },
14
14
  // Default configuration options of the Nuxt module
15
15
  defaults: {
16
- apiPath: "/api/_zenstack"
16
+ apiPath: "/api/_zenstack",
17
+ fetchPolicy: "cache-first"
17
18
  },
18
19
  setup(_options, _nuxt) {
19
20
  _nuxt.options.runtimeConfig.public = defu(_nuxt.options.runtimeConfig.public, {
20
21
  zenstack: {
21
- apiPath: _options.apiPath
22
+ apiPath: _options.apiPath,
23
+ fetchPolicy: _options.fetchPolicy
22
24
  }
23
25
  });
24
26
  const resolver = createResolver(import.meta.url);
@@ -54,10 +56,10 @@ export type $Zmodel = keyof SchemaType['models']
54
56
  export type $Zdef = ModelDef
55
57
  export type $Zoperations<Zmodel extends $Zmodel> = ModelOperations<SchemaType, Zmodel>
56
58
  export type $Zid<Zmodel extends $Zmodel> = ModelResult<SchemaType, Zmodel> extends { id: infer Id } ? Id : never
57
- export type $Zinclude<Zmodel extends $Zmodel> = IncludeInput<SchemaType, Zmodel>
58
- export type $Zitem<Zmodel extends $Zmodel, Zinclude extends $Zinclude<Zmodel> = never> = ItemGetPayload<Zmodel, { include: Zinclude }>
59
- export type $Zwhere<Zmodel extends $Zmodel> = WhereInput<SchemaType, Zmodel>
60
- export type $ZorderBy<Zmodel extends $Zmodel> = FindManyArgs<SchemaType, Zmodel>['orderBy']
59
+ export type $Zinclude<Zmodel extends $Zmodel> = IncludeInput<SchemaType, Zmodel> | undefined
60
+ export type $Zitem<Zmodel extends $Zmodel, Zinclude extends $Zinclude = undefined> = ItemGetPayload<Zmodel, { include: Zinclude }>
61
+ export type $Zwhere<Zmodel extends $Zmodel> = WhereInput<SchemaType, Zmodel> | undefined
62
+ export type $ZorderBy<Zmodel extends $Zmodel> = FindManyArgs<SchemaType, Zmodel>['orderBy'] | undefined
61
63
  export type $ZcreateData<Zmodel extends $Zmodel> = CreateArgs<SchemaType, Zmodel>['data']
62
64
  export type $ZupdateData<Zmodel extends $Zmodel> = UpdateArgs<SchemaType, Zmodel>['data']
63
65
  `
@@ -10,4 +10,10 @@ export type Error = {
10
10
  };
11
11
  export declare function getConfig(): {
12
12
  apiPath: string;
13
+ fetchPolicy: FetchPolicy;
13
14
  };
15
+ /**
16
+ * @param instance a custom fetch method created by `$fetch.create`
17
+ */
18
+ export declare function provideFetch(instance: typeof $fetch): void;
19
+ export declare function getFetch(): import("nitropack/types").$Fetch<unknown, import("nitropack/types").NitroFetchRequest>;
@@ -3,3 +3,10 @@ export function getConfig() {
3
3
  const config = useRuntimeConfig();
4
4
  return config.public.zenstack;
5
5
  }
6
+ let _fetch = $fetch;
7
+ export function provideFetch(instance) {
8
+ _fetch = instance;
9
+ }
10
+ export function getFetch() {
11
+ return _fetch;
12
+ }
@@ -3,3 +3,4 @@ export { useZenstackReadMany } from './useZenstackReadMany/index.js';
3
3
  export { useZenstackRead } from './useZenstackRead/index.js';
4
4
  export { useZenstackDelete } from './useZenstackDelete/index.js';
5
5
  export { useZenstackUpdate } from './useZenstackUpdate/index.js';
6
+ export { provideFetch as provideZenstackFetch } from './common.js';
@@ -3,3 +3,4 @@ export { useZenstackReadMany } from "./useZenstackReadMany/index.js";
3
3
  export { useZenstackRead } from "./useZenstackRead/index.js";
4
4
  export { useZenstackDelete } from "./useZenstackDelete/index.js";
5
5
  export { useZenstackUpdate } from "./useZenstackUpdate/index.js";
6
+ export { provideFetch as provideZenstackFetch } from "./common.js";
@@ -1,4 +1,4 @@
1
- import { getConfig } from "../common.js";
1
+ import { getConfig, getFetch } from "../common.js";
2
2
  import { ref } from "#imports";
3
3
  import { joinURL } from "ufo";
4
4
  import { useZenstackStore } from "../useZenstackStore/index.js";
@@ -14,17 +14,19 @@ export function useZenstackCreate(model) {
14
14
  status.value = "idle";
15
15
  }
16
16
  async function mutate(input) {
17
+ const _fetch = getFetch();
17
18
  const url = joinURL(config.apiPath, `/models/${model.toString()}`);
19
+ const method = "POST";
20
+ const body = { data: input };
21
+ store.addToFetchHistory({
22
+ model: model.toString(),
23
+ method,
24
+ body: JSON.stringify(body)
25
+ });
18
26
  reset();
19
27
  status.value = "pending";
20
28
  try {
21
- const res = await $fetch(url, {
22
- method: "POST",
23
- body: {
24
- data: input
25
- // TODO: maybe include relations
26
- }
27
- });
29
+ const res = await _fetch(url, { method, body });
28
30
  if (res.data)
29
31
  store.setOne(model, res.data);
30
32
  data.value = res.data;
@@ -1,7 +1,7 @@
1
1
  import { ref } from "#imports";
2
2
  import { joinURL } from "ufo";
3
3
  import { useZenstackStore } from "../useZenstackStore/index.js";
4
- import { getConfig } from "../common.js";
4
+ import { getConfig, getFetch } from "../common.js";
5
5
  export function useZenstackDelete(model) {
6
6
  const data = ref(null);
7
7
  const error = ref(null);
@@ -14,13 +14,18 @@ export function useZenstackDelete(model) {
14
14
  status.value = "idle";
15
15
  }
16
16
  async function mutate(id) {
17
+ const _fetch = getFetch();
17
18
  const url = joinURL(config.apiPath, `/models/${model.toString()}/${id}`);
19
+ const method = "DELETE";
20
+ store.addToFetchHistory({
21
+ model: model.toString(),
22
+ id,
23
+ method
24
+ });
18
25
  reset();
19
26
  status.value = "pending";
20
27
  try {
21
- const res = await $fetch(url, {
22
- method: "DELETE"
23
- });
28
+ const res = await _fetch(url, { method });
24
29
  store.deleteOne(model, id);
25
30
  data.value = res.data;
26
31
  status.value = "success";
@@ -1,7 +1,7 @@
1
1
  import type { $Zmodel, $Zitem, $Zid, $Zinclude } from '#build/types/nuxt-zenstack';
2
2
  import type { Status, FetchPolicy } from '../common.js';
3
3
  import type { Ref, MaybeRefOrGetter } from '#imports';
4
- type Options<Zmodel extends $Zmodel> = {
4
+ type Options<Zinclude> = {
5
5
  /**
6
6
  * - `cache-first` means that the query will first try to fetch the data from the store. If the data is not found in the store, it will fetch the data from the server and update the store.
7
7
  * - `cache-and-fetch` means that the query will first try to fetch the data from the cache. It will then fetch the data from the server and update the cache.
@@ -19,12 +19,12 @@ type Options<Zmodel extends $Zmodel> = {
19
19
  * The relations to include in the query.
20
20
  * @default undefined
21
21
  */
22
- include?: MaybeRefOrGetter<$Zinclude<Zmodel>>;
22
+ include?: MaybeRefOrGetter<Zinclude>;
23
23
  };
24
- export declare function useZenstackRead<Zmodel extends $Zmodel, Zitem extends $Zitem<Zmodel>>(model: Zmodel, id: $Zid<Zmodel>, opts?: Options<Zmodel>): {
24
+ export declare function useZenstackRead<Zmodel extends $Zmodel, Zinclude extends $Zinclude<Zmodel>, Zitem extends $Zitem<Zmodel, Zinclude>>(model: Zmodel, id: $Zid<Zmodel>, opts?: Options<Zinclude>): Promise<{
25
25
  data: Ref<Zitem | null>;
26
26
  error: Ref<Error | null>;
27
27
  status: Ref<Status>;
28
28
  refetch: () => Promise<void>;
29
- };
29
+ }>;
30
30
  export {};
@@ -1,57 +1,65 @@
1
- import { ref, toValue, watch, isRef } from "#imports";
1
+ import { ref, toValue, watch, isRef, useNuxtApp } from "#imports";
2
2
  import { joinURL } from "ufo";
3
3
  import { useZenstackStore } from "../useZenstackStore/index.js";
4
4
  import { stringify } from "superjson";
5
- import { getConfig } from "../common.js";
6
- export function useZenstackRead(model, id, opts = {}) {
5
+ import { getConfig, getFetch } from "../common.js";
6
+ export async function useZenstackRead(model, id, opts = {}) {
7
7
  const data = ref(null);
8
8
  const error = ref(null);
9
9
  const status = ref("idle");
10
10
  const store = useZenstackStore();
11
11
  const config = getConfig();
12
- opts.fetchPolicy ??= "cache-first";
13
- opts.immediate ??= true;
14
- switch (opts.fetchPolicy) {
15
- case "cache-first":
16
- updateData();
17
- if (data.value) opts.immediate = false;
18
- break;
19
- case "cache-and-fetch":
20
- updateData();
21
- break;
22
- case "cache-only":
23
- updateData();
24
- opts.immediate = false;
25
- break;
26
- }
12
+ const nuxtApp = useNuxtApp();
27
13
  const watchedOptions = [opts.include].filter((option) => isRef(option) || typeof option === "function");
14
+ const method = "GET";
15
+ opts.fetchPolicy ??= config.fetchPolicy;
16
+ opts.immediate ??= true;
17
+ if (opts.fetchPolicy !== "fetch-only")
18
+ updateData();
28
19
  watch(store.state, () => updateData());
29
20
  watch(watchedOptions, () => refetch());
30
- if (opts.immediate)
31
- refetch();
21
+ if (shouldFetchInitially())
22
+ await refetch();
23
+ function shouldFetchInitially() {
24
+ if (opts.immediate === false)
25
+ return false;
26
+ const entry = store.fetchHistory.value.find((entry2) => entry2.model === model && entry2.id === id && entry2.method === method && entry2.query === JSON.stringify(getQuery()));
27
+ if (entry?.ssr && nuxtApp.isHydrating)
28
+ return false;
29
+ if (opts.fetchPolicy === "cache-first" && entry)
30
+ return false;
31
+ return true;
32
+ }
32
33
  function updateData() {
33
34
  data.value = store.getOne(model, id);
34
35
  }
36
+ function getQuery() {
37
+ const json = stringify({
38
+ include: toValue(opts.include)
39
+ });
40
+ return { q: json };
41
+ }
35
42
  async function refetch() {
36
43
  if (opts.fetchPolicy === "cache-only")
37
44
  return;
45
+ const _fetch = getFetch();
38
46
  const url = joinURL(config.apiPath, `/models/${model.toString()}/${id}`);
39
- const json = stringify({
40
- include: toValue(opts.include)
47
+ const query = getQuery();
48
+ store.addToFetchHistory({
49
+ model: model.toString(),
50
+ id,
51
+ method,
52
+ query: JSON.stringify(query)
41
53
  });
42
54
  error.value = null;
43
55
  status.value = "pending";
44
56
  try {
45
- const res = await $fetch(url, {
46
- method: "GET",
47
- query: {
48
- q: json
49
- }
50
- });
57
+ const res = await _fetch(url, { method, query });
51
58
  if (res.data)
52
59
  store.setOne(model, res.data);
53
60
  else
54
61
  store.deleteOne(model, id);
62
+ updateData();
55
63
  status.value = "success";
56
64
  } catch (err) {
57
65
  error.value = err.data;
@@ -1,7 +1,7 @@
1
1
  import type { $Zmodel, $Zitem, $Zinclude, $Zwhere, $ZorderBy } from '#build/types/nuxt-zenstack';
2
2
  import type { Status, FetchPolicy } from '../common.js';
3
3
  import type { MaybeRefOrGetter, Ref } from '#imports';
4
- type Options<Zmodel extends $Zmodel> = {
4
+ type Options<Zinclude, Zwhere, ZorderBy> = {
5
5
  /**
6
6
  * - `cache-first` means that the query will first try to fetch the data from the store. If the data is not found in the store, it will fetch the data from the server and update the store.
7
7
  * - `cache-and-fetch` means that the query will first try to fetch the data from the cache. It will then fetch the data from the server and update the cache.
@@ -19,17 +19,17 @@ type Options<Zmodel extends $Zmodel> = {
19
19
  * The relations to include in the query.
20
20
  * @default undefined
21
21
  */
22
- include?: MaybeRefOrGetter<$Zinclude<Zmodel>>;
22
+ include?: MaybeRefOrGetter<Zinclude>;
23
23
  /**
24
24
  * The filter to apply to the query.
25
25
  * @default undefined
26
26
  */
27
- where?: MaybeRefOrGetter<$Zwhere<Zmodel>>;
27
+ where?: MaybeRefOrGetter<Zwhere>;
28
28
  /**
29
29
  * The order to apply to the query.
30
30
  * @default undefined
31
31
  */
32
- orderBy?: MaybeRefOrGetter<$ZorderBy<Zmodel>>;
32
+ orderBy?: MaybeRefOrGetter<ZorderBy>;
33
33
  /**
34
34
  * The number of items to skip.
35
35
  * @default 0
@@ -41,10 +41,10 @@ type Options<Zmodel extends $Zmodel> = {
41
41
  */
42
42
  take?: MaybeRefOrGetter<number>;
43
43
  };
44
- export declare function useZenstackReadMany<Zmodel extends $Zmodel, Zitem extends $Zitem<Zmodel>>(model: Zmodel, opts?: Options<Zmodel>): {
44
+ export declare function useZenstackReadMany<Zmodel extends $Zmodel, Zinclude extends $Zinclude<Zmodel>, Zitem extends $Zitem<Zmodel, Zinclude>, Zwhere extends $Zwhere<Zmodel>, ZorderBy extends $ZorderBy<Zmodel>>(model: Zmodel, opts?: Options<Zinclude, Zwhere, ZorderBy>): Promise<{
45
45
  data: Ref<Zitem[] | null>;
46
46
  error: Ref<Error | null>;
47
47
  status: Ref<Status>;
48
48
  refetch: () => Promise<void>;
49
- };
49
+ }>;
50
50
  export {};
@@ -1,46 +1,44 @@
1
- import { ref, toValue, watch, isRef } from "#imports";
1
+ import { ref, toValue, watch, isRef, useNuxtApp } from "#imports";
2
2
  import { joinURL } from "ufo";
3
3
  import { useZenstackStore } from "../useZenstackStore/index.js";
4
4
  import { stringify } from "superjson";
5
- import { getConfig } from "../common.js";
6
- export function useZenstackReadMany(model, opts = {}) {
5
+ import { getConfig, getFetch } from "../common.js";
6
+ export async function useZenstackReadMany(model, opts = {}) {
7
7
  const data = ref(null);
8
8
  const error = ref(null);
9
9
  const status = ref("idle");
10
10
  const store = useZenstackStore();
11
11
  const config = getConfig();
12
- opts.fetchPolicy ??= "cache-first";
12
+ const nuxtApp = useNuxtApp();
13
+ const watchedOptions = [opts.include, opts.where, opts.orderBy, opts.skip, opts.take].filter((option) => isRef(option) || typeof option === "function");
14
+ const method = "GET";
15
+ opts.fetchPolicy ??= config.fetchPolicy;
13
16
  opts.immediate ??= true;
14
17
  opts.skip ??= 0;
15
18
  opts.take ??= 1e3;
16
- switch (opts.fetchPolicy) {
17
- case "cache-first":
18
- updateData();
19
- if (data.value?.length) opts.immediate = false;
20
- break;
21
- case "cache-and-fetch":
22
- updateData();
23
- break;
24
- case "cache-only":
25
- updateData();
26
- opts.immediate = false;
27
- break;
28
- }
29
- const watchedOptions = [opts.include, opts.where, opts.orderBy, opts.skip, opts.take].filter((option) => isRef(option) || typeof option === "function");
19
+ if (opts.fetchPolicy !== "fetch-only")
20
+ updateData();
30
21
  watch(store.state, () => updateData());
31
22
  watch(watchedOptions, () => {
32
23
  updateData();
33
24
  refetch();
34
25
  });
35
- if (opts.immediate)
36
- refetch();
26
+ if (shouldFetchInitially())
27
+ await refetch();
28
+ function shouldFetchInitially() {
29
+ if (opts.immediate === false)
30
+ return false;
31
+ const entry = store.fetchHistory.value.find((entry2) => entry2.model === model && entry2.method === method && entry2.query === JSON.stringify(getQuery()));
32
+ if (entry?.ssr && nuxtApp.isHydrating)
33
+ return false;
34
+ if (opts.fetchPolicy === "cache-first" && entry)
35
+ return false;
36
+ return true;
37
+ }
37
38
  function updateData() {
38
39
  data.value = store.getMany(model);
39
40
  }
40
- async function refetch() {
41
- if (opts.fetchPolicy === "cache-only")
42
- return;
43
- const url = joinURL(config.apiPath, `/models/${model.toString()}`);
41
+ function getQuery() {
44
42
  const json = stringify({
45
43
  include: toValue(opts.include),
46
44
  where: toValue(opts.where),
@@ -48,16 +46,25 @@ export function useZenstackReadMany(model, opts = {}) {
48
46
  skip: toValue(opts.skip),
49
47
  take: toValue(opts.take)
50
48
  });
49
+ return { q: json };
50
+ }
51
+ async function refetch() {
52
+ if (opts.fetchPolicy === "cache-only")
53
+ return;
54
+ const _fetch = getFetch();
55
+ const url = joinURL(config.apiPath, `/models/${model.toString()}`);
56
+ const query = getQuery();
57
+ store.addToFetchHistory({
58
+ model: model.toString(),
59
+ method,
60
+ query: JSON.stringify(query)
61
+ });
51
62
  error.value = null;
52
63
  status.value = "pending";
53
64
  try {
54
- const res = await $fetch(url, {
55
- method: "GET",
56
- query: {
57
- q: json
58
- }
59
- });
65
+ const res = await _fetch(url, { method, query });
60
66
  store.setMany(model, res.data);
67
+ updateData();
61
68
  status.value = "success";
62
69
  } catch (err) {
63
70
  error.value = err.data;
@@ -3,10 +3,10 @@ export function getModelDef(model) {
3
3
  return zenstackSchema.models[model];
4
4
  }
5
5
  export function isIdString(model) {
6
- const def = getModelDef(model);
7
- if (!def.uniqueFields.id)
8
- throw new Error(`No id field for model ${model.toString()}`);
9
- return def.uniqueFields.id.type === "String";
6
+ const modelDef = getModelDef(model);
7
+ if (!modelDef.uniqueFields.id)
8
+ throw new Error(`Model ${model.toString()} does not have an id as a unique field`);
9
+ return modelDef.uniqueFields.id.type === "String";
10
10
  }
11
11
  export function getModels() {
12
12
  return Object.keys(zenstackSchema.models);
@@ -1,4 +1,13 @@
1
1
  import type { $Zmodel, $Zid } from '#build/types/nuxt-zenstack';
2
+ type FetchEntry = {
3
+ model: string;
4
+ method: 'GET' | 'PATCH' | 'POST' | 'DELETE';
5
+ ssr: boolean;
6
+ timestamp: number;
7
+ id?: string | number;
8
+ query?: string;
9
+ body?: string;
10
+ };
2
11
  export declare function useZenstackStore(): {
3
12
  state: Readonly<import("vue").Ref<{
4
13
  readonly [x: string]: {
@@ -9,10 +18,29 @@ export declare function useZenstackStore(): {
9
18
  readonly [x: string]: object;
10
19
  };
11
20
  }>>;
21
+ fetchHistory: Readonly<import("vue").Ref<readonly {
22
+ readonly model: string;
23
+ readonly method: "GET" | "PATCH" | "POST" | "DELETE";
24
+ readonly ssr: boolean;
25
+ readonly timestamp: number;
26
+ readonly id?: string | number | undefined;
27
+ readonly query?: string | undefined;
28
+ readonly body?: string | undefined;
29
+ }[], readonly {
30
+ readonly model: string;
31
+ readonly method: "GET" | "PATCH" | "POST" | "DELETE";
32
+ readonly ssr: boolean;
33
+ readonly timestamp: number;
34
+ readonly id?: string | number | undefined;
35
+ readonly query?: string | undefined;
36
+ readonly body?: string | undefined;
37
+ }[]>>;
12
38
  setOne: (model: $Zmodel, input: object) => void;
13
39
  setMany: (model: $Zmodel, input: object[]) => void;
14
40
  getOne: <Zmodel extends $Zmodel>(model: Zmodel, input: $Zid<Zmodel>) => any;
15
41
  getMany: (model: $Zmodel) => any;
16
42
  deleteOne: <Model extends $Zmodel>(model: Model, id: $Zid<Model>) => void;
17
43
  deleteMany: (model: $Zmodel) => void;
44
+ addToFetchHistory: (entry: Omit<FetchEntry, "ssr" | "timestamp">) => void;
18
45
  };
46
+ export {};
@@ -4,7 +4,8 @@ import { defu } from "defu";
4
4
  import { readonly, useState } from "#imports";
5
5
  generateNormalizrSchema();
6
6
  export function useZenstackStore() {
7
- const state = useState("zenstack-store", () => ({}));
7
+ const state = useState("zenstack-state", () => ({}));
8
+ const fetchHistory = useState("zenstack-fetch-history", () => []);
8
9
  function setOne(model, input) {
9
10
  const schema = getNormalizrSchema(model);
10
11
  const res = normalize(input, schema);
@@ -45,5 +46,26 @@ export function useZenstackStore() {
45
46
  }
46
47
  state.value = newState;
47
48
  }
48
- return { state: readonly(state), setOne, setMany, getOne, getMany, deleteOne, deleteMany };
49
+ function addToFetchHistory(entry) {
50
+ fetchHistory.value.push({
51
+ method: entry.method,
52
+ model: entry.model,
53
+ body: entry.body,
54
+ id: entry.id,
55
+ query: entry.query,
56
+ ssr: typeof window === "undefined",
57
+ timestamp: (/* @__PURE__ */ new Date()).getTime()
58
+ });
59
+ }
60
+ return {
61
+ state: readonly(state),
62
+ fetchHistory: readonly(fetchHistory),
63
+ setOne,
64
+ setMany,
65
+ getOne,
66
+ getMany,
67
+ deleteOne,
68
+ deleteMany,
69
+ addToFetchHistory
70
+ };
49
71
  }
@@ -1,7 +1,7 @@
1
1
  import { ref } from "#imports";
2
2
  import { joinURL } from "ufo";
3
3
  import { useZenstackStore } from "../useZenstackStore/index.js";
4
- import { getConfig } from "../common.js";
4
+ import { getConfig, getFetch } from "../common.js";
5
5
  export function useZenstackUpdate(model) {
6
6
  const data = ref(null);
7
7
  const error = ref(null);
@@ -14,17 +14,19 @@ export function useZenstackUpdate(model) {
14
14
  status.value = "idle";
15
15
  }
16
16
  async function mutate(id, input) {
17
+ const _fetch = getFetch();
17
18
  const url = joinURL(config.apiPath, `/models/${model.toString()}/${id}`);
19
+ const body = { data: input };
20
+ const method = "PATCH";
21
+ store.addToFetchHistory({
22
+ model: model.toString(),
23
+ method,
24
+ body: JSON.stringify(body)
25
+ });
18
26
  reset();
19
27
  status.value = "pending";
20
28
  try {
21
- const res = await $fetch(url, {
22
- method: "PATCH",
23
- body: {
24
- data: input
25
- // TODO: maybe include relations
26
- }
27
- });
29
+ const res = await _fetch(url, { method, body });
28
30
  if (res.data)
29
31
  store.setOne(model, res.data);
30
32
  data.value = res.data;
@@ -1,13 +1,15 @@
1
1
  import { parseModel, parseId, parseUpdateData } from "../../../utils/parsers.js";
2
2
  import { defineEventHandler } from "h3";
3
- import { getModelOperations } from "../../../utils/index.js";
3
+ import { getModelOperations, includeAll } from "../../../utils/index.js";
4
4
  export default defineEventHandler(async (event) => {
5
5
  const model = parseModel(event);
6
6
  const id = parseId(event, model);
7
7
  const updateData = await parseUpdateData(event, model);
8
8
  const operations = getModelOperations(model);
9
+ const include = includeAll(model);
9
10
  const data = await operations.update({
10
11
  data: updateData.data,
12
+ include,
11
13
  where: {
12
14
  id
13
15
  }
@@ -1,12 +1,14 @@
1
1
  import { parseModel, parseCreateData } from "../../../utils/parsers.js";
2
2
  import { defineEventHandler } from "h3";
3
- import { getModelOperations } from "../../../utils/index.js";
3
+ import { getModelOperations, includeAll } from "../../../utils/index.js";
4
4
  export default defineEventHandler(async (event) => {
5
5
  const model = parseModel(event);
6
6
  const createData = await parseCreateData(event, model);
7
7
  const operations = getModelOperations(model);
8
+ const include = includeAll(model);
8
9
  const data = await operations.create({
9
- data: createData.data
10
+ data: createData.data,
11
+ include
10
12
  });
11
13
  return { data };
12
14
  });
@@ -1,11 +1,12 @@
1
1
  import type { ClientContract } from '@zenstackhq/orm';
2
- import type { $Zschema, $Zmodel, $Zoperations } from '#build/types/nuxt-zenstack';
2
+ import type { $Zschema, $Zmodel, $Zoperations, $Zdef } from '#build/types/nuxt-zenstack';
3
3
  declare let _client: ClientContract<$Zschema> | null;
4
4
  export declare function provideClient(client: typeof _client): void;
5
5
  export declare function getClient(): ClientContract<SchemaType>;
6
6
  export declare function getModelOperations<Zmodel extends $Zmodel>(model: Zmodel): $Zoperations<Zmodel>;
7
- export declare function getModelDef(model: $Zmodel): any;
7
+ export declare function getModelDef(model: $Zmodel): $Zdef;
8
8
  export declare function isIdString(model: $Zmodel): boolean;
9
9
  export declare function getModels(): $Zmodel[];
10
10
  export declare function isValidModel(model: $Zmodel): boolean;
11
+ export declare function includeAll<Zmodel extends $Zmodel>(model: Zmodel): boolean | import("@zenstackhq/orm").SelectIncludeOmit<SchemaType, any, boolean, true>;
11
12
  export {};
@@ -17,7 +17,10 @@ export function getModelDef(model) {
17
17
  return zenstackSchema.models[model];
18
18
  }
19
19
  export function isIdString(model) {
20
- return getModelDef(model).uniqueFields.id.type === "String";
20
+ const modelDef = getModelDef(model);
21
+ if (!modelDef.uniqueFields.id)
22
+ throw new Error(`Model ${model.toString()} does not have an id as a unique field`);
23
+ return modelDef.uniqueFields.id.type === "String";
21
24
  }
22
25
  export function getModels() {
23
26
  return Object.keys(zenstackSchema.models);
@@ -25,3 +28,21 @@ export function getModels() {
25
28
  export function isValidModel(model) {
26
29
  return getModels().includes(model);
27
30
  }
31
+ export function includeAll(model) {
32
+ const include = {};
33
+ const modelSet = /* @__PURE__ */ new Set();
34
+ function iterate(_model, acc) {
35
+ const modelDef = getModelDef(_model);
36
+ for (const [field, fieldDef] of Object.entries(modelDef.fields)) {
37
+ if (isValidModel(fieldDef.type) && !modelSet.has(fieldDef.type)) {
38
+ acc["include"] ||= {};
39
+ acc["include"][field] = {};
40
+ modelSet.add(fieldDef.type);
41
+ iterate(fieldDef.type, acc["include"][field]);
42
+ }
43
+ }
44
+ }
45
+ modelSet.add(model);
46
+ iterate(model, include);
47
+ return include["include"] ?? {};
48
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bg-dev/nuxt-zenstack",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "ZenStack integration for Nuxt",
5
5
  "repository": {
6
6
  "url": "https://github.com/becem-gharbi/nuxt-zenstack"