kysely-rizzolver 0.0.2

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 (36) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +147 -0
  3. package/dist/cjs/fetch-result-factory.d.ts +52 -0
  4. package/dist/cjs/fetch-result-factory.js +88 -0
  5. package/dist/cjs/fetch-result.d.ts +111 -0
  6. package/dist/cjs/fetch-result.js +117 -0
  7. package/dist/cjs/index.d.ts +10 -0
  8. package/dist/cjs/index.js +21 -0
  9. package/dist/cjs/kysely-rizzolver.d.ts +138 -0
  10. package/dist/cjs/kysely-rizzolver.js +147 -0
  11. package/dist/cjs/model-collection.d.ts +26 -0
  12. package/dist/cjs/model-collection.js +24 -0
  13. package/dist/cjs/query-builder.d.ts +156 -0
  14. package/dist/cjs/query-builder.js +92 -0
  15. package/dist/cjs/selector.d.ts +72 -0
  16. package/dist/cjs/selector.js +45 -0
  17. package/dist/cjs/type-helpers.d.ts +11 -0
  18. package/dist/cjs/type-helpers.js +2 -0
  19. package/dist/esm/fetch-result-factory.js +85 -0
  20. package/dist/esm/fetch-result.js +105 -0
  21. package/dist/esm/index.js +5 -0
  22. package/dist/esm/kysely-rizzolver.js +143 -0
  23. package/dist/esm/model-collection.js +21 -0
  24. package/dist/esm/package.json +1 -0
  25. package/dist/esm/query-builder.js +89 -0
  26. package/dist/esm/selector.js +42 -0
  27. package/dist/esm/type-helpers.js +1 -0
  28. package/dist/types/fetch-result-factory.d.ts +52 -0
  29. package/dist/types/fetch-result.d.ts +111 -0
  30. package/dist/types/index.d.ts +10 -0
  31. package/dist/types/kysely-rizzolver.d.ts +138 -0
  32. package/dist/types/model-collection.d.ts +26 -0
  33. package/dist/types/query-builder.d.ts +156 -0
  34. package/dist/types/selector.d.ts +72 -0
  35. package/dist/types/type-helpers.d.ts +11 -0
  36. package/package.json +32 -0
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.newSelector = newSelector;
4
+ function newSelector(rizzolver, tableName, alias, keys) {
5
+ const effectiveKeys = (keys ?? rizzolver.fields[tableName]);
6
+ const tableAlias = `${tableName} as ${alias}`;
7
+ const fields = effectiveKeys.map((field) => `${alias}.${field} as _${alias}_${field}`);
8
+ function _rowToModel(result) {
9
+ if (!result || !result[`_${alias}_id`]) {
10
+ return undefined;
11
+ }
12
+ const model = {};
13
+ for (const field of effectiveKeys) {
14
+ const aliasedField = `_${alias}_${field}`;
15
+ model[field] = result[aliasedField] ?? undefined;
16
+ }
17
+ return model;
18
+ }
19
+ const selector = {
20
+ input: {
21
+ table: tableName,
22
+ alias,
23
+ tableFields: effectiveKeys
24
+ },
25
+ selectTable: tableAlias,
26
+ selectFields: fields,
27
+ field(field) {
28
+ return {
29
+ str: `_${alias}_${field}`,
30
+ from(table) {
31
+ return `${table}._${alias}_${field}`;
32
+ }
33
+ };
34
+ },
35
+ select(rows) {
36
+ const data = [];
37
+ for (const row of rows) {
38
+ const model = _rowToModel(row);
39
+ data.push({ row, model });
40
+ }
41
+ return data;
42
+ }
43
+ };
44
+ return selector;
45
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * I can't explain this.
3
+ *
4
+ * I badgered ChatGPT until it worked. it probably just referenced type-fest.
5
+ */
6
+ type LastInUnion<U> = (U extends any ? () => U : never) extends infer F ? (F extends any ? (k: F) => void : never) extends (k: infer I) => void ? I extends () => infer R ? R : never : never : never;
7
+ /**
8
+ * Recursively converts a union type to a tuple by splitting it into its head and tail.
9
+ */
10
+ export type UnionToTuple<U, Last = LastInUnion<U>> = [U] extends [never] ? [] : [...UnionToTuple<Exclude<U, Last>>, Last];
11
+ export {};
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,85 @@
1
+ import { assertIsFetchOneResult, assertIsFetchOneXResult, assertIsFetchSomeResult, isFetchOneResult, isFetchOneXResult, isFetchSomeResult, newFetchOneResult, newFetchOneXResult, newFetchSomeResult } from './fetch-result.js';
2
+ import { newModelCollection } from './model-collection.js';
3
+ export function newFetchResultFactory() {
4
+ return {
5
+ /**
6
+ * Creates a new {@link FetchOneResult} instance.
7
+ */
8
+ newFetchOne(table, result, models) {
9
+ models ??= newModelCollection();
10
+ if (result) {
11
+ models.add(table, result);
12
+ }
13
+ return newFetchOneResult(table, result, models);
14
+ },
15
+ /**
16
+ * Creates a new {@link FetchOneXResult} instance.
17
+ *
18
+ * Note: it may be counterintuitive, but this function accepts `undefined` as
19
+ * input. I found it is way more convenient to assert the type once in this
20
+ * funciton rather than in every caller.
21
+ */
22
+ newFetchOneX(table, result, models) {
23
+ models ??= newModelCollection();
24
+ if (result) {
25
+ models.add(table, result);
26
+ }
27
+ return newFetchOneXResult(table, result, models);
28
+ },
29
+ /**
30
+ * Creates a new {@link FetchSomeResult} instance.
31
+ */
32
+ newFetchSome(table, result, models) {
33
+ models ??= newModelCollection();
34
+ for (const item of result) {
35
+ models.add(table, item);
36
+ }
37
+ return newFetchSomeResult(table, result, models);
38
+ },
39
+ /**
40
+ * Checks if a {@link FetchResult} is a {@link FetchOneResult}.
41
+ */
42
+ isFetchOne(table, result) {
43
+ return isFetchOneResult(result) && result.table === table;
44
+ },
45
+ /**
46
+ * Checks if a {@link FetchResult} is a {@link FetchOneXResult}.
47
+ */
48
+ isFetchOneX(table, result) {
49
+ return isFetchOneXResult(result) && result.table === table;
50
+ },
51
+ /**
52
+ * Checks if a {@link FetchResult} is a {@link FetchSomeResult}.
53
+ */
54
+ isFetchSome(table, result) {
55
+ return isFetchSomeResult(result) && result.table === table;
56
+ },
57
+ /**
58
+ * Asserts that a {@link FetchResult} is a {@link FetchOneResult}.
59
+ */
60
+ assertIsFetchOne(table, result) {
61
+ assertIsFetchOneResult(result);
62
+ if (result.table !== table) {
63
+ throw new Error(`Expected a fetchOne result for table ${table}`);
64
+ }
65
+ },
66
+ /**
67
+ * Asserts that a {@link FetchResult} is a {@link FetchOneXResult}.
68
+ */
69
+ assertIsFetchOneX(table, result) {
70
+ assertIsFetchOneXResult(result);
71
+ if (result.table !== table) {
72
+ throw new Error(`Expected a fetchOne result with a non-null non for table ${table}`);
73
+ }
74
+ },
75
+ /**
76
+ * Asserts that a {@link FetchResult} is a {@link FetchSomeResult}.
77
+ */
78
+ assertIsFetchSome(table, result) {
79
+ assertIsFetchSomeResult(result);
80
+ if (result.table !== table) {
81
+ throw new Error(`Expected a fetchSome result for table ${table}`);
82
+ }
83
+ }
84
+ };
85
+ }
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Creates a new {@link FetchOneResult} instance.
3
+ */
4
+ export function newFetchOneResult(table, result, models) {
5
+ const ref = { value: null };
6
+ const me = {
7
+ fetchType: 'fetchOne',
8
+ table,
9
+ result,
10
+ models,
11
+ asFetchOneX() {
12
+ if (!me.result) {
13
+ throw new Error('Expected a fetchOneX result');
14
+ }
15
+ return ref.value;
16
+ }
17
+ };
18
+ ref.value = me;
19
+ return me;
20
+ }
21
+ /**
22
+ * Creates a new {@link FetchOneXResult} instance.
23
+ *
24
+ * Note: it may be counterintuitive, but this function accepts `undefined` as
25
+ * input. I found it is way more convenient to assert the type once in this
26
+ * funciton rather than in every caller.
27
+ */
28
+ export function newFetchOneXResult(table, result, models) {
29
+ if (!result) {
30
+ throw new Error('Expected a fetchOneX result');
31
+ }
32
+ const ref = { value: null };
33
+ const me = {
34
+ fetchType: 'fetchOne',
35
+ table,
36
+ result,
37
+ models,
38
+ asFetchOneX() {
39
+ return ref.value;
40
+ }
41
+ };
42
+ ref.value = me;
43
+ return me;
44
+ }
45
+ /**
46
+ * Creates a new {@link FetchSomeResult} instance.
47
+ */
48
+ export function newFetchSomeResult(table, result, models) {
49
+ return {
50
+ fetchType: 'fetchSome',
51
+ table,
52
+ result,
53
+ models
54
+ };
55
+ }
56
+ export function isFetchResult(result) {
57
+ return (!!result &&
58
+ typeof result === 'object' &&
59
+ 'fetchType' in result &&
60
+ !!result.fetchType &&
61
+ typeof result.fetchType === 'string' &&
62
+ 'table' in result &&
63
+ !!result.table &&
64
+ typeof result.table === 'string' &&
65
+ 'result' in result &&
66
+ (result.result === undefined ||
67
+ typeof result.result === 'object' ||
68
+ (Array.isArray(result.result) && result.result.every((r) => !!r && typeof r === 'object'))));
69
+ }
70
+ export function isFetchOneResult(value) {
71
+ return isFetchResult(value) && value.fetchType === 'fetchOne' && !Array.isArray(value.result);
72
+ }
73
+ export function isFetchOneXResult(value) {
74
+ return (isFetchResult(value) &&
75
+ value.fetchType === 'fetchOne' &&
76
+ !Array.isArray(value.result) &&
77
+ !!value.result);
78
+ }
79
+ export function isFetchSomeResult(value) {
80
+ return isFetchResult(value) && value.fetchType === 'fetchSome' && Array.isArray(value.result);
81
+ }
82
+ /**
83
+ * Asserts that `value` is a {@link FetchOneResult}.
84
+ */
85
+ export function assertIsFetchOneResult(value) {
86
+ if (!isFetchOneResult(value)) {
87
+ throw new Error('Expected a fetchOne result');
88
+ }
89
+ }
90
+ /**
91
+ * Asserts that `value` is a {@link FetchOneXResult}.
92
+ */
93
+ export function assertIsFetchOneXResult(value) {
94
+ if (!isFetchOneXResult(value)) {
95
+ throw new Error('Expected a fetchOne result with a non-null, non undefined result');
96
+ }
97
+ }
98
+ /**
99
+ * Asserts that `value` is a {@link FetchSomeResult}.
100
+ */
101
+ export function assertIsFetchSomeResult(value) {
102
+ if (!isFetchSomeResult(value)) {
103
+ throw new Error('Expected a fetchSome result');
104
+ }
105
+ }
@@ -0,0 +1,5 @@
1
+ export { KyselyRizzolver } from './kysely-rizzolver.js';
2
+ export { assertIsFetchOneResult, assertIsFetchOneXResult, assertIsFetchSomeResult, isFetchOneResult, isFetchOneXResult, isFetchSomeResult, newFetchOneResult, newFetchOneXResult, newFetchSomeResult } from './fetch-result.js';
3
+ export { newSelector } from './selector.js';
4
+ export { newQueryBuilder } from './query-builder.js';
5
+ export { newModelCollection } from './model-collection.js';
@@ -0,0 +1,143 @@
1
+ import { newFetchResultFactory } from './fetch-result-factory.js';
2
+ import { newQueryBuilder as kyNewQueryBuilder } from './query-builder.js';
3
+ import { newSelector as kyNewSelector } from './selector.js';
4
+ import { newModelCollection as kyNewModelCollection } from './model-collection.js';
5
+ /**
6
+ * A {@link KyselyRizzolver} is a class that is used to define the structure of
7
+ * a database schema.
8
+ *
9
+ * It streamlines instatiating type-safe {@link QueryBuilder}s,
10
+ * {@link Selector}s, {@link ModelCollection}s and {@link FetchResult}s.
11
+ *
12
+ * Define a new {@link KyselyRizzolver} using the
13
+ * {@link KyselyRizzolver.builder|.builderForSchema()} or
14
+ * {@link KyselyRizzolver.builderNoSchema|.builderNoSchema()}.
15
+ */
16
+ export class KyselyRizzolver {
17
+ fields;
18
+ fetches;
19
+ constructor(fields) {
20
+ this.fields = fields;
21
+ this.fetches = newFetchResultFactory();
22
+ }
23
+ /**
24
+ * Intantiates a new {@link Selector} for the given table.
25
+ */
26
+ newSelector(table, alias) {
27
+ return kyNewSelector(this, table, alias);
28
+ }
29
+ /**
30
+ * Instantiates a new {@link QueryBuilder}.
31
+ */
32
+ newQueryBuilder() {
33
+ return kyNewQueryBuilder(this);
34
+ }
35
+ /**
36
+ * Instantiates a new {@link ModelCollection}.
37
+ */
38
+ newModelCollection() {
39
+ return kyNewModelCollection();
40
+ }
41
+ /**
42
+ * Starts building a new {@link KyselyRizzolver} using a builder pattern for
43
+ * a schema.
44
+ *
45
+ * Call {@link KyselyRizzolverBuilderForSchema.table|.table()} for each
46
+ * table that exists on the `DB` type parameter with all of their column
47
+ * names as a const array. After all tables have been added, call
48
+ * {@link KyselyRizzolverBuilderForSchema.build|.build()} to get a new
49
+ * {@link KyselyRizzolver} instance.
50
+ *
51
+ * Example:
52
+ * ```
53
+ * const rizzolver = KyselyRizzolver.builderForSchema<DB>()
54
+ * .table('user', ['id', 'name', 'email'] as const)
55
+ * .table('post', ['id', 'title', 'content', 'authorId'] as const)
56
+ * .build();
57
+ * ```
58
+ *
59
+ * Note: The `as const` assertion is necessary for correct type inference.
60
+ */
61
+ static builderForSchema() {
62
+ return _newKyselyRizzolverBuilderForSchema({});
63
+ }
64
+ /**
65
+ * Starts building a new {@link KyselyRizzolver} using a builder pattern
66
+ * without a schema.
67
+ *
68
+ * Call {@link KyselyRizzolverBuilderNoSchema.table|.table()} for each
69
+ * table with all of their column names as a const array.
70
+ *
71
+ * Example:
72
+ * ```
73
+ * const rizzolver = KyselyRizzolver.builder()
74
+ * .table('user', ['id', 'name', 'email'] as const) // note `as const` is necessary
75
+ * .table('post', ['id', 'title', 'content', 'authorId'] as const)
76
+ * .build();
77
+ * ```
78
+ *
79
+ * Since this version of builder is schemaless, it cannot infer the value
80
+ * types for the columns. The `user` type will be `{ id: unknown, name:
81
+ * unknown, email: unknown }`.
82
+ *
83
+ * You may call
84
+ * {@link KyselyRizzolverBuilderNoSchema.asModel|.asModel\<M\>()}
85
+ * immediately after the .table() call to provide the types, where `M` is an
86
+ * type like `{ column1: type1, column2: type2, ... }`.
87
+ *
88
+ * Example:
89
+ * ```
90
+ * const rizzolver = KyselyRizzolver.builder()
91
+ * .table('user', ['id', 'name', 'email'] as const)
92
+ * .asModel<{id: number, name: string, email: string}>()
93
+ * .table('post', ['id', 'title', 'content', 'authorId'] as const)
94
+ * .asModel<{id: number, title: string, content: string, authorId: number}>()
95
+ * .build();
96
+ * ```
97
+ *
98
+ * p.s. if your .table() and .asModel() columns differ, it will let you know
99
+ * at compile time ;)
100
+ *
101
+ * Once all tables have been added, call
102
+ * {@link KyselyRizzolverBuilderNoSchema.build|.build()} to get a new
103
+ * {@link KyselyRizzolver} instance.
104
+ */
105
+ static builderNoSchema() {
106
+ return _newKyselyRizzolverBuilderNoSchema({}, null);
107
+ }
108
+ }
109
+ function _newKyselyRizzolverBuilderForSchema(fields) {
110
+ return {
111
+ table(tableName, tableFields) {
112
+ return _newKyselyRizzolverBuilderForSchema({
113
+ ...fields,
114
+ [tableName]: tableFields
115
+ });
116
+ },
117
+ build() {
118
+ return new KyselyRizzolver(fields);
119
+ }
120
+ };
121
+ }
122
+ function _newKyselyRizzolverBuilderNoSchema(fields, last) {
123
+ return {
124
+ table(tableName, tableFields) {
125
+ return _newKyselyRizzolverBuilderNoSchema({
126
+ ...fields,
127
+ [tableName]: {
128
+ model: null,
129
+ columns: tableFields
130
+ }
131
+ }, tableName);
132
+ },
133
+ asModel() {
134
+ if (!last) {
135
+ throw new Error('asModel() must be called after table()');
136
+ }
137
+ return _newKyselyRizzolverBuilderNoSchema(fields, null);
138
+ },
139
+ build() {
140
+ return new KyselyRizzolver(Object.fromEntries(Object.entries(fields).map((entry) => [entry[0], entry[1].columns])));
141
+ }
142
+ };
143
+ }
@@ -0,0 +1,21 @@
1
+ export function newModelCollection(init = {}) {
2
+ const collection = { ...init };
3
+ return {
4
+ add(table, selectable) {
5
+ if (!selectable ||
6
+ !('id' in selectable) ||
7
+ !selectable.id ||
8
+ typeof selectable.id !== 'number') {
9
+ return this;
10
+ }
11
+ if (!(table in collection)) {
12
+ collection[table] = {};
13
+ }
14
+ collection[table][selectable.id] = selectable;
15
+ return this;
16
+ },
17
+ get collection() {
18
+ return collection;
19
+ }
20
+ };
21
+ }
@@ -0,0 +1 @@
1
+ {"type": "module"}
@@ -0,0 +1,89 @@
1
+ import { newFetchOneResult, newFetchOneXResult, newFetchSomeResult } from './fetch-result.js';
2
+ import { newSelector } from './selector.js';
3
+ import { newModelCollection } from './model-collection.js';
4
+ export function newQueryBuilder(rizzolver) {
5
+ const selectors = {};
6
+ return {
7
+ selectors,
8
+ table(tableAlias) {
9
+ return selectors[tableAlias].selectTable;
10
+ },
11
+ allFields: Object.values(selectors)
12
+ .map((selector) => selector.selectFields)
13
+ .flat(),
14
+ fieldsOf(...tableAliases) {
15
+ return tableAliases.map((alias) => selectors[alias].selectFields).flat();
16
+ },
17
+ field(field) {
18
+ const [t, f] = field.split('.');
19
+ const alias = `_${t}_${f}`;
20
+ return {
21
+ value: alias,
22
+ from(a) {
23
+ return `${a}.${alias}`;
24
+ }
25
+ };
26
+ },
27
+ add(selectorOrTable, alias, keys) {
28
+ let selector;
29
+ if (typeof selectorOrTable === 'string') {
30
+ if (!alias) {
31
+ throw new Error('Must provide an alias when calling QueryBuilder.add with a table name');
32
+ }
33
+ selector = newSelector(rizzolver, selectorOrTable, alias, (keys ?? rizzolver.fields[selectorOrTable]));
34
+ }
35
+ else {
36
+ if (alias || keys) {
37
+ throw new Error('Must not provide an alias or keys when calling QueryBuilder.add with a selector');
38
+ }
39
+ selector = selectorOrTable;
40
+ }
41
+ selectors[selector.input.alias] = selector;
42
+ return this;
43
+ },
44
+ run(rowsOrCallback) {
45
+ const promise = (async () => {
46
+ const rows = Array.isArray(rowsOrCallback) ? rowsOrCallback : await rowsOrCallback(this);
47
+ const modelCollection = newModelCollection();
48
+ const selectorResults = {};
49
+ for (const [alias, selector] of Object.entries(selectors)) {
50
+ const selectorResult = selector.select(rows);
51
+ for (const { model } of selectorResult) {
52
+ if (!model) {
53
+ continue;
54
+ }
55
+ modelCollection.add(selector.input.table, model);
56
+ }
57
+ selectorResults[alias] = selectorResult;
58
+ }
59
+ const result = [];
60
+ for (let i = 0; i < rows.length; i++) {
61
+ const row = rows[i];
62
+ const selectedModels = {};
63
+ for (const [alias, selectorResult] of Object.entries(selectorResults)) {
64
+ selectedModels[alias] = selectorResult[i].model;
65
+ }
66
+ result.push({ row, selectors: selectedModels });
67
+ }
68
+ return {
69
+ first: result.length ? result[0] : undefined,
70
+ rows: result,
71
+ models: modelCollection,
72
+ newFetchOneResult(selectorAlias) {
73
+ return newFetchOneResult(selectors[selectorAlias].input.table, (result.length ? result[0] : undefined)?.selectors[selectorAlias], modelCollection);
74
+ },
75
+ newFetchOneXResult(selectorAlias) {
76
+ return newFetchOneXResult(selectors[selectorAlias].input.table, (result.length ? result[0] : undefined)?.selectors[selectorAlias], modelCollection);
77
+ },
78
+ newFetchSomeResult(selectorAlias) {
79
+ return newFetchSomeResult(selectors[selectorAlias].input.table, result.map((r) => r.selectors[selectorAlias]).filter((r) => !!r), modelCollection);
80
+ }
81
+ };
82
+ })();
83
+ promise.newFetchOneResult = (selectorAlias) => promise.then((result) => result.newFetchOneResult(selectorAlias));
84
+ promise.newFetchOneXResult = (selectorAlias) => promise.then((result) => result.newFetchOneXResult(selectorAlias));
85
+ promise.newFetchSomeResult = (selectorAlias) => promise.then((result) => result.newFetchSomeResult(selectorAlias));
86
+ return promise;
87
+ }
88
+ };
89
+ }
@@ -0,0 +1,42 @@
1
+ export function newSelector(rizzolver, tableName, alias, keys) {
2
+ const effectiveKeys = (keys ?? rizzolver.fields[tableName]);
3
+ const tableAlias = `${tableName} as ${alias}`;
4
+ const fields = effectiveKeys.map((field) => `${alias}.${field} as _${alias}_${field}`);
5
+ function _rowToModel(result) {
6
+ if (!result || !result[`_${alias}_id`]) {
7
+ return undefined;
8
+ }
9
+ const model = {};
10
+ for (const field of effectiveKeys) {
11
+ const aliasedField = `_${alias}_${field}`;
12
+ model[field] = result[aliasedField] ?? undefined;
13
+ }
14
+ return model;
15
+ }
16
+ const selector = {
17
+ input: {
18
+ table: tableName,
19
+ alias,
20
+ tableFields: effectiveKeys
21
+ },
22
+ selectTable: tableAlias,
23
+ selectFields: fields,
24
+ field(field) {
25
+ return {
26
+ str: `_${alias}_${field}`,
27
+ from(table) {
28
+ return `${table}._${alias}_${field}`;
29
+ }
30
+ };
31
+ },
32
+ select(rows) {
33
+ const data = [];
34
+ for (const row of rows) {
35
+ const model = _rowToModel(row);
36
+ data.push({ row, model });
37
+ }
38
+ return data;
39
+ }
40
+ };
41
+ return selector;
42
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,52 @@
1
+ import type { Selectable } from 'kysely';
2
+ import { type FetchOneResult, type FetchOneXResult, type FetchSomeResult } from './fetch-result.js';
3
+ import { type ModelCollection } from './model-collection.js';
4
+ /**
5
+ * A {@link FetchResultFactory} exposes variants of fetch-related functions, but
6
+ * with the `DB` type parameter already set.
7
+ *
8
+ * This makes it less verbose to work with fetch results in a type-safe way.
9
+ */
10
+ export type FetchResultFactory<DB> = ReturnType<typeof newFetchResultFactory<DB>>;
11
+ export declare function newFetchResultFactory<DB>(): {
12
+ /**
13
+ * Creates a new {@link FetchOneResult} instance.
14
+ */
15
+ newFetchOne<K extends keyof DB & string>(table: K, result: Selectable<DB[K]> | undefined, models?: ModelCollection<DB>): FetchOneResult<DB, K, Selectable<DB[K]>>;
16
+ /**
17
+ * Creates a new {@link FetchOneXResult} instance.
18
+ *
19
+ * Note: it may be counterintuitive, but this function accepts `undefined` as
20
+ * input. I found it is way more convenient to assert the type once in this
21
+ * funciton rather than in every caller.
22
+ */
23
+ newFetchOneX<K extends keyof DB & string>(table: K, result: Selectable<DB[K]> | undefined, models?: ModelCollection<DB>): FetchOneXResult<DB, K, Selectable<DB[K]>>;
24
+ /**
25
+ * Creates a new {@link FetchSomeResult} instance.
26
+ */
27
+ newFetchSome<K extends keyof DB & string>(table: K, result: Selectable<DB[K]>[], models?: ModelCollection<DB>): FetchSomeResult<DB, K, Selectable<DB[K]>>;
28
+ /**
29
+ * Checks if a {@link FetchResult} is a {@link FetchOneResult}.
30
+ */
31
+ isFetchOne<K extends keyof DB & string>(table: K, result: unknown): result is FetchOneResult<DB, K, Selectable<DB[K]>>;
32
+ /**
33
+ * Checks if a {@link FetchResult} is a {@link FetchOneXResult}.
34
+ */
35
+ isFetchOneX<K extends keyof DB & string>(table: K, result: unknown): result is FetchOneXResult<DB, K, Selectable<DB[K]>>;
36
+ /**
37
+ * Checks if a {@link FetchResult} is a {@link FetchSomeResult}.
38
+ */
39
+ isFetchSome<K extends keyof DB & string>(table: K, result: unknown): result is FetchSomeResult<DB, K, Selectable<DB[K]>>;
40
+ /**
41
+ * Asserts that a {@link FetchResult} is a {@link FetchOneResult}.
42
+ */
43
+ assertIsFetchOne<K extends keyof DB & string>(table: K, result: unknown): asserts result is FetchOneResult<DB, K, Selectable<DB[K]>>;
44
+ /**
45
+ * Asserts that a {@link FetchResult} is a {@link FetchOneXResult}.
46
+ */
47
+ assertIsFetchOneX<K extends keyof DB & string>(table: K, result: unknown): asserts result is FetchOneXResult<DB, K, Selectable<DB[K]>>;
48
+ /**
49
+ * Asserts that a {@link FetchResult} is a {@link FetchSomeResult}.
50
+ */
51
+ assertIsFetchSome<K extends keyof DB & string>(table: K, result: unknown): asserts result is FetchSomeResult<DB, K, Selectable<DB[K]>>;
52
+ };