@primate/core 0.9.4 → 0.9.6
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/lib/private/db/errors.d.ts +3 -0
- package/lib/private/db/errors.js +4 -0
- package/lib/private/db/test.js +18 -0
- package/lib/private/frontend.js +5 -4
- package/lib/private/response/ResponseFunction.d.ts +2 -1
- package/lib/private/response/ResponseLike.d.ts +2 -1
- package/lib/private/response/json.d.ts +2 -2
- package/lib/private/response/json.js +4 -1
- package/lib/private/response/respond.d.ts +2 -1
- package/lib/private/route.client.d.ts +2 -2
- package/lib/private/route.d.ts +1 -1
- package/lib/private/store/Store.d.ts +11 -0
- package/lib/private/store/Store.js +10 -0
- package/lib/public/response.d.ts +2 -1
- package/package.json +1 -1
|
@@ -34,6 +34,7 @@ declare function sort_invalid_value(field: string, value: unknown): import("@rco
|
|
|
34
34
|
declare function select_empty(): import("@rcompat/error").TemplateError;
|
|
35
35
|
declare function select_invalid(): import("@rcompat/error").TemplateError;
|
|
36
36
|
declare function limit_invalid(): import("@rcompat/error").TemplateError;
|
|
37
|
+
declare function first_limit_invalid(): import("@rcompat/error").TemplateError;
|
|
37
38
|
declare function select_invalid_value(index: number, x: unknown): import("@rcompat/error").TemplateError;
|
|
38
39
|
declare function where_required(): import("@rcompat/error").TemplateError;
|
|
39
40
|
declare function where_invalid(): import("@rcompat/error").TemplateError;
|
|
@@ -94,6 +95,7 @@ declare const errors: {
|
|
|
94
95
|
where_invalid_value: typeof where_invalid_value;
|
|
95
96
|
set_empty: typeof set_empty;
|
|
96
97
|
limit_invalid: typeof limit_invalid;
|
|
98
|
+
first_limit_invalid: typeof first_limit_invalid;
|
|
97
99
|
offset_invalid: typeof offset_invalid;
|
|
98
100
|
offset_requires_limit: typeof offset_requires_limit;
|
|
99
101
|
relation_unknown: typeof relation_unknown;
|
|
@@ -150,6 +152,7 @@ export declare const Code: {
|
|
|
150
152
|
where_invalid_value: "where_invalid_value";
|
|
151
153
|
set_empty: "set_empty";
|
|
152
154
|
limit_invalid: "limit_invalid";
|
|
155
|
+
first_limit_invalid: "first_limit_invalid";
|
|
153
156
|
offset_invalid: "offset_invalid";
|
|
154
157
|
offset_requires_limit: "offset_requires_limit";
|
|
155
158
|
relation_unknown: "relation_unknown";
|
package/lib/private/db/errors.js
CHANGED
|
@@ -152,6 +152,9 @@ function select_invalid() {
|
|
|
152
152
|
function limit_invalid() {
|
|
153
153
|
return t `invalid limit`;
|
|
154
154
|
}
|
|
155
|
+
function first_limit_invalid() {
|
|
156
|
+
return t `${"first"} does not accept ${"limit"}`;
|
|
157
|
+
}
|
|
155
158
|
function select_invalid_value(index, x) {
|
|
156
159
|
return t `select[${index}]: must be string, received ${kind_of(x)}`;
|
|
157
160
|
}
|
|
@@ -185,6 +188,7 @@ const QUERY = error.coded({
|
|
|
185
188
|
where_invalid_value,
|
|
186
189
|
set_empty,
|
|
187
190
|
limit_invalid,
|
|
191
|
+
first_limit_invalid,
|
|
188
192
|
offset_invalid,
|
|
189
193
|
offset_requires_limit,
|
|
190
194
|
});
|
package/lib/private/db/test.js
CHANGED
|
@@ -1498,6 +1498,24 @@ export default (db) => {
|
|
|
1498
1498
|
assert(yes.length).equals(1);
|
|
1499
1499
|
assert(yes[0].name).equals("MiXeDCase");
|
|
1500
1500
|
});
|
|
1501
|
+
$user("first: returns first matching record", async (assert) => {
|
|
1502
|
+
await User.insert({ name: "FirstLow", age: 1 });
|
|
1503
|
+
await User.insert({ name: "FirstHigh", age: 2 });
|
|
1504
|
+
const user = await User.first({
|
|
1505
|
+
where: { name: { $like: "First%" } },
|
|
1506
|
+
sort: { age: "desc" },
|
|
1507
|
+
});
|
|
1508
|
+
assert(user?.name).equals("FirstHigh");
|
|
1509
|
+
});
|
|
1510
|
+
$user("first: returns undefined when no record matches", async (assert) => {
|
|
1511
|
+
const user = await User.first({ where: { name: "MissingFirst" } });
|
|
1512
|
+
assert(user).undefined();
|
|
1513
|
+
});
|
|
1514
|
+
$user$("first: rejects limit", async (assert) => {
|
|
1515
|
+
await throws(assert, Code.first_limit_invalid, () => {
|
|
1516
|
+
return User.first({ limit: 10 });
|
|
1517
|
+
});
|
|
1518
|
+
});
|
|
1501
1519
|
$user("find: $ilike is case-insensitive", async (assert) => {
|
|
1502
1520
|
await User.insert({ name: "MiXeDCase2" });
|
|
1503
1521
|
const rows = await User.find({ where: { name: { $ilike: "mixed%" } } });
|
package/lib/private/frontend.js
CHANGED
|
@@ -18,8 +18,9 @@ export default function frontend_module(init) {
|
|
|
18
18
|
const conditions = init.conditions ?? [];
|
|
19
19
|
const schema = base_schema.extend(init.schema ?? {});
|
|
20
20
|
async function normalize(path) {
|
|
21
|
-
const
|
|
22
|
-
|
|
21
|
+
const extension = init.extensions.find(extension => path.endsWith(extension))
|
|
22
|
+
?? fs.ref(path).fullExtension;
|
|
23
|
+
const basename = path.slice(0, -extension.length);
|
|
23
24
|
return `p_${await hash(`${basename}.${module_name}`)}`;
|
|
24
25
|
}
|
|
25
26
|
return (input) => {
|
|
@@ -206,11 +207,11 @@ export default function frontend_module(init) {
|
|
|
206
207
|
build.onLoad({ filter: views_filter }, async () => {
|
|
207
208
|
const views = await views_base.files({
|
|
208
209
|
recursive: true,
|
|
209
|
-
filter: c => extensions.
|
|
210
|
+
filter: c => extensions.some(ext => c.path.endsWith(ext)),
|
|
210
211
|
});
|
|
211
212
|
const pages = await pages_base.files({
|
|
212
213
|
recursive: true,
|
|
213
|
-
filter: c => extensions.
|
|
214
|
+
filter: c => extensions.some(ext => c.path.endsWith(ext)),
|
|
214
215
|
});
|
|
215
216
|
let contents = "";
|
|
216
217
|
for (const view of views) {
|
|
@@ -2,9 +2,10 @@ import type View from "#client/View";
|
|
|
2
2
|
import type RequestFacade from "#request/RequestFacade";
|
|
3
3
|
import type ServeApp from "#serve/App";
|
|
4
4
|
import type { Dict, MaybePromise } from "@rcompat/type";
|
|
5
|
-
type ResponseFunction<Props =
|
|
5
|
+
type ResponseFunction<Props = never, Result = never> = {
|
|
6
6
|
(app: ServeApp, transfer: Dict, request: RequestFacade): MaybePromise<View | null | Response | undefined>;
|
|
7
7
|
readonly _props?: Props;
|
|
8
|
+
readonly _result?: Result;
|
|
8
9
|
};
|
|
9
10
|
export { ResponseFunction as default };
|
|
10
11
|
//# sourceMappingURL=ResponseFunction.d.ts.map
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type ResponseFunction from "#response/ResponseFunction";
|
|
2
2
|
import type Streamable from "@rcompat/fs/Streamable";
|
|
3
3
|
import type { Dict } from "@rcompat/type";
|
|
4
|
-
type
|
|
4
|
+
type UnknownResponseFunction = ResponseFunction<unknown, unknown>;
|
|
5
|
+
type ResponseLike = string | Dict | Dict[] | URL | Blob | ReadableStream | Streamable | Response | UnknownResponseFunction | null;
|
|
5
6
|
export { ResponseLike as default };
|
|
6
7
|
//# sourceMappingURL=ResponseLike.d.ts.map
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import type ResponseFunction from "#response/ResponseFunction";
|
|
1
2
|
/**
|
|
2
3
|
* Issue a JSON response
|
|
3
4
|
* @param body body object
|
|
4
5
|
* @param options response options
|
|
5
6
|
* @return Response rendering function
|
|
6
7
|
*/
|
|
7
|
-
|
|
8
|
-
export default _default;
|
|
8
|
+
export default function json<T>(body: T, init?: ResponseInit): ResponseFunction<never, T>;
|
|
9
9
|
//# sourceMappingURL=json.d.ts.map
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import response from "#response";
|
|
2
2
|
import http from "@rcompat/http";
|
|
3
|
+
const json_response = response(http.MIME.APPLICATION_JSON, JSON.stringify);
|
|
3
4
|
/**
|
|
4
5
|
* Issue a JSON response
|
|
5
6
|
* @param body body object
|
|
6
7
|
* @param options response options
|
|
7
8
|
* @return Response rendering function
|
|
8
9
|
*/
|
|
9
|
-
export default
|
|
10
|
+
export default function json(body, init) {
|
|
11
|
+
return json_response(body, init);
|
|
12
|
+
}
|
|
10
13
|
//# sourceMappingURL=json.js.map
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type ResponseFunction from "#response/ResponseFunction";
|
|
2
2
|
import type ResponseLike from "#response/ResponseLike";
|
|
3
|
+
type UnknownResponseFunction = ResponseFunction<unknown, unknown>;
|
|
3
4
|
export default _default;
|
|
4
|
-
declare function _default(result: ResponseLike):
|
|
5
|
+
declare function _default(result: ResponseLike): UnknownResponseFunction;
|
|
5
6
|
//# sourceMappingURL=respond.d.ts.map
|
|
@@ -23,8 +23,8 @@ type MethodMeta = {
|
|
|
23
23
|
type RequestMeta = {
|
|
24
24
|
headers?: HeadersInit;
|
|
25
25
|
};
|
|
26
|
-
type Page<R> = Awaited<R> extends infer Result ? Result extends ResponseFunction<infer Props> ? Props : never : never;
|
|
27
|
-
type ClientResult<R> = Awaited<R> extends infer Result ? Result extends ResponseFunction ?
|
|
26
|
+
type Page<R> = Awaited<R> extends infer Result ? Result extends ResponseFunction<infer Props, unknown> ? Props : never : never;
|
|
27
|
+
type ClientResult<R> = Awaited<R> extends infer Result ? Result extends ResponseFunction<unknown, infer Payload> ? Payload : Result : never;
|
|
28
28
|
type ClientMethod<O extends RouteOptions, R = unknown> = MethodMeta & {
|
|
29
29
|
_result?: ClientResult<R>;
|
|
30
30
|
Page: Page<R>;
|
package/lib/private/route.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ type WithResult<O extends RouteOptions, R extends ResponseLike> = {
|
|
|
11
11
|
handler: RouteHandler<O, R>;
|
|
12
12
|
options: O;
|
|
13
13
|
};
|
|
14
|
-
type Page<R> = Awaited<R> extends infer Result ? Result extends ResponseFunction<infer Props> ? Props : never : never;
|
|
14
|
+
type Page<R> = Awaited<R> extends infer Result ? Result extends ResponseFunction<infer Props, unknown> ? Props : never : never;
|
|
15
15
|
type AnyHandler = RouteHandler | WithResult<RouteOptions, ResponseLike>;
|
|
16
16
|
type RouteHandlers = {
|
|
17
17
|
[key in Method]?: AnyHandler;
|
|
@@ -179,6 +179,17 @@ export default class Store<T extends StoreInput, N extends string = string> impl
|
|
|
179
179
|
offset?: number;
|
|
180
180
|
with?: W;
|
|
181
181
|
}): Promise<WithRelations<Projected<Schema<T>, S>, ExtractRelations<T>, W>[]>;
|
|
182
|
+
/**
|
|
183
|
+
* Find the first matching record.
|
|
184
|
+
*/
|
|
185
|
+
first<const S extends Select<Schema<T>> | undefined = undefined, const W extends WithInput<ExtractRelations<T>> | undefined = undefined>(options?: {
|
|
186
|
+
where?: Where<T>;
|
|
187
|
+
select?: S;
|
|
188
|
+
sort?: Sort<Schema<T>>;
|
|
189
|
+
offset?: number;
|
|
190
|
+
with?: W;
|
|
191
|
+
limit?: never;
|
|
192
|
+
}): Promise<WithRelations<Projected<Schema<T>, S>, ExtractRelations<T>, W> | undefined>;
|
|
182
193
|
toJSON(): {
|
|
183
194
|
type: "object";
|
|
184
195
|
properties: Dict<import("pema").Serialized>;
|
|
@@ -590,6 +590,16 @@ export default class Store {
|
|
|
590
590
|
});
|
|
591
591
|
return result;
|
|
592
592
|
}
|
|
593
|
+
/**
|
|
594
|
+
* Find the first matching record.
|
|
595
|
+
*/
|
|
596
|
+
async first(options) {
|
|
597
|
+
guard_options(options, ["where", "select", "sort", "offset", "with", "limit"]);
|
|
598
|
+
if (is.defined(options?.limit))
|
|
599
|
+
throw E.first_limit_invalid();
|
|
600
|
+
const [first] = await this.find({ ...options, limit: 1 });
|
|
601
|
+
return first;
|
|
602
|
+
}
|
|
593
603
|
toJSON() {
|
|
594
604
|
return this.#schema.toJSON();
|
|
595
605
|
}
|
package/lib/public/response.d.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import binary from "#response/binary";
|
|
2
2
|
import error from "#response/error";
|
|
3
|
+
import json from "#response/json";
|
|
3
4
|
import page from "#response/page";
|
|
4
5
|
import view from "#response/view";
|
|
5
6
|
import $null from "#response/null";
|
|
6
7
|
declare const response: {
|
|
7
8
|
binary: typeof binary;
|
|
8
9
|
error: typeof error;
|
|
9
|
-
json:
|
|
10
|
+
json: typeof json;
|
|
10
11
|
page: typeof page;
|
|
11
12
|
redirect: (location: string, status?: 300 | 301 | 302 | 303 | 304 | 307 | 308) => import("./index.js").ResponseFunction<never>;
|
|
12
13
|
sse: (body: (source: {
|