bigboyjo
bigboyjo
Explore posts from servers
DTDrizzle Team
Created by bigboyjo on 9/27/2024 in #help
Types aren't being inferred properly
I have the following schema.
export const taskFolders = pgTable('task_folders', {
id: uuid('id').primaryKey().defaultRandom(),
taskId: uuid('taskId').references(() => tasks.id, { onDelete: 'cascade' }),
name: text('name').notNull(),
createdAt: timestamp('created_at', { mode: 'string' }).notNull().defaultNow(),
deletedAt: timestamp('deleted_at'),
});
export type InsertTaskFolder = typeof taskFolders.$inferInsert;
// ?^ { name: string }
export const taskFolders = pgTable('task_folders', {
id: uuid('id').primaryKey().defaultRandom(),
taskId: uuid('taskId').references(() => tasks.id, { onDelete: 'cascade' }),
name: text('name').notNull(),
createdAt: timestamp('created_at', { mode: 'string' }).notNull().defaultNow(),
deletedAt: timestamp('deleted_at'),
});
export type InsertTaskFolder = typeof taskFolders.$inferInsert;
// ?^ { name: string }
I'm trying to update the deleted_at column but when I do, Typescript is erroring.
@Delete(':id')
async delete(@Param('id', new ParseUUIDPipe()) id: Guid) {
await this.db
.update(scheme.taskFolders)
.set({ deletedAt: new Date() }) // Typescript error here: Object literal may only specify known properties, and 'deletedAt' does not exist in type '{ name?: string | SQL<unknown>; }'.
.where(eq(scheme.taskFolders.id, id));
}
@Delete(':id')
async delete(@Param('id', new ParseUUIDPipe()) id: Guid) {
await this.db
.update(scheme.taskFolders)
.set({ deletedAt: new Date() }) // Typescript error here: Object literal may only specify known properties, and 'deletedAt' does not exist in type '{ name?: string | SQL<unknown>; }'.
.where(eq(scheme.taskFolders.id, id));
}
My question is why deletedAt isn't being inferred and how I can fix this
2 replies
TTCTheo's Typesafe Cult
Created by bigboyjo on 2/26/2024 in #questions
Using Vitest to test React component that uses custom hook
I'm using Vitest to test a React component that uses a custom hook. The custom hook creates a column for MUI DataGridPro with a custom renderCell function that renders a button in the column. The hook accepts a void callback function that is used for the onClick of the button. When the button is clicked, a modal should open up to display information based on the row. In prod and dev this works as expected, but I'm not sure how to test it. I want a test that will test the clicking of the button to ensure the Modal opens up. If I don't mock the hook, I get an error telling me renderEntryIconColumn is not a function, but when I do mock it and debug the test, renderEntryIconColumn is undefined. Below is the hook and component.
// useEntryIcon.js
const useEntryIcon = (callback) => {
const [entryIcon, setEntryIcon] = useState('floppy')

const { api } = useApiContext()

const renderEntryIconColumn = useCallback(
({
align = 'center',
headerAlign = 'center',
filterable = false,
sortable = false,
resizable = false,
disableColumnMenu = false,
title,
id,
...rest
}) => ({
align,
headerAlign,
filterable,
sortable,
resizable,
disableColumnMenu,
renderCell: ({ id: rowId, row }) => {
const params = { rowId, row }

return (
// EntriesIcon renders an svg based on `entryIcon`
<EntriesIcon
iconType={entryIcon}
title={typeof title === 'string' ? title : title(rowId)}
tabIndex={0}
onClick={(e) => callback(params, e)}
onKeyDown={(e) => {
if (e.key === ' ' || e.key === 'Enter') {
callback(params, e)
}
}}
/>
)
},
...rest,
}),
[callback, entryIcon]
)

useEffect(() => {
api
.get('/api/app-info/entry-icon')
.then(({ data }) => setEntryIcon(data))
.catch(() => setEntryIcon('floppy'))
}, [api])

return renderEntryIconColumn
}
// useEntryIcon.js
const useEntryIcon = (callback) => {
const [entryIcon, setEntryIcon] = useState('floppy')

const { api } = useApiContext()

const renderEntryIconColumn = useCallback(
({
align = 'center',
headerAlign = 'center',
filterable = false,
sortable = false,
resizable = false,
disableColumnMenu = false,
title,
id,
...rest
}) => ({
align,
headerAlign,
filterable,
sortable,
resizable,
disableColumnMenu,
renderCell: ({ id: rowId, row }) => {
const params = { rowId, row }

return (
// EntriesIcon renders an svg based on `entryIcon`
<EntriesIcon
iconType={entryIcon}
title={typeof title === 'string' ? title : title(rowId)}
tabIndex={0}
onClick={(e) => callback(params, e)}
onKeyDown={(e) => {
if (e.key === ' ' || e.key === 'Enter') {
callback(params, e)
}
}}
/>
)
},
...rest,
}),
[callback, entryIcon]
)

useEffect(() => {
api
.get('/api/app-info/entry-icon')
.then(({ data }) => setEntryIcon(data))
.catch(() => setEntryIcon('floppy'))
}, [api])

return renderEntryIconColumn
}
// MyComponent.jsx
function MyComponent({
columns,
rows,
...rest
}) {
const [modalConfig, setModalConfig] = useState({
recordId: '',
memberId: '',
open: false
})
const renderEntryIconColumn = useEntryIcon(({ row }) => {
const { recordId, memberId } = row

if (memberId) {
setModalConfig({ open: true, recordId: recordId.toString(), memberId })
}
}
)
const firstColumn = renderEntryIconColumn({
field: 'entries',
headerName: 'Entries',
id: (rowId) => `entries-icon-${rowId}`,
title: (id) => `render-${id}`,
})

return (
<>
<DataGridPro columns={[firstColumn, ...columns]} rows={rows} {...rest} />
<Modal
{...modalConfig}
onClose={() => {
setModalConfig({ open: false, recordId: '', memberId: '' })
}}
/>
</>
)
}
// MyComponent.jsx
function MyComponent({
columns,
rows,
...rest
}) {
const [modalConfig, setModalConfig] = useState({
recordId: '',
memberId: '',
open: false
})
const renderEntryIconColumn = useEntryIcon(({ row }) => {
const { recordId, memberId } = row

if (memberId) {
setModalConfig({ open: true, recordId: recordId.toString(), memberId })
}
}
)
const firstColumn = renderEntryIconColumn({
field: 'entries',
headerName: 'Entries',
id: (rowId) => `entries-icon-${rowId}`,
title: (id) => `render-${id}`,
})

return (
<>
<DataGridPro columns={[firstColumn, ...columns]} rows={rows} {...rest} />
<Modal
{...modalConfig}
onClose={() => {
setModalConfig({ open: false, recordId: '', memberId: '' })
}}
/>
</>
)
}
1 replies