Repository: ponder-sh/ponder (ts)

Issue:
One-to-Many relations with relationName returning invalid results
### Version

ponder v0.10.18

### Current behavior

When using the [example reference-erc20 project](https://github.com/ponder-sh/ponder/tree/main/examples/reference-erc20), the one-to-many relationships are not being correctly parsed when configured with a `relationName` field.

[In the example project here](https://github.com/ponder-sh/ponder/blob/main/examples/reference-erc20/ponder.schema.ts#L9), on the accounts table we are trying to create 2 one-to-many relations. One that tracks transfers that we have sent and another that tracks transfers we have received.

What actually happens is that both relations return the same set of data, which seems to be the first `one` relation specified on the opposite side of the relation [here](https://github.com/ponder-sh/ponder/blob/main/examples/reference-erc20/ponder.schema.ts#L28).

In this screenshot you can see the `transferToEvents` which should be returning transfers to `0x0000000000000000000000000000000000000000` are actually returning the `transferFromEvents` results too.

<img width="1341" alt="Image" src="https://github.com/user-attachments/assets/12d325fe-7a6e-4e8e-9cdc-11823f87e551" />

### Expected behavior

The relations should be correctly mapped to their chosen `relationName` so that the correct data can be returned.

### Steps to reproduce

1) Clone the [reference-erc20](https://github.com/ponder-sh/ponder/tree/main/examples/reference-erc20) repository
2) Install the required dependencies and configure the `.env.local` with a mainnet RPC
3) Run `npm run dev` and allow ponder to index up to the specified `endBlock`
4) Use the below GraphQL query in the playground to see the invalid response

```graphql
{
  accounts (limit: 1) {
    items {
      address
      transferFromEvents (limit: 1) {
        items {
          id
          from
          to
        }
      }
      transferToEvents (limit: 1) {
        items {
          id
          from
          to
        }
      }
    }
  }
}
```

### Link to repository

https://github.com/ponder-sh/ponder/tree/main/examples/reference-erc20

### Anything else?

I believe this may be related to the fact that foreign key constraints are disabled

Pull request:
Fix: GraphQL `many` relations resolver
Closes #1700 

Patch:
diff --git a/.changeset/curvy-lizards-prove.md b/.changeset/curvy-lizards-prove.md
new file mode 100644
index 00000000..84403369
--- /dev/null
+++ b/.changeset/curvy-lizards-prove.md
@@ -0,0 +1,5 @@
+---
+"ponder": patch
+---
+
+Fixed graphql resolver for `many` relations.
diff --git a/packages/core/src/graphql/index.ts b/packages/core/src/graphql/index.ts
index 4452db2e..fdea2ae9 100644
--- a/packages/core/src/graphql/index.ts
+++ b/packages/core/src/graphql/index.ts
@@ -266,13 +266,32 @@ export function buildGraphQLSchema({
           } else if (is(relation, Many)) {
             // Search the relations of the referenced table for the corresponding `one` relation.
             // If "relationName" is not provided, use the first `one` relation that references this table.
-            const oneRelation = Object.values(referencedTable.relations).find(
-              (relation) =>
-                relation.relationName === relationName ||
-                (is(relation, One) &&
-                  relation.referencedTableName === table.dbName),
-            ) as One | undefined;
-            if (!oneRelation)
+
+            let oneRelation: One | undefined;
+
+            for (const _relation of Object.values(referencedTable.relations)) {
+              if (
+                is(_relation, One) &&
+                relation.relationName === _relation.relationName
+              ) {
+                oneRelation = _relation;
+              }
+            }
+
+            if (oneRelation === undefined) {
+              for (const _relation of Object.values(
+                referencedTable.relations,
+              )) {
+                if (
+                  is(_relation, One) &&
+                  table.dbName === _relation.referencedTableName
+                ) {
+                  oneRelation = _relation;
+                }
+              }
+            }
+
+            if (oneRelation === undefined)
               throw new Error(
                 `Internal error: Relation "${relationName}" not found in table "${referencedTable.tsName}"`,
               );


Test patch:
diff --git a/packages/core/src/graphql/index.test.ts b/packages/core/src/graphql/index.test.ts
index 2487d1a6..d406c8a4 100644
--- a/packages/core/src/graphql/index.test.ts
+++ b/packages/core/src/graphql/index.test.ts
@@ -591,6 +591,95 @@ test("singular with many relation", async (context) => {
   });
 });
 
+test("multiple many relations", async (context) => {
+  const person = onchainTable("person", (t) => ({
+    id: t.text().primaryKey(),
+    name: t.text(),
+  }));
+
+  const personRelations = relations(person, ({ many }) => ({
+    pets1: many(pet, { relationName: "owner1_relation" }),
+    pets2: many(pet, { relationName: "owner2_relation" }),
+  }));
+
+  const pet = onchainTable("pet", (t) => ({
+    id: t.text().primaryKey(),
+    owner1: t.text(),
+    owner2: t.text(),
+  }));
+
+  const petRelations = relations(pet, ({ one }) => ({
+    owner1Relation: one(person, {
+      fields: [pet.owner1],
+      relationName: "owner1_relation",
+      references: [person.id],
+    }),
+    owner2Relation: one(person, {
+      fields: [pet.owner2],
+      relationName: "owner2_relation",
+      references: [person.id],
+    }),
+  }));
+
+  const schema = { person, personRelations, pet, petRelations };
+
+  const { database, indexingStore } = await setupDatabaseServices(context, {
+    schemaBuild: { schema },
+  });
+  const contextValue = buildContextValue(database);
+  const query = (source: string) =>
+    execute({ schema: graphqlSchema, contextValue, document: parse(source) });
+
+  await indexingStore
+    .insert(schema.person)
+    .values({ id: "jake", name: "jake" });
+  await indexingStore.insert(schema.pet).values([
+    { id: "dog1", owner1: "jake", owner2: "jim" },
+    { id: "dog2", owner1: "jake", owner2: "kyle" },
+    { id: "dog3", owner1: "kyle", owner2: "jim" },
+  ]);
+
+  const graphqlSchema = buildGraphQLSchema({ schema });
+
+  const result = await query(`
+    query {
+      person(id: "jake") {
+       pets1 {
+          items {
+            id
+          }
+        }
+        pets2 {
+          items {
+            id
+          }
+        }
+      }
+    }
+  `);
+
+  expect(result.errors?.[0]?.message).toBeUndefined();
+  expect(result.data).toMatchInlineSnapshot(`
+    {
+      "person": {
+        "pets1": {
+          "items": [
+            {
+              "id": "dog1",
+            },
+            {
+              "id": "dog2",
+            },
+          ],
+        },
+        "pets2": {
+          "items": [],
+        },
+      },
+    }
+  `);
+});
+
 test("singular with many relation using filter", async (context) => {
   const person = onchainTable("person", (t) => ({
     id: t.text().primaryKey(),