start DI
All checks were successful
ci/woodpecker/push/build Pipeline was successful
ci/woodpecker/push/lint Pipeline was successful
ci/woodpecker/push/test/1 Pipeline was successful
ci/woodpecker/push/test/2 Pipeline was successful
ci/woodpecker/push/test/3 Pipeline was successful

This commit is contained in:
qpismont 2024-12-30 21:29:16 +00:00
parent da035bf5c4
commit 7377bd3538
14 changed files with 76 additions and 4 deletions

BIN
bun.lockb

Binary file not shown.

View file

@ -0,0 +1,11 @@
CREATE TABLE IF NOT EXISTS public.accounts
(
id integer NOT NULL GENERATED ALWAYS AS IDENTITY,
username text NOT NULL,
password text NOT NULL,
role_id smallint NOT NULL DEFAULT '1'::smallint,
created_at timestamp without time zone NOT NULL DEFAULT now(),
updated_at timestamp without time zone NOT NULL DEFAULT now(),
CONSTRAINT accounts_pkey PRIMARY KEY (id),
CONSTRAINT accounts_username_key UNIQUE (username)
);

View file

@ -0,0 +1,15 @@
-- Add migration script here
CREATE TABLE IF NOT EXISTS public.movies
(
id integer NOT NULL GENERATED ALWAYS AS IDENTITY,
title text NOT NULL,
overview text NOT NULL,
poster_path text NOT NULL,
backdrop_path text,
release_date date NOT NULL,
tmdb_id integer NOT NULL,
created_at timestamp without time zone NOT NULL DEFAULT now(),
updated_at timestamp without time zone NOT NULL DEFAULT now(),
PRIMARY KEY (id)
);

View file

@ -16,7 +16,10 @@
"typescript": "^5.6.2"
},
"dependencies": {
"fastify": "^5.2.0",
"hono": "^4.6.15",
"pg": "^8.13.1"
"inversify": "^6.2.1",
"pg": "^8.13.1",
"reflect-metadata": "^0.2.2"
}
}

View file

@ -0,0 +1,4 @@
import { injectable } from "inversify";
@injectable()
export default class AccountsController {}

View file

@ -0,0 +1,7 @@
import type { FastifyInstance, FastifyPluginCallback } from "fastify";
const accountsRouter: FastifyPluginCallback = (fastify, opts, done) => {
done();
};
export default accountsRouter;

View file

View file

View file

@ -0,0 +1,17 @@
import Fastify from "fastify";
import APIError from "./core/errors/APIError";
import accountsRouter from "./accounts/AccountsRouter";
const app = Fastify();
app.register(accountsRouter, { prefix: "/accounts" });
app.setErrorHandler((err, request, reply) => {
const apiError =
err instanceof APIError
? err
: new APIError("Internal Server Error", 500, err);
reply.status(apiError.statusCode).send(apiError.toStruct());
});

View file

@ -1,4 +1,5 @@
import { Client, Pool, type PoolClient, type QueryResult } from "pg";
import { injectable } from "inversify";
import { Pool, type PoolClient, type QueryResult } from "pg";
import type { SqlParams } from "./IDatabase";
import type IDatabase from "./IDatabase";
@ -10,6 +11,7 @@ export interface PgConnectionOptions {
password: string;
}
@injectable()
export default class PgDatabase implements IDatabase {
private pool: Pool;

View file

@ -1,21 +1,31 @@
export interface APIErrorStruct {
msg: string;
statusCode: number;
cause?: string;
}
export default class APIError extends Error {
public statusCode: number;
constructor(msg?: string, statusCode?: number, options?: ErrorOptions) {
public cause?: Error;
constructor(
msg?: string,
statusCode?: number,
cause?: Error,
options?: ErrorOptions,
) {
super(msg, options);
this.statusCode = statusCode || 500;
this.cause = cause;
}
toStruct(): APIErrorStruct {
return {
msg: this.message,
statusCode: this.statusCode,
cause: this.cause?.message,
};
}
}

View file

@ -22,6 +22,9 @@
// Some stricter flags (disabled by default)
"noUnusedLocals": false,
"noUnusedParameters": false,
"noPropertyAccessFromIndexSignature": false
"noPropertyAccessFromIndexSignature": false,
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}