@ensnode/ponder-subgraph 0.1.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.
@@ -0,0 +1,814 @@
1
+ // src/graphql.ts
2
+ import DataLoader from "dataloader";
3
+ import {
4
+ Many,
5
+ One,
6
+ and,
7
+ arrayContained,
8
+ arrayContains,
9
+ asc,
10
+ createTableRelationsHelpers,
11
+ desc,
12
+ eq,
13
+ extractTablesRelationalConfig,
14
+ getTableColumns,
15
+ getTableUniqueName,
16
+ gt,
17
+ gte,
18
+ inArray,
19
+ is,
20
+ isNotNull,
21
+ isNull,
22
+ like,
23
+ lt,
24
+ lte,
25
+ ne,
26
+ not,
27
+ notInArray,
28
+ notLike,
29
+ or,
30
+ relations,
31
+ sql
32
+ } from "drizzle-orm";
33
+ import {
34
+ PgDialect,
35
+ PgEnumColumn,
36
+ PgInteger,
37
+ PgSerial,
38
+ isPgEnum,
39
+ pgTable
40
+ } from "drizzle-orm/pg-core";
41
+ import {
42
+ GraphQLBoolean,
43
+ GraphQLEnumType,
44
+ GraphQLFloat,
45
+ GraphQLInputObjectType,
46
+ GraphQLInt,
47
+ GraphQLInterfaceType,
48
+ GraphQLList,
49
+ GraphQLNonNull,
50
+ GraphQLObjectType,
51
+ GraphQLScalarType,
52
+ GraphQLSchema,
53
+ GraphQLString
54
+ } from "graphql";
55
+ import { GraphQLJSON } from "graphql-scalars";
56
+
57
+ // src/helpers.ts
58
+ var intersectionOf = (arrays) => arrays.reduce((a, b) => a.filter((c) => b.includes(c)));
59
+ var capitalize = (str) => {
60
+ if (!str) return str;
61
+ return `${str.charAt(0).toUpperCase()}${str.slice(1)}`;
62
+ };
63
+
64
+ // src/serialize.ts
65
+ function serialize(value) {
66
+ return JSON.stringify(
67
+ value,
68
+ (_, v) => typeof v === "bigint" ? { __type: "bigint", value: v.toString() } : v
69
+ );
70
+ }
71
+ function deserialize(value) {
72
+ return JSON.parse(
73
+ value,
74
+ (_, value_) => (value_ == null ? void 0 : value_.__type) === "bigint" ? BigInt(value_.value) : value_
75
+ );
76
+ }
77
+
78
+ // src/graphql.ts
79
+ var onchain = Symbol.for("ponder:onchain");
80
+ var DEFAULT_LIMIT = 100;
81
+ var MAX_LIMIT = 1e3;
82
+ var OrderDirectionEnum = new GraphQLEnumType({
83
+ name: "OrderDirection",
84
+ values: {
85
+ asc: { value: "asc" },
86
+ desc: { value: "desc" }
87
+ }
88
+ });
89
+ function buildGraphQLSchema(_schema, polymorphicConfig = { types: {}, fields: {} }) {
90
+ const schema = { ..._schema };
91
+ const _tablesConfig = extractTablesRelationalConfig(schema, createTableRelationsHelpers);
92
+ const polymorphicTableConfigs = Object.fromEntries(
93
+ Object.entries(polymorphicConfig.types).map(([interfaceTypeName, implementingTables]) => [
94
+ interfaceTypeName,
95
+ implementingTables.map((table) => getTableUniqueName(table)).map((tableName) => _tablesConfig.tables[_tablesConfig.tableNamesMap[tableName]])
96
+ ])
97
+ );
98
+ Object.assign(
99
+ schema,
100
+ ...Object.keys(polymorphicConfig.types).map(
101
+ (interfaceTypeName) => getIntersectionTableSchema(interfaceTypeName, polymorphicTableConfigs[interfaceTypeName])
102
+ )
103
+ );
104
+ const polymorphicFields = Object.entries(polymorphicConfig.fields).map(([fieldPath, interfaceTypeName]) => [
105
+ fieldPath.split("."),
106
+ interfaceTypeName
107
+ ]);
108
+ const tablesConfig = extractTablesRelationalConfig(schema, createTableRelationsHelpers);
109
+ const tables = Object.values(tablesConfig.tables);
110
+ const enums = Object.entries(schema).filter(
111
+ (el) => isPgEnum(el[1])
112
+ );
113
+ const enumTypes = {};
114
+ for (const [enumTsName, enumObject] of enums) {
115
+ enumTypes[enumObject.enumName] = new GraphQLEnumType({
116
+ name: enumTsName,
117
+ values: enumObject.enumValues.reduce(
118
+ (acc, cur) => ({ ...acc, [cur]: {} }),
119
+ {}
120
+ )
121
+ });
122
+ }
123
+ const entityOrderByEnums = {};
124
+ for (const table of tables) {
125
+ const values = Object.keys(table.columns).reduce(
126
+ (acc, columnName) => ({
127
+ ...acc,
128
+ [columnName]: { value: columnName }
129
+ }),
130
+ {}
131
+ );
132
+ entityOrderByEnums[table.tsName] = new GraphQLEnumType({
133
+ name: `${getSubgraphEntityName(table.tsName)}_orderBy`,
134
+ values
135
+ });
136
+ }
137
+ const entityFilterTypes = {};
138
+ for (const table of tables) {
139
+ const filterType = new GraphQLInputObjectType({
140
+ name: `${getSubgraphEntityName(table.tsName)}_filter`,
141
+ fields: () => {
142
+ const filterFields = {
143
+ // Logical operators
144
+ // NOTE: lower case and/or
145
+ and: { type: new GraphQLList(filterType) },
146
+ or: { type: new GraphQLList(filterType) }
147
+ };
148
+ for (const [columnName, column] of Object.entries(table.columns)) {
149
+ const type = columnToGraphQLCore(column, enumTypes);
150
+ if (type instanceof GraphQLList) {
151
+ const baseType = innerType(type);
152
+ conditionSuffixes.universal.forEach((suffix) => {
153
+ filterFields[`${columnName}${suffix}`] = {
154
+ type: new GraphQLList(baseType)
155
+ };
156
+ });
157
+ conditionSuffixes.plural.forEach((suffix) => {
158
+ filterFields[`${columnName}${suffix}`] = { type: baseType };
159
+ });
160
+ }
161
+ if (type instanceof GraphQLScalarType || type instanceof GraphQLEnumType) {
162
+ if (type.name === "JSON") continue;
163
+ conditionSuffixes.universal.forEach((suffix) => {
164
+ filterFields[`${columnName}${suffix}`] = {
165
+ type
166
+ };
167
+ });
168
+ conditionSuffixes.singular.forEach((suffix) => {
169
+ filterFields[`${columnName}${suffix}`] = {
170
+ type: new GraphQLList(type)
171
+ };
172
+ });
173
+ if (["String", "ID"].includes(type.name)) {
174
+ conditionSuffixes.string.forEach((suffix) => {
175
+ filterFields[`${columnName}${suffix}`] = {
176
+ type
177
+ };
178
+ });
179
+ conditionSuffixes.numeric.forEach((suffix) => {
180
+ filterFields[`${columnName}${suffix}`] = {
181
+ type
182
+ };
183
+ });
184
+ }
185
+ if (["Int", "Float", "BigInt"].includes(type.name)) {
186
+ conditionSuffixes.numeric.forEach((suffix) => {
187
+ filterFields[`${columnName}${suffix}`] = {
188
+ type
189
+ };
190
+ });
191
+ }
192
+ }
193
+ }
194
+ for (const [relationName, relation] of Object.entries(table.relations)) {
195
+ if (is(relation, One)) {
196
+ conditionSuffixes.universal.forEach((suffix) => {
197
+ filterFields[`${relation.fieldName}${suffix}`] = {
198
+ type: GraphQLString
199
+ };
200
+ });
201
+ }
202
+ }
203
+ return filterFields;
204
+ }
205
+ });
206
+ entityFilterTypes[table.tsName] = filterType;
207
+ }
208
+ const entityTypes = {};
209
+ const interfaceTypes = {};
210
+ const entityPageTypes = {};
211
+ for (const interfaceTypeName of Object.keys(polymorphicTableConfigs)) {
212
+ const table = tablesConfig.tables[interfaceTypeName];
213
+ interfaceTypes[interfaceTypeName] = new GraphQLInterfaceType({
214
+ name: interfaceTypeName,
215
+ fields: () => {
216
+ const fieldConfigMap = {};
217
+ for (const [columnName, column] of Object.entries(table.columns)) {
218
+ const type = columnToGraphQLCore(column, enumTypes);
219
+ fieldConfigMap[columnName] = {
220
+ type: column.notNull ? new GraphQLNonNull(type) : type
221
+ };
222
+ }
223
+ return fieldConfigMap;
224
+ }
225
+ });
226
+ }
227
+ for (const table of tables) {
228
+ if (isInterfaceType(polymorphicConfig, table.tsName)) continue;
229
+ const entityTypeName = getSubgraphEntityName(table.tsName);
230
+ entityTypes[table.tsName] = new GraphQLObjectType({
231
+ name: entityTypeName,
232
+ interfaces: Object.entries(polymorphicTableConfigs).filter(
233
+ ([, implementingTables]) => implementingTables.map((table2) => table2.tsName).includes(table.tsName)
234
+ ).map(([interfaceTypeName]) => interfaceTypes[interfaceTypeName]),
235
+ fields: () => {
236
+ var _a, _b, _c, _d;
237
+ const fieldConfigMap = {};
238
+ for (const [columnName, column] of Object.entries(table.columns)) {
239
+ const type = columnToGraphQLCore(column, enumTypes);
240
+ fieldConfigMap[columnName] = {
241
+ type: column.notNull ? new GraphQLNonNull(type) : type
242
+ };
243
+ }
244
+ const relations2 = Object.entries(table.relations);
245
+ for (const [relationName, relation] of relations2) {
246
+ const referencedTable = tables.find(
247
+ (table2) => table2.dbName === relation.referencedTableName
248
+ );
249
+ if (!referencedTable)
250
+ throw new Error(
251
+ `Internal error: Referenced table "${relation.referencedTableName}" not found`
252
+ );
253
+ const referencedEntityType = entityTypes[referencedTable.tsName];
254
+ const referencedEntityPageType = entityPageTypes[referencedTable.tsName];
255
+ const referencedEntityFilterType = entityFilterTypes[referencedTable.tsName];
256
+ if (referencedEntityType === void 0 || referencedEntityPageType === void 0 || referencedEntityFilterType === void 0)
257
+ throw new Error(
258
+ `Internal error: Referenced entity types not found for table "${referencedTable.tsName}" `
259
+ );
260
+ if (is(relation, One)) {
261
+ const fields = ((_a = relation.config) == null ? void 0 : _a.fields) ?? [];
262
+ const references = ((_b = relation.config) == null ? void 0 : _b.references) ?? [];
263
+ if (fields.length !== references.length) {
264
+ throw new Error(
265
+ "Internal error: Fields and references arrays must be the same length"
266
+ );
267
+ }
268
+ fieldConfigMap[relationName] = {
269
+ // Note: There is a `relation.isNullable` field here but it appears
270
+ // to be internal / incorrect. Until we have support for foriegn
271
+ // key constraints, all `one` relations must be nullable.
272
+ type: referencedEntityType,
273
+ resolve: (parent, _args, context) => {
274
+ const loader = context.getDataLoader({ table: referencedTable });
275
+ const rowFragment = {};
276
+ for (let i = 0; i < references.length; i++) {
277
+ const referenceColumn = references[i];
278
+ const fieldColumn = fields[i];
279
+ const fieldColumnTsName = getColumnTsName(fieldColumn);
280
+ const referenceColumnTsName = getColumnTsName(referenceColumn);
281
+ rowFragment[referenceColumnTsName] = parent[fieldColumnTsName];
282
+ }
283
+ const encodedId = encodeRowFragment(rowFragment);
284
+ return loader.load(encodedId);
285
+ }
286
+ };
287
+ } else if (is(relation, Many)) {
288
+ const oneRelation = Object.values(referencedTable.relations).find(
289
+ (relation2) => relation2.relationName === relationName || is(relation2, One) && relation2.referencedTableName === table.dbName
290
+ );
291
+ if (!oneRelation)
292
+ throw new Error(
293
+ `Internal error: Relation "${relationName}" not found in table "${referencedTable.tsName}"`
294
+ );
295
+ const fields = ((_c = oneRelation.config) == null ? void 0 : _c.fields) ?? [];
296
+ const references = ((_d = oneRelation.config) == null ? void 0 : _d.references) ?? [];
297
+ const referencedEntityOrderByType = entityOrderByEnums[referencedTable.tsName];
298
+ if (!referencedEntityOrderByType)
299
+ throw new Error(`Entity_orderBy Enum not found for ${referencedTable.tsName}`);
300
+ fieldConfigMap[relationName] = {
301
+ type: referencedEntityPageType,
302
+ args: {
303
+ where: { type: referencedEntityFilterType },
304
+ orderBy: { type: referencedEntityOrderByType },
305
+ orderDirection: { type: OrderDirectionEnum },
306
+ first: { type: GraphQLInt },
307
+ skip: { type: GraphQLInt }
308
+ },
309
+ resolve: (parent, args, context, info) => {
310
+ const relationalConditions = [];
311
+ for (let i = 0; i < references.length; i++) {
312
+ const column = fields[i];
313
+ const value = parent[references[i].name];
314
+ relationalConditions.push(eq(column, value));
315
+ }
316
+ return executePluralQuery(
317
+ referencedTable,
318
+ schema[referencedTable.tsName],
319
+ context.drizzle,
320
+ args,
321
+ relationalConditions
322
+ );
323
+ }
324
+ };
325
+ } else {
326
+ throw new Error(
327
+ `Internal error: Relation "${relationName}" is unsupported, expected One or Many`
328
+ );
329
+ }
330
+ }
331
+ polymorphicFields.filter(([[parent]]) => parent === entityTypeName).forEach(([[, fieldName], interfaceTypeName]) => {
332
+ fieldConfigMap[fieldName] = definePolymorphicPluralField({
333
+ schema,
334
+ interfaceType: interfaceTypes[interfaceTypeName],
335
+ filterType: entityFilterTypes[interfaceTypeName],
336
+ orderByType: entityOrderByEnums[interfaceTypeName],
337
+ intersectionTableConfig: tablesConfig.tables[interfaceTypeName],
338
+ implementingTableConfigs: polymorphicTableConfigs[interfaceTypeName]
339
+ });
340
+ });
341
+ return fieldConfigMap;
342
+ }
343
+ });
344
+ entityPageTypes[table.tsName] = new GraphQLNonNull(
345
+ new GraphQLList(new GraphQLNonNull(entityTypes[table.tsName]))
346
+ );
347
+ }
348
+ const queryFields = {};
349
+ for (const table of tables) {
350
+ if (isInterfaceType(polymorphicConfig, table.tsName)) continue;
351
+ const entityType = entityTypes[table.tsName];
352
+ const entityPageType = entityPageTypes[table.tsName];
353
+ const entityFilterType = entityFilterTypes[table.tsName];
354
+ const singularFieldName = table.tsName.charAt(0).toLowerCase() + table.tsName.slice(1);
355
+ const pluralFieldName = `${singularFieldName}s`;
356
+ queryFields[singularFieldName] = {
357
+ type: entityType,
358
+ // Find the primary key columns and GraphQL core types and include them
359
+ // as arguments to the singular query type.
360
+ args: Object.fromEntries(
361
+ table.primaryKey.map((column) => [
362
+ getColumnTsName(column),
363
+ {
364
+ type: new GraphQLNonNull(columnToGraphQLCore(column, enumTypes))
365
+ }
366
+ ])
367
+ ),
368
+ resolve: async (_parent, args, context) => {
369
+ const loader = context.getDataLoader({ table });
370
+ const encodedId = encodeRowFragment(args);
371
+ return loader.load(encodedId);
372
+ }
373
+ };
374
+ const entityOrderByType = entityOrderByEnums[table.tsName];
375
+ if (!entityOrderByType) throw new Error(`Entity_orderBy Enum not found for ${table.tsName}`);
376
+ queryFields[pluralFieldName] = {
377
+ type: entityPageType,
378
+ args: {
379
+ where: { type: entityFilterType },
380
+ orderBy: { type: entityOrderByType },
381
+ orderDirection: { type: OrderDirectionEnum },
382
+ first: { type: GraphQLInt },
383
+ skip: { type: GraphQLInt }
384
+ },
385
+ resolve: async (_parent, args, context, info) => {
386
+ return executePluralQuery(table, schema[table.tsName], context.drizzle, args);
387
+ }
388
+ };
389
+ }
390
+ polymorphicFields.filter(([[parent]]) => parent === "Query").forEach(([[, fieldName], interfaceTypeName]) => {
391
+ queryFields[fieldName] = definePolymorphicPluralField({
392
+ schema,
393
+ interfaceType: interfaceTypes[interfaceTypeName],
394
+ filterType: entityFilterTypes[interfaceTypeName],
395
+ orderByType: entityOrderByEnums[interfaceTypeName],
396
+ intersectionTableConfig: tablesConfig.tables[interfaceTypeName],
397
+ implementingTableConfigs: polymorphicTableConfigs[interfaceTypeName]
398
+ });
399
+ });
400
+ return new GraphQLSchema({
401
+ // Include these here so they are listed first in the printed schema.
402
+ types: [GraphQLJSON, GraphQLBigInt, GraphQLPageInfo],
403
+ query: new GraphQLObjectType({
404
+ name: "Query",
405
+ fields: queryFields
406
+ })
407
+ });
408
+ }
409
+ var GraphQLPageInfo = new GraphQLObjectType({
410
+ name: "PageInfo",
411
+ fields: {
412
+ hasNextPage: { type: new GraphQLNonNull(GraphQLBoolean) },
413
+ hasPreviousPage: { type: new GraphQLNonNull(GraphQLBoolean) },
414
+ startCursor: { type: GraphQLString },
415
+ endCursor: { type: GraphQLString }
416
+ }
417
+ });
418
+ var GraphQLBigInt = new GraphQLScalarType({
419
+ name: "BigInt",
420
+ serialize: (value) => String(value),
421
+ parseValue: (value) => BigInt(value),
422
+ parseLiteral: (value) => {
423
+ if (value.kind === "StringValue") {
424
+ return BigInt(value.value);
425
+ } else {
426
+ throw new Error(
427
+ `Invalid value kind provided for field of type BigInt: ${value.kind}. Expected: StringValue`
428
+ );
429
+ }
430
+ }
431
+ });
432
+ var columnToGraphQLCore = (column, enumTypes) => {
433
+ if (column.columnType === "PgEvmBigint") {
434
+ return GraphQLBigInt;
435
+ }
436
+ if (column instanceof PgEnumColumn) {
437
+ if (column.enum === void 0) {
438
+ throw new Error(
439
+ `Internal error: Expected enum column "${getColumnTsName(column)}" to have an "enum" property`
440
+ );
441
+ }
442
+ const enumType = enumTypes[column.enum.enumName];
443
+ if (enumType === void 0) {
444
+ throw new Error(
445
+ `Internal error: Expected to find a GraphQL enum named "${column.enum.enumName}"`
446
+ );
447
+ }
448
+ return enumType;
449
+ }
450
+ switch (column.dataType) {
451
+ case "boolean":
452
+ return GraphQLBoolean;
453
+ case "json":
454
+ return GraphQLJSON;
455
+ case "date":
456
+ return GraphQLString;
457
+ case "string":
458
+ return GraphQLString;
459
+ case "bigint":
460
+ return GraphQLString;
461
+ case "number":
462
+ return is(column, PgInteger) || is(column, PgSerial) ? GraphQLInt : GraphQLFloat;
463
+ case "buffer":
464
+ return new GraphQLList(new GraphQLNonNull(GraphQLInt));
465
+ case "array": {
466
+ if (column.columnType === "PgVector") {
467
+ return new GraphQLList(new GraphQLNonNull(GraphQLFloat));
468
+ }
469
+ if (column.columnType === "PgGeometry") {
470
+ return new GraphQLList(new GraphQLNonNull(GraphQLFloat));
471
+ }
472
+ const innerType2 = columnToGraphQLCore(column.baseColumn, enumTypes);
473
+ return new GraphQLList(new GraphQLNonNull(innerType2));
474
+ }
475
+ default:
476
+ throw new Error(`Type ${column.dataType} is not implemented`);
477
+ }
478
+ };
479
+ var innerType = (type) => {
480
+ if (type instanceof GraphQLScalarType || type instanceof GraphQLEnumType) return type;
481
+ if (type instanceof GraphQLList || type instanceof GraphQLNonNull) return innerType(type.ofType);
482
+ throw new Error(`Type ${type.toString()} is not implemented`);
483
+ };
484
+ async function executePluralQuery(table, from, drizzle, args, extraConditions = []) {
485
+ const limit = args.first ?? DEFAULT_LIMIT;
486
+ if (limit > MAX_LIMIT) {
487
+ throw new Error(`Invalid limit. Got ${limit}, expected <=${MAX_LIMIT}.`);
488
+ }
489
+ const skip = args.skip ?? 0;
490
+ const orderBySchema = buildOrderBySchema(table, args);
491
+ const orderBy = orderBySchema.map(([columnName, direction]) => {
492
+ const column = table.columns[columnName];
493
+ if (column === void 0) {
494
+ throw new Error(`Unknown column "${columnName}" used in orderBy argument`);
495
+ }
496
+ return direction === "asc" ? asc(column) : desc(column);
497
+ });
498
+ const whereConditions = buildWhereConditions(args.where, table);
499
+ const query = drizzle.select().from(from).where(and(...whereConditions, ...extraConditions)).orderBy(...orderBy).limit(limit).offset(skip);
500
+ const startTime = performance.now();
501
+ const rows = await query;
502
+ const queryDurationSeconds = (performance.now() - startTime) / 1e3;
503
+ const isSlowQuery = queryDurationSeconds > 2;
504
+ if (isSlowQuery) {
505
+ console.warn(`Slow Query Detected (${queryDurationSeconds.toFixed(4)}s)`);
506
+ console.warn(new PgDialect().sqlToQuery(query.getSQL()).sql);
507
+ console.log("\n");
508
+ }
509
+ return rows;
510
+ }
511
+ var conditionSuffixes = {
512
+ universal: ["", "_not"],
513
+ singular: ["_in", "_not_in"],
514
+ plural: ["_has", "_not_has"],
515
+ numeric: ["_gt", "_lt", "_gte", "_lte"],
516
+ string: [
517
+ "_contains",
518
+ "_not_contains",
519
+ "_starts_with",
520
+ "_ends_with",
521
+ "_not_starts_with",
522
+ "_not_ends_with"
523
+ ]
524
+ };
525
+ var conditionSuffixesByLengthDesc = Object.values(conditionSuffixes).flat().sort((a, b) => b.length - a.length);
526
+ function buildWhereConditions(where, table) {
527
+ const conditions = [];
528
+ if (where === void 0) return conditions;
529
+ for (const [whereKey, rawValue] of Object.entries(where)) {
530
+ if (whereKey === "and" || whereKey === "or") {
531
+ if (!Array.isArray(rawValue)) {
532
+ throw new Error(
533
+ `Invalid query: Expected an array for the ${whereKey} operator. Got: ${rawValue}`
534
+ );
535
+ }
536
+ const nestedConditions = rawValue.flatMap(
537
+ (subWhere) => buildWhereConditions(subWhere, table)
538
+ );
539
+ if (nestedConditions.length > 0) {
540
+ conditions.push(whereKey === "and" ? and(...nestedConditions) : or(...nestedConditions));
541
+ }
542
+ continue;
543
+ }
544
+ const conditionSuffix = conditionSuffixesByLengthDesc.find((s) => whereKey.endsWith(s));
545
+ if (conditionSuffix === void 0) {
546
+ throw new Error(`Invariant violation: Condition suffix not found for where key ${whereKey}`);
547
+ }
548
+ const columnName = whereKey.slice(0, whereKey.length - conditionSuffix.length);
549
+ const column = columnName in table.relations ? (
550
+ // if the referenced name is a relation, the relevant column is this table's `${relationName}Id`
551
+ table.columns[`${columnName}Id`]
552
+ ) : (
553
+ // otherwise validate that the column name is present in the table
554
+ table.columns[columnName]
555
+ );
556
+ if (column === void 0) {
557
+ throw new Error(`Invalid query: Where clause contains unknown column ${columnName}`);
558
+ }
559
+ switch (conditionSuffix) {
560
+ case "":
561
+ if (column.columnType === "PgArray") {
562
+ conditions.push(and(arrayContains(column, rawValue), arrayContained(column, rawValue)));
563
+ } else {
564
+ if (rawValue === null) {
565
+ conditions.push(isNull(column));
566
+ } else {
567
+ conditions.push(eq(column, rawValue));
568
+ }
569
+ }
570
+ break;
571
+ case "_not":
572
+ if (column.columnType === "PgArray") {
573
+ conditions.push(
574
+ not(and(arrayContains(column, rawValue), arrayContained(column, rawValue)))
575
+ );
576
+ } else {
577
+ if (rawValue === null) {
578
+ conditions.push(isNotNull(column));
579
+ } else {
580
+ conditions.push(ne(column, rawValue));
581
+ }
582
+ }
583
+ break;
584
+ case "_in":
585
+ conditions.push(inArray(column, rawValue));
586
+ break;
587
+ case "_not_in":
588
+ conditions.push(notInArray(column, rawValue));
589
+ break;
590
+ case "_has":
591
+ conditions.push(arrayContains(column, [rawValue]));
592
+ break;
593
+ case "_not_has":
594
+ conditions.push(not(arrayContains(column, [rawValue])));
595
+ break;
596
+ case "_gt":
597
+ conditions.push(gt(column, rawValue));
598
+ break;
599
+ case "_lt":
600
+ conditions.push(lt(column, rawValue));
601
+ break;
602
+ case "_gte":
603
+ conditions.push(gte(column, rawValue));
604
+ break;
605
+ case "_lte":
606
+ conditions.push(lte(column, rawValue));
607
+ break;
608
+ case "_contains":
609
+ conditions.push(like(column, `%${rawValue}%`));
610
+ break;
611
+ case "_not_contains":
612
+ conditions.push(notLike(column, `%${rawValue}%`));
613
+ break;
614
+ case "_starts_with":
615
+ conditions.push(like(column, `${rawValue}%`));
616
+ break;
617
+ case "_ends_with":
618
+ conditions.push(like(column, `%${rawValue}`));
619
+ break;
620
+ case "_not_starts_with":
621
+ conditions.push(notLike(column, `${rawValue}%`));
622
+ break;
623
+ case "_not_ends_with":
624
+ conditions.push(notLike(column, `%${rawValue}`));
625
+ break;
626
+ default:
627
+ throw new Error(`Invalid Condition Suffix ${conditionSuffix}`);
628
+ }
629
+ }
630
+ return conditions;
631
+ }
632
+ function buildOrderBySchema(table, args) {
633
+ const userDirection = args.orderDirection ?? "asc";
634
+ const userColumns = args.orderBy !== void 0 ? [[args.orderBy, userDirection]] : [];
635
+ const pkColumns = table.primaryKey.map((column) => [getColumnTsName(column), userDirection]);
636
+ const missingPkColumns = pkColumns.filter(
637
+ (pkColumn) => !userColumns.some((userColumn) => userColumn[0] === pkColumn[0])
638
+ );
639
+ return [...userColumns, ...missingPkColumns];
640
+ }
641
+ function buildDataLoaderCache({ drizzle }) {
642
+ const dataLoaderMap = /* @__PURE__ */ new Map();
643
+ return ({ table }) => {
644
+ const baseQuery = drizzle.query[table.tsName];
645
+ if (baseQuery === void 0)
646
+ throw new Error(`Internal error: Unknown table "${table.tsName}" in data loader cache`);
647
+ let dataLoader = dataLoaderMap.get(table);
648
+ if (dataLoader === void 0) {
649
+ dataLoader = new DataLoader(
650
+ async (encodedIds) => {
651
+ const decodedRowFragments = encodedIds.map(decodeRowFragment);
652
+ const idConditions = decodedRowFragments.map(
653
+ (decodedRowFragment) => and(...buildWhereConditions(decodedRowFragment, table))
654
+ );
655
+ const rows = await baseQuery.findMany({
656
+ where: or(...idConditions),
657
+ limit: encodedIds.length
658
+ });
659
+ return decodedRowFragments.map(
660
+ (fragment) => rows.find(
661
+ (row) => Object.entries(fragment).every(([col, val]) => row[col] === val)
662
+ )
663
+ );
664
+ },
665
+ { maxBatchSize: 1e3 }
666
+ );
667
+ dataLoaderMap.set(table, dataLoader);
668
+ }
669
+ return dataLoader;
670
+ };
671
+ }
672
+ function getColumnTsName(column) {
673
+ const tableColumns = getTableColumns(column.table);
674
+ return Object.entries(tableColumns).find(([_, c]) => c.name === column.name)[0];
675
+ }
676
+ function encodeRowFragment(rowFragment) {
677
+ return Buffer.from(serialize(rowFragment)).toString("base64");
678
+ }
679
+ function decodeRowFragment(encodedRowFragment) {
680
+ return deserialize(Buffer.from(encodedRowFragment, "base64").toString());
681
+ }
682
+ function getSubgraphEntityName(tsName) {
683
+ return capitalize(tsName);
684
+ }
685
+ function isInterfaceType(polymorphicConfig, columnName) {
686
+ return columnName in polymorphicConfig.types;
687
+ }
688
+ function getIntersectionTableSchema(interfaceTypeName, tableConfigs) {
689
+ if (tableConfigs.length === 0) throw new Error("Must have some tables to intersect");
690
+ const baseColumns = tableConfigs[0].columns;
691
+ const baseRelations = tableConfigs[0].relations;
692
+ const commonColumnNames = intersectionOf(
693
+ tableConfigs.map((table) => Object.keys(table.columns))
694
+ //
695
+ );
696
+ const commonRelationsNames = intersectionOf(
697
+ tableConfigs.map((table) => Object.keys(table.relations))
698
+ );
699
+ const intersectionTable = pgTable("intersection_table", (t) => {
700
+ function getColumnBuilder(column) {
701
+ const sqlType = column.getSQLType();
702
+ if (sqlType === "numeric(78)") {
703
+ return t.numeric({ precision: 78 });
704
+ }
705
+ const built = t[sqlType.split("(")[0]]();
706
+ return column.primary ? built.primaryKey() : built;
707
+ }
708
+ const columnMap = {};
709
+ for (const columnName of commonColumnNames) {
710
+ const baseColumn = baseColumns[columnName];
711
+ columnMap[columnName] = getColumnBuilder(baseColumn).notNull(baseColumn.notNull);
712
+ }
713
+ return columnMap;
714
+ });
715
+ const intersectionTableRelations = relations(
716
+ intersectionTable,
717
+ ({ one }) => commonRelationsNames.reduce((memo, relationName) => {
718
+ const relation = baseRelations[relationName];
719
+ if (is(relation, One)) {
720
+ memo[relationName] = one(relation.referencedTable, relation.config);
721
+ } else if (is(relation, Many)) {
722
+ }
723
+ return memo;
724
+ }, {})
725
+ );
726
+ return {
727
+ [interfaceTypeName]: intersectionTable,
728
+ [`${interfaceTypeName}Relations`]: intersectionTableRelations
729
+ };
730
+ }
731
+ function getColumnsUnion(tables) {
732
+ return tables.reduce(
733
+ (memo, table) => ({
734
+ ...memo,
735
+ ...table.columns
736
+ }),
737
+ {}
738
+ );
739
+ }
740
+ function buildUnionAllQuery(drizzle, schema, tables, where = {}) {
741
+ const allColumns = getColumnsUnion(tables);
742
+ const allColumnNames = Object.keys(allColumns).sort();
743
+ const subqueries = tables.map((table) => {
744
+ const selectAllColumnsIncludingNulls = allColumnNames.reduce((memo, columnName) => {
745
+ var _a;
746
+ const column = allColumns[columnName];
747
+ return {
748
+ ...memo,
749
+ [columnName]: sql.raw(`${((_a = table.columns[columnName]) == null ? void 0 : _a.name) ?? "NULL"}::${column.getSQLType()}`).as(column.name)
750
+ };
751
+ }, {});
752
+ const relationalConditions = Object.entries(where).map(
753
+ ([foreignKeyName, foreignKeyValue]) => eq(table.columns[foreignKeyName], foreignKeyValue)
754
+ );
755
+ return drizzle.select({
756
+ ...selectAllColumnsIncludingNulls,
757
+ // inject __typename into each subquery
758
+ __typename: sql.raw(`'${getSubgraphEntityName(table.tsName)}'`).as("__typename")
759
+ }).from(schema[table.tsName]).where(and(...relationalConditions)).$dynamic();
760
+ });
761
+ return subqueries.reduce((memo, fragment, i) => i === 0 ? fragment : memo.unionAll(fragment)).as("intersection_table");
762
+ }
763
+ function definePolymorphicPluralField({
764
+ schema,
765
+ interfaceType,
766
+ filterType,
767
+ orderByType,
768
+ intersectionTableConfig,
769
+ implementingTableConfigs
770
+ }) {
771
+ return {
772
+ type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(interfaceType))),
773
+ args: {
774
+ where: { type: filterType },
775
+ orderBy: { type: orderByType },
776
+ orderDirection: { type: OrderDirectionEnum },
777
+ first: { type: GraphQLInt },
778
+ skip: { type: GraphQLInt }
779
+ },
780
+ resolve: async (parent, args, { drizzle }, info) => {
781
+ const foreignKeyName = getForeignKeyFieldName(intersectionTableConfig, info.parentType.name);
782
+ const relationalFilter = foreignKeyName ? { [foreignKeyName]: parent.id } : {};
783
+ const subquery = buildUnionAllQuery(
784
+ drizzle,
785
+ schema,
786
+ implementingTableConfigs,
787
+ relationalFilter
788
+ );
789
+ return executePluralQuery(intersectionTableConfig, subquery, drizzle, args);
790
+ }
791
+ };
792
+ }
793
+ function getForeignKeyFieldName(table, parentTypeName) {
794
+ var _a, _b, _c;
795
+ const relationName = Object.keys(table.relations).find(
796
+ (relationName2) => getSubgraphEntityName(relationName2) === parentTypeName
797
+ );
798
+ if (!relationName) return;
799
+ const relation = table.relations[relationName];
800
+ if (!is(relation, One)) return;
801
+ 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(
802
+ ([_, column]) => {
803
+ var _a2, _b2, _c2;
804
+ return column.name === ((_c2 = (_b2 = (_a2 = relation.config) == null ? void 0 : _a2.fields) == null ? void 0 : _b2[0]) == null ? void 0 : _c2.name);
805
+ }
806
+ );
807
+ return fkEntry == null ? void 0 : fkEntry[0];
808
+ }
809
+ export {
810
+ buildDataLoaderCache,
811
+ buildGraphQLSchema,
812
+ onchain
813
+ };
814
+ //# sourceMappingURL=graphql.js.map