@bg-dev/nuxt-zenstack 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.
Files changed (38) hide show
  1. package/dist/module.d.mts +2 -0
  2. package/dist/module.json +1 -1
  3. package/dist/module.mjs +29 -14
  4. package/dist/runtime/composables/common.d.ts +6 -8
  5. package/dist/runtime/composables/common.js +7 -0
  6. package/dist/runtime/composables/index.d.ts +1 -0
  7. package/dist/runtime/composables/index.js +1 -0
  8. package/dist/runtime/composables/useZenstackCreate/index.d.ts +3 -3
  9. package/dist/runtime/composables/useZenstackCreate/index.js +10 -8
  10. package/dist/runtime/composables/useZenstackDelete/index.d.ts +3 -3
  11. package/dist/runtime/composables/useZenstackDelete/index.js +9 -4
  12. package/dist/runtime/composables/useZenstackRead/index.d.ts +7 -7
  13. package/dist/runtime/composables/useZenstackRead/index.js +38 -29
  14. package/dist/runtime/composables/useZenstackReadMany/index.d.ts +9 -8
  15. package/dist/runtime/composables/useZenstackReadMany/index.js +54 -34
  16. package/dist/runtime/composables/useZenstackReadMany/orderBy.d.ts +5 -0
  17. package/dist/runtime/composables/useZenstackReadMany/orderBy.js +25 -0
  18. package/dist/runtime/composables/useZenstackReadMany/where.d.ts +2 -0
  19. package/dist/runtime/composables/useZenstackReadMany/where.js +235 -0
  20. package/dist/runtime/composables/useZenstackStore/helpers.js +4 -4
  21. package/dist/runtime/composables/useZenstackStore/index.d.ts +34 -2
  22. package/dist/runtime/composables/useZenstackStore/index.js +27 -6
  23. package/dist/runtime/composables/useZenstackStore/normalization.d.ts +16 -3
  24. package/dist/runtime/composables/useZenstackStore/normalization.js +16 -3
  25. package/dist/runtime/composables/useZenstackUpdate/index.d.ts +2 -2
  26. package/dist/runtime/composables/useZenstackUpdate/index.js +10 -8
  27. package/dist/runtime/server/api/models/[model]/[id].delete.js +4 -1
  28. package/dist/runtime/server/api/models/[model]/[id].get.js +4 -1
  29. package/dist/runtime/server/api/models/[model]/[id].patch.js +10 -5
  30. package/dist/runtime/server/api/models/[model]/index.get.js +4 -1
  31. package/dist/runtime/server/api/models/[model]/index.post.js +10 -5
  32. package/dist/runtime/server/utils/error.d.ts +9 -0
  33. package/dist/runtime/server/utils/error.js +49 -0
  34. package/dist/runtime/server/utils/index.d.ts +5 -8
  35. package/dist/runtime/server/utils/index.js +27 -10
  36. package/dist/runtime/server/utils/parsers.d.ts +2 -2
  37. package/dist/runtime/server/utils/parsers.js +2 -2
  38. package/package.json +3 -1
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.4",
4
4
  "configKey": "zenstack",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
package/dist/module.mjs CHANGED
@@ -1,9 +1,9 @@
1
- import { defineNuxtModule, createResolver, addServerImports, addTemplate, addServerTemplate, addTypeTemplate, addServerHandler, addImportsDir } from '@nuxt/kit';
1
+ import { defineNuxtModule, createResolver, addTemplate, addServerTemplate, addTypeTemplate, addServerHandler, addImportsDir } from '@nuxt/kit';
2
2
  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.4";
7
7
 
8
8
  const module$1 = defineNuxtModule({
9
9
  meta: {
@@ -13,20 +13,17 @@ 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);
25
- addServerImports({
26
- from: resolver.resolve("./runtime/server/utils"),
27
- name: "provideClient",
28
- as: "provideZenstackClient"
29
- });
30
27
  addTemplate({
31
28
  write: true,
32
29
  filename: "nuxt-zenstack.mjs",
@@ -43,9 +40,11 @@ export { schema as zenstackSchema } from '~~/zenstack/schema'
43
40
  addTypeTemplate({
44
41
  filename: "types/nuxt-zenstack.d.ts",
45
42
  getContents: () => `
46
- import type { ModelOperations, ModelResult, IncludeInput, WhereInput, FindManyArgs, SimplifiedPlainResult, SelectIncludeOmit, QueryOptions, CreateArgs, UpdateArgs } from '@zenstackhq/orm'
43
+ import type { ClientContract, ModelOperations, ModelResult, IncludeInput, WhereInput, FindManyArgs, SimplifiedPlainResult, SelectIncludeOmit, QueryOptions, CreateArgs, UpdateArgs } from '@zenstackhq/orm'
47
44
  import type { SchemaType } from '~~/zenstack/schema'
48
45
  import type { ModelDef } from '@zenstackhq/orm/schema'
46
+ import type { H3Error } from 'h3'
47
+ import { ORMError, RejectedByPolicyReason, ORMErrorReason } from '@zenstackhq/orm'
49
48
 
50
49
  type ItemGetPayload<Zmodel extends $Zmodel, Args extends SelectIncludeOmit<SchemaType, Zmodel, true>, Options extends QueryOptions<SchemaType> = QueryOptions<SchemaType>> = SimplifiedPlainResult<SchemaType, Zmodel, Args, Options>
51
50
 
@@ -54,12 +53,28 @@ export type $Zmodel = keyof SchemaType['models']
54
53
  export type $Zdef = ModelDef
55
54
  export type $Zoperations<Zmodel extends $Zmodel> = ModelOperations<SchemaType, Zmodel>
56
55
  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']
56
+ export type $Zinclude<Zmodel extends $Zmodel> = IncludeInput<SchemaType, Zmodel> | undefined
57
+ export type $Zitem<Zmodel extends $Zmodel, Zinclude extends $Zinclude = undefined> = ItemGetPayload<Zmodel, { include: Zinclude }>
58
+ export type $Zwhere<Zmodel extends $Zmodel> = WhereInput<SchemaType, Zmodel> | undefined
59
+ export type $ZorderBy<Zmodel extends $Zmodel> = FindManyArgs<SchemaType, Zmodel>['orderBy'] | undefined
61
60
  export type $ZcreateData<Zmodel extends $Zmodel> = CreateArgs<SchemaType, Zmodel>['data']
62
61
  export type $ZupdateData<Zmodel extends $Zmodel> = UpdateArgs<SchemaType, Zmodel>['data']
62
+ export type $ZormError = ORMError
63
+ export type $Zerror = H3Error<{
64
+ ormErrorReason: ORMErrorReason
65
+ dbErrorCode?: unknown
66
+ dbErrorMessage?: string
67
+ model?: string
68
+ rejectedByPolicyReason?: RejectedByPolicyReason
69
+ }>
70
+
71
+ declare module 'h3' {
72
+ interface H3EventContext {
73
+ zenstack: {
74
+ client: ClientContract<SchemaType>
75
+ }
76
+ }
77
+ }
63
78
  `
64
79
  });
65
80
  addServerHandler({
@@ -1,13 +1,11 @@
1
1
  export type Status = 'idle' | 'pending' | 'success' | 'error';
2
2
  export type FetchPolicy = 'cache-first' | 'fetch-only' | 'cache-only' | 'cache-and-fetch';
3
- export type Error = {
4
- error: boolean;
5
- url: string;
6
- statusCode: number;
7
- statusMessage: string;
8
- message: string;
9
- stack?: string[];
10
- };
11
3
  export declare function getConfig(): {
12
4
  apiPath: string;
5
+ fetchPolicy: FetchPolicy;
13
6
  };
7
+ /**
8
+ * @param instance a custom fetch method created by `$fetch.create`
9
+ */
10
+ export declare function provideFetch(instance: typeof $fetch): void;
11
+ 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,9 +1,9 @@
1
- import type { $Zmodel, $Zitem, $ZcreateData } from '#build/types/nuxt-zenstack';
2
- import type { Status, Error } from '../common.js';
1
+ import type { $Zmodel, $Zitem, $ZcreateData, $Zerror } from '#build/types/nuxt-zenstack';
2
+ import type { Status } from '../common.js';
3
3
  import { type Ref } from '#imports';
4
4
  export declare function useZenstackCreate<Zmodel extends $Zmodel, Zitem extends $Zitem<Zmodel>>(model: Zmodel): {
5
5
  data: Ref<Zitem | null>;
6
- error: Ref<Error | null>;
6
+ error: Ref<$Zerror | null>;
7
7
  status: Ref<Status>;
8
8
  mutate: (input: $ZcreateData<Zmodel>) => Promise<void>;
9
9
  reset: () => void;
@@ -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,9 +1,9 @@
1
- import type { $Zmodel, $Zitem, $Zid } from '#build/types/nuxt-zenstack';
2
- import type { Status, Error } from '../common.js';
1
+ import type { $Zmodel, $Zitem, $Zid, $Zerror } from '#build/types/nuxt-zenstack';
2
+ import type { Status } from '../common.js';
3
3
  import { type Ref } from '#imports';
4
4
  export declare function useZenstackDelete<Zmodel extends $Zmodel, Zitem extends $Zitem<Zmodel>>(model: Zmodel): {
5
5
  data: Ref<Zitem | null>;
6
- error: Ref<Error | null>;
6
+ error: Ref<$Zerror | null>;
7
7
  status: Ref<Status>;
8
8
  mutate: (id: $Zid<Zmodel>) => Promise<void>;
9
9
  reset: () => void;
@@ -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
- import type { $Zmodel, $Zitem, $Zid, $Zinclude } from '#build/types/nuxt-zenstack';
1
+ import type { $Zmodel, $Zitem, $Zid, $Zinclude, $Zerror } from '#build/types/nuxt-zenstack';
2
2
  import type { Status, FetchPolicy } from '../common.js';
3
- import type { Ref, MaybeRefOrGetter } from '#imports';
4
- type Options<Zmodel extends $Zmodel> = {
3
+ import type { Ref } from '#imports';
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?: 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
- error: Ref<Error | null>;
26
+ error: Ref<$Zerror | null>;
27
27
  status: Ref<Status>;
28
28
  refetch: () => Promise<void>;
29
- };
29
+ }>;
30
30
  export {};
@@ -1,57 +1,66 @@
1
- import { ref, toValue, watch, isRef } from "#imports";
1
+ import { ref, watch, 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";
12
+ const nuxtApp = useNuxtApp();
13
+ const method = "GET";
14
+ opts.fetchPolicy ??= config.fetchPolicy;
13
15
  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
- }
27
- const watchedOptions = [opts.include].filter((option) => isRef(option) || typeof option === "function");
16
+ if (opts.fetchPolicy !== "fetch-only")
17
+ updateData();
28
18
  watch(store.state, () => updateData());
29
- watch(watchedOptions, () => refetch());
30
- if (opts.immediate)
31
- refetch();
19
+ if (shouldFetchInitially())
20
+ await refetch();
21
+ function canFetchAutomatically() {
22
+ const entry = store.fetchHistory.value.find((entry2) => entry2.model === model && entry2.id === id && entry2.method === method && entry2.query === JSON.stringify(getQuery()));
23
+ if (entry?.ssr && nuxtApp.isHydrating)
24
+ return false;
25
+ if (opts.fetchPolicy === "cache-first" && entry)
26
+ return false;
27
+ return true;
28
+ }
29
+ function shouldFetchInitially() {
30
+ if (opts.immediate === false)
31
+ return false;
32
+ return canFetchAutomatically();
33
+ }
32
34
  function updateData() {
33
35
  data.value = store.getOne(model, id);
34
36
  }
37
+ function getQuery() {
38
+ const json = stringify({
39
+ include: opts.include
40
+ });
41
+ return { q: json };
42
+ }
35
43
  async function refetch() {
36
44
  if (opts.fetchPolicy === "cache-only")
37
45
  return;
46
+ const _fetch = getFetch();
38
47
  const url = joinURL(config.apiPath, `/models/${model.toString()}/${id}`);
39
- const json = stringify({
40
- include: toValue(opts.include)
48
+ const query = getQuery();
49
+ store.addToFetchHistory({
50
+ model: model.toString(),
51
+ id,
52
+ method,
53
+ query: JSON.stringify(query)
41
54
  });
42
55
  error.value = null;
43
56
  status.value = "pending";
44
57
  try {
45
- const res = await $fetch(url, {
46
- method: "GET",
47
- query: {
48
- q: json
49
- }
50
- });
58
+ const res = await _fetch(url, { method, query });
51
59
  if (res.data)
52
60
  store.setOne(model, res.data);
53
61
  else
54
62
  store.deleteOne(model, id);
63
+ updateData();
55
64
  status.value = "success";
56
65
  } catch (err) {
57
66
  error.value = err.data;
@@ -1,7 +1,7 @@
1
- import type { $Zmodel, $Zitem, $Zinclude, $Zwhere, $ZorderBy } from '#build/types/nuxt-zenstack';
1
+ import type { $Zmodel, $Zitem, $Zinclude, $Zwhere, $ZorderBy, $Zerror } 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?: 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,11 @@ 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
- error: Ref<Error | null>;
46
+ error: Ref<$Zerror | null>;
47
47
  status: Ref<Status>;
48
+ canFetchMore: Ref<boolean>;
48
49
  refetch: () => Promise<void>;
49
- };
50
+ }>;
50
51
  export {};
@@ -1,68 +1,88 @@
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
+ import { sort } from "./orderBy.js";
7
+ import { matchesWhere } from "./where.js";
8
+ export async function useZenstackReadMany(model, opts = {}) {
7
9
  const data = ref(null);
8
10
  const error = ref(null);
9
11
  const status = ref("idle");
12
+ const canFetchMore = ref(true);
10
13
  const store = useZenstackStore();
11
14
  const config = getConfig();
12
- opts.fetchPolicy ??= "cache-first";
15
+ const nuxtApp = useNuxtApp();
16
+ const watchedOptions = [opts.where, opts.orderBy, opts.skip, opts.take].filter((option) => isRef(option) || typeof option === "function");
17
+ const method = "GET";
18
+ opts.fetchPolicy ??= config.fetchPolicy;
13
19
  opts.immediate ??= true;
14
20
  opts.skip ??= 0;
15
21
  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");
22
+ if (opts.fetchPolicy !== "fetch-only")
23
+ updateData();
30
24
  watch(store.state, () => updateData());
31
25
  watch(watchedOptions, () => {
32
26
  updateData();
33
- refetch();
27
+ if (canFetchAutomatically())
28
+ refetch();
34
29
  });
35
- if (opts.immediate)
36
- refetch();
30
+ if (shouldFetchInitially())
31
+ await refetch();
32
+ function canFetchAutomatically() {
33
+ const entry = store.fetchHistory.value.find((entry2) => entry2.model === model && entry2.method === method && entry2.query === JSON.stringify(getQuery()));
34
+ if (entry?.ssr && nuxtApp.isHydrating)
35
+ return false;
36
+ if (opts.fetchPolicy === "cache-first" && entry)
37
+ return false;
38
+ return true;
39
+ }
40
+ function shouldFetchInitially() {
41
+ if (opts.immediate === false)
42
+ return false;
43
+ return canFetchAutomatically();
44
+ }
37
45
  function updateData() {
38
- data.value = store.getMany(model);
46
+ const items = store.getMany(model);
47
+ const filteredItems = items.filter((el) => matchesWhere(el, toValue(opts.where)));
48
+ const orderedFilteredItems = sort(filteredItems, toValue(opts.orderBy));
49
+ data.value = orderedFilteredItems;
39
50
  }
40
- async function refetch() {
41
- if (opts.fetchPolicy === "cache-only")
42
- return;
43
- const url = joinURL(config.apiPath, `/models/${model.toString()}`);
51
+ function getQuery() {
44
52
  const json = stringify({
45
- include: toValue(opts.include),
53
+ include: opts.include,
46
54
  where: toValue(opts.where),
47
55
  orderBy: toValue(opts.orderBy),
48
56
  skip: toValue(opts.skip),
49
57
  take: toValue(opts.take)
50
58
  });
59
+ return { q: json };
60
+ }
61
+ async function refetch() {
62
+ if (opts.fetchPolicy === "cache-only")
63
+ return;
64
+ const _fetch = getFetch();
65
+ const url = joinURL(config.apiPath, `/models/${model.toString()}`);
66
+ const query = getQuery();
67
+ store.addToFetchHistory({
68
+ model: model.toString(),
69
+ method,
70
+ query: JSON.stringify(query)
71
+ });
51
72
  error.value = null;
52
73
  status.value = "pending";
74
+ canFetchMore.value = false;
53
75
  try {
54
- const res = await $fetch(url, {
55
- method: "GET",
56
- query: {
57
- q: json
58
- }
59
- });
76
+ const res = await _fetch(url, { method, query });
60
77
  store.setMany(model, res.data);
78
+ updateData();
61
79
  status.value = "success";
80
+ canFetchMore.value = res.data.length === toValue(opts.take);
62
81
  } catch (err) {
63
82
  error.value = err.data;
64
83
  status.value = "error";
84
+ canFetchMore.value = true;
65
85
  }
66
86
  }
67
- return { data, error, status, refetch };
87
+ return { data, error, status, canFetchMore, refetch };
68
88
  }
@@ -0,0 +1,5 @@
1
+ import type { $Zitem, $ZorderBy, $Zinclude, $Zmodel } from '#build/types/nuxt-zenstack';
2
+ /**
3
+ * @note Sort by relational fields not supported
4
+ */
5
+ export declare function sort<Zmodel extends $Zmodel, Zinclude extends $Zinclude<Zmodel>, Zitem extends $Zitem<Zmodel, Zinclude>>(items: Zitem[], orderBy: $ZorderBy<Zmodel>): Zitem[];
@@ -0,0 +1,25 @@
1
+ export function sort(items, orderBy) {
2
+ if (!items.length || !orderBy)
3
+ return items;
4
+ return items.sort((a, b) => {
5
+ const orderByArray = Array.isArray(orderBy) ? orderBy : [orderBy];
6
+ for (const orderByObj of orderByArray) {
7
+ const orderByEntries = Object.entries(orderByObj);
8
+ for (const [field, direction] of orderByEntries) {
9
+ if (direction !== "asc" && direction !== "desc") continue;
10
+ const aValue = a[field];
11
+ const bValue = b[field];
12
+ if (aValue == null && bValue == null) continue;
13
+ if (aValue == null) return 1;
14
+ if (bValue == null) return -1;
15
+ let comparison = 0;
16
+ if (aValue < bValue) comparison = -1;
17
+ else if (aValue > bValue) comparison = 1;
18
+ if (comparison !== 0) {
19
+ return direction === "asc" ? comparison : -comparison;
20
+ }
21
+ }
22
+ }
23
+ return 0;
24
+ });
25
+ }
@@ -0,0 +1,2 @@
1
+ import type { $Zitem, $Zwhere, $Zinclude, $Zmodel } from '#build/types/nuxt-zenstack';
2
+ export declare function matchesWhere<Zmodel extends $Zmodel, Zinclude extends $Zinclude<Zmodel>>(item: $Zitem<Zmodel, Zinclude>, where: $Zwhere<Zmodel>): boolean;