@confect/core 1.0.0-next.0
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/CHANGELOG.md +7 -0
- package/LICENSE +7 -0
- package/dist/FunctionSpec.d.ts +95 -0
- package/dist/FunctionSpec.d.ts.map +1 -0
- package/dist/FunctionSpec.js +38 -0
- package/dist/FunctionSpec.js.map +1 -0
- package/dist/GenericId.d.ts +13 -0
- package/dist/GenericId.d.ts.map +1 -0
- package/dist/GenericId.js +15 -0
- package/dist/GenericId.js.map +1 -0
- package/dist/GroupPath.d.ts +33 -0
- package/dist/GroupPath.d.ts.map +1 -0
- package/dist/GroupPath.js +6 -0
- package/dist/GroupPath.js.map +1 -0
- package/dist/GroupSpec.d.ts +32 -0
- package/dist/GroupSpec.d.ts.map +1 -0
- package/dist/GroupSpec.js +49 -0
- package/dist/GroupSpec.js.map +1 -0
- package/dist/PaginationResult.d.ts +20 -0
- package/dist/PaginationResult.d.ts.map +1 -0
- package/dist/PaginationResult.js +16 -0
- package/dist/PaginationResult.js.map +1 -0
- package/dist/Ref.d.ts +40 -0
- package/dist/Ref.d.ts.map +1 -0
- package/dist/Ref.js +20 -0
- package/dist/Ref.js.map +1 -0
- package/dist/Refs.d.ts +22 -0
- package/dist/Refs.d.ts.map +1 -0
- package/dist/Refs.js +24 -0
- package/dist/Refs.js.map +1 -0
- package/dist/Spec.d.ts +23 -0
- package/dist/Spec.d.ts.map +1 -0
- package/dist/Spec.js +23 -0
- package/dist/Spec.js.map +1 -0
- package/dist/SystemFields.d.ts +28 -0
- package/dist/SystemFields.d.ts.map +1 -0
- package/dist/SystemFields.js +24 -0
- package/dist/SystemFields.js.map +1 -0
- package/dist/Types.d.ts +35 -0
- package/dist/Types.d.ts.map +1 -0
- package/dist/Types.js +6 -0
- package/dist/Types.js.map +1 -0
- package/dist/UserIdentity.d.ts +65 -0
- package/dist/UserIdentity.d.ts.map +1 -0
- package/dist/UserIdentity.js +32 -0
- package/dist/UserIdentity.js.map +1 -0
- package/dist/_virtual/rolldown_runtime.js +13 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +13 -0
- package/dist/internal/utils.d.ts +5 -0
- package/dist/internal/utils.d.ts.map +1 -0
- package/dist/internal/utils.js +68 -0
- package/dist/internal/utils.js.map +1 -0
- package/package.json +73 -0
- package/src/FunctionSpec.ts +153 -0
- package/src/GenericId.ts +18 -0
- package/src/GroupPath.ts +61 -0
- package/src/GroupSpec.ts +120 -0
- package/src/PaginationResult.ts +21 -0
- package/src/Ref.ts +175 -0
- package/src/Refs.ts +99 -0
- package/src/Spec.ts +52 -0
- package/src/SystemFields.ts +51 -0
- package/src/Types.ts +166 -0
- package/src/UserIdentity.ts +28 -0
- package/src/index.ts +11 -0
- package/src/internal/utils.ts +86 -0
package/src/GroupPath.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { Record } from "effect";
|
|
2
|
+
import type * as GroupSpec from "./GroupSpec";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Recursively generates paths for a group and its nested groups.
|
|
6
|
+
*
|
|
7
|
+
* - For a group with no subgroups, returns just the group name.
|
|
8
|
+
* - For a group with subgroups, returns the group name plus all possible paths through its direct subgroups.
|
|
9
|
+
*/
|
|
10
|
+
export type All<
|
|
11
|
+
Group extends GroupSpec.AnyWithProps,
|
|
12
|
+
Depth extends 1[] = [],
|
|
13
|
+
> = Depth["length"] extends 15
|
|
14
|
+
? string
|
|
15
|
+
: Group extends any
|
|
16
|
+
? [GroupSpec.Groups<Group>] extends [never]
|
|
17
|
+
? GroupSpec.Name<Group>
|
|
18
|
+
: GroupSpec.Name<Group> | AllHelper<Group, GroupSpec.Groups<Group>, Depth>
|
|
19
|
+
: never;
|
|
20
|
+
|
|
21
|
+
type AllHelper<
|
|
22
|
+
Parent extends GroupSpec.AnyWithProps,
|
|
23
|
+
Groups_ extends GroupSpec.AnyWithProps,
|
|
24
|
+
Depth extends 1[] = [],
|
|
25
|
+
> = Groups_ extends GroupSpec.AnyWithProps
|
|
26
|
+
? `${GroupSpec.Name<Parent>}.${All<Groups_, [...Depth, 1]>}`
|
|
27
|
+
: never;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Recursively extracts the group at the given dot-separated path.
|
|
31
|
+
* Path must match the format defined in `Path` above, e.g. "group" or "group.subgroup".
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* type G = WithPath<RootGroup, "group.subgroup">;
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export type GroupAt<
|
|
39
|
+
Group,
|
|
40
|
+
Path extends string,
|
|
41
|
+
> = Group extends GroupSpec.AnyWithProps
|
|
42
|
+
? Path extends `${infer Head}.${infer Tail}`
|
|
43
|
+
? Group extends { readonly name: Head }
|
|
44
|
+
? Group extends {
|
|
45
|
+
readonly groups: Record.ReadonlyRecord<string, infer SubGroup>;
|
|
46
|
+
}
|
|
47
|
+
? GroupAt<SubGroup, Tail>
|
|
48
|
+
: never
|
|
49
|
+
: never
|
|
50
|
+
: GroupSpec.WithName<Group, Path>
|
|
51
|
+
: never;
|
|
52
|
+
|
|
53
|
+
export type SubGroupsAt<
|
|
54
|
+
Group extends GroupSpec.AnyWithProps,
|
|
55
|
+
GroupPath extends string,
|
|
56
|
+
> =
|
|
57
|
+
GroupSpec.Groups<GroupAt<Group, GroupPath>> extends infer SubGroups
|
|
58
|
+
? SubGroups extends GroupSpec.AnyWithProps
|
|
59
|
+
? `${GroupPath}.${GroupSpec.Name<SubGroups>}`
|
|
60
|
+
: never
|
|
61
|
+
: never;
|
package/src/GroupSpec.ts
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { Predicate, Record } from "effect";
|
|
2
|
+
import type * as FunctionSpec from "./FunctionSpec";
|
|
3
|
+
import { validateConfectFunctionIdentifier } from "./internal/utils";
|
|
4
|
+
|
|
5
|
+
export const TypeId = "@confect/core/api/GroupSpec";
|
|
6
|
+
export type TypeId = typeof TypeId;
|
|
7
|
+
|
|
8
|
+
export const isGroupSpec = (u: unknown): u is Any =>
|
|
9
|
+
Predicate.hasProperty(u, TypeId);
|
|
10
|
+
|
|
11
|
+
export interface GroupSpec<
|
|
12
|
+
Name_ extends string,
|
|
13
|
+
Functions_ extends FunctionSpec.AnyWithProps = never,
|
|
14
|
+
Groups_ extends AnyWithProps = never,
|
|
15
|
+
> {
|
|
16
|
+
readonly [TypeId]: TypeId;
|
|
17
|
+
readonly name: Name_;
|
|
18
|
+
readonly functions: {
|
|
19
|
+
[FunctionName in FunctionSpec.Name<Functions_>]: FunctionSpec.WithName<
|
|
20
|
+
Functions_,
|
|
21
|
+
FunctionName
|
|
22
|
+
>;
|
|
23
|
+
};
|
|
24
|
+
readonly groups: {
|
|
25
|
+
[GroupName in Name<Groups_>]: WithName<Groups_, GroupName>;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
addFunction<Function extends FunctionSpec.AnyWithProps>(
|
|
29
|
+
function_: Function,
|
|
30
|
+
): GroupSpec<Name_, Functions_ | Function, Groups_>;
|
|
31
|
+
|
|
32
|
+
addGroup<Group extends AnyWithProps>(
|
|
33
|
+
group: Group,
|
|
34
|
+
): GroupSpec<Name_, Functions_, Groups_ | Group>;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface Any {
|
|
38
|
+
readonly [TypeId]: TypeId;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface AnyWithProps
|
|
42
|
+
extends GroupSpec<string, FunctionSpec.AnyWithProps, AnyWithProps> {}
|
|
43
|
+
|
|
44
|
+
export type Name<Group extends AnyWithProps> = Group["name"];
|
|
45
|
+
|
|
46
|
+
export type Functions<Group extends AnyWithProps> =
|
|
47
|
+
Group["functions"][keyof Group["functions"]];
|
|
48
|
+
|
|
49
|
+
export type Groups<Group extends AnyWithProps> =
|
|
50
|
+
Group["groups"][keyof Group["groups"]];
|
|
51
|
+
|
|
52
|
+
export type GroupNames<Group extends AnyWithProps> = [Groups<Group>] extends [
|
|
53
|
+
never,
|
|
54
|
+
]
|
|
55
|
+
? never
|
|
56
|
+
: Name<Groups<Group>>;
|
|
57
|
+
|
|
58
|
+
export type WithName<
|
|
59
|
+
Group extends AnyWithProps,
|
|
60
|
+
Name_ extends Name<Group>,
|
|
61
|
+
> = Extract<Group, { readonly name: Name_ }>;
|
|
62
|
+
|
|
63
|
+
const Proto = {
|
|
64
|
+
[TypeId]: TypeId,
|
|
65
|
+
|
|
66
|
+
addFunction<Function extends FunctionSpec.AnyWithProps>(
|
|
67
|
+
this: Any,
|
|
68
|
+
function_: Function,
|
|
69
|
+
) {
|
|
70
|
+
const this_ = this as AnyWithProps;
|
|
71
|
+
|
|
72
|
+
return makeProto({
|
|
73
|
+
name: this_.name,
|
|
74
|
+
functions: Record.set(this_.functions, function_.name, function_),
|
|
75
|
+
groups: this_.groups,
|
|
76
|
+
});
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
addGroup<Group extends Any>(this: Any, group: Group) {
|
|
80
|
+
const this_ = this as AnyWithProps;
|
|
81
|
+
const group_ = group as unknown as AnyWithProps;
|
|
82
|
+
|
|
83
|
+
return makeProto({
|
|
84
|
+
name: this_.name,
|
|
85
|
+
functions: this_.functions,
|
|
86
|
+
groups: Record.set(this_.groups, group_.name, group_),
|
|
87
|
+
});
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const makeProto = <
|
|
92
|
+
Name_ extends string,
|
|
93
|
+
Functions_ extends FunctionSpec.AnyWithProps,
|
|
94
|
+
Groups_ extends AnyWithProps,
|
|
95
|
+
>({
|
|
96
|
+
name,
|
|
97
|
+
functions,
|
|
98
|
+
groups,
|
|
99
|
+
}: {
|
|
100
|
+
name: Name_;
|
|
101
|
+
functions: Record.ReadonlyRecord<string, Functions_>;
|
|
102
|
+
groups: Record.ReadonlyRecord<string, Groups_>;
|
|
103
|
+
}): GroupSpec<Name_, Functions_, Groups_> =>
|
|
104
|
+
Object.assign(Object.create(Proto), {
|
|
105
|
+
name,
|
|
106
|
+
functions,
|
|
107
|
+
groups,
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
export const make = <const Name_ extends string>(
|
|
111
|
+
name: Name_,
|
|
112
|
+
): GroupSpec<Name_> => {
|
|
113
|
+
validateConfectFunctionIdentifier(name);
|
|
114
|
+
|
|
115
|
+
return makeProto({
|
|
116
|
+
name,
|
|
117
|
+
functions: Record.empty(),
|
|
118
|
+
groups: Record.empty(),
|
|
119
|
+
});
|
|
120
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
|
|
3
|
+
export const PaginationResult = <Doc extends Schema.Schema.AnyNoContext>(
|
|
4
|
+
Doc: Doc,
|
|
5
|
+
) =>
|
|
6
|
+
Schema.Struct({
|
|
7
|
+
page: Schema.mutable(Schema.Array(Doc)),
|
|
8
|
+
isDone: Schema.Boolean,
|
|
9
|
+
continueCursor: Schema.String,
|
|
10
|
+
splitCursor: Schema.optionalWith(Schema.Union(Schema.String, Schema.Null), {
|
|
11
|
+
exact: true,
|
|
12
|
+
}),
|
|
13
|
+
pageStatus: Schema.optionalWith(
|
|
14
|
+
Schema.Union(
|
|
15
|
+
Schema.Literal("SplitRecommended"),
|
|
16
|
+
Schema.Literal("SplitRequired"),
|
|
17
|
+
Schema.Null,
|
|
18
|
+
),
|
|
19
|
+
{ exact: true },
|
|
20
|
+
),
|
|
21
|
+
});
|
package/src/Ref.ts
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import type { FunctionType, FunctionVisibility } from "convex/server";
|
|
2
|
+
import type { Schema } from "effect";
|
|
3
|
+
import type * as FunctionSpec from "./FunctionSpec";
|
|
4
|
+
|
|
5
|
+
export interface Ref<
|
|
6
|
+
_FunctionType extends FunctionType,
|
|
7
|
+
_FunctionVisibility extends FunctionVisibility,
|
|
8
|
+
_Args extends Schema.Schema.AnyNoContext,
|
|
9
|
+
_Returns extends Schema.Schema.AnyNoContext,
|
|
10
|
+
> {
|
|
11
|
+
readonly _FunctionType?: _FunctionType;
|
|
12
|
+
readonly _FunctionVisibility?: _FunctionVisibility;
|
|
13
|
+
readonly _Args?: _Args;
|
|
14
|
+
readonly _Returns?: _Returns;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface Any extends Ref<any, any, any, any> {}
|
|
18
|
+
|
|
19
|
+
export interface AnyInternal extends Ref<any, "internal", any, any> {}
|
|
20
|
+
|
|
21
|
+
export interface AnyPublic extends Ref<any, "public", any, any> {}
|
|
22
|
+
|
|
23
|
+
export interface AnyQuery
|
|
24
|
+
extends Ref<
|
|
25
|
+
"query",
|
|
26
|
+
FunctionVisibility,
|
|
27
|
+
Schema.Schema.AnyNoContext,
|
|
28
|
+
Schema.Schema.AnyNoContext
|
|
29
|
+
> {}
|
|
30
|
+
|
|
31
|
+
export interface AnyMutation
|
|
32
|
+
extends Ref<
|
|
33
|
+
"mutation",
|
|
34
|
+
FunctionVisibility,
|
|
35
|
+
Schema.Schema.AnyNoContext,
|
|
36
|
+
Schema.Schema.AnyNoContext
|
|
37
|
+
> {}
|
|
38
|
+
|
|
39
|
+
export interface AnyAction
|
|
40
|
+
extends Ref<
|
|
41
|
+
"action",
|
|
42
|
+
FunctionVisibility,
|
|
43
|
+
Schema.Schema.AnyNoContext,
|
|
44
|
+
Schema.Schema.AnyNoContext
|
|
45
|
+
> {}
|
|
46
|
+
|
|
47
|
+
export interface AnyPublicQuery
|
|
48
|
+
extends Ref<
|
|
49
|
+
"query",
|
|
50
|
+
"public",
|
|
51
|
+
Schema.Schema.AnyNoContext,
|
|
52
|
+
Schema.Schema.AnyNoContext
|
|
53
|
+
> {}
|
|
54
|
+
|
|
55
|
+
export interface AnyPublicMutation
|
|
56
|
+
extends Ref<
|
|
57
|
+
"mutation",
|
|
58
|
+
"public",
|
|
59
|
+
Schema.Schema.AnyNoContext,
|
|
60
|
+
Schema.Schema.AnyNoContext
|
|
61
|
+
> {}
|
|
62
|
+
|
|
63
|
+
export interface AnyPublicAction
|
|
64
|
+
extends Ref<
|
|
65
|
+
"action",
|
|
66
|
+
"public",
|
|
67
|
+
Schema.Schema.AnyNoContext,
|
|
68
|
+
Schema.Schema.AnyNoContext
|
|
69
|
+
> {}
|
|
70
|
+
|
|
71
|
+
export type GetFunctionType<Ref_> =
|
|
72
|
+
Ref_ extends Ref<
|
|
73
|
+
infer FunctionType_,
|
|
74
|
+
infer _FunctionVisibility,
|
|
75
|
+
infer _Args,
|
|
76
|
+
infer _Returns
|
|
77
|
+
>
|
|
78
|
+
? FunctionType_
|
|
79
|
+
: never;
|
|
80
|
+
|
|
81
|
+
export type GetFunctionVisibility<Ref_> =
|
|
82
|
+
Ref_ extends Ref<
|
|
83
|
+
infer _FunctionType,
|
|
84
|
+
infer FunctionVisibility_,
|
|
85
|
+
infer _Args,
|
|
86
|
+
infer _Returns
|
|
87
|
+
>
|
|
88
|
+
? FunctionVisibility_
|
|
89
|
+
: never;
|
|
90
|
+
|
|
91
|
+
export type Args<Ref_> =
|
|
92
|
+
Ref_ extends Ref<
|
|
93
|
+
infer _FunctionType,
|
|
94
|
+
infer _FunctionVisibility,
|
|
95
|
+
infer Args_,
|
|
96
|
+
infer _Returns
|
|
97
|
+
>
|
|
98
|
+
? Args_
|
|
99
|
+
: never;
|
|
100
|
+
|
|
101
|
+
export type Returns<Ref_> =
|
|
102
|
+
Ref_ extends Ref<
|
|
103
|
+
infer _FunctionType,
|
|
104
|
+
infer _FunctionVisibility,
|
|
105
|
+
infer _Args,
|
|
106
|
+
infer Returns_
|
|
107
|
+
>
|
|
108
|
+
? Returns_
|
|
109
|
+
: never;
|
|
110
|
+
|
|
111
|
+
export type FromFunctionSpec<F extends FunctionSpec.AnyWithProps> = Ref<
|
|
112
|
+
FunctionSpec.GetFunctionType<F>,
|
|
113
|
+
FunctionSpec.GetFunctionVisibility<F>,
|
|
114
|
+
FunctionSpec.Args<F>,
|
|
115
|
+
FunctionSpec.Returns<F>
|
|
116
|
+
>;
|
|
117
|
+
|
|
118
|
+
export const make = <
|
|
119
|
+
FunctionType_ extends FunctionType,
|
|
120
|
+
FunctionVisibility_ extends FunctionVisibility,
|
|
121
|
+
Args_ extends Schema.Schema.AnyNoContext,
|
|
122
|
+
Returns_ extends Schema.Schema.AnyNoContext,
|
|
123
|
+
>(
|
|
124
|
+
/**
|
|
125
|
+
* This is a Convex "function name" of the format "myGroupDir/myGroupMod:myFunc".
|
|
126
|
+
*/
|
|
127
|
+
convexFunctionName: string,
|
|
128
|
+
// TODO: Pull out all of the fields from the function spec except the name (we don't need it because we already have the convex function name) and spread them here
|
|
129
|
+
function_: FunctionSpec.FunctionSpec<
|
|
130
|
+
FunctionType_,
|
|
131
|
+
FunctionVisibility_,
|
|
132
|
+
string,
|
|
133
|
+
Args_,
|
|
134
|
+
Returns_
|
|
135
|
+
>,
|
|
136
|
+
): Ref<FunctionType_, FunctionVisibility_, Args_, Returns_> =>
|
|
137
|
+
({
|
|
138
|
+
[HiddenFunctionKey]: function_,
|
|
139
|
+
[HiddenConvexFunctionNameKey]: convexFunctionName,
|
|
140
|
+
}) as Ref<FunctionType_, FunctionVisibility_, Args_, Returns_>;
|
|
141
|
+
|
|
142
|
+
// TODO: Is this hidden stuff necessary/useful still?
|
|
143
|
+
const HiddenFunctionKey = "@confect/core/api/HiddenFunctionKey";
|
|
144
|
+
type HiddenFunctionKey = typeof HiddenFunctionKey;
|
|
145
|
+
type HiddenFunction<Ref_ extends Any> = FunctionSpec.FunctionSpec<
|
|
146
|
+
GetFunctionType<Ref_>,
|
|
147
|
+
GetFunctionVisibility<Ref_>,
|
|
148
|
+
string,
|
|
149
|
+
Args<Ref_>,
|
|
150
|
+
Returns<Ref_>
|
|
151
|
+
>;
|
|
152
|
+
|
|
153
|
+
export const getFunction = <
|
|
154
|
+
FunctionType_ extends FunctionType,
|
|
155
|
+
FunctionVisibility_ extends FunctionVisibility,
|
|
156
|
+
Args_ extends Schema.Schema.AnyNoContext,
|
|
157
|
+
Returns_ extends Schema.Schema.AnyNoContext,
|
|
158
|
+
Ref_ extends Ref<FunctionType_, FunctionVisibility_, Args_, Returns_>,
|
|
159
|
+
>(
|
|
160
|
+
ref: Ref_,
|
|
161
|
+
): HiddenFunction<Ref_> => (ref as any)[HiddenFunctionKey];
|
|
162
|
+
|
|
163
|
+
const HiddenConvexFunctionNameKey =
|
|
164
|
+
"@confect/core/api/HiddenConvexFunctionNameKey";
|
|
165
|
+
type HiddenConvexFunctionNameKey = typeof HiddenConvexFunctionNameKey;
|
|
166
|
+
type HiddenConvexFunctionName = string;
|
|
167
|
+
|
|
168
|
+
export const getConvexFunctionName = <
|
|
169
|
+
FunctionType_ extends FunctionType,
|
|
170
|
+
FunctionVisibility_ extends FunctionVisibility,
|
|
171
|
+
Args_ extends Schema.Schema.AnyNoContext,
|
|
172
|
+
Returns_ extends Schema.Schema.AnyNoContext,
|
|
173
|
+
>(
|
|
174
|
+
ref: Ref<FunctionType_, FunctionVisibility_, Args_, Returns_>,
|
|
175
|
+
): HiddenConvexFunctionName => (ref as any)[HiddenConvexFunctionNameKey];
|
package/src/Refs.ts
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import type { Types } from "effect";
|
|
2
|
+
import { pipe, Record } from "effect";
|
|
3
|
+
import type * as FunctionSpec from "./FunctionSpec";
|
|
4
|
+
import type * as GroupSpec from "./GroupSpec";
|
|
5
|
+
import * as Ref from "./Ref";
|
|
6
|
+
import type * as Spec from "./Spec";
|
|
7
|
+
|
|
8
|
+
export type Refs<
|
|
9
|
+
Spec_ extends Spec.AnyWithProps,
|
|
10
|
+
Predicate extends Ref.Any = Ref.Any,
|
|
11
|
+
> = Types.Simplify<Helper<Spec.Groups<Spec_>, Predicate>>;
|
|
12
|
+
|
|
13
|
+
type GroupRefs<
|
|
14
|
+
Group extends GroupSpec.AnyWithProps,
|
|
15
|
+
Predicate extends Ref.Any,
|
|
16
|
+
> = Types.Simplify<
|
|
17
|
+
Helper<GroupSpec.Groups<Group>, Predicate> &
|
|
18
|
+
FilteredFunctions<GroupSpec.Functions<Group>, Predicate>
|
|
19
|
+
>;
|
|
20
|
+
|
|
21
|
+
type FilteredFunctions<
|
|
22
|
+
Functions extends FunctionSpec.AnyWithProps,
|
|
23
|
+
Predicate extends Ref.Any,
|
|
24
|
+
> = {
|
|
25
|
+
[Name in FunctionSpec.Name<Functions> as FunctionSpec.WithName<
|
|
26
|
+
Functions,
|
|
27
|
+
Name
|
|
28
|
+
> extends infer F extends FunctionSpec.AnyWithProps
|
|
29
|
+
? Ref.FromFunctionSpec<F> extends Predicate
|
|
30
|
+
? Name
|
|
31
|
+
: never
|
|
32
|
+
: never]: FunctionSpec.WithName<Functions, Name> extends infer F extends
|
|
33
|
+
FunctionSpec.AnyWithProps
|
|
34
|
+
? Ref.FromFunctionSpec<F>
|
|
35
|
+
: never;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
type Helper<
|
|
39
|
+
Groups extends GroupSpec.AnyWithProps,
|
|
40
|
+
Predicate extends Ref.Any,
|
|
41
|
+
> = {
|
|
42
|
+
[GroupName in GroupSpec.Name<Groups> as GroupSpec.WithName<
|
|
43
|
+
Groups,
|
|
44
|
+
GroupName
|
|
45
|
+
> extends infer Group extends GroupSpec.AnyWithProps
|
|
46
|
+
? GroupRefs<Group, Predicate> extends Record<string, never>
|
|
47
|
+
? never
|
|
48
|
+
: GroupName
|
|
49
|
+
: never]: GroupSpec.WithName<Groups, GroupName> extends infer Group extends
|
|
50
|
+
GroupSpec.AnyWithProps
|
|
51
|
+
? GroupRefs<Group, Predicate>
|
|
52
|
+
: never;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
type Any =
|
|
56
|
+
| {
|
|
57
|
+
readonly [key: string]: Any;
|
|
58
|
+
}
|
|
59
|
+
| Ref.Any;
|
|
60
|
+
|
|
61
|
+
export const make = <Spec_ extends Spec.AnyWithProps>(
|
|
62
|
+
spec: Spec_,
|
|
63
|
+
): {
|
|
64
|
+
all: Refs<Spec_>;
|
|
65
|
+
public: Refs<Spec_, Ref.AnyPublic>;
|
|
66
|
+
internal: Refs<Spec_, Ref.AnyInternal>;
|
|
67
|
+
} => {
|
|
68
|
+
const refs = makeHelper(spec.groups);
|
|
69
|
+
return {
|
|
70
|
+
all: refs as Refs<Spec_>,
|
|
71
|
+
public: refs as Refs<Spec_, Ref.AnyPublic>,
|
|
72
|
+
internal: refs as Refs<Spec_, Ref.AnyInternal>,
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const makeHelper = (
|
|
77
|
+
groups: Record.ReadonlyRecord<string, GroupSpec.Any>,
|
|
78
|
+
groupPath: string | null = null,
|
|
79
|
+
): Any =>
|
|
80
|
+
pipe(
|
|
81
|
+
groups as Record.ReadonlyRecord<string, GroupSpec.AnyWithProps>,
|
|
82
|
+
Record.map((group) => {
|
|
83
|
+
const currentGroupPath = groupPath
|
|
84
|
+
? `${groupPath}/${group.name}`
|
|
85
|
+
: group.name;
|
|
86
|
+
|
|
87
|
+
return Record.union(
|
|
88
|
+
makeHelper(group.groups, currentGroupPath),
|
|
89
|
+
Record.map(group.functions, (function_) =>
|
|
90
|
+
Ref.make(`${currentGroupPath}:${function_.name}`, function_),
|
|
91
|
+
),
|
|
92
|
+
(_subGroup, _function) => {
|
|
93
|
+
throw new Error(
|
|
94
|
+
`Group and function at same level have same name ('${Ref.getConvexFunctionName(_function)}')`,
|
|
95
|
+
);
|
|
96
|
+
},
|
|
97
|
+
);
|
|
98
|
+
}),
|
|
99
|
+
);
|
package/src/Spec.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Predicate, Record } from "effect";
|
|
2
|
+
import type * as GroupSpec from "./GroupSpec";
|
|
3
|
+
|
|
4
|
+
export const TypeId = "@confect/core/api/Spec";
|
|
5
|
+
export type TypeId = typeof TypeId;
|
|
6
|
+
|
|
7
|
+
export const isSpec = (u: unknown): u is AnyWithProps =>
|
|
8
|
+
Predicate.hasProperty(u, TypeId);
|
|
9
|
+
|
|
10
|
+
export interface Spec<Groups_ extends GroupSpec.AnyWithProps = never> {
|
|
11
|
+
readonly [TypeId]: TypeId;
|
|
12
|
+
readonly groups: {
|
|
13
|
+
[GroupName in GroupSpec.Name<Groups_>]: GroupSpec.WithName<
|
|
14
|
+
Groups_,
|
|
15
|
+
GroupName
|
|
16
|
+
>;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
add<Group extends GroupSpec.AnyWithProps>(
|
|
20
|
+
group: Group,
|
|
21
|
+
): Spec<Groups_ | Group>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface Any {
|
|
25
|
+
readonly [TypeId]: TypeId;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface AnyWithProps extends Spec<GroupSpec.AnyWithProps> {}
|
|
29
|
+
|
|
30
|
+
export type Groups<Spec_ extends AnyWithProps> =
|
|
31
|
+
Spec_["groups"][keyof Spec_["groups"]];
|
|
32
|
+
|
|
33
|
+
const Proto = {
|
|
34
|
+
[TypeId]: TypeId,
|
|
35
|
+
|
|
36
|
+
add<Group extends GroupSpec.AnyWithProps>(this: AnyWithProps, group: Group) {
|
|
37
|
+
return makeProto({
|
|
38
|
+
groups: Record.set(this.groups, group.name, group),
|
|
39
|
+
});
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const makeProto = <Groups_ extends GroupSpec.AnyWithProps>({
|
|
44
|
+
groups,
|
|
45
|
+
}: {
|
|
46
|
+
groups: Record.ReadonlyRecord<string, Groups_>;
|
|
47
|
+
}): Spec<Groups_> =>
|
|
48
|
+
Object.assign(Object.create(Proto), {
|
|
49
|
+
groups,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
export const make = (): Spec => makeProto({ groups: {} });
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Expand,
|
|
3
|
+
IdField,
|
|
4
|
+
SystemFields as NonIdSystemFields,
|
|
5
|
+
} from "convex/server";
|
|
6
|
+
import { Schema } from "effect";
|
|
7
|
+
import * as GenericId from "./GenericId";
|
|
8
|
+
|
|
9
|
+
type SystemFieldsSchema<TableName extends string> = Schema.Struct<{
|
|
10
|
+
_id: Schema.Schema<
|
|
11
|
+
GenericId.GenericId<TableName>,
|
|
12
|
+
GenericId.GenericId<TableName>,
|
|
13
|
+
never
|
|
14
|
+
>;
|
|
15
|
+
_creationTime: typeof Schema.Number;
|
|
16
|
+
}>;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Produces a schema for Convex system fields.
|
|
20
|
+
*/
|
|
21
|
+
export const SystemFields = <TableName extends string>(
|
|
22
|
+
tableName: TableName,
|
|
23
|
+
): SystemFieldsSchema<TableName> =>
|
|
24
|
+
Schema.Struct({
|
|
25
|
+
_id: GenericId.GenericId(tableName),
|
|
26
|
+
_creationTime: Schema.Number,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Extend a table schema with Convex system fields.
|
|
31
|
+
*/
|
|
32
|
+
export const extendWithSystemFields = <
|
|
33
|
+
TableName extends string,
|
|
34
|
+
TableSchema extends Schema.Schema.AnyNoContext,
|
|
35
|
+
>(
|
|
36
|
+
tableName: TableName,
|
|
37
|
+
schema: TableSchema,
|
|
38
|
+
): ExtendWithSystemFields<TableName, TableSchema> =>
|
|
39
|
+
Schema.extend(SystemFields(tableName), schema);
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Extend a table schema with Convex system fields at the type level.
|
|
43
|
+
*/
|
|
44
|
+
export type ExtendWithSystemFields<
|
|
45
|
+
TableName extends string,
|
|
46
|
+
TableSchema extends Schema.Schema.AnyNoContext,
|
|
47
|
+
> = Schema.extend<SystemFieldsSchema<TableName>, TableSchema>;
|
|
48
|
+
|
|
49
|
+
export type WithSystemFields<TableName extends string, Document> = Expand<
|
|
50
|
+
Readonly<IdField<TableName>> & Readonly<NonIdSystemFields> & Document
|
|
51
|
+
>;
|