@bg-dev/nuxt-zenstack 0.0.3 → 0.0.5
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 +2 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +61 -12
- package/dist/runtime/composables/common.d.ts +3 -13
- package/dist/runtime/composables/useZenstackCreate/index.d.ts +3 -3
- package/dist/runtime/composables/useZenstackDelete/index.d.ts +3 -3
- package/dist/runtime/composables/useZenstackRead/index.d.ts +4 -4
- package/dist/runtime/composables/useZenstackRead/index.js +8 -7
- package/dist/runtime/composables/useZenstackReadMany/index.d.ts +4 -3
- package/dist/runtime/composables/useZenstackReadMany/index.js +21 -8
- package/dist/runtime/composables/useZenstackReadMany/orderBy.d.ts +5 -0
- package/dist/runtime/composables/useZenstackReadMany/orderBy.js +25 -0
- package/dist/runtime/composables/useZenstackReadMany/where.d.ts +2 -0
- package/dist/runtime/composables/useZenstackReadMany/where.js +235 -0
- package/dist/runtime/composables/useZenstackRealtime/index.d.ts +6 -0
- package/dist/runtime/composables/useZenstackRealtime/index.js +53 -0
- package/dist/runtime/composables/useZenstackStore/index.d.ts +6 -2
- package/dist/runtime/composables/useZenstackStore/index.js +3 -4
- package/dist/runtime/composables/useZenstackStore/normalization.d.ts +16 -3
- package/dist/runtime/composables/useZenstackStore/normalization.js +16 -3
- package/dist/runtime/composables/useZenstackUpdate/index.d.ts +2 -2
- package/dist/runtime/server/api/models/[model]/[id].delete.d.ts +1 -1
- package/dist/runtime/server/api/models/[model]/[id].delete.js +5 -9
- package/dist/runtime/server/api/models/[model]/[id].get.d.ts +1 -1
- package/dist/runtime/server/api/models/[model]/[id].get.js +5 -10
- package/dist/runtime/server/api/models/[model]/[id].patch.d.ts +1 -1
- package/dist/runtime/server/api/models/[model]/[id].patch.js +6 -13
- package/dist/runtime/server/api/models/[model]/index.get.d.ts +2 -2
- package/dist/runtime/server/api/models/[model]/index.get.js +9 -7
- package/dist/runtime/server/api/models/[model]/index.post.d.ts +1 -1
- package/dist/runtime/server/api/models/[model]/index.post.js +6 -10
- package/dist/runtime/server/routes/realtime.d.ts +2 -0
- package/dist/runtime/server/routes/realtime.js +18 -0
- package/dist/runtime/server/utils/helpers.d.ts +7 -0
- package/dist/runtime/server/utils/helpers.js +34 -0
- package/dist/runtime/server/utils/index.d.ts +15 -12
- package/dist/runtime/server/utils/index.js +12 -46
- package/dist/runtime/server/utils/operations/common.d.ts +10 -0
- package/dist/runtime/server/utils/operations/common.js +52 -0
- package/dist/runtime/server/utils/operations/create.d.ts +10 -0
- package/dist/runtime/server/utils/operations/create.js +15 -0
- package/dist/runtime/server/utils/operations/delete.d.ts +10 -0
- package/dist/runtime/server/utils/operations/delete.js +16 -0
- package/dist/runtime/server/utils/operations/findMany.d.ts +14 -0
- package/dist/runtime/server/utils/operations/findMany.js +14 -0
- package/dist/runtime/server/utils/operations/findUnique.d.ts +11 -0
- package/dist/runtime/server/utils/operations/findUnique.js +14 -0
- package/dist/runtime/server/utils/operations/update.d.ts +11 -0
- package/dist/runtime/server/utils/operations/update.js +19 -0
- package/dist/runtime/server/utils/parsers.d.ts +3 -2
- package/dist/runtime/server/utils/parsers.js +9 -3
- package/package.json +3 -1
package/dist/module.d.mts
CHANGED
|
@@ -4,6 +4,8 @@ import { FetchPolicy } from '../dist/runtime/composables/common.js';
|
|
|
4
4
|
interface ModuleOptions {
|
|
5
5
|
apiPath: string;
|
|
6
6
|
fetchPolicy: FetchPolicy;
|
|
7
|
+
realtime: boolean;
|
|
8
|
+
baseUrl: string;
|
|
7
9
|
}
|
|
8
10
|
declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
|
|
9
11
|
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { defineNuxtModule, createResolver,
|
|
1
|
+
import { defineNuxtModule, createResolver, addTemplate, addServerTemplate, addTypeTemplate, addServerHandler, addImportsDir, addServerImports, addImports } 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.
|
|
6
|
+
const version = "0.0.5";
|
|
7
7
|
|
|
8
8
|
const module$1 = defineNuxtModule({
|
|
9
9
|
meta: {
|
|
@@ -14,21 +14,20 @@ const module$1 = defineNuxtModule({
|
|
|
14
14
|
// Default configuration options of the Nuxt module
|
|
15
15
|
defaults: {
|
|
16
16
|
apiPath: "/api/_zenstack",
|
|
17
|
-
fetchPolicy: "cache-first"
|
|
17
|
+
fetchPolicy: "cache-first",
|
|
18
|
+
realtime: false,
|
|
19
|
+
baseUrl: "http://localhost:3000"
|
|
18
20
|
},
|
|
19
21
|
setup(_options, _nuxt) {
|
|
20
22
|
_nuxt.options.runtimeConfig.public = defu(_nuxt.options.runtimeConfig.public, {
|
|
21
23
|
zenstack: {
|
|
22
24
|
apiPath: _options.apiPath,
|
|
23
|
-
fetchPolicy: _options.fetchPolicy
|
|
25
|
+
fetchPolicy: _options.fetchPolicy,
|
|
26
|
+
realtime: _options.realtime,
|
|
27
|
+
baseUrl: _options.baseUrl
|
|
24
28
|
}
|
|
25
29
|
});
|
|
26
30
|
const resolver = createResolver(import.meta.url);
|
|
27
|
-
addServerImports({
|
|
28
|
-
from: resolver.resolve("./runtime/server/utils"),
|
|
29
|
-
name: "provideClient",
|
|
30
|
-
as: "provideZenstackClient"
|
|
31
|
-
});
|
|
32
31
|
addTemplate({
|
|
33
32
|
write: true,
|
|
34
33
|
filename: "nuxt-zenstack.mjs",
|
|
@@ -45,13 +44,16 @@ export { schema as zenstackSchema } from '~~/zenstack/schema'
|
|
|
45
44
|
addTypeTemplate({
|
|
46
45
|
filename: "types/nuxt-zenstack.d.ts",
|
|
47
46
|
getContents: () => `
|
|
48
|
-
import type { ModelOperations, ModelResult, IncludeInput, WhereInput, FindManyArgs, SimplifiedPlainResult, SelectIncludeOmit, QueryOptions, CreateArgs, UpdateArgs } from '@zenstackhq/orm'
|
|
47
|
+
import type { ClientContract, ModelOperations, ModelResult, IncludeInput, WhereInput, FindManyArgs, SimplifiedPlainResult, SelectIncludeOmit, QueryOptions, CreateArgs, UpdateArgs } from '@zenstackhq/orm'
|
|
49
48
|
import type { SchemaType } from '~~/zenstack/schema'
|
|
50
49
|
import type { ModelDef } from '@zenstackhq/orm/schema'
|
|
50
|
+
import type { H3Error } from 'h3'
|
|
51
|
+
import { ORMError, RejectedByPolicyReason, ORMErrorReason } from '@zenstackhq/orm'
|
|
51
52
|
|
|
52
53
|
type ItemGetPayload<Zmodel extends $Zmodel, Args extends SelectIncludeOmit<SchemaType, Zmodel, true>, Options extends QueryOptions<SchemaType> = QueryOptions<SchemaType>> = SimplifiedPlainResult<SchemaType, Zmodel, Args, Options>
|
|
53
54
|
|
|
54
55
|
export type $Zschema = SchemaType
|
|
56
|
+
export type $Zclient = ClientContract<SchemaType>
|
|
55
57
|
export type $Zmodel = keyof SchemaType['models']
|
|
56
58
|
export type $Zdef = ModelDef
|
|
57
59
|
export type $Zoperations<Zmodel extends $Zmodel> = ModelOperations<SchemaType, Zmodel>
|
|
@@ -60,8 +62,41 @@ export type $Zinclude<Zmodel extends $Zmodel> = IncludeInput<SchemaType, Zmodel>
|
|
|
60
62
|
export type $Zitem<Zmodel extends $Zmodel, Zinclude extends $Zinclude = undefined> = ItemGetPayload<Zmodel, { include: Zinclude }>
|
|
61
63
|
export type $Zwhere<Zmodel extends $Zmodel> = WhereInput<SchemaType, Zmodel> | undefined
|
|
62
64
|
export type $ZorderBy<Zmodel extends $Zmodel> = FindManyArgs<SchemaType, Zmodel>['orderBy'] | undefined
|
|
63
|
-
|
|
64
|
-
|
|
65
|
+
|
|
66
|
+
type NonRelationalFields<Zmodel extends $Zmodel> = keyof $Zitem<Zmodel>
|
|
67
|
+
type CreateData<Zmodel extends $Zmodel> = CreateArgs<SchemaType, Zmodel>['data']
|
|
68
|
+
type UpdateData<Zmodel extends $Zmodel> = UpdateArgs<SchemaType, Zmodel>['data']
|
|
69
|
+
|
|
70
|
+
export type $ZcreateData<Zmodel extends $Zmodel> = Pick<CreateData<Zmodel>, NonRelationalFields<Zmodel>>
|
|
71
|
+
export type $ZupdateData<Zmodel extends $Zmodel> = Pick<UpdateData<Zmodel>, NonRelationalFields<Zmodel>>
|
|
72
|
+
export type $ZormError = ORMError
|
|
73
|
+
export type $Zerror = H3Error<{
|
|
74
|
+
ormErrorReason: ORMErrorReason
|
|
75
|
+
dbErrorCode?: unknown
|
|
76
|
+
dbErrorMessage?: string
|
|
77
|
+
model?: string
|
|
78
|
+
rejectedByPolicyReason?: RejectedByPolicyReason
|
|
79
|
+
}>
|
|
80
|
+
|
|
81
|
+
declare module 'h3' {
|
|
82
|
+
interface H3EventContext {
|
|
83
|
+
zenstack: {
|
|
84
|
+
client: ClientContract<SchemaType>
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
type RealtimeData = {
|
|
90
|
+
action: 'create' | 'update' | 'delete'
|
|
91
|
+
model: $Zmodel
|
|
92
|
+
ids: Array<number | string>
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
declare module 'nitropack' {
|
|
96
|
+
interface NitroRuntimeHooks {
|
|
97
|
+
'zenstack:after_mutation': (action: 'create' | 'update' | 'delete', model: $Zmodel, items: Record<string, unknown>[]) => Promise<void> | void
|
|
98
|
+
}
|
|
99
|
+
}
|
|
65
100
|
`
|
|
66
101
|
});
|
|
67
102
|
addServerHandler({
|
|
@@ -85,6 +120,20 @@ export type $ZupdateData<Zmodel extends $Zmodel> = UpdateArgs<SchemaType, Zmodel
|
|
|
85
120
|
handler: resolver.resolve("./runtime/server/api/models/[model]/[id].get")
|
|
86
121
|
});
|
|
87
122
|
addImportsDir(resolver.resolve("./runtime/composables"));
|
|
123
|
+
addServerImports({
|
|
124
|
+
from: resolver.resolve("./runtime/server/utils"),
|
|
125
|
+
name: "useZenstack"
|
|
126
|
+
});
|
|
127
|
+
if (_options.realtime) {
|
|
128
|
+
addServerHandler({
|
|
129
|
+
route: joinURL(_options.apiPath, "realtime"),
|
|
130
|
+
handler: resolver.resolve("./runtime/server/routes/realtime")
|
|
131
|
+
});
|
|
132
|
+
addImports({
|
|
133
|
+
from: resolver.resolve("./runtime/composables/useZenstackRealtime"),
|
|
134
|
+
name: "useZenstackRealtime"
|
|
135
|
+
});
|
|
136
|
+
}
|
|
88
137
|
}
|
|
89
138
|
});
|
|
90
139
|
|
|
@@ -1,19 +1,9 @@
|
|
|
1
|
+
import type { ModuleOptions } from '../../module.js';
|
|
1
2
|
export type Status = 'idle' | 'pending' | 'success' | 'error';
|
|
2
3
|
export type FetchPolicy = 'cache-first' | 'fetch-only' | 'cache-only' | 'cache-and-fetch';
|
|
3
|
-
export
|
|
4
|
-
error: boolean;
|
|
5
|
-
url: string;
|
|
6
|
-
statusCode: number;
|
|
7
|
-
statusMessage: string;
|
|
8
|
-
message: string;
|
|
9
|
-
stack?: string[];
|
|
10
|
-
};
|
|
11
|
-
export declare function getConfig(): {
|
|
12
|
-
apiPath: string;
|
|
13
|
-
fetchPolicy: FetchPolicy;
|
|
14
|
-
};
|
|
4
|
+
export declare function getConfig(): ModuleOptions;
|
|
15
5
|
/**
|
|
16
6
|
* @param instance a custom fetch method created by `$fetch.create`
|
|
17
7
|
*/
|
|
18
8
|
export declare function provideFetch(instance: typeof $fetch): void;
|
|
19
|
-
export declare function getFetch(): import("nitropack
|
|
9
|
+
export declare function getFetch(): import("nitropack").$Fetch<unknown, import("nitropack").NitroFetchRequest>;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type { $Zmodel, $Zitem, $ZcreateData } from '#build/types/nuxt-zenstack';
|
|
2
|
-
import type { Status
|
|
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
|
|
6
|
+
error: Ref<$Zerror | null>;
|
|
7
7
|
status: Ref<Status>;
|
|
8
8
|
mutate: (input: $ZcreateData<Zmodel>) => Promise<void>;
|
|
9
9
|
reset: () => void;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type { $Zmodel, $Zitem, $Zid } from '#build/types/nuxt-zenstack';
|
|
2
|
-
import type { Status
|
|
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
|
|
6
|
+
error: Ref<$Zerror | null>;
|
|
7
7
|
status: Ref<Status>;
|
|
8
8
|
mutate: (id: $Zid<Zmodel>) => Promise<void>;
|
|
9
9
|
reset: () => void;
|
|
@@ -1,6 +1,6 @@
|
|
|
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
|
|
3
|
+
import type { Ref } from '#imports';
|
|
4
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.
|
|
@@ -19,11 +19,11 @@ type Options<Zinclude> = {
|
|
|
19
19
|
* The relations to include in the query.
|
|
20
20
|
* @default undefined
|
|
21
21
|
*/
|
|
22
|
-
include?:
|
|
22
|
+
include?: Zinclude;
|
|
23
23
|
};
|
|
24
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
|
|
26
|
+
error: Ref<$Zerror | null>;
|
|
27
27
|
status: Ref<Status>;
|
|
28
28
|
refetch: () => Promise<void>;
|
|
29
29
|
}>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ref,
|
|
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";
|
|
@@ -10,19 +10,15 @@ export async function useZenstackRead(model, id, opts = {}) {
|
|
|
10
10
|
const store = useZenstackStore();
|
|
11
11
|
const config = getConfig();
|
|
12
12
|
const nuxtApp = useNuxtApp();
|
|
13
|
-
const watchedOptions = [opts.include].filter((option) => isRef(option) || typeof option === "function");
|
|
14
13
|
const method = "GET";
|
|
15
14
|
opts.fetchPolicy ??= config.fetchPolicy;
|
|
16
15
|
opts.immediate ??= true;
|
|
17
16
|
if (opts.fetchPolicy !== "fetch-only")
|
|
18
17
|
updateData();
|
|
19
18
|
watch(store.state, () => updateData());
|
|
20
|
-
watch(watchedOptions, () => refetch());
|
|
21
19
|
if (shouldFetchInitially())
|
|
22
20
|
await refetch();
|
|
23
|
-
function
|
|
24
|
-
if (opts.immediate === false)
|
|
25
|
-
return false;
|
|
21
|
+
function canFetchAutomatically() {
|
|
26
22
|
const entry = store.fetchHistory.value.find((entry2) => entry2.model === model && entry2.id === id && entry2.method === method && entry2.query === JSON.stringify(getQuery()));
|
|
27
23
|
if (entry?.ssr && nuxtApp.isHydrating)
|
|
28
24
|
return false;
|
|
@@ -30,12 +26,17 @@ export async function useZenstackRead(model, id, opts = {}) {
|
|
|
30
26
|
return false;
|
|
31
27
|
return true;
|
|
32
28
|
}
|
|
29
|
+
function shouldFetchInitially() {
|
|
30
|
+
if (opts.immediate === false)
|
|
31
|
+
return false;
|
|
32
|
+
return canFetchAutomatically();
|
|
33
|
+
}
|
|
33
34
|
function updateData() {
|
|
34
35
|
data.value = store.getOne(model, id);
|
|
35
36
|
}
|
|
36
37
|
function getQuery() {
|
|
37
38
|
const json = stringify({
|
|
38
|
-
include:
|
|
39
|
+
include: opts.include
|
|
39
40
|
});
|
|
40
41
|
return { q: json };
|
|
41
42
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
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
4
|
type Options<Zinclude, Zwhere, ZorderBy> = {
|
|
@@ -19,7 +19,7 @@ type Options<Zinclude, Zwhere, ZorderBy> = {
|
|
|
19
19
|
* The relations to include in the query.
|
|
20
20
|
* @default undefined
|
|
21
21
|
*/
|
|
22
|
-
include?:
|
|
22
|
+
include?: Zinclude;
|
|
23
23
|
/**
|
|
24
24
|
* The filter to apply to the query.
|
|
25
25
|
* @default undefined
|
|
@@ -43,8 +43,9 @@ type Options<Zinclude, Zwhere, ZorderBy> = {
|
|
|
43
43
|
};
|
|
44
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
|
|
46
|
+
error: Ref<$Zerror | null>;
|
|
47
47
|
status: Ref<Status>;
|
|
48
|
+
canFetchMore: Ref<boolean>;
|
|
48
49
|
refetch: () => Promise<void>;
|
|
49
50
|
}>;
|
|
50
51
|
export {};
|
|
@@ -3,14 +3,17 @@ import { joinURL } from "ufo";
|
|
|
3
3
|
import { useZenstackStore } from "../useZenstackStore/index.js";
|
|
4
4
|
import { stringify } from "superjson";
|
|
5
5
|
import { getConfig, getFetch } from "../common.js";
|
|
6
|
+
import { sort } from "./orderBy.js";
|
|
7
|
+
import { matchesWhere } from "./where.js";
|
|
6
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
15
|
const nuxtApp = useNuxtApp();
|
|
13
|
-
const watchedOptions = [opts.
|
|
16
|
+
const watchedOptions = [opts.where, opts.orderBy, opts.skip, opts.take].filter((option) => isRef(option) || typeof option === "function");
|
|
14
17
|
const method = "GET";
|
|
15
18
|
opts.fetchPolicy ??= config.fetchPolicy;
|
|
16
19
|
opts.immediate ??= true;
|
|
@@ -21,13 +24,12 @@ export async function useZenstackReadMany(model, opts = {}) {
|
|
|
21
24
|
watch(store.state, () => updateData());
|
|
22
25
|
watch(watchedOptions, () => {
|
|
23
26
|
updateData();
|
|
24
|
-
|
|
27
|
+
if (canFetchAutomatically())
|
|
28
|
+
refetch();
|
|
25
29
|
});
|
|
26
30
|
if (shouldFetchInitially())
|
|
27
31
|
await refetch();
|
|
28
|
-
function
|
|
29
|
-
if (opts.immediate === false)
|
|
30
|
-
return false;
|
|
32
|
+
function canFetchAutomatically() {
|
|
31
33
|
const entry = store.fetchHistory.value.find((entry2) => entry2.model === model && entry2.method === method && entry2.query === JSON.stringify(getQuery()));
|
|
32
34
|
if (entry?.ssr && nuxtApp.isHydrating)
|
|
33
35
|
return false;
|
|
@@ -35,12 +37,20 @@ export async function useZenstackReadMany(model, opts = {}) {
|
|
|
35
37
|
return false;
|
|
36
38
|
return true;
|
|
37
39
|
}
|
|
40
|
+
function shouldFetchInitially() {
|
|
41
|
+
if (opts.immediate === false)
|
|
42
|
+
return false;
|
|
43
|
+
return canFetchAutomatically();
|
|
44
|
+
}
|
|
38
45
|
function updateData() {
|
|
39
|
-
|
|
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;
|
|
40
50
|
}
|
|
41
51
|
function getQuery() {
|
|
42
52
|
const json = stringify({
|
|
43
|
-
include:
|
|
53
|
+
include: opts.include,
|
|
44
54
|
where: toValue(opts.where),
|
|
45
55
|
orderBy: toValue(opts.orderBy),
|
|
46
56
|
skip: toValue(opts.skip),
|
|
@@ -61,15 +71,18 @@ export async function useZenstackReadMany(model, opts = {}) {
|
|
|
61
71
|
});
|
|
62
72
|
error.value = null;
|
|
63
73
|
status.value = "pending";
|
|
74
|
+
canFetchMore.value = false;
|
|
64
75
|
try {
|
|
65
76
|
const res = await _fetch(url, { method, query });
|
|
66
77
|
store.setMany(model, res.data);
|
|
67
78
|
updateData();
|
|
68
79
|
status.value = "success";
|
|
80
|
+
canFetchMore.value = res.data.length === toValue(opts.take);
|
|
69
81
|
} catch (err) {
|
|
70
82
|
error.value = err.data;
|
|
71
83
|
status.value = "error";
|
|
84
|
+
canFetchMore.value = true;
|
|
72
85
|
}
|
|
73
86
|
}
|
|
74
|
-
return { data, error, status, refetch };
|
|
87
|
+
return { data, error, status, canFetchMore, refetch };
|
|
75
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,235 @@
|
|
|
1
|
+
export function matchesWhere(item, where) {
|
|
2
|
+
if (!where) return true;
|
|
3
|
+
if (!item) return false;
|
|
4
|
+
const itemRecord = item;
|
|
5
|
+
const whereRecord = where;
|
|
6
|
+
for (const key of Object.keys(whereRecord)) {
|
|
7
|
+
if (whereRecord[key] === void 0) continue;
|
|
8
|
+
const filter = whereRecord[key];
|
|
9
|
+
if (key === "AND") {
|
|
10
|
+
if (Array.isArray(filter)) {
|
|
11
|
+
if (!filter.every((cond) => matchesWhere(item, cond))) return false;
|
|
12
|
+
} else {
|
|
13
|
+
if (!matchesWhere(item, filter)) return false;
|
|
14
|
+
}
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
if (key === "OR") {
|
|
18
|
+
if (Array.isArray(filter)) {
|
|
19
|
+
if (!filter.some((cond) => matchesWhere(item, cond))) return false;
|
|
20
|
+
} else {
|
|
21
|
+
if (!matchesWhere(item, filter)) return false;
|
|
22
|
+
}
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
if (key === "NOT") {
|
|
26
|
+
if (Array.isArray(filter)) {
|
|
27
|
+
if (filter.some((cond) => matchesWhere(item, cond))) return false;
|
|
28
|
+
} else {
|
|
29
|
+
if (matchesWhere(item, filter)) return false;
|
|
30
|
+
}
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
const value = itemRecord[key];
|
|
34
|
+
if (!checkCondition(value, filter)) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
function checkCondition(value, filter) {
|
|
41
|
+
if (filter === null) {
|
|
42
|
+
return value === null;
|
|
43
|
+
}
|
|
44
|
+
if (filter === void 0) {
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
if (typeof filter !== "object" && typeof filter !== "function") {
|
|
48
|
+
if (value instanceof Date && typeof filter === "string") {
|
|
49
|
+
return value.toISOString() === filter;
|
|
50
|
+
}
|
|
51
|
+
return value === filter;
|
|
52
|
+
}
|
|
53
|
+
if (value instanceof Date && filter instanceof Date) {
|
|
54
|
+
return value.getTime() === filter.getTime();
|
|
55
|
+
}
|
|
56
|
+
const filterRecord = filter;
|
|
57
|
+
const keys = Object.keys(filterRecord);
|
|
58
|
+
if (keys.length === 0) return true;
|
|
59
|
+
let caseInsensitive = false;
|
|
60
|
+
if (filterRecord.mode === "insensitive") {
|
|
61
|
+
caseInsensitive = true;
|
|
62
|
+
}
|
|
63
|
+
for (const op of keys) {
|
|
64
|
+
if (op === "mode") continue;
|
|
65
|
+
let expected = filterRecord[op];
|
|
66
|
+
let actual = value;
|
|
67
|
+
if (["lt", "lte", "gt", "gte", "equals", "not"].includes(op)) {
|
|
68
|
+
if (actual instanceof Date && typeof expected === "string") {
|
|
69
|
+
const d = new Date(expected);
|
|
70
|
+
if (!Number.isNaN(d.getTime())) expected = d;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (caseInsensitive && typeof actual === "string" && typeof expected === "string") {
|
|
74
|
+
if (["equals", "not", "contains", "startsWith", "endsWith"].includes(op)) {
|
|
75
|
+
actual = actual.toLowerCase();
|
|
76
|
+
expected = expected.toLowerCase();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
switch (op) {
|
|
80
|
+
case "equals":
|
|
81
|
+
if (actual instanceof Date && expected instanceof Date) {
|
|
82
|
+
if (actual.getTime() !== expected.getTime()) return false;
|
|
83
|
+
} else if (actual !== expected) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
break;
|
|
87
|
+
case "not":
|
|
88
|
+
if (typeof expected === "object" && expected !== null && !Array.isArray(expected) && !(expected instanceof Date)) {
|
|
89
|
+
if (checkCondition(value, expected)) return false;
|
|
90
|
+
} else {
|
|
91
|
+
if (actual instanceof Date && expected instanceof Date) {
|
|
92
|
+
if (actual.getTime() === expected.getTime()) return false;
|
|
93
|
+
} else if (actual === expected) {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
break;
|
|
98
|
+
case "in":
|
|
99
|
+
if (!Array.isArray(expected)) return false;
|
|
100
|
+
if (caseInsensitive && typeof actual === "string") {
|
|
101
|
+
const lowerVal = actual.toLowerCase();
|
|
102
|
+
const lowerList = expected.map((e) => typeof e === "string" ? e.toLowerCase() : e);
|
|
103
|
+
if (!lowerList.includes(lowerVal)) return false;
|
|
104
|
+
} else {
|
|
105
|
+
if (actual instanceof Date) {
|
|
106
|
+
const time = actual.getTime();
|
|
107
|
+
if (!expected.some((e) => e instanceof Date && e.getTime() === time || e === actual)) return false;
|
|
108
|
+
} else {
|
|
109
|
+
if (!expected.includes(actual)) return false;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
break;
|
|
113
|
+
case "notIn":
|
|
114
|
+
if (!Array.isArray(expected)) return false;
|
|
115
|
+
if (caseInsensitive && typeof actual === "string") {
|
|
116
|
+
const lowerVal = actual.toLowerCase();
|
|
117
|
+
const lowerList = expected.map((e) => typeof e === "string" ? e.toLowerCase() : e);
|
|
118
|
+
if (lowerList.includes(lowerVal)) return false;
|
|
119
|
+
} else {
|
|
120
|
+
if (actual instanceof Date) {
|
|
121
|
+
const time = actual.getTime();
|
|
122
|
+
if (expected.some((e) => e instanceof Date && e.getTime() === time || e === actual)) return false;
|
|
123
|
+
} else {
|
|
124
|
+
if (expected.includes(actual)) return false;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
break;
|
|
128
|
+
case "lt":
|
|
129
|
+
if (typeof actual === "number" && typeof expected === "number") {
|
|
130
|
+
if (!(actual < expected)) return false;
|
|
131
|
+
} else if (actual instanceof Date && expected instanceof Date) {
|
|
132
|
+
if (!(actual < expected)) return false;
|
|
133
|
+
} else if (typeof actual === "string" && typeof expected === "string") {
|
|
134
|
+
if (!(actual < expected)) return false;
|
|
135
|
+
} else {
|
|
136
|
+
if (!(actual < expected)) return false;
|
|
137
|
+
}
|
|
138
|
+
break;
|
|
139
|
+
case "lte":
|
|
140
|
+
if (!(actual <= expected)) return false;
|
|
141
|
+
break;
|
|
142
|
+
case "gt":
|
|
143
|
+
if (!(actual > expected)) return false;
|
|
144
|
+
break;
|
|
145
|
+
case "gte":
|
|
146
|
+
if (!(actual >= expected)) return false;
|
|
147
|
+
break;
|
|
148
|
+
case "contains":
|
|
149
|
+
if (typeof actual !== "string" || typeof expected !== "string" || !actual.includes(expected)) return false;
|
|
150
|
+
break;
|
|
151
|
+
case "startsWith":
|
|
152
|
+
if (typeof actual !== "string" || typeof expected !== "string" || !actual.startsWith(expected)) return false;
|
|
153
|
+
break;
|
|
154
|
+
case "endsWith":
|
|
155
|
+
if (typeof actual !== "string" || typeof expected !== "string" || !actual.endsWith(expected)) return false;
|
|
156
|
+
break;
|
|
157
|
+
// Relations
|
|
158
|
+
case "some":
|
|
159
|
+
if (!Array.isArray(value)) return false;
|
|
160
|
+
if (!value.some((v) => checkInternal(v, expected))) return false;
|
|
161
|
+
break;
|
|
162
|
+
case "every":
|
|
163
|
+
if (!Array.isArray(value)) return false;
|
|
164
|
+
if (!value.every((v) => checkInternal(v, expected))) return false;
|
|
165
|
+
break;
|
|
166
|
+
case "none":
|
|
167
|
+
if (!Array.isArray(value)) return false;
|
|
168
|
+
if (value.some((v) => checkInternal(v, expected))) return false;
|
|
169
|
+
break;
|
|
170
|
+
case "is":
|
|
171
|
+
if (expected === null) {
|
|
172
|
+
if (value != null) return false;
|
|
173
|
+
} else {
|
|
174
|
+
if (value == null) return false;
|
|
175
|
+
if (!checkInternal(value, expected)) return false;
|
|
176
|
+
}
|
|
177
|
+
break;
|
|
178
|
+
case "isNot":
|
|
179
|
+
if (expected === null) {
|
|
180
|
+
if (value == null) return false;
|
|
181
|
+
} else {
|
|
182
|
+
if (value == null) break;
|
|
183
|
+
if (checkInternal(value, expected)) return false;
|
|
184
|
+
}
|
|
185
|
+
break;
|
|
186
|
+
default:
|
|
187
|
+
if (value && typeof value === "object" && !Array.isArray(value) && !(value instanceof Date)) {
|
|
188
|
+
if (!checkCondition(value[op], expected)) return false;
|
|
189
|
+
} else {
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
function checkInternal(item, where) {
|
|
197
|
+
return matchesWhereInternal(item, where);
|
|
198
|
+
}
|
|
199
|
+
function matchesWhereInternal(item, where) {
|
|
200
|
+
if (!where) return true;
|
|
201
|
+
if (!item) return false;
|
|
202
|
+
for (const key of Object.keys(where)) {
|
|
203
|
+
if (where[key] === void 0) continue;
|
|
204
|
+
const filter = where[key];
|
|
205
|
+
if (key === "AND") {
|
|
206
|
+
if (Array.isArray(filter)) {
|
|
207
|
+
if (!filter.every((cond) => matchesWhereInternal(item, cond))) return false;
|
|
208
|
+
} else {
|
|
209
|
+
if (!matchesWhereInternal(item, filter)) return false;
|
|
210
|
+
}
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
if (key === "OR") {
|
|
214
|
+
if (Array.isArray(filter)) {
|
|
215
|
+
if (!filter.some((cond) => matchesWhereInternal(item, cond))) return false;
|
|
216
|
+
} else {
|
|
217
|
+
if (!matchesWhereInternal(item, filter)) return false;
|
|
218
|
+
}
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
if (key === "NOT") {
|
|
222
|
+
if (Array.isArray(filter)) {
|
|
223
|
+
if (filter.some((cond) => matchesWhereInternal(item, cond))) return false;
|
|
224
|
+
} else {
|
|
225
|
+
if (matchesWhereInternal(item, filter)) return false;
|
|
226
|
+
}
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
const value = item[key];
|
|
230
|
+
if (!checkCondition(value, filter)) {
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return true;
|
|
235
|
+
}
|