@nkzw/fate 0.1.2 → 1.0.0-rc.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/README.md +810 -129
- package/docs/api/classes/FateClient.md +832 -0
- package/docs/api/functions/clientRoot.md +27 -0
- package/docs/api/functions/createClient.md +21 -0
- package/docs/api/functions/createHTTPTransport.md +51 -0
- package/docs/api/functions/createTRPCTransport.md +46 -0
- package/docs/api/functions/getListEntries.md +15 -0
- package/docs/api/functions/getSelectionPlan.md +36 -0
- package/docs/api/functions/isRecord.md +15 -0
- package/docs/api/functions/isViewTag.md +17 -0
- package/docs/api/functions/liveConnectionTopic.md +19 -0
- package/docs/api/functions/liveEntityTopic.md +19 -0
- package/docs/api/functions/liveGlobalConnectionTopic.md +15 -0
- package/docs/api/functions/mutation.md +32 -0
- package/docs/api/functions/toEntityId.md +21 -0
- package/docs/api/functions/view.md +26 -0
- package/docs/api/index.md +81 -0
- package/docs/api/interfaces/FateThenable.md +31 -0
- package/docs/api/interfaces/Transport.md +199 -0
- package/docs/api/server/classes/FateRequestError.md +67 -0
- package/docs/api/server/drizzle/functions/createDrizzleFate.md +431 -0
- package/docs/api/server/drizzle/functions/createDrizzleSourceAdapter.md +21 -0
- package/docs/api/server/drizzle/functions/createDrizzleSourceRegistry.md +21 -0
- package/docs/api/server/drizzle/index.md +23 -0
- package/docs/api/server/drizzle/type-aliases/DrizzleManyToManyConfig.md +15 -0
- package/docs/api/server/drizzle/type-aliases/DrizzleManyToManyInput.md +5 -0
- package/docs/api/server/drizzle/type-aliases/DrizzleQueryExtra.md +21 -0
- package/docs/api/server/drizzle/type-aliases/DrizzleSourceAdapter.md +337 -0
- package/docs/api/server/drizzle/type-aliases/DrizzleViewConfig.md +29 -0
- package/docs/api/server/functions/bindSourceProcedures.md +32 -0
- package/docs/api/server/functions/computed.md +43 -0
- package/docs/api/server/functions/count.md +21 -0
- package/docs/api/server/functions/createFateFetchHandler.md +21 -0
- package/docs/api/server/functions/createFateServer.md +41 -0
- package/docs/api/server/functions/createHonoFateHandler.md +21 -0
- package/docs/api/server/functions/createLiveEventBus.md +17 -0
- package/docs/api/server/functions/createNestedSourcePlan.md +103 -0
- package/docs/api/server/functions/createResolver.md +74 -0
- package/docs/api/server/functions/createSourcePlan.md +95 -0
- package/docs/api/server/functions/createSourceProcedures.md +46 -0
- package/docs/api/server/functions/dataView.md +32 -0
- package/docs/api/server/functions/field.md +15 -0
- package/docs/api/server/functions/getNestedSelection.md +19 -0
- package/docs/api/server/functions/getScopedArgs.md +21 -0
- package/docs/api/server/functions/hasNestedSelection.md +19 -0
- package/docs/api/server/functions/list.md +28 -0
- package/docs/api/server/functions/refetchSourceById.md +55 -0
- package/docs/api/server/functions/resolveSourceById.md +55 -0
- package/docs/api/server/functions/resolveSourceByIds.md +55 -0
- package/docs/api/server/functions/resolveSourceConnection.md +67 -0
- package/docs/api/server/functions/resolver.md +42 -0
- package/docs/api/server/functions/toPrismaSelect.md +25 -0
- package/docs/api/server/functions/withConnection.md +24 -0
- package/docs/api/server/index.md +109 -0
- package/docs/api/server/prisma/functions/createPrismaFate.md +435 -0
- package/docs/api/server/prisma/functions/createPrismaSourceAdapter.md +21 -0
- package/docs/api/server/prisma/functions/createPrismaSourceRegistry.md +21 -0
- package/docs/api/server/prisma/functions/prismaConnectionArgs.md +57 -0
- package/docs/api/server/prisma/index.md +23 -0
- package/docs/api/server/prisma/type-aliases/PrismaDelegate.md +59 -0
- package/docs/api/server/prisma/type-aliases/PrismaQueryExtra.md +5 -0
- package/docs/api/server/prisma/type-aliases/PrismaSourceAdapter.md +343 -0
- package/docs/api/server/prisma/type-aliases/PrismaViewConfig.md +31 -0
- package/docs/api/server/type-aliases/ComputedField.md +55 -0
- package/docs/api/server/type-aliases/ComputedSelection.md +5 -0
- package/docs/api/server/type-aliases/ConnectionItem.md +29 -0
- package/docs/api/server/type-aliases/ConnectionPagination.md +39 -0
- package/docs/api/server/type-aliases/ConnectionResult.md +29 -0
- package/docs/api/server/type-aliases/CountSelection.md +29 -0
- package/docs/api/server/type-aliases/CountWhere.md +5 -0
- package/docs/api/server/type-aliases/DataViewListOptions.md +13 -0
- package/docs/api/server/type-aliases/DataViewOrderBy.md +5 -0
- package/docs/api/server/type-aliases/DataViewOrderDirection.md +5 -0
- package/docs/api/server/type-aliases/DataViewResult.md +11 -0
- package/docs/api/server/type-aliases/Entity.md +21 -0
- package/docs/api/server/type-aliases/FateServer.md +75 -0
- package/docs/api/server/type-aliases/FateServerManifest.md +5 -0
- package/docs/api/server/type-aliases/FieldSelection.md +21 -0
- package/docs/api/server/type-aliases/LiveConnectionEventType.md +5 -0
- package/docs/api/server/type-aliases/LiveConnectionSourceEvent.md +5 -0
- package/docs/api/server/type-aliases/LiveEventBus.md +5 -0
- package/docs/api/server/type-aliases/LiveEventType.md +5 -0
- package/docs/api/server/type-aliases/LiveSourceEvent.md +5 -0
- package/docs/api/server/type-aliases/NativeFateAPI.md +47 -0
- package/docs/api/server/type-aliases/OrderDirection.md +5 -0
- package/docs/api/server/type-aliases/SourceConfig.md +55 -0
- package/docs/api/server/type-aliases/SourceDefinition.md +55 -0
- package/docs/api/server/type-aliases/SourceOrder.md +5 -0
- package/docs/api/server/type-aliases/SourceOrderField.md +21 -0
- package/docs/api/server/type-aliases/SourcePlan.md +29 -0
- package/docs/api/server/type-aliases/SourcePlanNode.md +29 -0
- package/docs/api/server/type-aliases/SourceRegistry.md +11 -0
- package/docs/api/server/type-aliases/SourceRelation.md +15 -0
- package/docs/api/server/type-aliases/SourceRelationConfig.md +23 -0
- package/docs/api/server/variables/byIdInput.md +5 -0
- package/docs/api/server/variables/connectionArgs.md +7 -0
- package/docs/api/type-aliases/ConnectionMetadata.md +7 -0
- package/docs/api/type-aliases/ConnectionRef.md +13 -0
- package/docs/api/type-aliases/Entity.md +15 -0
- package/docs/api/type-aliases/EntityId.md +7 -0
- package/docs/api/type-aliases/FateLiveConnectionEvent.md +5 -0
- package/docs/api/type-aliases/FateLiveEvent.md +5 -0
- package/docs/api/type-aliases/FateMutations.md +7 -0
- package/docs/api/type-aliases/FateOperation.md +5 -0
- package/docs/api/type-aliases/FateProtocolRequest.md +5 -0
- package/docs/api/type-aliases/FateProtocolResponse.md +5 -0
- package/docs/api/type-aliases/FateRecord.md +7 -0
- package/docs/api/type-aliases/FateRoots.md +7 -0
- package/docs/api/type-aliases/InferFateAPI.md +11 -0
- package/docs/api/type-aliases/List.md +5 -0
- package/docs/api/type-aliases/ListEntry.md +5 -0
- package/docs/api/type-aliases/ListItem.md +13 -0
- package/docs/api/type-aliases/Mask.md +15 -0
- package/docs/api/type-aliases/MutationDefinition.md +21 -0
- package/docs/api/type-aliases/MutationEntity.md +13 -0
- package/docs/api/type-aliases/MutationIdentifier.md +19 -0
- package/docs/api/type-aliases/MutationInput.md +13 -0
- package/docs/api/type-aliases/MutationResult.md +13 -0
- package/docs/api/type-aliases/NodesItem.md +13 -0
- package/docs/api/type-aliases/Pagination.md +39 -0
- package/docs/api/type-aliases/Request.md +7 -0
- package/docs/api/type-aliases/RequestMode.md +7 -0
- package/docs/api/type-aliases/RequestOptions.md +7 -0
- package/docs/api/type-aliases/RequestResult.md +18 -0
- package/docs/api/type-aliases/Selection.md +13 -0
- package/docs/api/type-aliases/Snapshot.md +7 -0
- package/docs/api/type-aliases/TypeConfig.md +41 -0
- package/docs/api/type-aliases/View.md +17 -0
- package/docs/api/type-aliases/ViewData.md +18 -0
- package/docs/api/type-aliases/ViewEntity.md +13 -0
- package/docs/api/type-aliases/ViewEntityName.md +13 -0
- package/docs/api/type-aliases/ViewRef.md +13 -0
- package/docs/api/type-aliases/ViewSelection.md +13 -0
- package/docs/api/type-aliases/ViewSnapshot.md +18 -0
- package/docs/api/type-aliases/ViewTag.md +7 -0
- package/docs/api/variables/ConnectionTag.md +7 -0
- package/docs/guide/actions.md +263 -0
- package/docs/guide/core-concepts.md +22 -0
- package/docs/guide/getting-started.md +57 -0
- package/docs/guide/list-views.md +86 -0
- package/docs/guide/live-views.md +245 -0
- package/docs/guide/requests.md +130 -0
- package/docs/guide/server-integration.md +630 -0
- package/docs/guide/views.md +278 -0
- package/docs/guide/void-integration.md +167 -0
- package/docs/index.md +4 -0
- package/lib/cli.mjs +17 -250
- package/lib/clientStub.d.mts +6 -0
- package/lib/clientStub.mjs +6 -0
- package/lib/executor-BqwHdN3n.d.mts +468 -0
- package/lib/index.d.mts +64 -3
- package/lib/index.mjs +1965 -559
- package/lib/list-4wRNSVgI.d.mts +10 -0
- package/lib/list-C_mi6GnE.mjs +16 -0
- package/lib/list.d.mts +2 -0
- package/lib/list.mjs +2 -0
- package/lib/liveTopics-DzNtJaBD.mjs +197 -0
- package/lib/{record-DnhZuvUe.mjs → record-AeZJC9fd.mjs} +1 -2
- package/lib/record-ENh92gyb.d.mts +315 -0
- package/lib/server/drizzle.d.mts +304 -0
- package/lib/server/drizzle.mjs +688 -0
- package/lib/server/prisma.d.mts +309 -0
- package/lib/server/prisma.mjs +345 -0
- package/lib/server.d.mts +82 -184
- package/lib/server.mjs +870 -416
- package/lib/sourceRouter-Bwpkr062.mjs +972 -0
- package/lib/{types-Djlh7mMH.d.mts → types-Dz46PXr3.d.mts} +327 -197
- package/lib/vite.d.mts +17 -0
- package/lib/vite.mjs +592 -0
- package/package.json +44 -6
|
@@ -0,0 +1,688 @@
|
|
|
1
|
+
import { t as isRecord } from "../record-AeZJC9fd.mjs";
|
|
2
|
+
import { O as withConnection, S as isDataView, c as resolveSourceConnection, d as createSourceDefinitions, f as createSourcePlan, g as attachComputedState, i as createSourceRegistry, l as collectDataViewConfigs, o as resolveSourceById, p as getDataViewSourceConfig, s as resolveSourceByIds, t as bindSourceProcedures } from "../sourceRouter-Bwpkr062.mjs";
|
|
3
|
+
import { and, asc, createTableRelationsHelpers, desc, eq, extractTablesRelationalConfig, getTableColumns, gt, inArray, isTable, lt, normalizeRelation, or, sql } from "drizzle-orm";
|
|
4
|
+
//#region src/server/drizzle.ts
|
|
5
|
+
/**
|
|
6
|
+
* Fate's Drizzle integration.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* import { createDrizzleFate } from '@nkzw/fate/server/drizzle';
|
|
10
|
+
*
|
|
11
|
+
* @module @nkzw/fate/server/drizzle
|
|
12
|
+
*/
|
|
13
|
+
const resolveSource = (source) => typeof source === "function" ? source() : source;
|
|
14
|
+
const isSourceDefinition = (target) => "view" in target && "id" in target;
|
|
15
|
+
const getColumn = (columns, field) => {
|
|
16
|
+
const column = columns[field];
|
|
17
|
+
if (!column) throw new Error(`No Drizzle column registered for field ${field}.`);
|
|
18
|
+
return column;
|
|
19
|
+
};
|
|
20
|
+
const paginationArgs = (args) => ({
|
|
21
|
+
after: typeof args?.after === "string" ? args.after : void 0,
|
|
22
|
+
before: typeof args?.before === "string" ? args.before : void 0,
|
|
23
|
+
first: typeof args?.first === "number" ? args.first : void 0,
|
|
24
|
+
last: typeof args?.last === "number" ? args.last : void 0
|
|
25
|
+
});
|
|
26
|
+
const hasPagination = (args) => {
|
|
27
|
+
const value = paginationArgs(args);
|
|
28
|
+
return value.after !== void 0 || value.before !== void 0 || value.first !== void 0 || value.last !== void 0;
|
|
29
|
+
};
|
|
30
|
+
const getConnectionDirection = (args) => args?.before !== void 0 || typeof args?.last === "number" ? "backward" : "forward";
|
|
31
|
+
const getConnectionSize = (fallback, args) => (typeof args?.first === "number" ? args.first : void 0) ?? (typeof args?.last === "number" ? args.last : void 0) ?? fallback;
|
|
32
|
+
const buildConnection = ({ cursor, direction, items, pageSize }) => {
|
|
33
|
+
const hasMore = items.length > pageSize;
|
|
34
|
+
const connectionItems = (direction === "forward" ? items.slice(0, pageSize) : items.slice(-pageSize)).map((node) => ({
|
|
35
|
+
cursor: node.id,
|
|
36
|
+
node
|
|
37
|
+
}));
|
|
38
|
+
const firstItem = connectionItems[0];
|
|
39
|
+
const lastItem = connectionItems.at(-1);
|
|
40
|
+
return {
|
|
41
|
+
items: connectionItems,
|
|
42
|
+
pagination: {
|
|
43
|
+
hasNext: direction === "backward" ? Boolean(cursor) : hasMore,
|
|
44
|
+
hasPrevious: direction === "backward" ? hasMore : Boolean(cursor),
|
|
45
|
+
nextCursor: lastItem?.cursor,
|
|
46
|
+
previousCursor: (direction === "backward" ? hasMore : Boolean(cursor)) ? firstItem?.cursor : void 0
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
const mapByField = (items, field) => new Map(items.map((item) => [item[field], item]));
|
|
51
|
+
const compactKeys = (values) => [...new Set(values.filter((value) => value !== null && value !== void 0))];
|
|
52
|
+
const reorderByIds = (ids, items) => {
|
|
53
|
+
const itemsById = mapByField(items, "id");
|
|
54
|
+
return ids.flatMap((id) => {
|
|
55
|
+
const item = itemsById.get(id);
|
|
56
|
+
return item ? [item] : [];
|
|
57
|
+
});
|
|
58
|
+
};
|
|
59
|
+
const addColumnField = (fields, field) => {
|
|
60
|
+
if (!field || field === "cursor") return;
|
|
61
|
+
fields.add(field);
|
|
62
|
+
};
|
|
63
|
+
const addComputedSelectionColumns = (fields, select) => {
|
|
64
|
+
if (!select) return;
|
|
65
|
+
for (const selection of Object.values(select)) if (selection.kind === "field") {
|
|
66
|
+
const [field] = selection.path.split(".");
|
|
67
|
+
addColumnField(fields, field);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
const getRequiredFields = (node, extraFields = []) => {
|
|
71
|
+
const fields = new Set(extraFields);
|
|
72
|
+
addColumnField(fields, node.source.id);
|
|
73
|
+
for (const field of node.selectedFields) addColumnField(fields, field);
|
|
74
|
+
for (const order of node.orderBy) addColumnField(fields, order.field);
|
|
75
|
+
for (const computed of node.computeds.values()) addComputedSelectionColumns(fields, computed.select);
|
|
76
|
+
for (const [field] of node.relations) {
|
|
77
|
+
const sourceRelation = node.source.relations?.[field];
|
|
78
|
+
if (sourceRelation) addColumnField(fields, sourceRelation.localKey);
|
|
79
|
+
}
|
|
80
|
+
return fields;
|
|
81
|
+
};
|
|
82
|
+
const compareColumn = (direction, naturalDirection, column, value) => {
|
|
83
|
+
const forward = naturalDirection === "asc" ? gt(column, value) : lt(column, value);
|
|
84
|
+
const backward = naturalDirection === "asc" ? lt(column, value) : gt(column, value);
|
|
85
|
+
return direction === "forward" ? forward : backward;
|
|
86
|
+
};
|
|
87
|
+
const buildCursorWhere = ({ columns, cursorValues, direction, node }) => {
|
|
88
|
+
const branches = node.orderBy.map((entry, index) => {
|
|
89
|
+
const column = getColumn(columns, entry.field);
|
|
90
|
+
const compare = compareColumn(direction, entry.direction, column, cursorValues[entry.field]);
|
|
91
|
+
const equalities = node.orderBy.slice(0, index).map((previous) => eq(getColumn(columns, previous.field), cursorValues[previous.field]));
|
|
92
|
+
return equalities.length ? and(...equalities, compare) : compare;
|
|
93
|
+
});
|
|
94
|
+
return branches.length === 1 ? branches[0] : or(...branches);
|
|
95
|
+
};
|
|
96
|
+
const getQueryOrder = (direction, node, columns) => node.orderBy.map((entry) => {
|
|
97
|
+
const column = getColumn(columns, entry.field);
|
|
98
|
+
return direction === "forward" ? entry.direction === "asc" ? asc(column) : desc(column) : entry.direction === "asc" ? desc(column) : asc(column);
|
|
99
|
+
});
|
|
100
|
+
const isSQLWrapper = (value) => isRecord(value) && typeof value.getSQL === "function";
|
|
101
|
+
const whereFromCountSelection = (columns, where) => {
|
|
102
|
+
if (!where) return;
|
|
103
|
+
if (typeof where === "function") return where(columns);
|
|
104
|
+
if (isSQLWrapper(where)) return where;
|
|
105
|
+
if (Object.keys(where).length === 0) return;
|
|
106
|
+
const conditions = Object.entries(where).map(([field, value]) => eq(getColumn(columns, field), value));
|
|
107
|
+
return conditions.length === 1 ? conditions[0] : and(...conditions);
|
|
108
|
+
};
|
|
109
|
+
const toRegisteredConfig = (config) => ({
|
|
110
|
+
...config,
|
|
111
|
+
columns: config.columns ?? getTableColumns(config.table)
|
|
112
|
+
});
|
|
113
|
+
const lowerFirst = (value) => `${value.slice(0, 1).toLowerCase()}${value.slice(1)}`;
|
|
114
|
+
const getColumnKey = (columns, column) => {
|
|
115
|
+
const entry = Object.entries(columns).find(([, candidate]) => candidate === column);
|
|
116
|
+
if (!entry) throw new Error(`Unable to resolve Drizzle column ${column.name}.`);
|
|
117
|
+
return entry[0];
|
|
118
|
+
};
|
|
119
|
+
const includesColumn = (columns, column) => Object.values(columns).includes(column);
|
|
120
|
+
const getDrizzleSchemaMetadata = ({ db, schema }) => {
|
|
121
|
+
if (schema) {
|
|
122
|
+
const extracted = extractTablesRelationalConfig(schema, createTableRelationsHelpers);
|
|
123
|
+
return {
|
|
124
|
+
fullSchema: schema,
|
|
125
|
+
schema: extracted.tables,
|
|
126
|
+
tableNamesMap: extracted.tableNamesMap
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
if (typeof db === "function") return;
|
|
130
|
+
const metadata = db._;
|
|
131
|
+
return metadata?.schema && metadata.fullSchema && metadata.tableNamesMap ? {
|
|
132
|
+
fullSchema: metadata.fullSchema,
|
|
133
|
+
schema: metadata.schema,
|
|
134
|
+
tableNamesMap: metadata.tableNamesMap
|
|
135
|
+
} : void 0;
|
|
136
|
+
};
|
|
137
|
+
const getTableConfig = ({ config, metadata }) => {
|
|
138
|
+
const entry = Object.entries(metadata.fullSchema).find(([, table]) => table === config.table);
|
|
139
|
+
if (!entry) throw new Error(`No Drizzle schema metadata found for ${config.view.typeName}.`);
|
|
140
|
+
const tableConfig = metadata.schema[entry[0]];
|
|
141
|
+
if (!tableConfig) throw new Error(`No Drizzle relational config found for ${config.view.typeName}.`);
|
|
142
|
+
return tableConfig;
|
|
143
|
+
};
|
|
144
|
+
const getTableForView = (view, metadata) => {
|
|
145
|
+
const directTable = metadata.fullSchema[lowerFirst(view.typeName)];
|
|
146
|
+
if (isTable(directTable)) return directTable;
|
|
147
|
+
const tableConfig = Object.values(metadata.schema).find((config) => config.tsName === lowerFirst(view.typeName) || config.dbName === view.typeName || lowerFirst(config.dbName) === lowerFirst(view.typeName));
|
|
148
|
+
if (tableConfig) {
|
|
149
|
+
const table = metadata.fullSchema[tableConfig.tsName];
|
|
150
|
+
if (isTable(table)) return table;
|
|
151
|
+
}
|
|
152
|
+
throw new Error(`No Drizzle table found for view ${view.typeName}.`);
|
|
153
|
+
};
|
|
154
|
+
const isDrizzleViewConfig = (value) => isRecord(value) && isDataView(value.view) && isTable(value.table);
|
|
155
|
+
const createDrizzleViewConfigs = ({ metadata, views }) => {
|
|
156
|
+
if (Array.isArray(views)) return views.map((view) => {
|
|
157
|
+
if (isDrizzleViewConfig(view)) return view;
|
|
158
|
+
if (!isDataView(view)) throw new Error(`Expected a data view or Drizzle view config.`);
|
|
159
|
+
if (!metadata) throw new Error(`Drizzle table for ${view.typeName} could not be inferred. Pass 'schema' to createDrizzleFate or use an explicit view config.`);
|
|
160
|
+
const config = getDataViewSourceConfig(view);
|
|
161
|
+
return {
|
|
162
|
+
...config,
|
|
163
|
+
table: getTableForView(config.view, metadata)
|
|
164
|
+
};
|
|
165
|
+
});
|
|
166
|
+
if (!metadata) throw new Error(`Drizzle tables could not be inferred. Pass 'schema' to createDrizzleFate or use explicit view configs.`);
|
|
167
|
+
return collectDataViewConfigs(views).map((config) => ({
|
|
168
|
+
...config,
|
|
169
|
+
table: getTableForView(config.view, metadata)
|
|
170
|
+
}));
|
|
171
|
+
};
|
|
172
|
+
const inferDirectRelation = ({ field, metadata, sourceConfig, targetConfig }) => {
|
|
173
|
+
const sourceTableConfig = getTableConfig({
|
|
174
|
+
config: sourceConfig,
|
|
175
|
+
metadata
|
|
176
|
+
});
|
|
177
|
+
const targetTableConfig = getTableConfig({
|
|
178
|
+
config: targetConfig,
|
|
179
|
+
metadata
|
|
180
|
+
});
|
|
181
|
+
const relation = sourceTableConfig.relations[field];
|
|
182
|
+
if (!relation) return null;
|
|
183
|
+
const normalized = normalizeRelation(metadata.schema, metadata.tableNamesMap, relation);
|
|
184
|
+
return {
|
|
185
|
+
foreignKey: getColumnKey(targetTableConfig.columns, normalized.references[0]),
|
|
186
|
+
localKey: getColumnKey(sourceTableConfig.columns, normalized.fields[0])
|
|
187
|
+
};
|
|
188
|
+
};
|
|
189
|
+
const inferManyToManyRelation = ({ field, metadata, sourceConfig, targetConfig }) => {
|
|
190
|
+
const sourceTableConfig = getTableConfig({
|
|
191
|
+
config: sourceConfig,
|
|
192
|
+
metadata
|
|
193
|
+
});
|
|
194
|
+
const targetTableConfig = getTableConfig({
|
|
195
|
+
config: targetConfig,
|
|
196
|
+
metadata
|
|
197
|
+
});
|
|
198
|
+
for (const joinTableConfig of Object.values(metadata.schema)) {
|
|
199
|
+
if (joinTableConfig === sourceTableConfig || joinTableConfig === targetTableConfig) continue;
|
|
200
|
+
let sourceJoin = null;
|
|
201
|
+
let targetJoin = null;
|
|
202
|
+
for (const relation of Object.values(joinTableConfig.relations)) {
|
|
203
|
+
let normalized;
|
|
204
|
+
try {
|
|
205
|
+
normalized = normalizeRelation(metadata.schema, metadata.tableNamesMap, relation);
|
|
206
|
+
} catch {
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
const fieldColumn = normalized.fields[0];
|
|
210
|
+
const referenceColumn = normalized.references[0];
|
|
211
|
+
if (!fieldColumn || !referenceColumn) continue;
|
|
212
|
+
if (includesColumn(sourceTableConfig.columns, referenceColumn)) sourceJoin = {
|
|
213
|
+
field: fieldColumn,
|
|
214
|
+
reference: referenceColumn
|
|
215
|
+
};
|
|
216
|
+
else if (includesColumn(targetTableConfig.columns, referenceColumn)) targetJoin = {
|
|
217
|
+
field: fieldColumn,
|
|
218
|
+
reference: referenceColumn
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
if (!sourceJoin || !targetJoin) continue;
|
|
222
|
+
const joinTable = metadata.fullSchema[joinTableConfig.tsName];
|
|
223
|
+
if (!isTable(joinTable)) continue;
|
|
224
|
+
sourceConfig.manyToMany = {
|
|
225
|
+
...sourceConfig.manyToMany,
|
|
226
|
+
[field]: sourceConfig.manyToMany?.[field] ?? joinTable
|
|
227
|
+
};
|
|
228
|
+
return {
|
|
229
|
+
foreignKey: getColumnKey(targetTableConfig.columns, targetJoin.reference),
|
|
230
|
+
localKey: getColumnKey(sourceTableConfig.columns, sourceJoin.reference),
|
|
231
|
+
through: {
|
|
232
|
+
foreignKey: getColumnKey(joinTableConfig.columns, targetJoin.field),
|
|
233
|
+
localKey: getColumnKey(joinTableConfig.columns, sourceJoin.field)
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
return null;
|
|
238
|
+
};
|
|
239
|
+
const resolveManyToManyConfig = ({ field, source, sourceRelation, through: throughInput }) => {
|
|
240
|
+
const through = isTable(throughInput) ? { table: throughInput } : throughInput;
|
|
241
|
+
if (through.localColumn && through.foreignColumn) return {
|
|
242
|
+
foreignColumn: through.foreignColumn,
|
|
243
|
+
localColumn: through.localColumn,
|
|
244
|
+
table: through.table
|
|
245
|
+
};
|
|
246
|
+
if (!sourceRelation.through) throw new Error(`Drizzle many-to-many relation ${source.view.typeName}.${field} requires source relation 'through' keys or explicit join columns.`);
|
|
247
|
+
const throughColumns = through.columns ?? getTableColumns(through.table);
|
|
248
|
+
return {
|
|
249
|
+
foreignColumn: getColumn(throughColumns, sourceRelation.through.foreignKey),
|
|
250
|
+
localColumn: getColumn(throughColumns, sourceRelation.through.localKey),
|
|
251
|
+
table: through.table
|
|
252
|
+
};
|
|
253
|
+
};
|
|
254
|
+
function createDrizzleSourceAdapter({ db, schema, views }) {
|
|
255
|
+
const metadata = getDrizzleSchemaMetadata({
|
|
256
|
+
db,
|
|
257
|
+
schema
|
|
258
|
+
});
|
|
259
|
+
const viewConfigs = createDrizzleViewConfigs({
|
|
260
|
+
metadata,
|
|
261
|
+
views
|
|
262
|
+
}).map((config) => ({
|
|
263
|
+
...config,
|
|
264
|
+
manyToMany: config.manyToMany ? { ...config.manyToMany } : void 0,
|
|
265
|
+
relations: config.relations ? { ...config.relations } : void 0
|
|
266
|
+
}));
|
|
267
|
+
const configsByView = new Map(viewConfigs.map((config) => [config.view, config]));
|
|
268
|
+
const configsByFields = new Map(viewConfigs.map((config) => [config.view.fields, config]));
|
|
269
|
+
const sourceDefinitions = createSourceDefinitions(viewConfigs, { resolveRelation: ({ config, field, kind, target }) => {
|
|
270
|
+
if (!metadata) return;
|
|
271
|
+
const targetConfig = configsByView.get(target.view) ?? configsByFields.get(target.view.fields);
|
|
272
|
+
if (!targetConfig) return;
|
|
273
|
+
return inferDirectRelation({
|
|
274
|
+
field,
|
|
275
|
+
metadata,
|
|
276
|
+
sourceConfig: config,
|
|
277
|
+
targetConfig
|
|
278
|
+
}) ?? (kind === "many" ? inferManyToManyRelation({
|
|
279
|
+
field,
|
|
280
|
+
metadata,
|
|
281
|
+
sourceConfig: config,
|
|
282
|
+
targetConfig
|
|
283
|
+
}) : void 0) ?? void 0;
|
|
284
|
+
} });
|
|
285
|
+
const sourcesByView = new Map(sourceDefinitions.map((source) => [source.view, source]));
|
|
286
|
+
const sourcesByFields = new Map(sourceDefinitions.map((source) => [source.view.fields, source]));
|
|
287
|
+
const sourceConfigs = new Map(viewConfigs.map((config, index) => [sourceDefinitions[index], {
|
|
288
|
+
...toRegisteredConfig(config),
|
|
289
|
+
source: sourceDefinitions[index]
|
|
290
|
+
}]));
|
|
291
|
+
const getSource = (target) => {
|
|
292
|
+
if (isSourceDefinition(target)) return target;
|
|
293
|
+
const source = sourcesByView.get(target) ?? sourcesByFields.get(target.fields);
|
|
294
|
+
if (!source) throw new Error(`No source registered for view ${target.typeName}.`);
|
|
295
|
+
return source;
|
|
296
|
+
};
|
|
297
|
+
const getSourceConfig = (source) => {
|
|
298
|
+
const config = sourceConfigs.get(source);
|
|
299
|
+
if (!config) throw new Error(`No Drizzle table registered for source ${source.view.typeName}.`);
|
|
300
|
+
return config;
|
|
301
|
+
};
|
|
302
|
+
const getDb = (ctx) => {
|
|
303
|
+
if (typeof db === "function") return db(ctx);
|
|
304
|
+
return db;
|
|
305
|
+
};
|
|
306
|
+
const buildSelection = (node, extraFields = []) => {
|
|
307
|
+
const config = getSourceConfig(node.source);
|
|
308
|
+
const selection = {};
|
|
309
|
+
for (const field of getRequiredFields(node, extraFields)) selection[field] = getColumn(config.columns, field);
|
|
310
|
+
return selection;
|
|
311
|
+
};
|
|
312
|
+
const queryRows = async ({ ctx, extraFields, node, where }) => {
|
|
313
|
+
const config = getSourceConfig(node.source);
|
|
314
|
+
return await getDb(ctx).select(buildSelection(node, extraFields)).from(config.table).where(where).orderBy(...getQueryOrder("forward", node, config.columns));
|
|
315
|
+
};
|
|
316
|
+
const queryNodePage = async ({ baseWhere, ctx, cursor, direction, node, take }) => {
|
|
317
|
+
const config = getSourceConfig(node.source);
|
|
318
|
+
const currentDb = getDb(ctx);
|
|
319
|
+
let whereClause = baseWhere;
|
|
320
|
+
if (cursor) {
|
|
321
|
+
const cursorSelection = Object.fromEntries(node.orderBy.map((entry) => [entry.field, getColumn(config.columns, entry.field)]));
|
|
322
|
+
const [cursorRow] = await currentDb.select(cursorSelection).from(config.table).where(baseWhere ? and(baseWhere, eq(getColumn(config.columns, node.source.id), cursor)) : eq(getColumn(config.columns, node.source.id), cursor)).limit(1);
|
|
323
|
+
if (cursorRow) {
|
|
324
|
+
const cursorWhere = buildCursorWhere({
|
|
325
|
+
columns: config.columns,
|
|
326
|
+
cursorValues: cursorRow,
|
|
327
|
+
direction,
|
|
328
|
+
node
|
|
329
|
+
});
|
|
330
|
+
whereClause = whereClause ? and(whereClause, cursorWhere) : cursorWhere;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
const rows = await currentDb.select(buildSelection(node)).from(config.table).where(whereClause).orderBy(...getQueryOrder(direction, node, config.columns)).limit(take);
|
|
334
|
+
return direction === "backward" ? rows.reverse() : rows;
|
|
335
|
+
};
|
|
336
|
+
const attachComputedCounts = async (items, node, ctx) => {
|
|
337
|
+
if (items.length === 0) return;
|
|
338
|
+
for (const [field, computed] of node.computeds) {
|
|
339
|
+
if (!computed.select) continue;
|
|
340
|
+
for (const [selectionName, selection] of Object.entries(computed.select)) {
|
|
341
|
+
if (selection.kind !== "count") continue;
|
|
342
|
+
const sourceRelation = node.source.relations?.[selection.relation];
|
|
343
|
+
if (!sourceRelation || sourceRelation.kind !== "many" && sourceRelation.kind !== "manyToMany") throw new Error(`Computed count ${node.source.view.typeName}.${field} requires a collection relation named ${selection.relation}.`);
|
|
344
|
+
const parentKeys = compactKeys(items.map((item) => item[sourceRelation.localKey]));
|
|
345
|
+
if (parentKeys.length === 0) continue;
|
|
346
|
+
const childConfig = getSourceConfig(resolveSource(sourceRelation.source));
|
|
347
|
+
let rows;
|
|
348
|
+
if (sourceRelation.kind === "manyToMany") {
|
|
349
|
+
const throughConfig = getSourceConfig(node.source).manyToMany?.[selection.relation];
|
|
350
|
+
if (!throughConfig) throw new Error(`No Drizzle many-to-many table registered for ${node.source.view.typeName}.${selection.relation}.`);
|
|
351
|
+
const through = resolveManyToManyConfig({
|
|
352
|
+
field: selection.relation,
|
|
353
|
+
source: node.source,
|
|
354
|
+
sourceRelation,
|
|
355
|
+
through: throughConfig
|
|
356
|
+
});
|
|
357
|
+
rows = await getDb(ctx).select({
|
|
358
|
+
count: sql`count(*)`.mapWith(Number),
|
|
359
|
+
parentKey: through.localColumn
|
|
360
|
+
}).from(through.table).innerJoin(childConfig.table, eq(through.foreignColumn, getColumn(childConfig.columns, sourceRelation.foreignKey))).where(and(inArray(through.localColumn, parentKeys), whereFromCountSelection(childConfig.columns, selection.where))).groupBy(through.localColumn);
|
|
361
|
+
} else {
|
|
362
|
+
const parentKeyColumn = getColumn(childConfig.columns, sourceRelation.foreignKey);
|
|
363
|
+
rows = await getDb(ctx).select({
|
|
364
|
+
count: sql`count(*)`.mapWith(Number),
|
|
365
|
+
parentKey: parentKeyColumn
|
|
366
|
+
}).from(childConfig.table).where(and(inArray(parentKeyColumn, parentKeys), whereFromCountSelection(childConfig.columns, selection.where))).groupBy(parentKeyColumn);
|
|
367
|
+
}
|
|
368
|
+
const counts = new Map(rows.map((row) => [row.parentKey, row.count]));
|
|
369
|
+
for (const item of items) attachComputedState(item, field, { [selectionName]: counts.get(item[sourceRelation.localKey]) ?? 0 });
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
};
|
|
373
|
+
const fetchManyRelation = async ({ ctx, items, relationNode, sourceRelation }) => {
|
|
374
|
+
const childConfig = getSourceConfig(resolveSource(sourceRelation.source));
|
|
375
|
+
const parentKeys = compactKeys(items.map((item) => item[sourceRelation.localKey]));
|
|
376
|
+
if (parentKeys.length === 0) return /* @__PURE__ */ new Map();
|
|
377
|
+
const hydrated = await hydrateRows(await queryRows({
|
|
378
|
+
ctx,
|
|
379
|
+
extraFields: [sourceRelation.foreignKey],
|
|
380
|
+
node: relationNode,
|
|
381
|
+
where: inArray(getColumn(childConfig.columns, sourceRelation.foreignKey), parentKeys)
|
|
382
|
+
}), relationNode, ctx);
|
|
383
|
+
const byParentKey = /* @__PURE__ */ new Map();
|
|
384
|
+
for (const item of hydrated) {
|
|
385
|
+
const key = item[sourceRelation.foreignKey];
|
|
386
|
+
const entries = byParentKey.get(key) ?? [];
|
|
387
|
+
entries.push(item);
|
|
388
|
+
byParentKey.set(key, entries);
|
|
389
|
+
}
|
|
390
|
+
return byParentKey;
|
|
391
|
+
};
|
|
392
|
+
const fetchManyConnection = async (parentKey, relationNode, sourceRelation, ctx) => {
|
|
393
|
+
const childConfig = getSourceConfig(resolveSource(sourceRelation.source));
|
|
394
|
+
const args = paginationArgs(relationNode.args);
|
|
395
|
+
const direction = getConnectionDirection(args);
|
|
396
|
+
const pageSize = getConnectionSize(20, args);
|
|
397
|
+
const cursor = direction === "forward" ? args.after : args.before;
|
|
398
|
+
if (parentKey === null || parentKey === void 0) return buildConnection({
|
|
399
|
+
cursor,
|
|
400
|
+
direction,
|
|
401
|
+
items: [],
|
|
402
|
+
pageSize
|
|
403
|
+
});
|
|
404
|
+
return buildConnection({
|
|
405
|
+
cursor,
|
|
406
|
+
direction,
|
|
407
|
+
items: await hydrateRows(await queryNodePage({
|
|
408
|
+
baseWhere: eq(getColumn(childConfig.columns, sourceRelation.foreignKey), parentKey),
|
|
409
|
+
ctx,
|
|
410
|
+
cursor,
|
|
411
|
+
direction,
|
|
412
|
+
node: relationNode,
|
|
413
|
+
take: pageSize + 1
|
|
414
|
+
}), relationNode, ctx),
|
|
415
|
+
pageSize
|
|
416
|
+
});
|
|
417
|
+
};
|
|
418
|
+
const queryManyToManyPage = async ({ ctx, cursor, direction, node, parentKey, sourceRelation, take, through }) => {
|
|
419
|
+
const childConfig = getSourceConfig(resolveSource(sourceRelation.source));
|
|
420
|
+
const currentDb = getDb(ctx);
|
|
421
|
+
let whereClause = eq(through.localColumn, parentKey);
|
|
422
|
+
if (cursor) {
|
|
423
|
+
const cursorSelection = Object.fromEntries(node.orderBy.map((entry) => [entry.field, getColumn(childConfig.columns, entry.field)]));
|
|
424
|
+
const [cursorRow] = await currentDb.select(cursorSelection).from(through.table).innerJoin(childConfig.table, eq(through.foreignColumn, getColumn(childConfig.columns, sourceRelation.foreignKey))).where(and(eq(through.localColumn, parentKey), eq(getColumn(childConfig.columns, node.source.id), cursor))).limit(1);
|
|
425
|
+
if (cursorRow) whereClause = and(whereClause, buildCursorWhere({
|
|
426
|
+
columns: childConfig.columns,
|
|
427
|
+
cursorValues: cursorRow,
|
|
428
|
+
direction,
|
|
429
|
+
node
|
|
430
|
+
}));
|
|
431
|
+
}
|
|
432
|
+
const rows = await currentDb.select({
|
|
433
|
+
...buildSelection(node),
|
|
434
|
+
parentKey: through.localColumn
|
|
435
|
+
}).from(through.table).innerJoin(childConfig.table, eq(through.foreignColumn, getColumn(childConfig.columns, sourceRelation.foreignKey))).where(whereClause).orderBy(...getQueryOrder(direction, node, childConfig.columns)).limit(take);
|
|
436
|
+
return direction === "backward" ? rows.reverse() : rows;
|
|
437
|
+
};
|
|
438
|
+
const fetchManyToManyConnection = async (parentKey, relationNode, sourceRelation, through, ctx) => {
|
|
439
|
+
const args = paginationArgs(relationNode.args);
|
|
440
|
+
const direction = getConnectionDirection(args);
|
|
441
|
+
const pageSize = getConnectionSize(20, args);
|
|
442
|
+
const cursor = direction === "forward" ? args.after : args.before;
|
|
443
|
+
if (parentKey === null || parentKey === void 0) return buildConnection({
|
|
444
|
+
cursor,
|
|
445
|
+
direction,
|
|
446
|
+
items: [],
|
|
447
|
+
pageSize
|
|
448
|
+
});
|
|
449
|
+
return buildConnection({
|
|
450
|
+
cursor,
|
|
451
|
+
direction,
|
|
452
|
+
items: await hydrateRows(await queryManyToManyPage({
|
|
453
|
+
ctx,
|
|
454
|
+
cursor,
|
|
455
|
+
direction,
|
|
456
|
+
node: relationNode,
|
|
457
|
+
parentKey,
|
|
458
|
+
sourceRelation,
|
|
459
|
+
take: pageSize + 1,
|
|
460
|
+
through
|
|
461
|
+
}), relationNode, ctx),
|
|
462
|
+
pageSize
|
|
463
|
+
});
|
|
464
|
+
};
|
|
465
|
+
const fetchManyToManyRelation = async ({ ctx, items, node, relationField, relationNode, sourceRelation }) => {
|
|
466
|
+
const parentConfig = getSourceConfig(node.source);
|
|
467
|
+
const childConfig = getSourceConfig(resolveSource(sourceRelation.source));
|
|
468
|
+
const throughConfig = parentConfig.manyToMany?.[relationField];
|
|
469
|
+
if (!throughConfig) throw new Error(`No Drizzle many-to-many table registered for ${node.source.view.typeName}.${relationField}.`);
|
|
470
|
+
const through = resolveManyToManyConfig({
|
|
471
|
+
field: relationField,
|
|
472
|
+
source: node.source,
|
|
473
|
+
sourceRelation,
|
|
474
|
+
through: throughConfig
|
|
475
|
+
});
|
|
476
|
+
const parentKeys = compactKeys(items.map((item) => item[sourceRelation.localKey]));
|
|
477
|
+
if (parentKeys.length === 0) return /* @__PURE__ */ new Map();
|
|
478
|
+
const hydrated = await hydrateRows(await getDb(ctx).select({
|
|
479
|
+
...buildSelection(relationNode),
|
|
480
|
+
parentKey: through.localColumn
|
|
481
|
+
}).from(through.table).innerJoin(childConfig.table, eq(through.foreignColumn, getColumn(childConfig.columns, sourceRelation.foreignKey))).where(inArray(through.localColumn, parentKeys)).orderBy(...getQueryOrder("forward", relationNode, childConfig.columns)), relationNode, ctx);
|
|
482
|
+
const byParentKey = /* @__PURE__ */ new Map();
|
|
483
|
+
for (const item of hydrated) {
|
|
484
|
+
const entries = byParentKey.get(item.parentKey) ?? [];
|
|
485
|
+
entries.push(item);
|
|
486
|
+
byParentKey.set(item.parentKey, entries);
|
|
487
|
+
}
|
|
488
|
+
return byParentKey;
|
|
489
|
+
};
|
|
490
|
+
const hydrateRows = async (rows, node, ctx) => {
|
|
491
|
+
const items = rows.map((row) => ({ ...row }));
|
|
492
|
+
await attachComputedCounts(items, node, ctx);
|
|
493
|
+
for (const [field, relationNode] of node.relations) {
|
|
494
|
+
const sourceRelation = node.source.relations?.[field];
|
|
495
|
+
if (!sourceRelation) continue;
|
|
496
|
+
if (sourceRelation.kind === "one") {
|
|
497
|
+
const childConfig = getSourceConfig(resolveSource(sourceRelation.source));
|
|
498
|
+
const childKeys = compactKeys(items.map((item) => item[sourceRelation.localKey]));
|
|
499
|
+
const childByKey = mapByField(await hydrateRows(childKeys.length ? await queryRows({
|
|
500
|
+
ctx,
|
|
501
|
+
node: relationNode,
|
|
502
|
+
where: inArray(getColumn(childConfig.columns, sourceRelation.foreignKey), childKeys)
|
|
503
|
+
}) : [], relationNode, ctx), sourceRelation.foreignKey);
|
|
504
|
+
for (const item of items) {
|
|
505
|
+
const localKey = item[sourceRelation.localKey];
|
|
506
|
+
item[field] = localKey !== null && localKey !== void 0 ? childByKey.get(localKey) ?? null : null;
|
|
507
|
+
}
|
|
508
|
+
continue;
|
|
509
|
+
}
|
|
510
|
+
if (sourceRelation.kind === "manyToMany") {
|
|
511
|
+
const throughConfig = getSourceConfig(node.source).manyToMany?.[field];
|
|
512
|
+
if (!throughConfig) throw new Error(`No Drizzle many-to-many table registered for ${node.source.view.typeName}.${field}.`);
|
|
513
|
+
const through = resolveManyToManyConfig({
|
|
514
|
+
field,
|
|
515
|
+
source: node.source,
|
|
516
|
+
sourceRelation,
|
|
517
|
+
through: throughConfig
|
|
518
|
+
});
|
|
519
|
+
if (hasPagination(relationNode.args)) {
|
|
520
|
+
const connections = await Promise.all(items.map(async (item) => [item[sourceRelation.localKey], await fetchManyToManyConnection(item[sourceRelation.localKey], relationNode, sourceRelation, through, ctx)]));
|
|
521
|
+
const connectionByParentKey = new Map(connections);
|
|
522
|
+
for (const item of items) item[field] = connectionByParentKey.get(item[sourceRelation.localKey]);
|
|
523
|
+
continue;
|
|
524
|
+
}
|
|
525
|
+
const byParentKey = await fetchManyToManyRelation({
|
|
526
|
+
ctx,
|
|
527
|
+
items,
|
|
528
|
+
node,
|
|
529
|
+
relationField: field,
|
|
530
|
+
relationNode,
|
|
531
|
+
sourceRelation
|
|
532
|
+
});
|
|
533
|
+
for (const item of items) item[field] = byParentKey.get(item[sourceRelation.localKey]) ?? [];
|
|
534
|
+
continue;
|
|
535
|
+
}
|
|
536
|
+
if (hasPagination(relationNode.args)) {
|
|
537
|
+
const connections = await Promise.all(items.map(async (item) => [item[sourceRelation.localKey], await fetchManyConnection(item[sourceRelation.localKey], relationNode, sourceRelation, ctx)]));
|
|
538
|
+
const connectionByParentKey = new Map(connections);
|
|
539
|
+
for (const item of items) item[field] = connectionByParentKey.get(item[sourceRelation.localKey]);
|
|
540
|
+
continue;
|
|
541
|
+
}
|
|
542
|
+
const byParentKey = await fetchManyRelation({
|
|
543
|
+
ctx,
|
|
544
|
+
items,
|
|
545
|
+
relationNode,
|
|
546
|
+
sourceRelation
|
|
547
|
+
});
|
|
548
|
+
for (const item of items) item[field] = byParentKey.get(item[sourceRelation.localKey]) ?? [];
|
|
549
|
+
}
|
|
550
|
+
return items;
|
|
551
|
+
};
|
|
552
|
+
const fetchByIds = async ({ ctx, extra, ids, plan }) => {
|
|
553
|
+
if (!ids.length) return [];
|
|
554
|
+
const config = getSourceConfig(plan.source);
|
|
555
|
+
return reorderByIds(ids, await hydrateRows(await queryRows({
|
|
556
|
+
ctx,
|
|
557
|
+
extraFields: extra?.extraFields,
|
|
558
|
+
node: plan.root,
|
|
559
|
+
where: inArray(getColumn(config.columns, plan.source.id), [...new Set(ids)])
|
|
560
|
+
}), plan.root, ctx));
|
|
561
|
+
};
|
|
562
|
+
const fetchById = async ({ ctx, extra, id, plan }) => (await fetchByIds({
|
|
563
|
+
ctx,
|
|
564
|
+
extra,
|
|
565
|
+
ids: [id],
|
|
566
|
+
plan
|
|
567
|
+
}))[0] ?? null;
|
|
568
|
+
const fetchConnection = async ({ ctx, cursor, direction, extra, plan, take }) => hydrateRows(await queryNodePage({
|
|
569
|
+
baseWhere: extra?.where,
|
|
570
|
+
ctx,
|
|
571
|
+
cursor,
|
|
572
|
+
direction,
|
|
573
|
+
node: plan.root,
|
|
574
|
+
take
|
|
575
|
+
}), plan.root, ctx);
|
|
576
|
+
const registry = createSourceRegistry(sourceDefinitions.map((source) => [source, {
|
|
577
|
+
byId: ({ ctx, extra, id, plan }) => fetchById({
|
|
578
|
+
ctx,
|
|
579
|
+
extra,
|
|
580
|
+
id,
|
|
581
|
+
plan
|
|
582
|
+
}),
|
|
583
|
+
byIds: ({ ctx, extra, ids, plan }) => fetchByIds({
|
|
584
|
+
ctx,
|
|
585
|
+
extra,
|
|
586
|
+
ids,
|
|
587
|
+
plan
|
|
588
|
+
}),
|
|
589
|
+
connection: ({ ctx, cursor, direction, extra, plan, take }) => fetchConnection({
|
|
590
|
+
ctx,
|
|
591
|
+
cursor,
|
|
592
|
+
direction,
|
|
593
|
+
extra,
|
|
594
|
+
plan,
|
|
595
|
+
take
|
|
596
|
+
})
|
|
597
|
+
}]));
|
|
598
|
+
return {
|
|
599
|
+
fetchById,
|
|
600
|
+
fetchByIds,
|
|
601
|
+
fetchConnection,
|
|
602
|
+
getSource,
|
|
603
|
+
registry,
|
|
604
|
+
resolveById: ({ ctx, extra, id, input, view }) => resolveSourceById({
|
|
605
|
+
ctx,
|
|
606
|
+
extra,
|
|
607
|
+
id,
|
|
608
|
+
input,
|
|
609
|
+
registry,
|
|
610
|
+
source: getSource(view)
|
|
611
|
+
}),
|
|
612
|
+
resolveByIds: ({ ctx, extra, ids, input, view }) => resolveSourceByIds({
|
|
613
|
+
ctx,
|
|
614
|
+
extra,
|
|
615
|
+
ids,
|
|
616
|
+
input,
|
|
617
|
+
registry,
|
|
618
|
+
source: getSource(view)
|
|
619
|
+
}),
|
|
620
|
+
resolveConnection: ({ ctx, cursor, direction, extra, input, skip, take, view }) => resolveSourceConnection({
|
|
621
|
+
ctx,
|
|
622
|
+
cursor,
|
|
623
|
+
direction,
|
|
624
|
+
extra,
|
|
625
|
+
input,
|
|
626
|
+
registry,
|
|
627
|
+
skip,
|
|
628
|
+
source: getSource(view),
|
|
629
|
+
take
|
|
630
|
+
})
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
const createDrizzleSourceRegistry = (options) => createDrizzleSourceAdapter(options).registry;
|
|
634
|
+
function createDrizzleFate({ procedure, ...options }) {
|
|
635
|
+
const adapter = createDrizzleSourceAdapter(options);
|
|
636
|
+
const connection = withConnection(procedure);
|
|
637
|
+
const procedures = bindSourceProcedures({
|
|
638
|
+
createConnectionProcedure: connection,
|
|
639
|
+
procedure,
|
|
640
|
+
registry: adapter.registry
|
|
641
|
+
});
|
|
642
|
+
return {
|
|
643
|
+
...adapter,
|
|
644
|
+
connection,
|
|
645
|
+
createPlan: ({ args, ctx, select, view }) => createSourcePlan({
|
|
646
|
+
args,
|
|
647
|
+
ctx,
|
|
648
|
+
select,
|
|
649
|
+
source: adapter.getSource(view)
|
|
650
|
+
}),
|
|
651
|
+
procedures: (input) => {
|
|
652
|
+
const procedureInput = input;
|
|
653
|
+
return procedures(procedureInput && typeof procedureInput === "object" && "view" in procedureInput ? {
|
|
654
|
+
...procedureInput,
|
|
655
|
+
source: adapter.getSource(procedureInput.view)
|
|
656
|
+
} : adapter.getSource(input));
|
|
657
|
+
},
|
|
658
|
+
resolveById: ({ ctx, extra, id, input, view }) => resolveSourceById({
|
|
659
|
+
ctx,
|
|
660
|
+
extra,
|
|
661
|
+
id,
|
|
662
|
+
input,
|
|
663
|
+
registry: adapter.registry,
|
|
664
|
+
source: adapter.getSource(view)
|
|
665
|
+
}),
|
|
666
|
+
resolveByIds: ({ ctx, extra, ids, input, view }) => resolveSourceByIds({
|
|
667
|
+
ctx,
|
|
668
|
+
extra,
|
|
669
|
+
ids,
|
|
670
|
+
input,
|
|
671
|
+
registry: adapter.registry,
|
|
672
|
+
source: adapter.getSource(view)
|
|
673
|
+
}),
|
|
674
|
+
resolveConnection: ({ ctx, cursor, direction, extra, input, skip, take, view }) => resolveSourceConnection({
|
|
675
|
+
ctx,
|
|
676
|
+
cursor,
|
|
677
|
+
direction,
|
|
678
|
+
extra,
|
|
679
|
+
input,
|
|
680
|
+
registry: adapter.registry,
|
|
681
|
+
skip,
|
|
682
|
+
source: adapter.getSource(view),
|
|
683
|
+
take
|
|
684
|
+
})
|
|
685
|
+
};
|
|
686
|
+
}
|
|
687
|
+
//#endregion
|
|
688
|
+
export { createDrizzleFate, createDrizzleSourceAdapter, createDrizzleSourceRegistry };
|