fix: align prisma client typing

This commit is contained in:
Esdras Renan 2025-11-19 15:42:21 -03:00
parent 307a291c71
commit 514b190a65
32 changed files with 106 additions and 34430 deletions

View file

@ -1,4 +1,7 @@
import { Prisma, type Company, prisma } from "@/lib/prisma"
import type { Prisma as PrismaTypes } from "@/generated/prisma/client"
import { Prisma, asPrismaKnownError } from "@/lib/prisma"
import type { PrismaDelegateClient } from "@/lib/prisma"
import { prisma } from "@/lib/prisma"
import { ZodError } from "zod"
import {
@ -9,6 +12,10 @@ import {
type CompanyStateRegistrationTypeOption,
} from "@/lib/schemas/company"
type DbCompany = Awaited<ReturnType<PrismaDelegateClient["company"]["create"]>>
type CompanyFindManyArgs = Parameters<PrismaDelegateClient["company"]["findMany"]>[0]
type CompanyCreatePayload = Parameters<PrismaDelegateClient["company"]["create"]>[0]["data"]
export type NormalizedCompany = CompanyFormValues & {
id: string
provisioningCode: string | null
@ -16,8 +23,6 @@ export type NormalizedCompany = CompanyFormValues & {
updatedAt: string
}
type CompanyCreatePayload = Omit<Prisma.CompanyCreateInput, "provisioningCode">
// Local representation of the DB enum to avoid relying on Prisma enum exports
type DbCompanyStateRegistrationType = "STANDARD" | "EXEMPT" | "SIMPLES"
@ -71,7 +76,26 @@ const STATE_REGISTRATION_TYPE_FROM_PRISMA: Record<
SIMPLES: "simples",
}
const JSON_NULL_VALUE = Prisma.JsonNull as unknown as Prisma.InputJsonValue
type PrismaJsonInput = PrismaTypes.InputJsonValue | PrismaTypes.NullableJsonNullValueInput
const JSON_NULL_VALUE: PrismaTypes.NullableJsonNullValueInput = Prisma.JsonNull
function toJsonInput(value: unknown): PrismaJsonInput {
if (value === null || value === undefined) {
return JSON_NULL_VALUE
}
if (value === Prisma.JsonNull || value === Prisma.DbNull) {
return value
}
return value as PrismaTypes.InputJsonValue
}
function asJsonRecord(value: PrismaTypes.JsonValue | null | undefined): Record<string, unknown> | undefined {
if (!value || typeof value !== "object" || Array.isArray(value)) {
return undefined
}
return value as Record<string, unknown>
}
const COMPANY_LEGACY_SELECT = {
id: true,
@ -81,13 +105,12 @@ const COMPANY_LEGACY_SELECT = {
isAvulso: true,
createdAt: true,
updatedAt: true,
} satisfies Prisma.CompanySelect
type LegacyCompanyRow = Prisma.CompanyGetPayload<{ select: typeof COMPANY_LEGACY_SELECT }>
} as const
function isMissingProvisioningCodeColumn(error: unknown): boolean {
if (error instanceof Prisma.PrismaClientKnownRequestError && error.code === "P2022") {
const meta = error.meta as Record<string, unknown> | undefined
const knownError = asPrismaKnownError(error)
if (knownError && knownError.code === "P2022") {
const meta = knownError.meta as Record<string, unknown> | undefined
const metaColumn =
typeof meta?.column === "string"
? meta.column
@ -97,15 +120,16 @@ function isMissingProvisioningCodeColumn(error: unknown): boolean {
? meta.model
: null
if (metaColumn && metaColumn.toLowerCase().includes("provisioningcode")) return true
if (error.message.toLowerCase().includes("provisioningcode")) return true
if (knownError.message?.toLowerCase().includes("provisioningcode")) return true
}
return false
}
function isMissingCompanyTable(error: unknown): boolean {
if (error instanceof Prisma.PrismaClientKnownRequestError) {
if (error.code === "P2021") return true
const message = error.message.toLowerCase()
const knownError = asPrismaKnownError(error)
if (knownError) {
if (knownError.code === "P2021") return true
const message = knownError.message?.toLowerCase() ?? ""
if (message.includes("table") && message.includes("company") && message.includes("does not exist")) {
return true
}
@ -113,7 +137,7 @@ function isMissingCompanyTable(error: unknown): boolean {
return false
}
export async function safeCompanyFindMany(args: Prisma.CompanyFindManyArgs): Promise<Company[]> {
export async function safeCompanyFindMany(args: CompanyFindManyArgs = {} as CompanyFindManyArgs): Promise<DbCompany[]> {
try {
return await prisma.company.findMany(args)
} catch (error) {
@ -124,14 +148,15 @@ export async function safeCompanyFindMany(args: Prisma.CompanyFindManyArgs): Pro
throw error
}
if (args.select || args.include) {
const hasProjection = Boolean(args?.select || args?.include)
if (hasProjection) {
throw error
}
const legacyRows = (await prisma.company.findMany({
const legacyRows = await prisma.company.findMany({
...args,
select: COMPANY_LEGACY_SELECT,
})) as LegacyCompanyRow[]
})
return legacyRows.map(
(row) => ({
@ -174,7 +199,7 @@ export async function safeCompanyFindMany(args: Prisma.CompanyFindManyArgs): Pro
notes: null,
createdAt: row.createdAt,
updatedAt: row.updatedAt,
}) as Company
}) as DbCompany
)
}
}
@ -326,11 +351,20 @@ export function buildCompanyData(payload: CompanyFormValues, tenantId: string):
const communicationChannels = mergeChannelsWithPrimary(payload)
const privacyPolicyMetadata = payload.privacyPolicy?.metadata ?? null
const contactPreferencesPayload =
payload.contactPreferences || payload.supportEmail || payload.billingEmail
? {
...(payload.contactPreferences ?? {}),
supportEmail: payload.supportEmail ?? null,
billingEmail: payload.billingEmail ?? null,
}
: null
const data: CompanyCreatePayload = {
tenantId,
name: payload.name.trim(),
slug: payload.slug.trim(),
provisioningCode: payload.slug.trim(),
isAvulso: payload.isAvulso ?? false,
contractedHoursPerMonth: payload.contractedHoursPerMonth ?? null,
cnpj: payload.cnpj ?? null,
@ -344,40 +378,31 @@ export function buildCompanyData(payload: CompanyFormValues, tenantId: string):
stateRegistrationType,
primaryCnae: payload.primaryCnae ?? null,
timezone: payload.businessHours?.timezone ?? null,
businessHours: payload.businessHours ?? JSON_NULL_VALUE,
businessHours: toJsonInput(payload.businessHours),
supportEmail: payload.supportEmail ?? null,
billingEmail: payload.billingEmail ?? null,
contactPreferences:
payload.contactPreferences || payload.supportEmail || payload.billingEmail
? ({
...payload.contactPreferences,
supportEmail: payload.supportEmail ?? null,
billingEmail: payload.billingEmail ?? null,
} satisfies Prisma.InputJsonValue)
: JSON_NULL_VALUE,
clientDomains: payload.clientDomains,
communicationChannels,
fiscalAddress: payload.fiscalAddress ?? JSON_NULL_VALUE,
contactPreferences: toJsonInput(contactPreferencesPayload),
clientDomains: toJsonInput(payload.clientDomains),
communicationChannels: toJsonInput(communicationChannels),
fiscalAddress: toJsonInput(payload.fiscalAddress),
hasBranches: payload.hasBranches ?? false,
regulatedEnvironments: payload.regulatedEnvironments,
regulatedEnvironments: toJsonInput(payload.regulatedEnvironments),
privacyPolicyAccepted: payload.privacyPolicy?.accepted ?? false,
privacyPolicyReference: payload.privacyPolicy?.reference ?? null,
privacyPolicyMetadata: privacyPolicyMetadata
? (privacyPolicyMetadata as Prisma.InputJsonValue)
: JSON_NULL_VALUE,
contacts: payload.contacts,
locations: payload.locations,
contracts: payload.contracts,
sla: payload.sla ?? JSON_NULL_VALUE,
tags: payload.tags,
customFields: payload.customFields,
privacyPolicyMetadata: toJsonInput(privacyPolicyMetadata),
contacts: toJsonInput(payload.contacts),
locations: toJsonInput(payload.locations),
contracts: toJsonInput(payload.contracts),
sla: toJsonInput(payload.sla),
tags: toJsonInput(payload.tags),
customFields: toJsonInput(payload.customFields),
notes: payload.notes ?? null,
}
return data
}
export function normalizeCompany(company: Company): NormalizedCompany {
export function normalizeCompany(company: DbCompany): NormalizedCompany {
const communicationChannels = normalizeChannels(
company.communicationChannels as CompanyCommunicationChannels | null | undefined
)
@ -413,9 +438,7 @@ export function normalizeCompany(company: Company): NormalizedCompany {
privacyPolicy: {
accepted: Boolean(company.privacyPolicyAccepted),
reference: company.privacyPolicyReference ?? null,
metadata: company.privacyPolicyMetadata
? (company.privacyPolicyMetadata as Record<string, unknown>)
: undefined,
metadata: asJsonRecord(company.privacyPolicyMetadata),
},
contacts: (company.contacts as CompanyFormValues["contacts"]) ?? [],
locations: (company.locations as CompanyFormValues["locations"]) ?? [],
@ -443,14 +466,14 @@ export function normalizeCompany(company: Company): NormalizedCompany {
}
}
export async function fetchCompaniesByTenant(tenantId: string): Promise<Company[]> {
export async function fetchCompaniesByTenant(tenantId: string): Promise<DbCompany[]> {
return safeCompanyFindMany({
where: { tenantId },
orderBy: { name: "asc" },
})
}
export async function fetchCompanyById(id: string): Promise<Company | null> {
export async function fetchCompanyById(id: string): Promise<DbCompany | null> {
const rows = await safeCompanyFindMany({
where: { id },
take: 1,

View file

@ -1,4 +1,4 @@
import type { AuthInvite, AuthInviteEvent } from "@/lib/prisma"
import type { AuthInvite, AuthInviteEvent } from "@/generated/prisma/client"
import { ROLE_OPTIONS, type RoleOption, normalizeRole } from "@/lib/authz"
import { DEFAULT_TENANT_ID } from "@/lib/constants"

View file

@ -1,7 +1,6 @@
"use server"
import type { Prisma } from "@/lib/prisma"
import type { Prisma as PrismaTypes } from "@/generated/prisma/client"
import { prisma } from "@/lib/prisma"
import { env } from "@/lib/env"
import { sendSmtpMail } from "@/server/email-smtp"
@ -62,7 +61,7 @@ export async function runReportSchedules(
): Promise<RunReportSchedulesResult> {
const now = options.now ?? new Date()
const where: Prisma.ReportExportScheduleWhereInput = {
const where: PrismaTypes.ReportExportScheduleWhereInput = {
status: "ACTIVE",
}
if (options.tenantId) {

View file

@ -1,7 +1,7 @@
import "server-only"
import { addMonths, addWeeks, isBefore } from "date-fns"
import type { ReportExportRun, ReportExportSchedule } from "@/lib/prisma"
import type { ReportExportRun, ReportExportSchedule } from "@/generated/prisma/client"
import { REPORT_EXPORT_DEFINITIONS, type ReportExportKey } from "@/lib/report-definitions"
type SerializableSchedule = ReportExportSchedule & {