2022-01-07
CRUD
Can this be automated and maintainable at the same time?
I was testing Blitz.js today and it’s almost good but they don’t try hard enough, so I think I could create something like this myself. Wanted this since I left Rails ecosystem.
How to build application?
Schema design DSL
Let’s assume simple forum website. I would like to just specify this and get plumbing done.
Post belongsTo:user ?url? title ?body:text ?score:int:0
Comment belongsTo:post belongsTo:user body -by ?parentId:int:0 -parentPath:text:"" The ? before name would mean that it’s optional when inputing and ? would mean it’s optional when commiting. - would mean it’s not required when inputing (will define before commiting).
Default would be required (I fixed enough data integrity issues in my lifetime).
[
{
"modelName": "Post",
"fields": [
{
"name": "url",
"input": {
"ignore": false,
"isOptional": true
},
"commit": {
"isOptional": true
},
"type": "text"
},
{
"name": "title",
"input": {
"ignore": false,
"isOptional": false
},
"commit": {
"isOptional": false
},
"type": "text"
},
{
"name": "body",
"input": {
"ignore": false,
"isOptional": true
},
"commit": {
"isOptional": false
},
"type": "text"
},
{
"name": "score",
"input": {
"ignore": false,
"isOptional": true
},
"commit": {
"isOptional": false
},
"type": "int",
"defaultValue": 0
}
]
},
{
"modelName": "Comment",
"fields": [
{
"name": "body",
"input": {
"ignore": false,
"isOptional": false
},
"commit": {
"isOptional": false
},
"type": "text"
},
{
"name": "by",
"input": {
"ignore": true,
"isOptional": false
},
"commit": {
"isOptional": false
},
"type": "text"
},
{
"name": "parentId",
"input": {
"ignore": false,
"isOptional": true
},
"commit": {
"isOptional": false
},
"type": "int",
"defaultValue": 0
},
{
"name": "parentPath",
"input": {
"ignore": true,
"isOptional": false
},
"commit": {
"isOptional": false
},
"type": "text",
"defaultValue": ""
}
]
}
] Generate schema design
Given spec above, how do we generate schema file? Ezzz
CREATE TABLE IF NOT EXISTS post (
postId int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
url TEXT,
title TEXT NOT NULL,
body TEXT NOT NULL,
score INT NOT NULL
);
CREATE TABLE IF NOT EXISTS comment (
commentId int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
body TEXT NOT NULL,
by TEXT NOT NULL,
parentId INT NOT NULL,
parentPath TEXT NOT NULL
); Run DB
docker run -p 5432:5432 --name db_name -e POSTGRES_PASSWORD=mysecretpassword -d postgres
Add schema
docker exec -it db_name psql -U postgres
Generate backend
Gonna use https://www.graphile.org/postgraphile/
npx postgraphile -c 'postgres://postgres:mysecretpassword@localhost:5432/postgres' --watch
Write frontend
Use Next.js with https://gqty.dev/docs/getting-started and Tailwind(twin.macro?)
npx create-next-app@latest --typescript
npm install gqty graphql
npm install -D @gqty/cli
npm install @gqty/react
npx gqty generate In next.config.js:
/** @type {import('next').NextConfig} */
module.exports = {
reactStrictMode: true,
async rewrites() {
return [
{
source: '/api/graphql',
destination: 'http://localhost:5000/graphql' // Proxy to Postgraphile
}
]
}
} Voila!
To handle forms one can use https://react-hook-form.com/
Alternative good client for more SPA style - https://react-query.tanstack.com/