Skip to content

Commit

Permalink
Merge pull request #46 from badgeteam/43-add-abstraction-layer-for-da…
Browse files Browse the repository at this point in the history
…tabase-and-filesystem

Add abstraction layer for database and filesystem
  • Loading branch information
francisduvivier authored Jan 2, 2025
2 parents cbba345 + f6b1e6f commit f04d4e8
Show file tree
Hide file tree
Showing 12 changed files with 260 additions and 149 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
npm run build
- name: Start environment
run: |
npm run test-db:up
npm run test-db:up -- --wait
- name: Run test
run: |
npm run test
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"build": "tsc",
"swagger": "tsoa spec-and-routes",
"dev": "node --import tsx --watch src/index.ts",
"test-db:up": "docker compose -f docker-compose.test-db.yml up -d --wait",
"test-db:up": "docker compose -f docker-compose.test-db.yml up -d",
"test-db:down": "docker compose -f docker-compose.test-db.yml down",
"backup": "docker exec -it badgehub-api-db-1 /usr/bin/pg_dump --username badgehub badgehub -f /var/backup/data-backup-`date +\"%Y-%m-%dT%H:%m\"`.sql",
"overwrite-mockup-data": "docker exec -it badgehub-api-db-1 /usr/bin/pg_dump --username badgehub --schema badgehub badgehub > mockup-data.sql",
Expand Down
11 changes: 2 additions & 9 deletions public/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -1381,15 +1381,8 @@
"post": {
"operationId": "WriteZip",
"responses": {
"200": {
"description": "Ok",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Version"
}
}
}
"204": {
"description": "No content"
}
},
"description": "Upload a file to the latest draft version of the project.",
Expand Down
17 changes: 10 additions & 7 deletions src/controllers/private-rest.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Body, Delete, Get, Patch, Path, Post, Route, Tags } from "tsoa";
import type { BadgeHubDataPort } from "@domain/BadgeHubDataPort";
import { BadgeHubDataPostgresAdapter } from "@db/BadgeHubDataPostgresAdapter";
import type { Version } from "@domain/readModels/app/Version";
import { BadgeHubData } from "@domain/BadgeHubData";
import { PostgreSQLBadgeHubMetadata } from "@db/PostgreSQLBadgeHubMetadata";
import type { ProjectSlug } from "@domain/readModels/app/Project";
import type { DBInsertUser, DBUser } from "@db/models/app/DBUser";
import type { DBInsertProject } from "@db/models/app/DBProject";
import type { DBInsertAppMetadataJSON } from "@db/models/app/DBAppMetadataJSON";
import { NodeFSBadgeHubFiles } from "@fs/NodeFSBadgeHubFiles";

interface UserProps extends Omit<DBInsertUser, "id"> {}

Expand All @@ -19,7 +19,10 @@ interface DbInsertAppMetadataJSONPartial
@Tags("private")
export class PrivateRestController {
public constructor(
private badgeHubData: BadgeHubDataPort = new BadgeHubDataPostgresAdapter()
private badgeHubData: BadgeHubData = new BadgeHubData(
new PostgreSQLBadgeHubMetadata(),
new NodeFSBadgeHubFiles()
)
) {}

/**
Expand Down Expand Up @@ -115,15 +118,15 @@ export class PrivateRestController {
public async writeZip(
@Path() slug: string,
@Body() zipContent: Uint8Array
): Promise<Version> {
return await this.badgeHubData.writeDraftProjectZip(slug, zipContent);
): Promise<void> {
await this.badgeHubData.writeDraftProjectZip(slug, zipContent);
}

/**
* Publish the latest draft version
*/
@Patch("/apps/{slug}/publish")
public async publishVersion(@Path() slug: string) {
public async publishVersion(@Path() slug: string): Promise<void> {
await this.badgeHubData.publishVersion(slug);
}
}
10 changes: 7 additions & 3 deletions src/controllers/public-rest.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import type { TsoaResponse } from "tsoa";
import { Get, Path, Query, Res, Route, Tags } from "tsoa";
import type { BadgeHubDataPort } from "@domain/BadgeHubDataPort";
import { BadgeHubData } from "@domain/BadgeHubData";
import { Project } from "@domain/readModels/app/Project";
import { BadgeHubDataPostgresAdapter } from "@db/BadgeHubDataPostgresAdapter";
import { PostgreSQLBadgeHubMetadata } from "@db/PostgreSQLBadgeHubMetadata";

import { Badge } from "@domain/readModels/Badge";
import { Category } from "@domain/readModels/app/Category";
import { NodeFSBadgeHubFiles } from "@fs/NodeFSBadgeHubFiles";

/**
* The code is annotated so that OpenAPI documentation can be generated with tsoa
Expand All @@ -23,7 +24,10 @@ import { Category } from "@domain/readModels/app/Category";
@Tags("public")
export class PublicRestController {
public constructor(
private badgeHubData: BadgeHubDataPort = new BadgeHubDataPostgresAdapter()
private badgeHubData: BadgeHubData = new BadgeHubData(
new PostgreSQLBadgeHubMetadata(),
new NodeFSBadgeHubFiles()
)
) {}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { BadgeHubDataPort } from "@domain/BadgeHubDataPort";
import { Badge } from "@domain/readModels/Badge";
import {
Project,
Expand Down Expand Up @@ -37,6 +36,7 @@ import {
assertValidColumKey,
getInsertKeysAndValuesSql,
} from "@db/sqlHelpers/objectToSQL";
import { BadgeHubMetadata } from "@domain/BadgeHubMetadata";

function getUpdateAssigmentsSql(changes: Object) {
const changeEntries = getEntriesWithDefinedValues(changes);
Expand All @@ -50,7 +50,7 @@ function getUpdateAssigmentsSql(changes: Object) {
);
}

export class BadgeHubDataPostgresAdapter implements BadgeHubDataPort {
export class PostgreSQLBadgeHubMetadata implements BadgeHubMetadata {
private readonly pool: Pool;

constructor() {
Expand All @@ -60,7 +60,7 @@ export class BadgeHubDataPostgresAdapter implements BadgeHubDataPort {
async insertUser(user: DBInsertUser): Promise<void> {
const { keys, values } = getInsertKeysAndValuesSql(user);
const insertQuery = sql`insert into users (${keys})
values (${values})`;
values (${values})`;
await this.pool.query(insertQuery);
}

Expand All @@ -74,17 +74,16 @@ export class BadgeHubDataPostgresAdapter implements BadgeHubDataPort {
async insertProject(project: DBProject): Promise<void> {
const { keys, values } = getInsertKeysAndValuesSql(project);
const insertAppMetadataSql = sql`insert into app_metadata_jsons (name)
values (${project.slug})`;
values (${project.slug})`;

await this.pool.query(sql`
with inserted_app_metadata as (${insertAppMetadataSql} returning id),
inserted_version as (
insert
into versions (project_slug, app_metadata_json_id)
values (${project.slug}, (select id from inserted_app_metadata)) returning id)
insert
into projects (${keys}, version_id)
values (${values}, (select id from inserted_version))`);
with inserted_app_metadata as (${insertAppMetadataSql} returning id), inserted_version as (
insert
into versions (project_slug, app_metadata_json_id)
values (${project.slug}, (select id from inserted_app_metadata)) returning id)
insert
into projects (${keys}, version_id)
values (${values}, (select id from inserted_version))`);
}

async updateProject(
Expand All @@ -96,65 +95,21 @@ export class BadgeHubDataPostgresAdapter implements BadgeHubDataPort {
return;
}
await this.pool.query(sql`update projects
set ${setters}
where slug = ${projectSlug}`);
set ${setters}
where slug = ${projectSlug}`);
}

async deleteProject(projectSlug: ProjectSlug): Promise<void> {
await this.pool.query(sql`update projects
set deleted_at = now()
where slug = ${projectSlug}`);
}

async writeDraftFile(
projectSlug: ProjectSlug,
filePath: string,
contents: string | Uint8Array
): Promise<void> {
if (filePath === "metadata.json") {
const appMetadata: DBAppMetadataJSON = JSON.parse(
typeof contents === "string"
? contents
: new TextDecoder().decode(contents)
);
const setters = getUpdateAssigmentsSql(appMetadata);
if (!setters) {
return;
}

const appMetadataUpdateQuery = sql`update app_metadata_jsons
set ${setters}
where id = (select app_metadata_json_id
from versions v
where v.id =
(select projects.version_id from projects where slug = ${projectSlug}))`;
await this.pool.query(appMetadataUpdateQuery);
} else {
throw new Error(
"Method not implemented for files other than the metadata.json file yet."
);
}
}

updateDraftMetadata(
slug: string,
appMetadataChanges: Partial<DBInsertAppMetadataJSON>
): Promise<void> {
throw new Error("Method not implemented.");
}

writeDraftProjectZip(
projectSlug: string,
zipContent: Uint8Array
): Promise<Version> {
throw new Error("Method not implemented.");
set deleted_at = now()
where slug = ${projectSlug}`);
}

async publishVersion(projectSlug: string): Promise<void> {
await this.pool.query(
sql`update versions v
set published_at=now()
where (published_at is null and v.id = (select version_id from projects p where slug = ${projectSlug}))`
set published_at=now()
where (published_at is null and v.id = (select version_id from projects p where slug = ${projectSlug}))`
);
}

Expand Down Expand Up @@ -206,21 +161,6 @@ export class BadgeHubDataPostgresAdapter implements BadgeHubDataPort {
throw new Error("Method not implemented.");
}

getFileContents(
projectSlug: string,
versionRevision: number | "draft" | "latest",
filePath: string
): Promise<Uint8Array> {
throw new Error("Method not implemented.");
}

getVersionZipContents(
projectSlug: string,
versionRevision: number
): Promise<Uint8Array> {
throw new Error("Method not implemented.");
}

async getBadges(): Promise<Badge[]> {
const dbBadges: DBBadge[] = await this.pool
.query(
Expand Down Expand Up @@ -290,4 +230,22 @@ export class BadgeHubDataPostgresAdapter implements BadgeHubDataPort {
);
return badgesMap;
}

async updateDraftMetadata(
projectSlug: string,
appMetadataChanges: Partial<DBInsertAppMetadataJSON>
): Promise<void> {
const setters = getUpdateAssigmentsSql(appMetadataChanges);
if (!setters) {
return;
}

const appMetadataUpdateQuery = sql`update app_metadata_jsons
set ${setters}
where id = (select app_metadata_json_id
from versions v
where v.id =
(select projects.version_id from projects where slug = ${projectSlug}))`;
await this.pool.query(appMetadataUpdateQuery);
}
}
Loading

0 comments on commit f04d4e8

Please sign in to comment.