✨ 24th November 2021
The Release Candidate for Keystone 6 General Availability has arrived! Within you'll find numerous improvements across the project. ⭐️
After this release, we will be moving Keystone 6 to General Availability and promoting the project to the @keystone-6
namespace on npm.
We highly recommend you upgrade to this release:
"@keystone-next/auth": "37.0.0",
"@keystone-next/cloudinary": "12.0.0",
"@keystone-next/document-renderer": "5.0.0",
"@keystone-next/fields-document": "14.0.0",
"@keystone-next/keystone": "29.0.0",
"@keystone-next/session-store-redis": "9.0.0",
Shorter Relationship Names 🤏
Warning:
⚠️ Breaking change! Please follow the guidance below to avoid losing data.
The names of one-sided and two-sided, many-many relationships has been shortened. Two-sided many-many relationship names contain only the left-hand side names now; and the _many
suffix has been dropped from one-sided many-many relationships.
This reduces the probability that you will exceed PostgreSQL's 63 character limit for identifiers with typical usage.
There are two different ways you can update your schema:
-
Explicitly set the
db.relationName
on many-to-many relations, allowing your database to remain unchanged. -
Rename your many-to-many relations and tables using a migration, changing your database.
Set db.relationName
on many to many relations
Rather than doing a migration, you can set the new field property db.relationName
, for either side of a many-to-many relationship field.
If set to the existing relation name, your database will remain unchanged.
For example, given a schema like this:
Post: list({
fields: {
tags: relationship({ ref: 'Tag.posts', many: true }),
},
}),
Tag: list({
fields: {
posts: relationship({ ref: 'Post.tags', many: true }),
},
}),
Before this release, the generated Prisma schema looked like this:
// This file is automatically generated by Keystone, do not modify it manually.
// Modify your Keystone config when you want to change this.
datasource postgresql {
url = env("DATABASE_URL")
provider = "postgresql"
}
generator client {
provider = "prisma-client-js"
output = "node_modules/.prisma/client"
engineType = "binary"
}
model Post {
id String @id @default(cuid())
tags Tag[] @relation("Post_tags_Tag_posts")
}
model Tag {
id String @id @default(cuid())
posts Post[] @relation("Post_tags_Tag_posts")
}
By adding db: { relationName: 'Post_tags_Tag_posts' }
to one side of the many-to-many relationship; you can preclude yourself from a migration.
Note: It doesn't matter which side of the relationship you put this property, but it should be only on one side; otherwise you will receive an error.
Post: list({
fields: {
tags: relationship({ ref: 'Tag.posts', many: true, db: { relationName: 'Post_tags_Tag_posts' } }),
},
}),
Tag: list({
fields: {
posts: relationship({ ref: 'Post.tags', many: true }),
},
}),
Rename your many relation tables using a migration
For example, given a schema like this:
Post: list({
fields: {
tags: relationship({ ref: 'Tag.posts', many: true }),
},
}),
Tag: list({
fields: {
posts: relationship({ ref: 'Post.tags', many: true }),
},
}),
When updating to this change, and running yarn dev
, Keystone will prompt you to update your schema.
Warning:
⚠️ Warning: DO NOT APPLY THE AUTOMATICALLY GENERATED MIGRATION!
You will lose your data. Only apply the migration if you want toDROP
your data.
If using useMigrations: true
, Keystone will follow the typical migration flow and offer to apply an automatically generated migration.
If using useMigrations: false
, Keystone will follow the typical flow and offer to automatically migrate your schema.
On PostgreSQL, Prisma will generate a migration that looks something like this:
/*
Warnings:
- You are about to drop the `_Post_tags_Tag_posts` table. If the table is not empty, all the data it contains will be lost.
*/
-- DropForeignKey
ALTER TABLE "_Post_tags_Tag_posts" DROP CONSTRAINT "_Post_tags_Tag_posts_A_fkey";
-- DropForeignKey
ALTER TABLE "_Post_tags_Tag_posts" DROP CONSTRAINT "_Post_tags_Tag_posts_B_fkey";
-- DropTable
DROP TABLE "_Post_tags_Tag_posts";
-- CreateTable
CREATE TABLE "_Post_tags" (
"A" TEXT NOT NULL,
"B" TEXT NOT NULL
);
-- CreateIndex
CREATE UNIQUE INDEX "_Post_tags_AB_unique" ON "_Post_tags"("A", "B");
-- CreateIndex
CREATE INDEX "_Post_tags_B_index" ON "_Post_tags"("B");
-- AddForeignKey
ALTER TABLE "_Post_tags" ADD FOREIGN KEY ("A") REFERENCES "Post"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "_Post_tags" ADD FOREIGN KEY ("B") REFERENCES "Tag"("id") ON DELETE CASCADE ON UPDATE CASCADE;
You need to modify it so that it looks like this with the old and new table names for your schema substituted:
ALTER TABLE "_Post_tags_Tag_posts" RENAME TO "_Post_tags";
ALTER INDEX "_Post_tags_Tag_posts_AB_unique" RENAME TO "_Post_tags_AB_unique";
ALTER INDEX "_Post_tags_Tag_posts_B_index" RENAME TO "_Post_tags_B_index";
ALTER TABLE "_Post_tags" RENAME CONSTRAINT "_Post_tags_Tag_posts_A_fkey" TO "_Post_tags_A_fkey";
ALTER TABLE "_Post_tags" RENAME CONSTRAINT "_Post_tags_Tag_posts_B_fkey" TO "_Post_tags_B_fkey";
On SQLite, Prisma will generate a migration that looks something like this:
/*
Warnings:
- You are about to drop the `_Post_tags_Tag_posts` table. If the table is not empty, all the data it contains will be lost.
*/
-- DropTable
PRAGMA foreign_keys=off;
DROP TABLE "_Post_tags_Tag_posts";
PRAGMA foreign_keys=on;
-- CreateTable
CREATE TABLE "_Post_tags" (
"A" TEXT NOT NULL,
"B" TEXT NOT NULL,
FOREIGN KEY ("A") REFERENCES "Post" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
FOREIGN KEY ("B") REFERENCES "Tag" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
-- CreateIndex
CREATE UNIQUE INDEX "_Post_tags_AB_unique" ON "_Post_tags"("A", "B");
-- CreateIndex
CREATE INDEX "_Post_tags_B_index" ON "_Post_tags"("B");
You need to modify it so that it looks like this with the old and new table names for your schema substituted:
ALTER TABLE "_Post_tags_Tag_posts" RENAME TO "_Post_tags";
DROP INDEX "_Post_tags_Tag_posts_AB_unique";
DROP INDEX "_Post_tags_Tag_posts_B_index";
CREATE UNIQUE INDEX "_Post_tags_AB_unique" ON "_Post_tags"("A", "B");
CREATE INDEX "_Post_tags_B_index" ON "_Post_tags"("B");
Query Engine Switch 🚂
Keystone now uses Prisma's Node-API Query Engine instead of the Binary Query Engine. This should improve the performance of operations using Prisma.
From our initial testing, performance has increased significantly when getting large amounts of data and is marginally better for smaller amounts.
See the Prisma docs for more details.
Node Engines 💽
Keystone officially supports running on LTS versions of Node.js - this is currently version 14 and 16. We've updated our engine values throughout the project to reflect this.
Note: We recommend you run Node.js
^14.15
or^16.13
for the best Keystone experience.
Miscellaneous Fixes ⚙️
-
Fixed the init/sign in page showing for a short amount of time after submitting on the init/sign in page and seeing a loading spinner.
-
Fixed clear button not removing inline relationships when used in the document field.
-
Relationship field now respects
ui.displayMode: 'cards'
in the create view. -
The
Set as Authenticated Item
/Add Authenticated Item
button is now hidden if the relationship field already has the authenticated item. -
Fixed
ui.isAccessAllowed
not being respected in the admin meta query when no session strategy was defined. -
The item page in the Admin UI no longer crashes when failing to fetch an item.
-
The admin meta query now bypasses
ui.isAccessAllowed
for sudo contexts. -
Fixed doing multiple writes at the same time on SQLite causing an timeout immediately.
Credits 💫
-
Thanks to gregpalaci, vicaia, jakegiri davebeauchemin, Temkit, and bkbooth for reporting bugs that were fixed in this release!
-
Fixed default renderer of
layout
block in<DocumentRenderer />
. Thanks @datner!
Like this release? Give us a star on GitHub!
Changelog
You can view the verbose changelog in the related PR (#6943) for this release.