This commit is contained in:
sam 2023-07-20 18:00:46 +02:00
commit dfcb6667ed
Signed by: sam
GPG key ID: B4EF20DDE721CAA1
16 changed files with 2453 additions and 0 deletions

11
src/config.ts Normal file
View file

@ -0,0 +1,11 @@
import { config as dotenv } from "dotenv";
dotenv();
export const PORT = Number(process.env.PORT) || 3000;
export const DATABASE_HOST = process.env.DATABASE_HOST || "localhost";
export const DATABASE_PORT = Number(process.env.DATABASE_PORT) || 5432;
export const DATABASE_USER = process.env.DATABASE_USER || "postgres";
export const DATABASE_PASS = process.env.DATABASE_PASS || "postgres";
export const DATABASE_NAME = process.env.DATABASE_NAME || "postgres";

View file

@ -0,0 +1,21 @@
import { Entity, Column, PrimaryColumn, Index, OneToMany } from "typeorm";
import { Blog } from "./blog.js";
@Entity()
@Index(["username", "host"], { unique: true })
export class Account {
@PrimaryColumn("text")
id: string;
@Column("text", { nullable: false })
username: string;
@Column("text", { nullable: true })
host: string | null;
@Column("text", { nullable: true, unique: true })
email: string | null;
@Column("text", { nullable: true })
password: string | null;
@OneToMany(() => Blog, (blog) => blog.account)
blogs: Blog[];
}

31
src/db/entities/blog.ts Normal file
View file

@ -0,0 +1,31 @@
import {
Entity,
Column,
PrimaryColumn,
Index,
ManyToOne,
OneToMany,
} from "typeorm";
import { Account } from "./account.js";
import { Post } from "./post.js";
@Entity()
@Index(["username", "host"], { unique: true })
export class Blog {
@PrimaryColumn("text")
id: string;
@Column("text", { nullable: false })
username: string;
@Column("text", { nullable: true })
host: string | null;
@ManyToOne(() => Account, (account) => account.blogs)
account: Account;
@OneToMany(() => Post, (post) => post.blog)
posts: Post[];
@Column("text", { nullable: false })
publicKey: string;
@Column("text", { nullable: true })
privateKey: string | null;
}

15
src/db/entities/post.ts Normal file
View file

@ -0,0 +1,15 @@
import { Entity, Column, PrimaryColumn, ManyToOne } from "typeorm";
import { Blog } from "./blog.js";
@Entity()
export class Post {
@PrimaryColumn("text")
id: string;
@Column("text", { nullable: true })
content: string | null;
@Column("text", { nullable: true })
contentType: string | null;
@ManyToOne(() => Blog, (blog) => blog.posts)
blog: Blog;
}

20
src/db/index.ts Normal file
View file

@ -0,0 +1,20 @@
import { DataSource } from "typeorm";
import * as config from "../config.js";
// Entity types
import { Account } from "./entities/account.js";
import { Blog } from "./entities/blog.js";
import { Post } from "./entities/post.js";
const MercuryDataSource = new DataSource({
type: "postgres",
host: config.DATABASE_HOST,
port: config.DATABASE_PORT,
username: config.DATABASE_USER,
password: config.DATABASE_PASS,
database: config.DATABASE_NAME,
entities: [Account, Blog, Post],
migrations: ["src/db/migrations/*.js"],
});
export default MercuryDataSource;

View file

@ -0,0 +1,76 @@
export class Init1689867206797 {
name = 'Init1689867206797'
async up(queryRunner) {
await queryRunner.query(`
CREATE TABLE "post" (
"id" text NOT NULL,
"content" text,
"contentType" text,
"blogId" text,
CONSTRAINT "PK_be5fda3aac270b134ff9c21cdee" PRIMARY KEY ("id")
)
`);
await queryRunner.query(`
CREATE TABLE "blog" (
"id" text NOT NULL,
"username" text NOT NULL,
"host" text,
"publicKey" text NOT NULL,
"privateKey" text,
"accountId" text,
CONSTRAINT "PK_85c6532ad065a448e9de7638571" PRIMARY KEY ("id")
)
`);
await queryRunner.query(`
CREATE UNIQUE INDEX "IDX_20609d68760ccd572e82155a84" ON "blog" ("username", "host")
`);
await queryRunner.query(`
CREATE TABLE "account" (
"id" text NOT NULL,
"username" text NOT NULL,
"host" text,
"email" text,
"password" text,
CONSTRAINT "UQ_4c8f96ccf523e9a3faefd5bdd4c" UNIQUE ("email"),
CONSTRAINT "PK_54115ee388cdb6d86bb4bf5b2ea" PRIMARY KEY ("id")
)
`);
await queryRunner.query(`
CREATE UNIQUE INDEX "IDX_0d4f7bfab65220a2aac213407b" ON "account" ("username", "host")
`);
await queryRunner.query(`
ALTER TABLE "post"
ADD CONSTRAINT "FK_d0418ddc42c5707dbc37b05bef9" FOREIGN KEY ("blogId") REFERENCES "blog"("id") ON DELETE NO ACTION ON UPDATE NO ACTION
`);
await queryRunner.query(`
ALTER TABLE "blog"
ADD CONSTRAINT "FK_9dd44887bd917f9ee76aff90a02" FOREIGN KEY ("accountId") REFERENCES "account"("id") ON DELETE NO ACTION ON UPDATE NO ACTION
`);
}
async down(queryRunner) {
await queryRunner.query(`
ALTER TABLE "blog" DROP CONSTRAINT "FK_9dd44887bd917f9ee76aff90a02"
`);
await queryRunner.query(`
ALTER TABLE "post" DROP CONSTRAINT "FK_d0418ddc42c5707dbc37b05bef9"
`);
await queryRunner.query(`
DROP INDEX "public"."IDX_0d4f7bfab65220a2aac213407b"
`);
await queryRunner.query(`
DROP TABLE "account"
`);
await queryRunner.query(`
DROP INDEX "public"."IDX_20609d68760ccd572e82155a84"
`);
await queryRunner.query(`
DROP TABLE "blog"
`);
await queryRunner.query(`
DROP TABLE "post"
`);
}
}

3
src/index.ts Normal file
View file

@ -0,0 +1,3 @@
import start from "./start.js";
start();

5
src/log.ts Normal file
View file

@ -0,0 +1,5 @@
import { Logger, ILogObj } from "tslog";
const log: Logger<ILogObj> = new Logger();
export default log;

33
src/start.ts Normal file
View file

@ -0,0 +1,33 @@
import "reflect-metadata"; // Required for TypeORM
import express from "express";
import MercuryDataSource from "./db/index.js";
import log from "./log.js";
import { Blog } from "./db/entities/blog.js";
import { PORT } from "./config.js";
export default async function start() {
log.info("Initializing database");
await MercuryDataSource.initialize();
const pendingMigrations = await MercuryDataSource.showMigrations();
if (pendingMigrations) {
log.error(
"There are pending migrations, please run these with `pnpm migrate`."
);
return;
}
log.debug("Setting up routes")
const app = express();
app.get("/", async (_, res) => {
const blogRepository = MercuryDataSource.getRepository(Blog);
const resp = await blogRepository.find();
return res.json(resp)
})
log.info("Listening on port %d", PORT)
app.listen(PORT);
}