Skip to content

Commit

Permalink
implement pgDbApi, preparing methodes that should be used directly in…
Browse files Browse the repository at this point in the history
… trpc router when ready
  • Loading branch information
JeromeBu committed Jul 5, 2024
1 parent 6d63d80 commit 0a8fd48
Show file tree
Hide file tree
Showing 7 changed files with 518 additions and 121 deletions.
461 changes: 346 additions & 115 deletions api/src/core/adapters/dbApi/kysely/createPgDbApi.ts

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion api/src/core/adapters/dbApi/kysely/kysely.database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ type SoftwareType =
};

type SoftwaresTable = {
id: number;
id: Generated<number>;
name: string;
description: string;
referencedSinceTime: number;
Expand Down
7 changes: 6 additions & 1 deletion api/src/core/adapters/dbApi/kysely/kysely.utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Expression, FunctionModule, RawBuilder, Simplify, sql } from "kysely";
import { Expression, FunctionModule, RawBuilder, SelectExpression, Simplify, sql } from "kysely";

export const jsonBuildObject = <O extends Record<string, Expression<unknown>>>(
obj: O
Expand All @@ -20,3 +20,8 @@ export const jsonAggOrEmptyArray = <Db, E extends Expression<unknown>>(fn: Funct

export const emptyArrayIfNull = <Db, E extends Expression<unknown>>(fn: FunctionModule<Db, keyof Db>, value: E) =>
fn.coalesce(value, sql`'[]'`);

export const castSql = <Db>(
expression: SelectExpression<Db, keyof Db>,
type: "int" | "text" | "bool" | "uuid"
): SelectExpression<Db, keyof Db> => sql`CAST(${expression} AS ${sql.raw(type)})` as any;
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import type { Kysely } from "kysely";

const compiledSoftwares_SoftwareIdIdx = "compiled_softwares__softwareId_idx";
const compiledSoftwares_GroupByIdx = "compiled_softwares_group_by_idx";
const softwareReferents_softwareIdIdx = "softwareReferents_software_idx";
const softwareUsers_softwareIdIdx = "softwareUsers_software_idx";
const instances_mainSoftwareSillIdIdx = "instances_mainSoftwareSillId_idx";

export async function up(db: Kysely<any>): Promise<void> {
await db.schema
.createIndex(compiledSoftwares_SoftwareIdIdx)
.on("compiled_softwares")
.column("softwareId")
.execute();

await db.schema
.createIndex(softwareReferents_softwareIdIdx)
.on("software_referents")
.column("softwareId")
.execute();

await db.schema.createIndex(softwareUsers_softwareIdIdx).on("software_users").column("softwareId").execute();
await db.schema.createIndex(instances_mainSoftwareSillIdIdx).on("instances").column("mainSoftwareSillId").execute();

// CREATE INDEX idx_compiled_softwares_group_by ON compiled_softwares (softwareId, annuaireCnllServiceProviders, comptoirDuLibreSoftware, latestVersion, parentWikidataSoftware, serviceProviders, similarExternalSoftwares, softwareExternalData);
await db.schema
.createIndex(compiledSoftwares_GroupByIdx)
.on("compiled_softwares")
.column("softwareId")
.column("annuaireCnllServiceProviders")
.column("comptoirDuLibreSoftware")
.column("latestVersion")
.column("parentWikidataSoftware")
.column("serviceProviders")
.column("similarExternalSoftwares")
.column("softwareExternalData")
.execute();
}

export async function down(db: Kysely<any>): Promise<void> {
await db.schema.dropIndex(compiledSoftwares_SoftwareIdIdx).execute();
await db.schema.dropIndex(softwareReferents_softwareIdIdx).execute();
await db.schema.dropIndex(softwareUsers_softwareIdIdx).execute();
await db.schema.dropIndex(instances_mainSoftwareSillIdIdx).execute();
await db.schema.dropIndex(compiledSoftwares_GroupByIdx).execute();
}
116 changes: 116 additions & 0 deletions api/src/core/adapters/dbApi/kysely/pgDbApi.integration.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import { Kysely, sql } from "kysely";
import { beforeEach, describe, it, expect } from "vitest";
import { expectToEqual } from "../../../../tools/test.helpers";
import { CompiledData } from "../../../ports/CompileData";
import { SoftwareFormData } from "../../../usecases/readWriteSillData";
import { createKyselyPgDbApi, PgDbApi } from "./createPgDbApi";
import { Database } from "./kysely.database";
import { createPgDialect } from "./kysely.dialect";

const softwareFormData: SoftwareFormData = {
comptoirDuLibreId: 50,
doRespectRgaa: true,
externalId: "external-id-111",
isFromFrenchPublicService: false,
isPresentInSupportContract: true,
similarSoftwareExternalDataIds: ["external-id-222"],
softwareDescription: "Super software",
softwareKeywords: ["bob", "l'éponge"],
softwareLicense: "MIT",
softwareLogoUrl: "https://example.com/logo.png",
softwareMinimalVersion: "",
softwareName: "",
softwareType: {
type: "desktop/mobile",
os: {
ios: true,
android: true,
mac: true,
linux: false,
windows: true
}
}
};

const db = new Kysely<Database>({ dialect: createPgDialect("postgresql://sill:pg_password@localhost:5433/sill") });

describe("pgDbApi", () => {
let dbApi: PgDbApi;

beforeEach(async () => {
dbApi = createKyselyPgDbApi(db);
await db.deleteFrom("softwares").execute();
});

describe("getCompiledDataPrivate", () => {
it("gets private compiled data", async () => {
const compiledDataPrivate = await dbApi.getCompiledDataPrivate();
const { users, referents, instances, ...firstSoftware } = compiledDataPrivate[0];
// console.log(firstSoftware);
//
// console.log(`Users n = ${users?.length} : `, users);
// console.log(`Referents n = ${referents?.length} : `, referents);
// console.log(`Instances n = ${instances?.length} : `, instances);
expect(compiledDataPrivate).toHaveLength(100);
});
});

describe("software", () => {
it("creates a software, than gets it with getAll", async () => {
await dbApi.software.create({
formData: softwareFormData,
agent: {
id: 1,
email: "[email protected]",
organization: "test-orga"
}
});

const softwares = await dbApi.software.getAll();

expectToEqual(softwares[0], {
addedTime: expect.any(Number),
updateTime: expect.any(Number),
annuaireCnllServiceProviders: undefined,
authors: [],
categories: [],
codeRepositoryUrl: undefined,
comptoirDuLibreId: 50,
comptoirDuLibreServiceProviderCount: 0,
dereferencing: undefined,
documentationUrl: undefined,
externalDataOrigin: undefined,
externalId: "external-id-111",
keywords: ["bob", "l'éponge"],
latestVersion: undefined,
license: "MIT",
logoUrl: "https://example.com/logo.png",
officialWebsiteUrl: undefined,
parentWikidataSoftware: undefined,
prerogatives: {
doRespectRgaa: true,
isFromFrenchPublicServices: false,
isPresentInSupportContract: true
},
serviceProviders: [],
similarSoftwares: [],
softwareDescription: "Super software",
softwareId: expect.any(Number),
softwareName: "",
softwareType: {
os: {
android: true,
ios: true,
linux: false,
mac: true,
windows: true
},
type: "desktop/mobile"
},
testUrl: undefined,
userAndReferentCountByOrganization: {},
versionMin: ""
});
});
});
});
4 changes: 0 additions & 4 deletions api/src/core/ports/CompileData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,6 @@ export type CompiledData<T extends "private" | "public"> = CompiledData.Software
export namespace CompiledData {
export type Software<T extends "private" | "public"> = T extends "private" ? Software.Private : Software.Public;

export type SimilarSoftware = Pick<
SoftwareExternalData,
"externalId" | "label" | "description" | "isLibreSoftware" | "externalDataOrigin"
>;
export namespace Software {
export type Common = Pick<
Db.SoftwareRow,
Expand Down
3 changes: 3 additions & 0 deletions api/src/rpc/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,9 @@ export function createRouter(params: {

const { formData } = input;

// TODO : there is some logic with logoUrl that should be moved here
// from readWriteSillData/thunks/getStorableLogo

try {
await core.functions.readWriteSillData.createSoftware({
formData,
Expand Down

0 comments on commit 0a8fd48

Please sign in to comment.