@ensnode/ponder-subgraph 0.18.0 → 0.19.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/dist/graphql.d.ts +41 -1
- package/dist/graphql.js +50 -1
- package/dist/graphql.js.map +1 -1
- package/dist/middleware.d.ts +3 -10
- package/dist/middleware.js +1 -560
- package/dist/middleware.js.map +1 -1
- package/package.json +9 -8
package/dist/middleware.js
CHANGED
|
@@ -62,20 +62,7 @@ import {
|
|
|
62
62
|
} from "graphql";
|
|
63
63
|
import { GraphQLJSON } from "graphql-scalars";
|
|
64
64
|
|
|
65
|
-
// src/helpers.ts
|
|
66
|
-
var intersectionOf = (arrays) => arrays.reduce((a, b) => a.filter((c) => b.includes(c)));
|
|
67
|
-
var capitalize = (str) => {
|
|
68
|
-
if (!str) return str;
|
|
69
|
-
return `${str.charAt(0).toUpperCase()}${str.slice(1)}`;
|
|
70
|
-
};
|
|
71
|
-
|
|
72
65
|
// src/serialize.ts
|
|
73
|
-
function serialize(value) {
|
|
74
|
-
return JSON.stringify(
|
|
75
|
-
value,
|
|
76
|
-
(_, v) => typeof v === "bigint" ? { __type: "bigint", value: v.toString() } : v
|
|
77
|
-
);
|
|
78
|
-
}
|
|
79
66
|
function deserialize(value) {
|
|
80
67
|
return JSON.parse(
|
|
81
68
|
value,
|
|
@@ -85,8 +72,6 @@ function deserialize(value) {
|
|
|
85
72
|
|
|
86
73
|
// src/graphql.ts
|
|
87
74
|
var onchain = Symbol.for("ponder:onchain");
|
|
88
|
-
var DEFAULT_LIMIT = 100;
|
|
89
|
-
var MAX_LIMIT = 1e3;
|
|
90
75
|
var OrderDirectionEnum = new GraphQLEnumType({
|
|
91
76
|
name: "OrderDirection",
|
|
92
77
|
values: {
|
|
@@ -94,326 +79,6 @@ var OrderDirectionEnum = new GraphQLEnumType({
|
|
|
94
79
|
desc: { value: "desc" }
|
|
95
80
|
}
|
|
96
81
|
});
|
|
97
|
-
function buildGraphQLSchema(_schema, polymorphicConfig = { types: {}, fields: {} }) {
|
|
98
|
-
const schema = { ..._schema };
|
|
99
|
-
const _tablesConfig = extractTablesRelationalConfig(schema, createTableRelationsHelpers);
|
|
100
|
-
const polymorphicTableConfigs = Object.fromEntries(
|
|
101
|
-
Object.entries(polymorphicConfig.types).map(([interfaceTypeName, implementingTables]) => [
|
|
102
|
-
interfaceTypeName,
|
|
103
|
-
implementingTables.map((table) => getTableUniqueName(table)).map((tableName) => _tablesConfig.tables[_tablesConfig.tableNamesMap[tableName]])
|
|
104
|
-
])
|
|
105
|
-
);
|
|
106
|
-
Object.assign(
|
|
107
|
-
schema,
|
|
108
|
-
...Object.keys(polymorphicConfig.types).map(
|
|
109
|
-
(interfaceTypeName) => getIntersectionTableSchema(interfaceTypeName, polymorphicTableConfigs[interfaceTypeName])
|
|
110
|
-
)
|
|
111
|
-
);
|
|
112
|
-
const polymorphicFields = Object.entries(polymorphicConfig.fields).map(([fieldPath, interfaceTypeName]) => [
|
|
113
|
-
fieldPath.split("."),
|
|
114
|
-
interfaceTypeName
|
|
115
|
-
]);
|
|
116
|
-
const tablesConfig = extractTablesRelationalConfig(schema, createTableRelationsHelpers);
|
|
117
|
-
const tables = Object.values(tablesConfig.tables);
|
|
118
|
-
const enums = Object.entries(schema).filter(
|
|
119
|
-
(el) => isPgEnum(el[1])
|
|
120
|
-
);
|
|
121
|
-
const enumTypes = {};
|
|
122
|
-
for (const [enumTsName, enumObject] of enums) {
|
|
123
|
-
enumTypes[enumObject.enumName] = new GraphQLEnumType({
|
|
124
|
-
name: enumTsName,
|
|
125
|
-
values: enumObject.enumValues.reduce(
|
|
126
|
-
(acc, cur) => ({ ...acc, [cur]: {} }),
|
|
127
|
-
{}
|
|
128
|
-
)
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
const entityOrderByEnums = {};
|
|
132
|
-
for (const table of tables) {
|
|
133
|
-
const values = Object.keys(table.columns).reduce(
|
|
134
|
-
(acc, columnName) => ({
|
|
135
|
-
...acc,
|
|
136
|
-
[columnName]: { value: columnName }
|
|
137
|
-
}),
|
|
138
|
-
{}
|
|
139
|
-
);
|
|
140
|
-
entityOrderByEnums[table.tsName] = new GraphQLEnumType({
|
|
141
|
-
name: `${getSubgraphEntityName(table.tsName)}_orderBy`,
|
|
142
|
-
values
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
const entityFilterTypes = {};
|
|
146
|
-
for (const table of tables) {
|
|
147
|
-
const filterType = new GraphQLInputObjectType({
|
|
148
|
-
name: `${getSubgraphEntityName(table.tsName)}_filter`,
|
|
149
|
-
fields: () => {
|
|
150
|
-
const filterFields = {
|
|
151
|
-
// Logical operators
|
|
152
|
-
// NOTE: lower case and/or
|
|
153
|
-
and: { type: new GraphQLList(filterType) },
|
|
154
|
-
or: { type: new GraphQLList(filterType) }
|
|
155
|
-
};
|
|
156
|
-
for (const [columnName, column] of Object.entries(table.columns)) {
|
|
157
|
-
const type = columnToGraphQLCore(column, enumTypes);
|
|
158
|
-
if (type instanceof GraphQLList) {
|
|
159
|
-
const baseType = innerType(type);
|
|
160
|
-
conditionSuffixes.universal.forEach((suffix) => {
|
|
161
|
-
filterFields[`${columnName}${suffix}`] = {
|
|
162
|
-
type: new GraphQLList(baseType)
|
|
163
|
-
};
|
|
164
|
-
});
|
|
165
|
-
conditionSuffixes.plural.forEach((suffix) => {
|
|
166
|
-
filterFields[`${columnName}${suffix}`] = { type: baseType };
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
if (type instanceof GraphQLScalarType || type instanceof GraphQLEnumType) {
|
|
170
|
-
if (type.name === "JSON") continue;
|
|
171
|
-
conditionSuffixes.universal.forEach((suffix) => {
|
|
172
|
-
filterFields[`${columnName}${suffix}`] = {
|
|
173
|
-
type
|
|
174
|
-
};
|
|
175
|
-
});
|
|
176
|
-
conditionSuffixes.singular.forEach((suffix) => {
|
|
177
|
-
filterFields[`${columnName}${suffix}`] = {
|
|
178
|
-
type: new GraphQLList(type)
|
|
179
|
-
};
|
|
180
|
-
});
|
|
181
|
-
if (["String", "ID"].includes(type.name)) {
|
|
182
|
-
conditionSuffixes.string.forEach((suffix) => {
|
|
183
|
-
filterFields[`${columnName}${suffix}`] = {
|
|
184
|
-
type
|
|
185
|
-
};
|
|
186
|
-
});
|
|
187
|
-
conditionSuffixes.numeric.forEach((suffix) => {
|
|
188
|
-
filterFields[`${columnName}${suffix}`] = {
|
|
189
|
-
type
|
|
190
|
-
};
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
if (["Int", "Float", "BigInt"].includes(type.name)) {
|
|
194
|
-
conditionSuffixes.numeric.forEach((suffix) => {
|
|
195
|
-
filterFields[`${columnName}${suffix}`] = {
|
|
196
|
-
type
|
|
197
|
-
};
|
|
198
|
-
});
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
for (const [relationName, relation] of Object.entries(table.relations)) {
|
|
203
|
-
if (is(relation, One)) {
|
|
204
|
-
conditionSuffixes.universal.forEach((suffix) => {
|
|
205
|
-
filterFields[`${relation.fieldName}${suffix}`] = {
|
|
206
|
-
type: GraphQLString
|
|
207
|
-
};
|
|
208
|
-
});
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
return filterFields;
|
|
212
|
-
}
|
|
213
|
-
});
|
|
214
|
-
entityFilterTypes[table.tsName] = filterType;
|
|
215
|
-
}
|
|
216
|
-
const entityTypes = {};
|
|
217
|
-
const interfaceTypes = {};
|
|
218
|
-
const entityPageTypes = {};
|
|
219
|
-
for (const interfaceTypeName of Object.keys(polymorphicTableConfigs)) {
|
|
220
|
-
const table = tablesConfig.tables[interfaceTypeName];
|
|
221
|
-
interfaceTypes[interfaceTypeName] = new GraphQLInterfaceType({
|
|
222
|
-
name: interfaceTypeName,
|
|
223
|
-
fields: () => {
|
|
224
|
-
const fieldConfigMap = {};
|
|
225
|
-
for (const [columnName, column] of Object.entries(table.columns)) {
|
|
226
|
-
const type = columnToGraphQLCore(column, enumTypes);
|
|
227
|
-
fieldConfigMap[columnName] = {
|
|
228
|
-
type: column.notNull ? new GraphQLNonNull(type) : type
|
|
229
|
-
};
|
|
230
|
-
}
|
|
231
|
-
return fieldConfigMap;
|
|
232
|
-
}
|
|
233
|
-
});
|
|
234
|
-
}
|
|
235
|
-
for (const table of tables) {
|
|
236
|
-
if (isInterfaceType(polymorphicConfig, table.tsName)) continue;
|
|
237
|
-
const entityTypeName = getSubgraphEntityName(table.tsName);
|
|
238
|
-
entityTypes[table.tsName] = new GraphQLObjectType({
|
|
239
|
-
name: entityTypeName,
|
|
240
|
-
interfaces: Object.entries(polymorphicTableConfigs).filter(
|
|
241
|
-
([, implementingTables]) => implementingTables.map((table2) => table2.tsName).includes(table.tsName)
|
|
242
|
-
).map(([interfaceTypeName]) => interfaceTypes[interfaceTypeName]),
|
|
243
|
-
fields: () => {
|
|
244
|
-
var _a, _b, _c, _d;
|
|
245
|
-
const fieldConfigMap = {};
|
|
246
|
-
for (const [columnName, column] of Object.entries(table.columns)) {
|
|
247
|
-
const type = columnToGraphQLCore(column, enumTypes);
|
|
248
|
-
fieldConfigMap[columnName] = {
|
|
249
|
-
type: column.notNull ? new GraphQLNonNull(type) : type
|
|
250
|
-
};
|
|
251
|
-
}
|
|
252
|
-
const relations2 = Object.entries(table.relations);
|
|
253
|
-
for (const [relationName, relation] of relations2) {
|
|
254
|
-
const referencedTable = tables.find(
|
|
255
|
-
(table2) => table2.dbName === relation.referencedTableName
|
|
256
|
-
);
|
|
257
|
-
if (!referencedTable)
|
|
258
|
-
throw new Error(
|
|
259
|
-
`Internal error: Referenced table "${relation.referencedTableName}" not found`
|
|
260
|
-
);
|
|
261
|
-
const referencedEntityType = entityTypes[referencedTable.tsName];
|
|
262
|
-
const referencedEntityPageType = entityPageTypes[referencedTable.tsName];
|
|
263
|
-
const referencedEntityFilterType = entityFilterTypes[referencedTable.tsName];
|
|
264
|
-
if (referencedEntityType === void 0 || referencedEntityPageType === void 0 || referencedEntityFilterType === void 0)
|
|
265
|
-
throw new Error(
|
|
266
|
-
`Internal error: Referenced entity types not found for table "${referencedTable.tsName}" `
|
|
267
|
-
);
|
|
268
|
-
if (is(relation, One)) {
|
|
269
|
-
const fields = ((_a = relation.config) == null ? void 0 : _a.fields) ?? [];
|
|
270
|
-
const references = ((_b = relation.config) == null ? void 0 : _b.references) ?? [];
|
|
271
|
-
if (fields.length !== references.length) {
|
|
272
|
-
throw new Error(
|
|
273
|
-
"Internal error: Fields and references arrays must be the same length"
|
|
274
|
-
);
|
|
275
|
-
}
|
|
276
|
-
fieldConfigMap[relationName] = {
|
|
277
|
-
// Note: There is a `relation.isNullable` field here but it appears
|
|
278
|
-
// to be internal / incorrect. Until we have support for foriegn
|
|
279
|
-
// key constraints, all `one` relations must be nullable.
|
|
280
|
-
type: referencedEntityType,
|
|
281
|
-
resolve: (parent, _args, context) => {
|
|
282
|
-
const loader = context.getDataLoader({ table: referencedTable });
|
|
283
|
-
const rowFragment = {};
|
|
284
|
-
for (let i = 0; i < references.length; i++) {
|
|
285
|
-
const referenceColumn = references[i];
|
|
286
|
-
const fieldColumn = fields[i];
|
|
287
|
-
const fieldColumnTsName = getColumnTsName(fieldColumn);
|
|
288
|
-
const referenceColumnTsName = getColumnTsName(referenceColumn);
|
|
289
|
-
rowFragment[referenceColumnTsName] = parent[fieldColumnTsName];
|
|
290
|
-
}
|
|
291
|
-
const encodedId = encodeRowFragment(rowFragment);
|
|
292
|
-
return loader.load(encodedId);
|
|
293
|
-
}
|
|
294
|
-
};
|
|
295
|
-
} else if (is(relation, Many)) {
|
|
296
|
-
const oneRelation = Object.values(referencedTable.relations).find(
|
|
297
|
-
(relation2) => relation2.relationName === relationName || is(relation2, One) && relation2.referencedTableName === table.dbName
|
|
298
|
-
);
|
|
299
|
-
if (!oneRelation)
|
|
300
|
-
throw new Error(
|
|
301
|
-
`Internal error: Relation "${relationName}" not found in table "${referencedTable.tsName}"`
|
|
302
|
-
);
|
|
303
|
-
const fields = ((_c = oneRelation.config) == null ? void 0 : _c.fields) ?? [];
|
|
304
|
-
const references = ((_d = oneRelation.config) == null ? void 0 : _d.references) ?? [];
|
|
305
|
-
const referencedEntityOrderByType = entityOrderByEnums[referencedTable.tsName];
|
|
306
|
-
if (!referencedEntityOrderByType)
|
|
307
|
-
throw new Error(`Entity_orderBy Enum not found for ${referencedTable.tsName}`);
|
|
308
|
-
fieldConfigMap[relationName] = {
|
|
309
|
-
type: referencedEntityPageType,
|
|
310
|
-
args: {
|
|
311
|
-
where: { type: referencedEntityFilterType },
|
|
312
|
-
orderBy: { type: referencedEntityOrderByType },
|
|
313
|
-
orderDirection: { type: OrderDirectionEnum },
|
|
314
|
-
first: { type: GraphQLInt },
|
|
315
|
-
skip: { type: GraphQLInt }
|
|
316
|
-
},
|
|
317
|
-
resolve: (parent, args, context, info) => {
|
|
318
|
-
const relationalConditions = [];
|
|
319
|
-
for (let i = 0; i < references.length; i++) {
|
|
320
|
-
const column = fields[i];
|
|
321
|
-
const value = parent[references[i].name];
|
|
322
|
-
relationalConditions.push(eq(column, value));
|
|
323
|
-
}
|
|
324
|
-
return executePluralQuery(
|
|
325
|
-
referencedTable,
|
|
326
|
-
schema[referencedTable.tsName],
|
|
327
|
-
context.drizzle,
|
|
328
|
-
args,
|
|
329
|
-
relationalConditions
|
|
330
|
-
);
|
|
331
|
-
}
|
|
332
|
-
};
|
|
333
|
-
} else {
|
|
334
|
-
throw new Error(
|
|
335
|
-
`Internal error: Relation "${relationName}" is unsupported, expected One or Many`
|
|
336
|
-
);
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
polymorphicFields.filter(([[parent]]) => parent === entityTypeName).forEach(([[, fieldName], interfaceTypeName]) => {
|
|
340
|
-
fieldConfigMap[fieldName] = definePolymorphicPluralField({
|
|
341
|
-
schema,
|
|
342
|
-
interfaceType: interfaceTypes[interfaceTypeName],
|
|
343
|
-
filterType: entityFilterTypes[interfaceTypeName],
|
|
344
|
-
orderByType: entityOrderByEnums[interfaceTypeName],
|
|
345
|
-
intersectionTableConfig: tablesConfig.tables[interfaceTypeName],
|
|
346
|
-
implementingTableConfigs: polymorphicTableConfigs[interfaceTypeName]
|
|
347
|
-
});
|
|
348
|
-
});
|
|
349
|
-
return fieldConfigMap;
|
|
350
|
-
}
|
|
351
|
-
});
|
|
352
|
-
entityPageTypes[table.tsName] = new GraphQLNonNull(
|
|
353
|
-
new GraphQLList(new GraphQLNonNull(entityTypes[table.tsName]))
|
|
354
|
-
);
|
|
355
|
-
}
|
|
356
|
-
const queryFields = {};
|
|
357
|
-
for (const table of tables) {
|
|
358
|
-
if (isInterfaceType(polymorphicConfig, table.tsName)) continue;
|
|
359
|
-
const entityType = entityTypes[table.tsName];
|
|
360
|
-
const entityPageType = entityPageTypes[table.tsName];
|
|
361
|
-
const entityFilterType = entityFilterTypes[table.tsName];
|
|
362
|
-
const singularFieldName = table.tsName.charAt(0).toLowerCase() + table.tsName.slice(1);
|
|
363
|
-
const pluralFieldName = `${singularFieldName}s`;
|
|
364
|
-
queryFields[singularFieldName] = {
|
|
365
|
-
type: entityType,
|
|
366
|
-
// Find the primary key columns and GraphQL core types and include them
|
|
367
|
-
// as arguments to the singular query type.
|
|
368
|
-
args: Object.fromEntries(
|
|
369
|
-
table.primaryKey.map((column) => [
|
|
370
|
-
getColumnTsName(column),
|
|
371
|
-
{
|
|
372
|
-
type: new GraphQLNonNull(columnToGraphQLCore(column, enumTypes))
|
|
373
|
-
}
|
|
374
|
-
])
|
|
375
|
-
),
|
|
376
|
-
resolve: async (_parent, args, context) => {
|
|
377
|
-
const loader = context.getDataLoader({ table });
|
|
378
|
-
const encodedId = encodeRowFragment(args);
|
|
379
|
-
return loader.load(encodedId);
|
|
380
|
-
}
|
|
381
|
-
};
|
|
382
|
-
const entityOrderByType = entityOrderByEnums[table.tsName];
|
|
383
|
-
if (!entityOrderByType) throw new Error(`Entity_orderBy Enum not found for ${table.tsName}`);
|
|
384
|
-
queryFields[pluralFieldName] = {
|
|
385
|
-
type: entityPageType,
|
|
386
|
-
args: {
|
|
387
|
-
where: { type: entityFilterType },
|
|
388
|
-
orderBy: { type: entityOrderByType },
|
|
389
|
-
orderDirection: { type: OrderDirectionEnum },
|
|
390
|
-
first: { type: GraphQLInt },
|
|
391
|
-
skip: { type: GraphQLInt }
|
|
392
|
-
},
|
|
393
|
-
resolve: async (_parent, args, context, info) => {
|
|
394
|
-
return executePluralQuery(table, schema[table.tsName], context.drizzle, args);
|
|
395
|
-
}
|
|
396
|
-
};
|
|
397
|
-
}
|
|
398
|
-
polymorphicFields.filter(([[parent]]) => parent === "Query").forEach(([[, fieldName], interfaceTypeName]) => {
|
|
399
|
-
queryFields[fieldName] = definePolymorphicPluralField({
|
|
400
|
-
schema,
|
|
401
|
-
interfaceType: interfaceTypes[interfaceTypeName],
|
|
402
|
-
filterType: entityFilterTypes[interfaceTypeName],
|
|
403
|
-
orderByType: entityOrderByEnums[interfaceTypeName],
|
|
404
|
-
intersectionTableConfig: tablesConfig.tables[interfaceTypeName],
|
|
405
|
-
implementingTableConfigs: polymorphicTableConfigs[interfaceTypeName]
|
|
406
|
-
});
|
|
407
|
-
});
|
|
408
|
-
return new GraphQLSchema({
|
|
409
|
-
// Include these here so they are listed first in the printed schema.
|
|
410
|
-
types: [GraphQLJSON, GraphQLBigInt, GraphQLPageInfo],
|
|
411
|
-
query: new GraphQLObjectType({
|
|
412
|
-
name: "Query",
|
|
413
|
-
fields: queryFields
|
|
414
|
-
})
|
|
415
|
-
});
|
|
416
|
-
}
|
|
417
82
|
var GraphQLPageInfo = new GraphQLObjectType({
|
|
418
83
|
name: "PageInfo",
|
|
419
84
|
fields: {
|
|
@@ -437,85 +102,6 @@ var GraphQLBigInt = new GraphQLScalarType({
|
|
|
437
102
|
}
|
|
438
103
|
}
|
|
439
104
|
});
|
|
440
|
-
var columnToGraphQLCore = (column, enumTypes) => {
|
|
441
|
-
if (column.columnType === "PgEvmBigint") {
|
|
442
|
-
return GraphQLBigInt;
|
|
443
|
-
}
|
|
444
|
-
if (column instanceof PgEnumColumn) {
|
|
445
|
-
if (column.enum === void 0) {
|
|
446
|
-
throw new Error(
|
|
447
|
-
`Internal error: Expected enum column "${getColumnTsName(column)}" to have an "enum" property`
|
|
448
|
-
);
|
|
449
|
-
}
|
|
450
|
-
const enumType = enumTypes[column.enum.enumName];
|
|
451
|
-
if (enumType === void 0) {
|
|
452
|
-
throw new Error(
|
|
453
|
-
`Internal error: Expected to find a GraphQL enum named "${column.enum.enumName}"`
|
|
454
|
-
);
|
|
455
|
-
}
|
|
456
|
-
return enumType;
|
|
457
|
-
}
|
|
458
|
-
switch (column.dataType) {
|
|
459
|
-
case "boolean":
|
|
460
|
-
return GraphQLBoolean;
|
|
461
|
-
case "json":
|
|
462
|
-
return GraphQLJSON;
|
|
463
|
-
case "date":
|
|
464
|
-
return GraphQLString;
|
|
465
|
-
case "string":
|
|
466
|
-
return GraphQLString;
|
|
467
|
-
case "bigint":
|
|
468
|
-
return GraphQLString;
|
|
469
|
-
case "number":
|
|
470
|
-
return is(column, PgInteger) || is(column, PgSerial) ? GraphQLInt : GraphQLFloat;
|
|
471
|
-
case "buffer":
|
|
472
|
-
return new GraphQLList(new GraphQLNonNull(GraphQLInt));
|
|
473
|
-
case "array": {
|
|
474
|
-
if (column.columnType === "PgVector") {
|
|
475
|
-
return new GraphQLList(new GraphQLNonNull(GraphQLFloat));
|
|
476
|
-
}
|
|
477
|
-
if (column.columnType === "PgGeometry") {
|
|
478
|
-
return new GraphQLList(new GraphQLNonNull(GraphQLFloat));
|
|
479
|
-
}
|
|
480
|
-
const innerType2 = columnToGraphQLCore(column.baseColumn, enumTypes);
|
|
481
|
-
return new GraphQLList(new GraphQLNonNull(innerType2));
|
|
482
|
-
}
|
|
483
|
-
default:
|
|
484
|
-
throw new Error(`Type ${column.dataType} is not implemented`);
|
|
485
|
-
}
|
|
486
|
-
};
|
|
487
|
-
var innerType = (type) => {
|
|
488
|
-
if (type instanceof GraphQLScalarType || type instanceof GraphQLEnumType) return type;
|
|
489
|
-
if (type instanceof GraphQLList || type instanceof GraphQLNonNull) return innerType(type.ofType);
|
|
490
|
-
throw new Error(`Type ${type.toString()} is not implemented`);
|
|
491
|
-
};
|
|
492
|
-
async function executePluralQuery(table, from, drizzle, args, extraConditions = []) {
|
|
493
|
-
const limit = args.first ?? DEFAULT_LIMIT;
|
|
494
|
-
if (limit > MAX_LIMIT) {
|
|
495
|
-
throw new Error(`Invalid limit. Got ${limit}, expected <=${MAX_LIMIT}.`);
|
|
496
|
-
}
|
|
497
|
-
const skip = args.skip ?? 0;
|
|
498
|
-
const orderBySchema = buildOrderBySchema(table, args);
|
|
499
|
-
const orderBy = orderBySchema.map(([columnName, direction]) => {
|
|
500
|
-
const column = table.columns[columnName];
|
|
501
|
-
if (column === void 0) {
|
|
502
|
-
throw new Error(`Unknown column "${columnName}" used in orderBy argument`);
|
|
503
|
-
}
|
|
504
|
-
return direction === "asc" ? asc(column) : desc(column);
|
|
505
|
-
});
|
|
506
|
-
const whereConditions = buildWhereConditions(args.where, table);
|
|
507
|
-
const query = drizzle.select().from(from).where(and(...whereConditions, ...extraConditions)).orderBy(...orderBy).limit(limit).offset(skip);
|
|
508
|
-
const startTime = performance.now();
|
|
509
|
-
const rows = await query;
|
|
510
|
-
const queryDurationSeconds = (performance.now() - startTime) / 1e3;
|
|
511
|
-
const isSlowQuery = queryDurationSeconds > 2;
|
|
512
|
-
if (isSlowQuery) {
|
|
513
|
-
console.warn(`Slow Query Detected (${queryDurationSeconds.toFixed(4)}s)`);
|
|
514
|
-
console.warn(new PgDialect().sqlToQuery(query.getSQL()).sql);
|
|
515
|
-
console.log("\n");
|
|
516
|
-
}
|
|
517
|
-
return rows;
|
|
518
|
-
}
|
|
519
105
|
var conditionSuffixes = {
|
|
520
106
|
universal: ["", "_not"],
|
|
521
107
|
singular: ["_in", "_not_in"],
|
|
@@ -637,15 +223,6 @@ function buildWhereConditions(where, table) {
|
|
|
637
223
|
}
|
|
638
224
|
return conditions;
|
|
639
225
|
}
|
|
640
|
-
function buildOrderBySchema(table, args) {
|
|
641
|
-
const userDirection = args.orderDirection ?? "asc";
|
|
642
|
-
const userColumns = args.orderBy !== void 0 ? [[args.orderBy, userDirection]] : [];
|
|
643
|
-
const pkColumns = table.primaryKey.map((column) => [getColumnTsName(column), userDirection]);
|
|
644
|
-
const missingPkColumns = pkColumns.filter(
|
|
645
|
-
(pkColumn) => !userColumns.some((userColumn) => userColumn[0] === pkColumn[0])
|
|
646
|
-
);
|
|
647
|
-
return [...userColumns, ...missingPkColumns];
|
|
648
|
-
}
|
|
649
226
|
function buildDataLoaderCache({ drizzle }) {
|
|
650
227
|
const dataLoaderMap = /* @__PURE__ */ new Map();
|
|
651
228
|
return ({ table }) => {
|
|
@@ -677,149 +254,14 @@ function buildDataLoaderCache({ drizzle }) {
|
|
|
677
254
|
return dataLoader;
|
|
678
255
|
};
|
|
679
256
|
}
|
|
680
|
-
function getColumnTsName(column) {
|
|
681
|
-
const tableColumns = getTableColumns(column.table);
|
|
682
|
-
return Object.entries(tableColumns).find(([_, c]) => c.name === column.name)[0];
|
|
683
|
-
}
|
|
684
|
-
function encodeRowFragment(rowFragment) {
|
|
685
|
-
return Buffer.from(serialize(rowFragment)).toString("base64");
|
|
686
|
-
}
|
|
687
257
|
function decodeRowFragment(encodedRowFragment) {
|
|
688
258
|
return deserialize(Buffer.from(encodedRowFragment, "base64").toString());
|
|
689
259
|
}
|
|
690
|
-
function getSubgraphEntityName(tsName) {
|
|
691
|
-
return capitalize(tsName);
|
|
692
|
-
}
|
|
693
|
-
function isInterfaceType(polymorphicConfig, columnName) {
|
|
694
|
-
return columnName in polymorphicConfig.types;
|
|
695
|
-
}
|
|
696
|
-
function getIntersectionTableSchema(interfaceTypeName, tableConfigs) {
|
|
697
|
-
if (tableConfigs.length === 0) throw new Error("Must have some tables to intersect");
|
|
698
|
-
const baseColumns = tableConfigs[0].columns;
|
|
699
|
-
const baseRelations = tableConfigs[0].relations;
|
|
700
|
-
const commonColumnNames = intersectionOf(
|
|
701
|
-
tableConfigs.map((table) => Object.keys(table.columns))
|
|
702
|
-
//
|
|
703
|
-
);
|
|
704
|
-
const commonRelationsNames = intersectionOf(
|
|
705
|
-
tableConfigs.map((table) => Object.keys(table.relations))
|
|
706
|
-
);
|
|
707
|
-
const intersectionTable = pgTable("intersection_table", (t) => {
|
|
708
|
-
function getColumnBuilder(column) {
|
|
709
|
-
const sqlType = column.getSQLType();
|
|
710
|
-
if (sqlType === "numeric(78)") {
|
|
711
|
-
return t.numeric({ precision: 78 });
|
|
712
|
-
}
|
|
713
|
-
const built = t[sqlType.split("(")[0]]();
|
|
714
|
-
return column.primary ? built.primaryKey() : built;
|
|
715
|
-
}
|
|
716
|
-
const columnMap = {};
|
|
717
|
-
for (const columnName of commonColumnNames) {
|
|
718
|
-
const baseColumn = baseColumns[columnName];
|
|
719
|
-
columnMap[columnName] = getColumnBuilder(baseColumn).notNull(baseColumn.notNull);
|
|
720
|
-
}
|
|
721
|
-
return columnMap;
|
|
722
|
-
});
|
|
723
|
-
const intersectionTableRelations = relations(
|
|
724
|
-
intersectionTable,
|
|
725
|
-
({ one }) => commonRelationsNames.reduce((memo, relationName) => {
|
|
726
|
-
const relation = baseRelations[relationName];
|
|
727
|
-
if (is(relation, One)) {
|
|
728
|
-
memo[relationName] = one(relation.referencedTable, relation.config);
|
|
729
|
-
} else if (is(relation, Many)) {
|
|
730
|
-
}
|
|
731
|
-
return memo;
|
|
732
|
-
}, {})
|
|
733
|
-
);
|
|
734
|
-
return {
|
|
735
|
-
[interfaceTypeName]: intersectionTable,
|
|
736
|
-
[`${interfaceTypeName}Relations`]: intersectionTableRelations
|
|
737
|
-
};
|
|
738
|
-
}
|
|
739
|
-
function getColumnsUnion(tables) {
|
|
740
|
-
return tables.reduce(
|
|
741
|
-
(memo, table) => ({
|
|
742
|
-
...memo,
|
|
743
|
-
...table.columns
|
|
744
|
-
}),
|
|
745
|
-
{}
|
|
746
|
-
);
|
|
747
|
-
}
|
|
748
|
-
function buildUnionAllQuery(drizzle, schema, tables, where = {}) {
|
|
749
|
-
const allColumns = getColumnsUnion(tables);
|
|
750
|
-
const allColumnNames = Object.keys(allColumns).sort();
|
|
751
|
-
const subqueries = tables.map((table) => {
|
|
752
|
-
const selectAllColumnsIncludingNulls = allColumnNames.reduce((memo, columnName) => {
|
|
753
|
-
const column = allColumns[columnName];
|
|
754
|
-
const dbColumnName = table.columns[columnName] ? toSnakeCase(table.columns[columnName].name) : "NULL";
|
|
755
|
-
return {
|
|
756
|
-
...memo,
|
|
757
|
-
[columnName]: sql.raw(`${dbColumnName}::${column.getSQLType()}`).as(column.name)
|
|
758
|
-
};
|
|
759
|
-
}, {});
|
|
760
|
-
const relationalConditions = Object.entries(where).map(
|
|
761
|
-
([foreignKeyName, foreignKeyValue]) => eq(table.columns[foreignKeyName], foreignKeyValue)
|
|
762
|
-
);
|
|
763
|
-
return drizzle.select({
|
|
764
|
-
...selectAllColumnsIncludingNulls,
|
|
765
|
-
// inject __typename into each subquery
|
|
766
|
-
__typename: sql.raw(`'${getSubgraphEntityName(table.tsName)}'`).as("__typename")
|
|
767
|
-
}).from(schema[table.tsName]).where(and(...relationalConditions)).$dynamic();
|
|
768
|
-
});
|
|
769
|
-
return subqueries.reduce((memo, fragment, i) => i === 0 ? fragment : memo.unionAll(fragment)).as("intersection_table");
|
|
770
|
-
}
|
|
771
|
-
function definePolymorphicPluralField({
|
|
772
|
-
schema,
|
|
773
|
-
interfaceType,
|
|
774
|
-
filterType,
|
|
775
|
-
orderByType,
|
|
776
|
-
intersectionTableConfig,
|
|
777
|
-
implementingTableConfigs
|
|
778
|
-
}) {
|
|
779
|
-
return {
|
|
780
|
-
type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(interfaceType))),
|
|
781
|
-
args: {
|
|
782
|
-
where: { type: filterType },
|
|
783
|
-
orderBy: { type: orderByType },
|
|
784
|
-
orderDirection: { type: OrderDirectionEnum },
|
|
785
|
-
first: { type: GraphQLInt },
|
|
786
|
-
skip: { type: GraphQLInt }
|
|
787
|
-
},
|
|
788
|
-
resolve: async (parent, args, { drizzle }, info) => {
|
|
789
|
-
const foreignKeyName = getForeignKeyFieldName(intersectionTableConfig, info.parentType.name);
|
|
790
|
-
const relationalFilter = foreignKeyName ? { [foreignKeyName]: parent.id } : {};
|
|
791
|
-
const subquery = buildUnionAllQuery(
|
|
792
|
-
drizzle,
|
|
793
|
-
schema,
|
|
794
|
-
implementingTableConfigs,
|
|
795
|
-
relationalFilter
|
|
796
|
-
);
|
|
797
|
-
return executePluralQuery(intersectionTableConfig, subquery, drizzle, args);
|
|
798
|
-
}
|
|
799
|
-
};
|
|
800
|
-
}
|
|
801
|
-
function getForeignKeyFieldName(table, parentTypeName) {
|
|
802
|
-
var _a, _b, _c;
|
|
803
|
-
const relationName = Object.keys(table.relations).find(
|
|
804
|
-
(relationName2) => getSubgraphEntityName(relationName2) === parentTypeName
|
|
805
|
-
);
|
|
806
|
-
if (!relationName) return;
|
|
807
|
-
const relation = table.relations[relationName];
|
|
808
|
-
if (!is(relation, One)) return;
|
|
809
|
-
const fkEntry = Object.entries(((_c = (_b = (_a = relation.config) == null ? void 0 : _a.fields) == null ? void 0 : _b[0]) == null ? void 0 : _c.table) ?? {}).find(
|
|
810
|
-
([_, column]) => {
|
|
811
|
-
var _a2, _b2, _c2;
|
|
812
|
-
return column.name === ((_c2 = (_b2 = (_a2 = relation.config) == null ? void 0 : _a2.fields) == null ? void 0 : _b2[0]) == null ? void 0 : _c2.name);
|
|
813
|
-
}
|
|
814
|
-
);
|
|
815
|
-
return fkEntry == null ? void 0 : fkEntry[0];
|
|
816
|
-
}
|
|
817
260
|
|
|
818
261
|
// src/middleware.ts
|
|
819
262
|
var graphql = ({
|
|
820
263
|
db,
|
|
821
|
-
|
|
822
|
-
polymorphicConfig
|
|
264
|
+
graphqlSchema
|
|
823
265
|
}, {
|
|
824
266
|
maxOperationTokens = 1e3,
|
|
825
267
|
maxOperationDepth = 100,
|
|
@@ -831,7 +273,6 @@ var graphql = ({
|
|
|
831
273
|
maxOperationDepth: 100,
|
|
832
274
|
maxOperationAliases: 30
|
|
833
275
|
}) => {
|
|
834
|
-
const graphqlSchema = buildGraphQLSchema(schema, polymorphicConfig);
|
|
835
276
|
const yoga = createYoga({
|
|
836
277
|
graphqlEndpoint: "*",
|
|
837
278
|
// Disable built-in route validation, use Hono routing instead
|