Anas Badran
Anas Badran
Explore posts from servers
DTDrizzle Team
Created by Anas Badran on 9/19/2024 in #help
Need help building up a query based on nested fields.
the user:
export const users = pgTable('users', {
id: integer('id').primaryKey().generatedByDefaultAsIdentity(),
createdAt: timestamp('created_at', { withTimezone: true, mode: 'string' })
.defaultNow()
.notNull(),
firstName: varchar('first_name', { length: 255 }).notNull(),
middleName: varchar('middle_name', { length: 255 }),
lastName: varchar('last_name', { length: 255 }).notNull(),
username: varchar('username', { length: 255 }).notNull().unique(),
nickname: varchar('nickname', { length: 255 }),
password: varchar('password', { length: 255 }).notNull(),
email: varchar('email', { length: 255 }).notNull().unique(),
role: UserRole('role').default('user').notNull(),
profileImage: varchar('profile_image', { length: 255 }),
isVerified: boolean('is_verified').default(false).notNull(),
bio: text('bio'),
isApproved: boolean('is_approved').default(false).notNull(),
isFamily: boolean('is_family').default(false).notNull(),
});
export const users = pgTable('users', {
id: integer('id').primaryKey().generatedByDefaultAsIdentity(),
createdAt: timestamp('created_at', { withTimezone: true, mode: 'string' })
.defaultNow()
.notNull(),
firstName: varchar('first_name', { length: 255 }).notNull(),
middleName: varchar('middle_name', { length: 255 }),
lastName: varchar('last_name', { length: 255 }).notNull(),
username: varchar('username', { length: 255 }).notNull().unique(),
nickname: varchar('nickname', { length: 255 }),
password: varchar('password', { length: 255 }).notNull(),
email: varchar('email', { length: 255 }).notNull().unique(),
role: UserRole('role').default('user').notNull(),
profileImage: varchar('profile_image', { length: 255 }),
isVerified: boolean('is_verified').default(false).notNull(),
bio: text('bio'),
isApproved: boolean('is_approved').default(false).notNull(),
isFamily: boolean('is_family').default(false).notNull(),
});
3 replies
DTDrizzle Team
Created by Anas Badran on 9/19/2024 in #help
Need help building up a query based on nested fields.
export const messages = pgTable('messages', {
id: integer('id').primaryKey().generatedByDefaultAsIdentity(),
createdAt: timestamp('created_at', { withTimezone: true })
.defaultNow()
.notNull(),
content: text('content').notNull(),
chatID: integer('chat_id')
.notNull()
.references(() => chats.id),
senderID: integer('from_id')
.references(() => users.id, { onDelete: 'cascade' })
.notNull(),
isEdited: boolean('is_edited').default(false).notNull(),
});

export const chats = pgTable('chats', {
id: integer('id').primaryKey().generatedByDefaultAsIdentity(),
createdAt: timestamp('created_at', { withTimezone: true })
.defaultNow()
.notNull(),
name: varchar('name', { length: 255 }).notNull(),
image: varchar('image'),
bio: text('bio'),
});

export const chatMembers = pgTable('chat_member', {
id: integer('id').primaryKey().generatedByDefaultAsIdentity(),
chatID: integer('chat_id')
.references(() => chats.id, { onDelete: 'cascade' })
.notNull(),
joinedAt: timestamp('joined_at', { withTimezone: true })
.defaultNow()
.notNull(),
leftAt: timestamp('left_at'),
userID: integer('user_id')
.references(() => users.id, { onDelete: 'cascade' })
.notNull(),
});

export const chatRelations = relations(chats, ({ many }) => ({
members: many(chatMembers),
messages: many(messages),
}));

export const chatMemberssRelations = relations(chatMembers, ({ one }) => ({
user: one(users, {
fields: [chatMembers.userID],
references: [users.id],
}),
chat: one(chats, {
fields: [chatMembers.chatID],
references: [chats.id],
}),
}));

export const messagessRelations = relations(messages, ({ one }) => ({
chat: one(chats, {
fields: [messages.chatID],
references: [chats.id],
}),
sender: one(users, { fields: [messages.senderID], references: [users.id] }),
}));
export const messages = pgTable('messages', {
id: integer('id').primaryKey().generatedByDefaultAsIdentity(),
createdAt: timestamp('created_at', { withTimezone: true })
.defaultNow()
.notNull(),
content: text('content').notNull(),
chatID: integer('chat_id')
.notNull()
.references(() => chats.id),
senderID: integer('from_id')
.references(() => users.id, { onDelete: 'cascade' })
.notNull(),
isEdited: boolean('is_edited').default(false).notNull(),
});

export const chats = pgTable('chats', {
id: integer('id').primaryKey().generatedByDefaultAsIdentity(),
createdAt: timestamp('created_at', { withTimezone: true })
.defaultNow()
.notNull(),
name: varchar('name', { length: 255 }).notNull(),
image: varchar('image'),
bio: text('bio'),
});

export const chatMembers = pgTable('chat_member', {
id: integer('id').primaryKey().generatedByDefaultAsIdentity(),
chatID: integer('chat_id')
.references(() => chats.id, { onDelete: 'cascade' })
.notNull(),
joinedAt: timestamp('joined_at', { withTimezone: true })
.defaultNow()
.notNull(),
leftAt: timestamp('left_at'),
userID: integer('user_id')
.references(() => users.id, { onDelete: 'cascade' })
.notNull(),
});

export const chatRelations = relations(chats, ({ many }) => ({
members: many(chatMembers),
messages: many(messages),
}));

export const chatMemberssRelations = relations(chatMembers, ({ one }) => ({
user: one(users, {
fields: [chatMembers.userID],
references: [users.id],
}),
chat: one(chats, {
fields: [chatMembers.chatID],
references: [chats.id],
}),
}));

export const messagessRelations = relations(messages, ({ one }) => ({
chat: one(chats, {
fields: [messages.chatID],
references: [chats.id],
}),
sender: one(users, { fields: [messages.senderID], references: [users.id] }),
}));
3 replies
DTDrizzle Team
Created by Anas Badran on 9/13/2024 in #help
Query based on nested relation
export const findOrCreateChat = async (fromID: number, toID: number) => {
const existingchat = await db.query.chats.findFirst({
with: {
members: {
where(fields, { and, eq }) {
return and(eq(fields.userID, fromID), eq(fields.userID, toID));
},
},
},
});
if (existingchat) {
return existingchat;
}

const newChat = await db
.insert(chats)
.values({
name: `new chat`,
})
.returning();

await db.insert(chatMembers).values([
{ chatID: newChat[0].id, userID: fromID },
{ chatID: newChat[0].id, userID: toID },
]);

return newChat[0];
};
export const findOrCreateChat = async (fromID: number, toID: number) => {
const existingchat = await db.query.chats.findFirst({
with: {
members: {
where(fields, { and, eq }) {
return and(eq(fields.userID, fromID), eq(fields.userID, toID));
},
},
},
});
if (existingchat) {
return existingchat;
}

const newChat = await db
.insert(chats)
.values({
name: `new chat`,
})
.returning();

await db.insert(chatMembers).values([
{ chatID: newChat[0].id, userID: fromID },
{ chatID: newChat[0].id, userID: toID },
]);

return newChat[0];
};
4 replies
DTDrizzle Team
Created by Anas Badran on 9/13/2024 in #help
Query based on nested relation
the related schema
4 replies
DTDrizzle Team
Created by Anas Badran on 9/13/2024 in #help
Query based on nested relation
import {
pgTable,
timestamp,
varchar,
text,
integer,
} from 'drizzle-orm/pg-core';
import { users } from './user';
import { relations } from 'drizzle-orm';

export const messages = pgTable('messagess', {
id: integer('id').primaryKey().generatedByDefaultAsIdentity(),
createdAt: timestamp('created_at', { withTimezone: true })
.defaultNow()
.notNull(),
content: text('content').notNull(),
chatID: integer('chat_id')
.notNull()
.references(() => chats.id),
senderID: integer('from_id')
.references(() => users.id, { onDelete: 'cascade' })
.notNull(),
});

export const chats = pgTable('chats', {
id: integer('id').primaryKey().generatedByDefaultAsIdentity(),
createdAt: timestamp('created_at', { withTimezone: true })
.defaultNow()
.notNull(),
name: varchar('name', { length: 255 }).notNull(),
image: varchar('image'),
bio: text('bio'),
});

export const chatMembers = pgTable('chat_member', {
id: integer('id').primaryKey().generatedByDefaultAsIdentity(),
chatID: integer('chat_id')
.references(() => chats.id, { onDelete: 'cascade' })
.notNull(),
joinedAt: timestamp('joined_at', { withTimezone: true })
.defaultNow()
.notNull(),
leftAt: timestamp('left_at'),
userID: integer('user_id')
.references(() => users.id, { onDelete: 'cascade' })
.notNull(),
});

export const chatRelations = relations(chats, ({ many }) => ({
members: many(chatMembers),
messages: many(messages),
}));

export const chatMemberssRelations = relations(chatMembers, ({ one }) => ({
user: one(users, {
fields: [chatMembers.userID],
references: [users.id],
}),
chat: one(chats, {
fields: [chatMembers.chatID],
references: [chats.id],
}),
}));

export const messagessRelations = relations(messages, ({ one }) => ({
chat: one(chats, {
fields: [messages.chatID],
references: [chats.id],
}),
sender: one(users, { fields: [messages.senderID], references: [users.id] }),
}));
import {
pgTable,
timestamp,
varchar,
text,
integer,
} from 'drizzle-orm/pg-core';
import { users } from './user';
import { relations } from 'drizzle-orm';

export const messages = pgTable('messagess', {
id: integer('id').primaryKey().generatedByDefaultAsIdentity(),
createdAt: timestamp('created_at', { withTimezone: true })
.defaultNow()
.notNull(),
content: text('content').notNull(),
chatID: integer('chat_id')
.notNull()
.references(() => chats.id),
senderID: integer('from_id')
.references(() => users.id, { onDelete: 'cascade' })
.notNull(),
});

export const chats = pgTable('chats', {
id: integer('id').primaryKey().generatedByDefaultAsIdentity(),
createdAt: timestamp('created_at', { withTimezone: true })
.defaultNow()
.notNull(),
name: varchar('name', { length: 255 }).notNull(),
image: varchar('image'),
bio: text('bio'),
});

export const chatMembers = pgTable('chat_member', {
id: integer('id').primaryKey().generatedByDefaultAsIdentity(),
chatID: integer('chat_id')
.references(() => chats.id, { onDelete: 'cascade' })
.notNull(),
joinedAt: timestamp('joined_at', { withTimezone: true })
.defaultNow()
.notNull(),
leftAt: timestamp('left_at'),
userID: integer('user_id')
.references(() => users.id, { onDelete: 'cascade' })
.notNull(),
});

export const chatRelations = relations(chats, ({ many }) => ({
members: many(chatMembers),
messages: many(messages),
}));

export const chatMemberssRelations = relations(chatMembers, ({ one }) => ({
user: one(users, {
fields: [chatMembers.userID],
references: [users.id],
}),
chat: one(chats, {
fields: [chatMembers.chatID],
references: [chats.id],
}),
}));

export const messagessRelations = relations(messages, ({ one }) => ({
chat: one(chats, {
fields: [messages.chatID],
references: [chats.id],
}),
sender: one(users, { fields: [messages.senderID], references: [users.id] }),
}));
4 replies
DTDrizzle Team
Created by Anas Badran on 8/25/2024 in #help
Nested queries
the key field in reaction can be in these two forms: - post-{postID}, eg: post-123. - comment-{commentID, eg: comment-123.
2 replies
DTDrizzle Team
Created by Anas Badran on 8/23/2024 in #help
Storing Images
Thanks for your help
14 replies
DTDrizzle Team
Created by Anas Badran on 8/24/2024 in #help
Inferring types for nested objects
// types.ts
import { student } from '~/.server/db/schema/user';
export type Student = typeof student.$inferSelect;
import { student } from '~/.server/db/schema/user';
export type Student = typeof student.$inferSelect;
4 replies
DTDrizzle Team
Created by Anas Badran on 8/24/2024 in #help
Inferring types for nested objects
columns definition: all red lines:
import { createColumnHelper } from '@tanstack/react-table';
import type { Student } from './types';

export const studentsColumns = () => {
const columnHelper = createColumnHelper<Student>();

return [
columnHelper.accessor('students.id', {}),
columnHelper.accessor('students.classID', {}),
columnHelper.accessor('students.status', {}),
columnHelper.accessor('profiles.firstName', {}),
columnHelper.accessor('profiles.middleName', {}),
columnHelper.accessor('profiles.lastName', {}),
];
};
import { createColumnHelper } from '@tanstack/react-table';
import type { Student } from './types';

export const studentsColumns = () => {
const columnHelper = createColumnHelper<Student>();

return [
columnHelper.accessor('students.id', {}),
columnHelper.accessor('students.classID', {}),
columnHelper.accessor('students.status', {}),
columnHelper.accessor('profiles.firstName', {}),
columnHelper.accessor('profiles.middleName', {}),
columnHelper.accessor('profiles.lastName', {}),
];
};
4 replies
DTDrizzle Team
Created by Anas Badran on 8/24/2024 in #help
Inferring types for nested objects
The table component:
import { ScrollArea, Table } from '@mantine/core';
import {
flexRender,
getCoreRowModel,
useReactTable,
} from '@tanstack/react-table';
import { useState } from 'react';
import { ITEMS_PER_PAGE } from '~/lib/constants';

const _Table = ({ columns, data, rowCount }) => {
const [pagination, setPagination] = useState({
pageIndex: 0,
pageSize: ITEMS_PER_PAGE,
});
const table = useReactTable({
columns,
data,
getCoreRowModel: getCoreRowModel(),
manualPagination: true,
rowCount,
onPaginationChange: setPagination,
state: {
pagination,
},
});
return (
<>
<ScrollArea className='py-8 mb-24' my='xl'>
<Table
className='bg-green-300'
py='xl'
withColumnBorders
withTableBorder
>
<Table.Thead>
{table.getHeaderGroups().map((headerGroup) => (
<Table.Tr key={headerGroup.id}>
{headerGroup.headers.map((header) => (
<Table.Th key={header.id} colSpan={header.colSpan}>
{flexRender(
header.column.columnDef.header,
header.getContext()
)}
</Table.Th>
))}
</Table.Tr>
))}
</Table.Thead>
<Table.Tbody>
{table.getRowModel().rows.map((row) => (
<Table.Tr key={row.id}>
{row.getVisibleCells().map((cell) => (
<Table.Td key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</Table.Td>
))}
</Table.Tr>
))}
</Table.Tbody>
</Table>
</ScrollArea>
</>
);
};

export default _Table;
import { ScrollArea, Table } from '@mantine/core';
import {
flexRender,
getCoreRowModel,
useReactTable,
} from '@tanstack/react-table';
import { useState } from 'react';
import { ITEMS_PER_PAGE } from '~/lib/constants';

const _Table = ({ columns, data, rowCount }) => {
const [pagination, setPagination] = useState({
pageIndex: 0,
pageSize: ITEMS_PER_PAGE,
});
const table = useReactTable({
columns,
data,
getCoreRowModel: getCoreRowModel(),
manualPagination: true,
rowCount,
onPaginationChange: setPagination,
state: {
pagination,
},
});
return (
<>
<ScrollArea className='py-8 mb-24' my='xl'>
<Table
className='bg-green-300'
py='xl'
withColumnBorders
withTableBorder
>
<Table.Thead>
{table.getHeaderGroups().map((headerGroup) => (
<Table.Tr key={headerGroup.id}>
{headerGroup.headers.map((header) => (
<Table.Th key={header.id} colSpan={header.colSpan}>
{flexRender(
header.column.columnDef.header,
header.getContext()
)}
</Table.Th>
))}
</Table.Tr>
))}
</Table.Thead>
<Table.Tbody>
{table.getRowModel().rows.map((row) => (
<Table.Tr key={row.id}>
{row.getVisibleCells().map((cell) => (
<Table.Td key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</Table.Td>
))}
</Table.Tr>
))}
</Table.Tbody>
</Table>
</ScrollArea>
</>
);
};

export default _Table;
4 replies
DTDrizzle Team
Created by Anas Badran on 8/23/2024 in #help
Storing Images
thanks for sharing
14 replies
DTDrizzle Team
Created by Anas Badran on 8/23/2024 in #help
Storing Images
how to properly set the updatedAt to be automatically updated when updaing the documnet in the database.
14 replies
DTDrizzle Team
Created by Anas Badran on 8/23/2024 in #help
Storing Images
I get this error
demo started
||||||||||||||||||||||||||||||||||||||||||||||||||||||
||||||||||||||||||||||||||||||||||||||||||||||||||||||
bad happened TypeError: value.toISOString is not a function
at PgTimestamp.mapToDriverValue (D:\code\developing\remix\badran\node_modules\.pnpm\drizzle-orm@0.33.0_@types+react@18.3.3_postgres@3.4.4_react@18.3.1\node_modules\src\pg-core\columns\timestamp.ts:67:16)
at <anonymous> (D:\code\developing\remix\badran\node_modules\.pnpm\drizzle-orm@0.33.0_@types+react@18.3.3_postgres@3.4.4_react@18.3.1\node_modules\src\sql\sql.ts:210:69)
at Array.map (<anonymous>)
at SQL.buildQueryFromSourceParams (D:\code\developing\remix\badran\node_modules\.pnpm\drizzle-orm@0.33.0_@types+react@18.3.3_postgres@3.4.4_react@18.3.1\node_modules\src\sql\sql.ts:144:30)
at <anonymous> (D:\code\developing\remix\badran\node_modules\.pnpm\drizzle-orm@0.33.0_@types+react@18.3.3_postgres@3.4.4_react@18.3.1\node_modules\src\sql\sql.ts:170:17)
at Array.map (<anonymous>)
at SQL.buildQueryFromSourceParams (D:\code\developing\remix\badran\node_modules\.pnpm\drizzle-orm@0.33.0_@types+react@18.3.3_postgres@3.4.4_react@18.3.1\node_modules\src\sql\sql.ts:144:30)
at <anonymous> (D:\code\developing\remix\badran\node_modules\.pnpm\drizzle-orm@0.33.0_@types+react@18.3.3_postgres@3.4.4_react@18.3.1\node_modules\src\sql\sql.ts:170:17)
at Array.map (<anonymous>)
at SQL.buildQueryFromSourceParams (D:\code\developing\remix\badran\node_modules\.pnpm\drizzle-orm@0.33.0_@types+react@18.3.3_postgres@3.4.4_react@18.3.1\node_modules\src\sql\sql.ts:144:30)
demo started
||||||||||||||||||||||||||||||||||||||||||||||||||||||
||||||||||||||||||||||||||||||||||||||||||||||||||||||
bad happened TypeError: value.toISOString is not a function
at PgTimestamp.mapToDriverValue (D:\code\developing\remix\badran\node_modules\.pnpm\drizzle-orm@0.33.0_@types+react@18.3.3_postgres@3.4.4_react@18.3.1\node_modules\src\pg-core\columns\timestamp.ts:67:16)
at <anonymous> (D:\code\developing\remix\badran\node_modules\.pnpm\drizzle-orm@0.33.0_@types+react@18.3.3_postgres@3.4.4_react@18.3.1\node_modules\src\sql\sql.ts:210:69)
at Array.map (<anonymous>)
at SQL.buildQueryFromSourceParams (D:\code\developing\remix\badran\node_modules\.pnpm\drizzle-orm@0.33.0_@types+react@18.3.3_postgres@3.4.4_react@18.3.1\node_modules\src\sql\sql.ts:144:30)
at <anonymous> (D:\code\developing\remix\badran\node_modules\.pnpm\drizzle-orm@0.33.0_@types+react@18.3.3_postgres@3.4.4_react@18.3.1\node_modules\src\sql\sql.ts:170:17)
at Array.map (<anonymous>)
at SQL.buildQueryFromSourceParams (D:\code\developing\remix\badran\node_modules\.pnpm\drizzle-orm@0.33.0_@types+react@18.3.3_postgres@3.4.4_react@18.3.1\node_modules\src\sql\sql.ts:144:30)
at <anonymous> (D:\code\developing\remix\badran\node_modules\.pnpm\drizzle-orm@0.33.0_@types+react@18.3.3_postgres@3.4.4_react@18.3.1\node_modules\src\sql\sql.ts:170:17)
at Array.map (<anonymous>)
at SQL.buildQueryFromSourceParams (D:\code\developing\remix\badran\node_modules\.pnpm\drizzle-orm@0.33.0_@types+react@18.3.3_postgres@3.4.4_react@18.3.1\node_modules\src\sql\sql.ts:144:30)
14 replies
DTDrizzle Team
Created by Anas Badran on 8/23/2024 in #help
Storing Images
As a second question
// the schema
export const post = pgTable('posts', {
id: uuid('id').primaryKey().defaultRandom(),
createdAt: timestamp('created_at').defaultNow().notNull(),
updatedAt: timestamp('updated_at')
.defaultNow()
.$onUpdate(() => sql`(CURRENT_TIMESTAMP)`),
name: varchar('name', { length: 255 }).notNull()
})
// the demo code
import { eq } from 'drizzle-orm';
import { db } from '.';
import { post } from './schema';

(async () => {
try {

console.log('demo started')
console.log('||||||||||||||||||||||||||||||||||||||||||||||||||||||');
// inserting
// await db.insert(post).values({
// name: 'Hello, world!'
// })
// updating
await db.update(post).set({ name: 'Hello, updated1' }).where(eq(post.id, '305115f6-82b1-447c-b869-76741b9e4058'))
console.log('demo finished')
console.log('||||||||||||||||||||||||||||||||||||||||||||||||||||||');
} catch (error) {
console.log('||||||||||||||||||||||||||||||||||||||||||||||||||||||');
console.log('bad happened', error)
}
})()
// the schema
export const post = pgTable('posts', {
id: uuid('id').primaryKey().defaultRandom(),
createdAt: timestamp('created_at').defaultNow().notNull(),
updatedAt: timestamp('updated_at')
.defaultNow()
.$onUpdate(() => sql`(CURRENT_TIMESTAMP)`),
name: varchar('name', { length: 255 }).notNull()
})
// the demo code
import { eq } from 'drizzle-orm';
import { db } from '.';
import { post } from './schema';

(async () => {
try {

console.log('demo started')
console.log('||||||||||||||||||||||||||||||||||||||||||||||||||||||');
// inserting
// await db.insert(post).values({
// name: 'Hello, world!'
// })
// updating
await db.update(post).set({ name: 'Hello, updated1' }).where(eq(post.id, '305115f6-82b1-447c-b869-76741b9e4058'))
console.log('demo finished')
console.log('||||||||||||||||||||||||||||||||||||||||||||||||||||||');
} catch (error) {
console.log('||||||||||||||||||||||||||||||||||||||||||||||||||||||');
console.log('bad happened', error)
}
})()
14 replies
DTDrizzle Team
Created by Anas Badran on 8/23/2024 in #help
Storing Images
You are right, I already doing that, I'm asking about the best approach to properly store images for multiple things, like persons images, posts images, activites images, should I put them all in one talbe, or each one needs it's own table
14 replies
DTDrizzle Team
Created by Anas Badran on 8/17/2024 in #help
conditional unique constraint
ok, thank you
21 replies
DTDrizzle Team
Created by Anas Badran on 8/17/2024 in #help
conditional unique constraint
yes, two people can have the same phone number as their primary phone number
21 replies
DTDrizzle Team
Created by Anas Badran on 8/17/2024 in #help
conditional unique constraint
Yes you are right
21 replies
DTDrizzle Team
Created by Anas Badran on 8/17/2024 in #help
conditional unique constraint
export const phone = pgTable('phones', {
id: uuid('id').primaryKey().defaultRandom(),
number: varchar('number', { length: 255 }).unique(),
});

export const personPhone = pgTable('person_phone', {
id: uuid('id').primaryKey().defaultRandom(),
isPrimary: boolean('is_primary').default(false),
personID: uuid('person_id')
.references(() => person.id, { onDelete: 'cascade' })
.notNull(),
phoneID: uuid('phone_id')
.references(() => phone.id, { onDelete: 'cascade' })
.notNull(),
});
export const phone = pgTable('phones', {
id: uuid('id').primaryKey().defaultRandom(),
number: varchar('number', { length: 255 }).unique(),
});

export const personPhone = pgTable('person_phone', {
id: uuid('id').primaryKey().defaultRandom(),
isPrimary: boolean('is_primary').default(false),
personID: uuid('person_id')
.references(() => person.id, { onDelete: 'cascade' })
.notNull(),
phoneID: uuid('phone_id')
.references(() => phone.id, { onDelete: 'cascade' })
.notNull(),
});
21 replies
DTDrizzle Team
Created by Anas Badran on 8/17/2024 in #help
conditional unique constraint
the isPrimary exists on the person_phone table not on the phone table
21 replies