Skip to content

Commit

Permalink
🐞 fix: use more precise nullable & undefined types
Browse files Browse the repository at this point in the history
  • Loading branch information
m1212e committed Mar 29, 2024
1 parent 7acb6f3 commit 76d7f4e
Show file tree
Hide file tree
Showing 9 changed files with 301 additions and 59 deletions.
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@
"@sinclair/typebox": "^0.32.15"
},
"scripts": {
"dev": "bun build.ts && bunx prisma generate && bun playground/main.ts",
"build": "bun build.ts"
"dev": "bun run build && bunx prisma generate",
"build": "bun run typecheck && bun build.ts",
"typecheck": "tsc --noEmit"
}
}
4 changes: 0 additions & 4 deletions playground/main.ts

This file was deleted.

288 changes: 255 additions & 33 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -12,50 +12,272 @@ generator prismabox {
dataModel = true
}

/// The user model

model Password {
id String @id @default(uuid())
user User @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade)
userId String
/// @prismabox.hide
passwordHash String
}

model Token {
id String @id @default(uuid())
/// @prismabox.hide
tokenHash String
expiresAt DateTime
pendingEmailConfirmations Email[]
pendingCredentialCreations PendingCredentialCreateTask[]
}

model PendingCredentialCreateTask {
id String @id @default(uuid())
user User @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade)
userId String
token Token @relation(fields: [tokenId], references: [id], onDelete: Cascade, onUpdate: Cascade)
tokenId String
}

model Email {
email String @id
user User @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade)
userId String
validated Boolean @default(false)
validationToken Token? @relation(fields: [validationTokenId], references: [id])
validationTokenId String?
@@unique([userId, email])
}

/// A user in the system
model User {
id Int @id @default(autoincrement())
name String? @unique
title String
subtitle String
misc String @unique
id String @id @default(uuid())
name String
conferenceMemberships ConferenceMember[]
committeeMemberships CommitteeMember[]
messages Message[]
emails Email[]
passwords Password[]
pendingCredentialCreationTasks PendingCredentialCreateTask[]
}

/// Consumeable token which grants the creation of a conference
model ConferenceCreateToken {
token String @id
}

/// A conference in the system
model Conference {
id String @id @default(uuid())
name String @unique
committees Committee[]
start DateTime?
end DateTime?
delegations Delegation[]
members ConferenceMember[]
}

/// The role of a user in a conference
enum ConferenceRole {
ADMIN
SECRETARIAT
CHAIR
COMMITTEE_ADVISOR
NON_STATE_ACTOR
PRESS_CORPS
GUEST
PARTICIPANT_CARE
MISCELLANEOUS_TEAM
}

/// A user's membership in a conference, providing them with a role in the conference
model ConferenceMember {
id String @id @default(uuid())
conference Conference @relation(fields: [conferenceId], references: [id])
conferenceId String
user User? @relation(fields: [userId], references: [id])
userId String?
role ConferenceRole
@@unique([userId, conferenceId])
}

/// @prismabox.hidden
type Account
age Int
/// The type of a committee in a conference
enum CommitteeCategory {
/// A standard committee
COMMITTEE
/// A crisis simulation
CRISIS
/// A International Court of Justice simulation
ICJ
}

enum CommitteeStatus {
FORMAL
INFORMAL
PAUSE
SUSPENSION
CLOSED /// Don't display a Widget
}

/// A committee in a conference
model Committee {
id String @id @default(uuid())
name String
abbreviation String
category CommitteeCategory
conference Conference @relation(fields: [conferenceId], references: [id])
conferenceId String
members CommitteeMember[]
parent Committee? @relation("subCommittee", fields: [parentId], references: [id])
parentId String?
subCommittees Committee[] @relation("subCommittee")
messages Message[]
agendaItems AgendaItem[]
whiteboardContent String @default("<h1>Hello, World</h1>")
status CommitteeStatus @default(CLOSED)
stateOfDebate String?
statusHeadline String?
statusUntil DateTime?
allowDelegationsToAddThemselvesToSpeakersList Boolean @default(false)
@@unique([name, conferenceId])
@@unique([abbreviation, conferenceId])
}

posts Post[]
/// The presence status of a CommitteeMember
enum Presence {
PRESENT
EXCUSED
ABSENT
}

/// A user's membership in a committee, providing them with a role in the committee
model CommitteeMember {
id String @id @default(uuid())
committee Committee @relation(fields: [committeeId], references: [id])
committeeId String
user User? @relation(fields: [userId], references: [id])
userId String?
speakerLists SpeakerOnList[]
delegation Delegation? @relation(fields: [delegationId], references: [id])
delegationId String?
presence Presence @default(ABSENT)
@@unique([title, subtitle])
@@unique([committeeId, delegationId])
@@unique([committeeId, userId])
}

/// The post model
model Post {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
User User? @relation(fields: [userId], references: [id])
/// @prismabox.options{max: 10}
/// this is the user id
userId Int?
/// An agenda item in a committee. This is a topic of discussion in a committee.
model AgendaItem {
id String @id @default(uuid())
committee Committee @relation(fields: [committeeId], references: [id])
committeeId String
title String
description String?
speakerLists SpeakersList[]
isActive Boolean @default(false)
}

status Status
status2 Status?
/// The type of a speakers list
enum SpeakersListCategory {
/// A standard speakers list
SPEAKERS_LIST
/// A comment list
COMMENT_LIST
/// A moderated caucus
MODERATED_CAUCUS
}

blah String
blah2 String?
/// A speakers list in a committee
model SpeakersList {
id String @id @default(uuid())
agendaItem AgendaItem @relation(fields: [agendaItemId], references: [id])
agendaItemId String
type SpeakersListCategory
speakers SpeakerOnList[]
/// The time in seconds that a speaker has to speak
speakingTime Int
timeLeft Int?
startTimestamp DateTime?
isClosed Boolean @default(false)
successorId Int? @unique
successor Post? @relation("history", fields: [successorId], references: [id])
predecessor Post? @relation("history")
@@unique([agendaItemId, type])
}

/// @prismabox.hidden
enum Account {
PASSKEY
PASSWORD
/// A speaker on a speakers list, storing their position in the list
model SpeakerOnList {
id String @id @default(uuid())
speakersList SpeakersList @relation(fields: [speakersListId], references: [id])
speakersListId String
committeeMember CommitteeMember @relation(fields: [committeeMemberId], references: [id])
committeeMemberId String
position Int
@@unique([speakersListId, position])
@@unique([speakersListId, committeeMemberId])
}

enum Status {
ENABLED
DISABLED
model Delegation {
id String @id @default(uuid())
conference Conference @relation(fields: [conferenceId], references: [id])
conferenceId String
nation Nation @relation(fields: [nationId], references: [id])
nationId String
members CommitteeMember[]
@@unique([conferenceId, nationId])
}

enum NationVariant {
NATION
NON_STATE_ACTOR
SPECIAL_PERSON
}

/// A nation in the system. E.g. Germany
model Nation {
id String @id @default(uuid())
alpha3Code String @unique
variant NationVariant @default(NATION)
delegations Delegation[]
}

enum MessageCategory {
TO_CHAIR
GUEST_SPEAKER
FACT_CHECK
INFORMATION
GENERAL_SECRETARY
OTHER
}

enum MessageStatus {
UNREAD
PRIORITY
ASSIGNED
ARCHIVED
}

model Message {
id String @id @default(uuid())
subject String
category MessageCategory @default(TO_CHAIR)
message String
committee Committee @relation(fields: [committeeId], references: [id])
committeeId String
author User @relation(fields: [authorId], references: [id])
authorId String
timestamp DateTime
status MessageStatus[] @default([UNREAD])
forwarded Boolean @default(false) /// If the message was forwarded to the Research Service
/// Saved Metadata without relation
metaEmail String?
metaDelegation String?
metaCommittee String?
metaAgendaItem String?
}
6 changes: 3 additions & 3 deletions src/generator/dataModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import type { DMMF } from "@prisma/generator-helper";
import { typeboxImportVariableName } from "./typeboxImport";
import { Annotation, parseDocumentation } from "./documentation";
import {
NullableVariant,
PrimitiveField,
isPrimitivePrismaFieldType,
} from "./plainModel";
import type { Models } from "../util/modelMap";
import { RelationField } from "./relationModel";
import { NullableVariant } from "./nullable";

let enabled = false;
export function enableDataModel() {
Expand Down Expand Up @@ -65,7 +65,7 @@ function internal(
? optional
? NullableVariant.OPTIONAL
: NullableVariant.REQUIRED
: NullableVariant.NULLABLE,
: NullableVariant.OPTIONAL_NULLABLE,
options: doc.options,
referenceableModels: referenceableEnums,
});
Expand Down Expand Up @@ -103,7 +103,7 @@ function internal(
? optional
? NullableVariant.OPTIONAL
: NullableVariant.REQUIRED
: NullableVariant.NULLABLE,
: NullableVariant.OPTIONAL_NULLABLE,
options: parseDocumentation(field.documentation).options,
});
})
Expand Down
11 changes: 9 additions & 2 deletions src/generator/nullable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,18 @@ import {
typeboxImportVariableName,
} from "./typeboxImport";

export enum NullableVariant {
NULLABLE = 0, // null or the value
OPTIONAL = 1, // undefined or the value
REQUIRED = 2, // the value
OPTIONAL_NULLABLE = 3, // null, undefined or the value
}

export const nullableVariableName = "Nullable";

export function Nullable() {
export function NullableType() {
return `import { ${typeboxImportVariableName}, type TSchema } from "${typeboxImportDependencyName}"
export const ${nullableVariableName} = <T extends TSchema>(schema: T) => ${typeboxImportVariableName}.Union([${typeboxImportVariableName}.Null(), ${typeboxImportVariableName}.Undefined(), schema])\n`;
export const ${nullableVariableName} = <T extends TSchema>(schema: T) => ${typeboxImportVariableName}.Union([${typeboxImportVariableName}.Null(), schema])\n`;
}

export function NullableImport() {
Expand Down
Loading

0 comments on commit 76d7f4e

Please sign in to comment.