save to db

This commit is contained in:
dylan 2024-03-31 17:33:27 -07:00
parent 8b987bc589
commit 7874167582
6 changed files with 163 additions and 18 deletions

View File

@ -1,5 +1,4 @@
import { css } from "@emotion/css";
import { Center, Cover, Stack } from "@firebox/components";
import { Pico8Console } from "./pico8-client/Pico8Console";
import testcarts from "./testcarts";

View File

@ -4,10 +4,11 @@ DROP TABLE releases;
CREATE TABLE releases (
id text,
picobook_version int,
repo text,
author text,
slug text,
version text,
carts json,
title text,
manifest json,
created_at time
);

View File

@ -0,0 +1,42 @@
import { Type } from "@sinclair/typebox";
import { FirRouteInput, FirRouteOptions } from "../util/routewrap.ts";
import { getRelease, getReleases } from "../dbal/dbal.ts";
const method = "GET";
const url = "/api/release";
const payloadT = Type.Any();
const handler = async ({payload}: FirRouteInput<typeof payloadT>) => {
const {author, slug, version} = payload;
if (typeof author !== "string") {
return {
release: null,
versions: [],
};
}
if (typeof slug !== "string") {
return {
release: null,
versions: [],
};
}
const release = await getRelease({author, slug, version});
const releases = await getReleases({author, slug});
const versions = releases.map(r => r.version);
return {
release,
versions,
}
};
export default {
method,
url,
payloadT,
handler,
} as const satisfies FirRouteOptions<typeof payloadT>;

View File

@ -1,11 +1,12 @@
import { Type } from "@sinclair/typebox";
import { TypeCompiler } from "@sinclair/typebox/compiler";
import { FirRouteInput, FirRouteOptions } from "../util/routewrap";
import {git} from "../util/git.ts";
import { randomUUID } from "crypto";
import path from "path";
import {fileURLToPath} from 'url';
import { getCarts } from "../util/carts.ts";
import { getRelease, insertRelease } from "../dbal/dbal.ts";
import { ManifestType } from "../types.ts";
const __dirname = fileURLToPath(new URL('.', import.meta.url));
const reposPath = path.resolve(__dirname, "..", "..", "..", "repos");
@ -14,19 +15,6 @@ const url = "/api/release";
const payloadT = Type.Any();
const manifestT = Type.Object({
picobook_version: Type.Number(),
id: Type.String(),
version: Type.String(),
carts: Type.Array(Type.String()),
repo: Type.String(),
title: Type.Optional(Type.String()),
author: Type.Optional(Type.String()),
readme: Type.Optional(Type.String()),
});
const ManifestType = TypeCompiler.Compile(manifestT)
const handler = async ({payload}: FirRouteInput<typeof payloadT>) => {
const {manifest, token} = payload;
@ -34,6 +22,11 @@ const handler = async ({payload}: FirRouteInput<typeof payloadT>) => {
return false;
}
const release = await getRelease({author: manifest.author, slug: manifest.id, version: manifest.version});
if (release) {
return false;
}
const uuid = randomUUID();
const repoPath = path.join(reposPath, uuid);
@ -45,6 +38,11 @@ const handler = async ({payload}: FirRouteInput<typeof payloadT>) => {
const carts = await getCarts(repoPath, manifest.carts);
insertRelease({
manifest,
carts,
});
console.log({
manifest,
carts,

View File

@ -1 +1,89 @@
// Database Access Layer stuff goes here
// Database Access Layer stuff goes here
// Database Access Layer stuff goes here
import { v4 as uuidv4 } from 'uuid';
import { db, sql } from "../../database/db"
import { JsonValue } from '@firebox/tsutil';
import { PicobookManifest } from '../types';
export type DbRelease = {
id: string;
slug: string;
repo: string;
version: string;
carts: {name: string; rom: number[]}[];
author: string;
manifest: PicobookManifest;
}
const compareVersions = (a: string, b: string) => {
const [a1, a2] = a.split(".").map(x => Number(x));
const [b1, b2] = b.split(".").map(x => Number(x));
if (a1 !== b1) {
return a1 - b1;
} else {
return a2 - b2;
}
}
const compareByVersion = (a: DbRelease, b: DbRelease) => compareVersions(a.version, b.version);
export const getReleases = async (where: {
author: string;
slug: string;
version?: string;
}): Promise<DbRelease[]> => {
const {author, slug, version} = where;
if (!version) {
const rows = await db.query(sql`
SELECT * from releases
WHERE
slug = ${slug} AND
author = ${author}
`);
return rows;
} else {
const rows = await db.query(sql`
SELECT * from releases
WHERE
slug = ${slug} AND
author = ${author} AND
version = ${version}
`);
return rows;
}
}
export const getRelease = async (where: {
author: string;
slug: string;
version?: string;
}) => {
const {version} = where;
const releases = await getReleases(where);
if (version) {
if (releases.length === 1) {
return releases[0];
} else {
return null;
}
} else {
if (releases.length < 1) {
return null;
}
releases.sort(compareByVersion);
return releases[releases.length-1];
}
}
export const insertRelease = async (props: {manifest: PicobookManifest, carts: {name: string; rom: number[]}[]}) => {
const {manifest, carts} = props;
const {id: slug, author, repo, version} = manifest;
const id = uuidv4();
const now = new Date();
await db.query(sql`
INSERT INTO chats (id, slug, repo, version, author, carts, manifest, created_at)
VALUES (${id}, ${slug}, ${repo}, ${version}, ${author} ${carts}, ${manifest}, ${now})
`);
return id;
}

17
src/server/types.ts Normal file
View File

@ -0,0 +1,17 @@
import { Static, Type } from "@sinclair/typebox";
import { TypeCompiler } from "@sinclair/typebox/compiler";
export const manifestT = Type.Object({
picobook_version: Type.Number(),
id: Type.String(),
version: Type.String(),
carts: Type.Array(Type.String()),
repo: Type.String(),
author: Type.String(),
title: Type.Optional(Type.String()),
readme: Type.Optional(Type.String()),
});
export const ManifestType = TypeCompiler.Compile(manifestT);
export type PicobookManifest = Static<typeof manifestT>;