Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Pg-kit] Allow where in with when relation is 1-1 #4011

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

ramipellumbi
Copy link

@ramipellumbi ramipellumbi commented Jan 26, 2025

Closes #3911. Namely, when a relation is 1-many, with allows for use of where for filtering. The typing did not expose this option in a 1-1 relation. A caveat I want feedback on is how to ensure the typing of the with column becomes nullable, which is the behavior of the query when the filter does not match (I believe this is related to #824). Though, realistically, the record should be omitted in the case it does not match as this is very confusing behavior.

Consider the following simple example (hoisting it from the issue which has had 0 interactions):

// schemas.ts
import {
  pgTable,
  varchar,
  timestamp,
  text,
  integer,
  uniqueIndex,
  foreignKey,
  boolean,
  index,
  primaryKey,
} from "drizzle-orm/pg-core";
import { relations, sql } from "drizzle-orm";

export const location = pgTable(
  "location",
  {
    id: text().primaryKey().notNull(),
    name: text().notNull(),
  }
);

export const bedAssignment = pgTable(
  "bed_assignment",
  {
    id: text().primaryKey().notNull(),
    startDate: text("start_date").notNull(),
    endDate: text("end_date"),
    clientId: text("client_id").notNull(),
    bedId: text("bed_id").notNull(),
  },
  (table) => [
    foreignKey({
      columns: [table.clientId],
      foreignColumns: [client.id],
      name: "bed_assignment_client_id_fkey",
    })
      .onUpdate("cascade")
      .onDelete("restrict"),
    foreignKey({
      columns: [table.bedId],
      foreignColumns: [bed.id],
      name: "bed_assignment_bed_id_fkey",
    })
      .onUpdate("cascade")
      .onDelete("restrict"),
  ],
);

export const client = pgTable(
  "client",
  {
    id: text().primaryKey().notNull(),
    locationId: text("location_id"),
  },
  (table) => [
    index("client_id_idx").using("btree", table.id.asc().nullsLast().op("text_ops")),
    foreignKey({
      columns: [table.locationId],
      foreignColumns: [location.id],
      name: "client_location_id_fkey",
    })
      .onUpdate("cascade")
      .onDelete("set null"),
  ],
);

export const bed = pgTable(
  "bed",
  {
    id: text().primaryKey().notNull(),
    locationId: text().notNull(),
  },
  (table) => [
    foreignKey({
      columns: [table.locationId],
      foreignColumns: [location.id],
      name: "bed_locationId_fkey",
    })
      .onUpdate("cascade")
      .onDelete("restrict"),
  ],
);

export const clientRelations = relations(client, ({ one, many }) => ({
  bedAssignments: many(bedAssignment),
  location: one(location, {
    fields: [client.locationId],
    references: [location.id],
  }),
}));

export const locationRelations = relations(location, ({ many }) => ({
  clients: many(client),
  beds: many(bed),
}));

export const bedRelations = relations(bed, ({ one, many }) => ({
  bedAssignments: many(bedAssignment),
  location: one(location, {
    fields: [bed.locationId],
    references: [location.id],
  }),
}));

export const bedAssignmentRelations = relations(bedAssignment, ({ one }) => ({
  client: one(client, {
    fields: [bedAssignment.clientId],
    references: [client.id],
  }),
  bed: one(bed, {
    fields: [bedAssignment.bedId],
    references: [bed.id],
  }),
}));

And suppose I do the following query:

const db = drizzle({
  connection: {
    connectionString: process.env.DATABASE_URL,
    ssl: process.env.NODE_ENV === "production",
  },
  schema: {
    location,
    bedAssignment,
    client,
    bed,
    locationRelations,
    clientRelations,
    bedRelations,
    bedAssignmentRelations,
  },
});

(async () => {
  const result = await db.query.client.findMany({
    with: {
      bedAssignments: {
        with: {
          bed: {
            where: (bed, { eq }) => eq(bed.locationId, "some-location-id"),
            // ^ this should omit bed assignments that have a bed that don't match the location id
          }
        }
      }
    }
  });
})()

But the expected behavior does not happen. Instead, I retrieve bedAssignments that have their bed property as null (but are not typed as such), which is very confusing behavior. A maintainer should take it from here.

When a relation is 1-many, `with` allows for use of `where` for filtering.
The typing did not expose this option in a 1-1 relation, even though it is valid.
When a relation is 1-many, `with` allows for use of `where` for filtering.
The typing did not expose this option in a 1-1 relation, even though it is valid.
@ramipellumbi ramipellumbi force-pushed the rp/where-on-with-in-one-to-one-relation branch from 7ae1e25 to e2b789e Compare January 26, 2025 16:53
…ramipellumbi/drizzle-orm into rp/where-on-with-in-one-to-one-relation
@ramipellumbi ramipellumbi force-pushed the rp/where-on-with-in-one-to-one-relation branch from e2b789e to 71406af Compare January 26, 2025 16:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[BUG]:Error Typescript for query where in relation (version "drizzle-orm": "^0.38.3")
1 participant