Skip to content

Commit

Permalink
Implement adding badges to project requests
Browse files Browse the repository at this point in the history
  • Loading branch information
Francis Duvivier committed Nov 27, 2024
1 parent 86dfeb4 commit fdb7a08
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 50 deletions.
8 changes: 4 additions & 4 deletions public/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -258,15 +258,15 @@
"type": "object",
"additionalProperties": false
},
"Record_BadgeSlug.string_": {
"Record_Badge-at-slug.string_": {
"properties": {},
"additionalProperties": {
"type": "string"
},
"type": "object",
"description": "Construct a type with a set of properties K of type T"
},
"Record_BadgeSlug.Array__source-string--destination-string___": {
"Record_Badge-at-slug.Array__source-string--destination-string___": {
"properties": {},
"additionalProperties": {
"items": {
Expand Down Expand Up @@ -322,7 +322,7 @@
"type": "string"
},
"main_executable_overrides": {
"$ref": "#/components/schemas/Record_BadgeSlug.string_"
"$ref": "#/components/schemas/Record_Badge-at-slug.string_"
},
"file_mappings": {
"items": {
Expand All @@ -340,7 +340,7 @@
"type": "array"
},
"file_mappings_overrides": {
"$ref": "#/components/schemas/Record_BadgeSlug.Array__source-string--destination-string___"
"$ref": "#/components/schemas/Record_Badge-at-slug.Array__source-string--destination-string___"
}
},
"type": "object",
Expand Down
63 changes: 42 additions & 21 deletions src/db/BadgeHubDataPostgresAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,17 +79,18 @@ 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})`;
const insertAppMetadataSql = sql`insert into app_metadata_jsons (name)
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 Down Expand Up @@ -143,15 +144,8 @@ export class BadgeHubDataPostgresAdapter implements BadgeHubDataPort {
);
}

// TODO test
async getProject(projectSlug: string): Promise<Project> {
const project: ProjectQueryResponse = await this.pool
.query(
sql`${getBaseSelectProjectQuery()} where
p.deleted_at is null and p.slug = ${projectSlug}`
)
.then((res) => res.rows[0]);
return projectQueryResponseToReadModel(project);
return (await this.getProjects({ projectSlug }))[0]!;
}

// TODO test
Expand Down Expand Up @@ -228,6 +222,7 @@ export class BadgeHubDataPostgresAdapter implements BadgeHubDataPort {
}

async getProjects(filter?: {
projectSlug?: Project["slug"];
pageStart?: number;
pageLength?: number;
badgeSlug?: Badge["slug"];
Expand All @@ -238,21 +233,47 @@ export class BadgeHubDataPostgresAdapter implements BadgeHubDataPort {
query = sql`${query}
inner join project_statuses_on_badges psb on p.slug = psb.project_slug and psb.badge_slug = ${filter.badgeSlug}`;
}
query = sql`${query} where p.deleted_at is null`;

if (filter?.categorySlug) {
query = sql`${query}
where c.slug = ${filter.categorySlug}`;
query = sql`${query} and c.slug = ${filter.categorySlug}`;
}

if (filter?.projectSlug) {
query = sql`${query} and p.slug = ${filter.projectSlug}`;
}

if (filter?.pageLength) {
query = sql`${query}
where p.deleted_at is null
limit
${filter.pageLength}
offset
${filter?.pageStart ?? 0}`;
}

const projects: ProjectQueryResponse[] = await this.pool
.query(query)
.then((res) => res.rows);
return projects.map(projectQueryResponseToReadModel);
const badgesMap = await this._getBadgesMap(projects.map((p) => p.slug));
return projects.map(projectQueryResponseToReadModel).map((p) => ({
...p,
badges: badgesMap[p.slug],
}));
}

private async _getBadgesMap(projectSlugs: Project["slug"][]) {
if (!projectSlugs.length) {
return {};
}
const query = sql`select project_slug, json_agg(badge_slug) as badges from project_statuses_on_badges where project_slug in (${join(projectSlugs)}) group by project_slug`;

const badges: { project_slug: Project["slug"]; badges: Badge["slug"][] }[] =
await this.pool.query(query).then((res) => res.rows);

const badgesMap: Record<Project["slug"], Badge["slug"][]> =
Object.fromEntries(
badges.map(({ project_slug, badges }) => [project_slug, badges])
);
return badgesMap;
}
}
3 changes: 1 addition & 2 deletions src/db/models/DBBadge.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { DBDatedData } from "./app/DBDatedData";

export type BadgeSlug = string;
export interface BadgeSlugRelation {
badge_slug: DBBadge["slug"];
}
export interface DBInsertBadge {
slug: BadgeSlug;
slug: string;
name: string;
}

Expand Down
32 changes: 16 additions & 16 deletions src/db/sqlHelpers/projectQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { DBUser } from "@db/models/app/DBUser";
import sql from "sql-template-tag";
import { extractDatedDataConverted } from "@db/sqlHelpers/dbDates";
import { Category } from "@domain/readModels/app/Category";
import { Badge } from "@domain/readModels/Badge";

export function getBaseSelectProjectQuery() {
return sql`select p.slug,
Expand Down Expand Up @@ -36,35 +37,34 @@ export function getBaseSelectProjectQuery() {
}

export const projectQueryResponseToReadModel = (
dbProject: ProjectQueryResponse
enrichedDBProject: ProjectQueryResponse
): Project => {
return {
version: undefined, // TODO
allow_team_fixes: false,
user_id: dbProject.user_id,
user_name: dbProject.author_name, // todo maybe change to email, full id or object with multiple fields
badges: [], // TODO
category: dbProject.category || "Uncategorised",
user_id: enrichedDBProject.user_id,
user_name: enrichedDBProject.author_name, // todo maybe change to email, full id or object with multiple fields
category: enrichedDBProject.category || "Uncategorised",
collaborators: [], // TODO
description: dbProject.description,
description: enrichedDBProject.description,
download_counter: undefined, // TODO
git: dbProject.git,
git_commit_id: dbProject.git_commit_id,
interpreter: dbProject.interpreter,
license: dbProject.license_file, // TODO check what we should do with the license, possibly we could say that this is either a path or 'MIT'|..., but then still we should read out the licens somewhere if it is a file.
name: dbProject.name,
published_at: moment(dbProject.published_at).toDate(),
revision: dbProject.revision,
git: enrichedDBProject.git,
git_commit_id: enrichedDBProject.git_commit_id,
interpreter: enrichedDBProject.interpreter,
license: enrichedDBProject.license_file, // TODO check what we should do with the license, possibly we could say that this is either a path or 'MIT'|..., but then still we should read out the licens somewhere if it is a file.
name: enrichedDBProject.name,
published_at: moment(enrichedDBProject.published_at).toDate(),
revision: enrichedDBProject.revision,
size_of_content: undefined, // TODO
size_of_zip: dbProject.size_of_zip,
slug: dbProject.slug,
size_of_zip: enrichedDBProject.size_of_zip,
slug: enrichedDBProject.slug,
states: undefined,
status: undefined, // TODO
versions: undefined, // TODO
dependencies: undefined, // TODO
votes: undefined, // TODO
warnings: undefined, // TODO
...extractDatedDataConverted(dbProject),
...extractDatedDataConverted(enrichedDBProject),
};
};
export type ProjectQueryResponse = DBProject &
Expand Down
6 changes: 3 additions & 3 deletions src/domain/readModels/app/AppMetadataJSON.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
// This is only put into the database for making interesting read queries possible.
// These contents should never be updated directly, but instead the metadata.json file should be modified and then read out again in order to fill the fields here.
// Metadata for a published version cannot be edited, except by republishing this version which would overwrite the old version.
import { BadgeSlug } from "@db/models/DBBadge";
import { Category } from "@domain/readModels/app/Category";
import { Badge } from "@domain/readModels/Badge";

export interface AppMetadataJSON {
name?: string;
Expand All @@ -17,10 +17,10 @@ export interface AppMetadataJSON {
semantic_version?: string; // Changed! [Semantic version](https://semver.org/) of the app, the semantic versioning is mostly relevant if the app is a library. Authors who don't use this semantic versioning will get a 0.x version with x just an number like we previously had the revision number.
interpreter?: string; // Changed! For example 'python' or the app slug of a 3rd party dependency of this app.
main_executable?: string; // Relative path of the executable file from this package that is the main executable file of this app.
main_executable_overrides?: Record<BadgeSlug, string>; // Optional field to allow overriding the main_executable for a certain badge.
main_executable_overrides?: Record<Badge["slug"], string>; // Optional field to allow overriding the main_executable for a certain badge.
file_mappings?: Array<{ source: string; destination: string }>; // Changed! Mapping to tell the badge where some files in this app should be placed on the filesystem. Source is a relative path. Desitination can either be relative or absolute.
file_mappings_overrides?: Record<
BadgeSlug,
Badge["slug"],
Array<{ source: string; destination: string }>
>; // Changed! optional field to allow overriding or adding a file mapping for a device name slug (key).
}
8 changes: 4 additions & 4 deletions src/generated/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ const models: TsoaRoute.Models = {
additionalProperties: false,
},
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
"Record_BadgeSlug.string_": {
"Record_Badge-at-slug.string_": {
dataType: "refAlias",
type: {
dataType: "nestedObjectLiteral",
Expand All @@ -155,7 +155,7 @@ const models: TsoaRoute.Models = {
},
},
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
"Record_BadgeSlug.Array__source-string--destination-string___": {
"Record_Badge-at-slug.Array__source-string--destination-string___": {
dataType: "refAlias",
type: {
dataType: "nestedObjectLiteral",
Expand Down Expand Up @@ -188,7 +188,7 @@ const models: TsoaRoute.Models = {
semantic_version: { dataType: "string" },
interpreter: { dataType: "string" },
main_executable: { dataType: "string" },
main_executable_overrides: { ref: "Record_BadgeSlug.string_" },
main_executable_overrides: { ref: "Record_Badge-at-slug.string_" },
file_mappings: {
dataType: "array",
array: {
Expand All @@ -200,7 +200,7 @@ const models: TsoaRoute.Models = {
},
},
file_mappings_overrides: {
ref: "Record_BadgeSlug.Array__source-string--destination-string___",
ref: "Record_Badge-at-slug.Array__source-string--destination-string___",
},
},
additionalProperties: false,
Expand Down

0 comments on commit fdb7a08

Please sign in to comment.