Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(referentialActions): add relationOnDelete #16

Merged
merged 3 commits into from
Sep 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
node_modules
dist
prisma/dev.sqlite
prisma/dev.db*
.env
33 changes: 33 additions & 0 deletions __tests__/dbml.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
datamodelDbmlManyToManyInvalid,
datamodelDbmlManyToManyRenameRelation,
datamodelDbmlManyToManySelfRelation,
datamodelDbmlReferentialActions,
datamodelDbmlRelations,
} from './fixtures/dbml.datamodel';
import { generateDMMF } from './utils/generateDMMF';
Expand Down Expand Up @@ -301,4 +302,36 @@ Table userReceivesPosts {

expect(dbml).toEqual(expectedDbml);
});

test('generating dbml schema with referential actions', async () => {
const dmmf = await generateDMMF(datamodelDbmlReferentialActions);

const expectedDbml = `${autoGeneratedComment}

Table User {
id Int [pk, increment]
profile Profile
posts Post [not null]
}

Table Profile {
id Int [pk, increment]
user User [not null]
userId Int [unique, not null]
}

Table Post {
id Int [pk, increment]
author User
authorId Int
}

Ref: Profile.userId - User.id [delete: Cascade]

Ref: Post.authorId > User.id [delete: SetNull]`;

const dbml = generateDBMLSchema(dmmf);

expect(dbml).toEqual(expectedDbml);
});
});
18 changes: 18 additions & 0 deletions __tests__/fixtures/dbml.datamodel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,21 @@ export const datamodelDbmlManyToManyRenameRelation = /* Prisma */ `
receivedBy User[] @relation("userReceivesPosts")
}
`;

export const datamodelDbmlReferentialActions = /* Prisma */ `
model User {
id Int @id @default(autoincrement())
profile Profile?
posts Post[]
}
model Profile {
id Int @id @default(autoincrement())
user User @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade)
userId Int @unique
}
model Post {
id Int @id @default(autoincrement())
author User? @relation(fields: [authorId], references: [id], onDelete: SetNull, onUpdate: Cascade)
authorId Int?
}
`;
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 2 additions & 8 deletions prisma/dbml/schema.dbml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ Table User {
name String
posts Post [not null]
profile Profile
role Role [not null, default: 'USER', note: 'user\'s role']
}

Table Profile {
Expand Down Expand Up @@ -53,11 +52,6 @@ Table CategoryToPost {
postsId Int [ref: > Post.id]
}

Enum Role {
ADMIN
USER
}

Ref: Profile.userId - User.id
Ref: Profile.userId - User.id [delete: Cascade]

Ref: Post.authorId > User.id
Ref: Post.authorId > User.id [delete: SetNull]
84 changes: 0 additions & 84 deletions prisma/migrations/20210121125958_init/migration.sql

This file was deleted.

62 changes: 62 additions & 0 deletions prisma/migrations/20210729110945_init/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
-- CreateTable
CREATE TABLE "User" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
"email" TEXT NOT NULL,
"name" TEXT
);

-- CreateTable
CREATE TABLE "Profile" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"bio" TEXT,
"userId" INTEGER NOT NULL,
FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);

-- CreateTable
CREATE TABLE "Post" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"title" TEXT NOT NULL DEFAULT '',
"content" TEXT,
"published" BOOLEAN NOT NULL DEFAULT false,
"authorId" INTEGER,
FOREIGN KEY ("authorId") REFERENCES "User" ("id") ON DELETE SET NULL ON UPDATE CASCADE
);

-- CreateTable
CREATE TABLE "Category" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"name" TEXT NOT NULL
);

-- CreateTable
CREATE TABLE "Token" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"device" TEXT NOT NULL,
"operatingSystem" TEXT NOT NULL
);

-- CreateTable
CREATE TABLE "_CategoryToPost" (
"A" INTEGER NOT NULL,
"B" INTEGER NOT NULL,
FOREIGN KEY ("A") REFERENCES "Category" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
FOREIGN KEY ("B") REFERENCES "Post" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);

-- CreateIndex
CREATE UNIQUE INDEX "User.email_unique" ON "User"("email");

-- CreateIndex
CREATE UNIQUE INDEX "Profile.userId_unique" ON "Profile"("userId");

-- CreateIndex
CREATE UNIQUE INDEX "Token.device_operatingSystem_unique" ON "Token"("device", "operatingSystem");

-- CreateIndex
CREATE UNIQUE INDEX "_CategoryToPost_AB_unique" ON "_CategoryToPost"("A", "B");

-- CreateIndex
CREATE INDEX "_CategoryToPost_B_index" ON "_CategoryToPost"("B");
3 changes: 2 additions & 1 deletion prisma/migrations/migration_lock.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
# Please do not edit this file manually
provider = "postgresql"
# It should be added in your version-control system (i.e. Git)
provider = "sqlite"
18 changes: 5 additions & 13 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
// learn more about it in the docs: https://pris.ly/d/prisma-schema

datasource db {
provider = "postgres"
url = env("POSTGRESQL_URL")
provider = "sqlite"
url = env("DATABASE_URL")
}

generator client {
provider = "prisma-client-js"
provider = "prisma-client-js"
}

generator dbml {
Expand All @@ -22,15 +22,13 @@ model User {
name String?
posts Post[]
profile Profile?
/// user's role
role Role @default(USER)
}

/// User profile
model Profile {
id Int @id @default(autoincrement())
bio String?
user User @relation(fields: [userId], references: [id])
user User @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade)
userId Int @unique
}

Expand All @@ -39,7 +37,7 @@ model Post {
title String @default("")
content String?
published Boolean @default(false)
author User? @relation(fields: [authorId], references: [id])
author User? @relation(fields: [authorId], references: [id], onDelete: SetNull)
authorId Int?
categories Category[]
}
Expand All @@ -57,9 +55,3 @@ model Token {

@@unique([device, operatingSystem])
}

/// user role
enum Role {
ADMIN /// allowed to do everything
USER
}
37 changes: 31 additions & 6 deletions src/generator/relations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,19 @@ export function generateRelations(models: DMMF.Model[]): string[] {
relationTo
);

refs.push(
`Ref: ${relationFrom}.${combineKeys(
field.relationFromFields!
)} ${relationOperator} ${relationTo}.${combineKeys(
field.relationToFields!!
)}`
const ref = `Ref: ${relationFrom}.${combineKeys(
field.relationFromFields!
)} ${relationOperator} ${relationTo}.${combineKeys(
field.relationToFields!!
)}`;

const referentialActions = getReferentialActions(
models,
relationFrom,
relationTo
);

refs.push(`${ref}${referentialActions}`);
});
});
return refs;
Expand All @@ -51,3 +57,22 @@ const getRelationOperator = (
const combineKeys = (keys: string[]): string => {
return keys.length > 1 ? `(${keys.join(', ')})` : keys[0];
};

const getReferentialActions = (
models: DMMF.Model[],
from: string,
to: string
): string => {
const model = models.find((model) => model.name === from);
const field = model?.fields.find((field) => field.type === to);
const referentialActions: string[] = [];

if (field?.relationOnDelete) {
referentialActions.push(`delete: ${field.relationOnDelete}`);
}

if (referentialActions.length) {
return ' [' + referentialActions.join(', ') + ']';
}
return '';
};