drizzle-team / drizzle-orm

Headless TypeScript ORM with a head. Runs on Node, Bun and Deno. Lives on the Edge and yes, it's a JavaScript ORM too 😅
https://orm.drizzle.team
Apache License 2.0
21.57k stars 490 forks source link

[BUG]: `mapWith` isn't working on `extras` when doing relational queries with `findFirst` or `findMany` #1157

Open Odas0R opened 10 months ago

Odas0R commented 10 months ago

What version of drizzle-orm are you using?

0.28.5

What version of drizzle-kit are you using?

0.19.13

Describe the Bug

extras: {
   polygon: sql`ST_AsGeoJSON(${polygon.geometry})`
   .mapWith(polygon.geometry)
   .as("polygon"),
   centroid: sql`ST_AsGeoJSON(${polygon.centroid})`
   .mapWith(polygon.centroid)
   .as("centroid"),
}

The mapWith isn't executing the fromDriver callback on the custom type:

export const geometry = customType<{ data: Geometry; driverData: string }>({
  dataType() {
    return `geometry(Polygon, 4326)`;
  },

  // BUG: this is not being executed when doing `mapWith`
  fromDriver(value: string): Geometry { 
    try {
      if (typeof value === "string") {
        return JSON.parse(value);
      }
      return value;
    } catch {
      throw new Error(`Invalid geometry: ${value}`);
    }
  },
});

Expected behavior

It should parse the value received from the driver, as for now I fix the result with custom hacks.

Environment & setup

NODE: 16.19.1 POP_os: 22.04

Odas0R commented 10 months ago

Just figured out that if I cast it to json, there's a JSON.parse being done? Confused, maybe this might not be a bug.

// This works
extras: {
   polygon: sql`ST_AsGeoJSON(${polygon.geometry})::json`
   .mapWith(polygon.geometry)
   .as("polygon"),
   centroid: sql`ST_AsGeoJSON(${polygon.centroid})::json`
   .mapWith(polygon.centroid)
   .as("centroid"),
}

Still the fromDriver is not being executed on the example above? I'm a bit confused.

luxaritas commented 10 months ago

I'm noticing that decoders on sql statements that are part of subqueries aren't being executed - I'm wondering if that's related?

andersoncardoso commented 8 months ago

I think I have the same issue. For example, a program table that has many(student):

const res = await db.query.program.findMany({
    extras: {
        studentsCount: sql<number>`(select count(*) from student s where s.program_id = program.id)`
            .mapWith(Number)
            .as("students_count")
        }
});

studentsCount is always returning as a string.