How to use Query with relations ?
Hello, I'm encountering an issue when trying to execute a query with relations in my code. Here's the function I'm working with:
When I run this function, I receive the following error:
I suspect there might be an issue with my schema. Could you help me identify and resolve the problem?
async getOneWithRelations(id: string): Promise<AlbumWithRelationsResponse> {
const { db, withErrorHandling } = this;
return withErrorHandling(async () => {
const { uuid } = uuidSchema.parse({ uuid: id });
const result = await db.query.albumTable.findFirst({
where: eq(albumTable.id, uuid),
with: {
images: true,
},
});
console.log(result);
return result;
});
}
async getOneWithRelations(id: string): Promise<AlbumWithRelationsResponse> {
const { db, withErrorHandling } = this;
return withErrorHandling(async () => {
const { uuid } = uuidSchema.parse({ uuid: id });
const result = await db.query.albumTable.findFirst({
where: eq(albumTable.id, uuid),
with: {
images: true,
},
});
console.log(result);
return result;
});
}
TypeError: Cannot read properties of undefined (reading 'referencedTable')
TypeError: Cannot read properties of undefined (reading 'referencedTable')
6 Replies
import { boolean, pgTable, smallint, uuid, varchar } from "drizzle-orm/pg-core";
import { relations } from "drizzle-orm";
import { randomUUID } from "node:crypto";
export const categoryTable = pgTable("Category", {
id: varchar("id", { length: 36 })
.primaryKey()
.$defaultFn(() => randomUUID()),
name: varchar("name", { length: 255 }).notNull().unique(),
order: smallint("order").default(0).notNull(),
show: boolean("show").default(false).notNull(),
});
export const albumTable = pgTable("Album", {
id: varchar("id", { length: 36 })
.primaryKey()
.$defaultFn(() => randomUUID()),
title: varchar("title", { length: 255 }).notNull().default(""),
subtitle: varchar("subtitle", { length: 255 }),
show: boolean("show").default(false).notNull(),
categoryId: varchar("categoryId", { length: 36 }).references(
() => categoryTable.id,
{
onDelete: "set null",
},
),
coverId: varchar("coverId", { length: 36 }),
});
export const imageTable = pgTable("Image", {
id: varchar("id", { length: 36 })
.primaryKey()
.$defaultFn(() => randomUUID()),
albumId: varchar("albumId", { length: 36 }).references(() => albumTable.id, {
onDelete: "cascade",
}),
path: varchar("patch", { length: 255 }).notNull(),
});
const categoryRelation = relations(categoryTable, ({ many }) => ({
albums: many(albumTable),
}));
const imageRelation = relations(imageTable, ({ one }) => ({
album: one(albumTable, {
fields: [imageTable.albumId],
references: [albumTable.id],
}),
}));
const albumRelation = relations(albumTable, ({ one, many }) => ({
category: one(categoryTable, {
fields: [albumTable.categoryId],
references: [categoryTable.id],
}),
images: many(imageTable),
}));
import { boolean, pgTable, smallint, uuid, varchar } from "drizzle-orm/pg-core";
import { relations } from "drizzle-orm";
import { randomUUID } from "node:crypto";
export const categoryTable = pgTable("Category", {
id: varchar("id", { length: 36 })
.primaryKey()
.$defaultFn(() => randomUUID()),
name: varchar("name", { length: 255 }).notNull().unique(),
order: smallint("order").default(0).notNull(),
show: boolean("show").default(false).notNull(),
});
export const albumTable = pgTable("Album", {
id: varchar("id", { length: 36 })
.primaryKey()
.$defaultFn(() => randomUUID()),
title: varchar("title", { length: 255 }).notNull().default(""),
subtitle: varchar("subtitle", { length: 255 }),
show: boolean("show").default(false).notNull(),
categoryId: varchar("categoryId", { length: 36 }).references(
() => categoryTable.id,
{
onDelete: "set null",
},
),
coverId: varchar("coverId", { length: 36 }),
});
export const imageTable = pgTable("Image", {
id: varchar("id", { length: 36 })
.primaryKey()
.$defaultFn(() => randomUUID()),
albumId: varchar("albumId", { length: 36 }).references(() => albumTable.id, {
onDelete: "cascade",
}),
path: varchar("patch", { length: 255 }).notNull(),
});
const categoryRelation = relations(categoryTable, ({ many }) => ({
albums: many(albumTable),
}));
const imageRelation = relations(imageTable, ({ one }) => ({
album: one(albumTable, {
fields: [imageTable.albumId],
references: [albumTable.id],
}),
}));
const albumRelation = relations(albumTable, ({ one, many }) => ({
category: one(categoryTable, {
fields: [albumTable.categoryId],
references: [categoryTable.id],
}),
images: many(imageTable),
}));
How are you creating the db object? You need to pass it the schema with the tables and relations defined.
# index.ts
export * from "./enums";
export * from "./album";
export * from "./week-intentions";
export * from "./admin";
export * from "./announcement";
# index.ts
export * from "./enums";
export * from "./album";
export * from "./week-intentions";
export * from "./admin";
export * from "./announcement";
# client.ts
import * as schema from "./schema";
import { drizzle } from "drizzle-orm/node-postgres";
import { Client } from "pg";
import { env } from "../config/env/server";
const { DATABASE_URL } = env;
export const client = new Client({
connectionString: DATABASE_URL,
});
(async () => {
try {
await client.connect();
} catch (error) {
console.log(error);
await client.end();
}
})();
export const db = drizzle(client, { schema });
# client.ts
import * as schema from "./schema";
import { drizzle } from "drizzle-orm/node-postgres";
import { Client } from "pg";
import { env } from "../config/env/server";
const { DATABASE_URL } = env;
export const client = new Client({
connectionString: DATABASE_URL,
});
(async () => {
try {
await client.connect();
} catch (error) {
console.log(error);
await client.end();
}
})();
export const db = drizzle(client, { schema });
export class DefaultCrud<T extends PgTable> {
// import from client.ts
protected db = db;
protected insertSchema: ReturnType<typeof createInsertSchema>;
constructor(protected model: T) {
this.insertSchema = createInsertSchema(this.model);
}
protected async withErrorHandling<R, D = null>(
fn: () => Promise<R>,
defaultValue: D = null as unknown as D,
): Promise<R | D> {
try {
return await fn();
} catch (error) {
console.error(error);
return defaultValue;
}
}
async create(data: InferInsertModel<T>): Promise<T["$inferSelect"] | null> {
const { withErrorHandling, db, model, insertSchema } = this;
return withErrorHandling(async () => {
const parsedData = insertSchema.parse(data);
const [result] = (await db
.insert(model)
.values(parsedData)
.returning()) as unknown[];
return result as T["$inferSelect"];
});
}
--- rest
export class DefaultCrud<T extends PgTable> {
// import from client.ts
protected db = db;
protected insertSchema: ReturnType<typeof createInsertSchema>;
constructor(protected model: T) {
this.insertSchema = createInsertSchema(this.model);
}
protected async withErrorHandling<R, D = null>(
fn: () => Promise<R>,
defaultValue: D = null as unknown as D,
): Promise<R | D> {
try {
return await fn();
} catch (error) {
console.error(error);
return defaultValue;
}
}
async create(data: InferInsertModel<T>): Promise<T["$inferSelect"] | null> {
const { withErrorHandling, db, model, insertSchema } = this;
return withErrorHandling(async () => {
const parsedData = insertSchema.parse(data);
const [result] = (await db
.insert(model)
.values(parsedData)
.returning()) as unknown[];
return result as T["$inferSelect"];
});
}
--- rest
class Album extends DefaultCrud<typeof albumTable> {
constructor() {
super(albumTable);
}
async getOneWithRelations(id: string): Promise<AlbumWithRelationsResponse> {
const { db, withErrorHandling } = this;
return withErrorHandling(async () => {
const { uuid } = uuidSchema.parse({ uuid: id });
const result = await db.query.albumTable.findFirst({
where: eq(albumTable.id, uuid),
with: {
images: true,
},
});
console.log(result);
return result;
});
}
}
class Album extends DefaultCrud<typeof albumTable> {
constructor() {
super(albumTable);
}
async getOneWithRelations(id: string): Promise<AlbumWithRelationsResponse> {
const { db, withErrorHandling } = this;
return withErrorHandling(async () => {
const { uuid } = uuidSchema.parse({ uuid: id });
const result = await db.query.albumTable.findFirst({
where: eq(albumTable.id, uuid),
with: {
images: true,
},
});
console.log(result);
return result;
});
}
}
Lol, I didn't do anything