Skip to content

Commit

Permalink
✨ sqlite backend (#86)
Browse files Browse the repository at this point in the history
  • Loading branch information
haliphax authored Sep 14, 2023
1 parent 1463485 commit 4ec3573
Show file tree
Hide file tree
Showing 10 changed files with 3,764 additions and 1,401 deletions.
5,006 changes: 3,688 additions & 1,318 deletions package-lock.json

Large diffs are not rendered by default.

14 changes: 8 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
"version": "1.0.0",
"private": true,
"devDependencies": {
"@parcel/optimizer-data-url": "^2.8.3",
"@parcel/transformer-inline-string": "^2.8.3",
"@parcel/transformer-less": "^2.8.3",
"@parcel/transformer-vue": "^2.8.3",
"@parcel/optimizer-data-url": "^2.9.3",
"@parcel/transformer-inline-string": "^2.9.3",
"@parcel/transformer-less": "^2.9.3",
"@parcel/transformer-vue": "^2.9.3",
"@semantic-release/changelog": "^6.0.3",
"@semantic-release/git": "^10.0.1",
"@types/compression": "^1.7.2",
Expand All @@ -26,7 +26,7 @@
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-vue": "^9.11.0",
"gitmoji-cli": "^8.1.1",
"parcel": "^2.8.3",
"parcel": "^2.9.3",
"prettier": "^2.8.8",
"prettier-plugin-organize-imports": "^3.2.2",
"process": "^0.11.10",
Expand All @@ -44,7 +44,9 @@
"cookie-parser": "^1.4.6",
"cors": "^2.8.5",
"express": "^4.18.2",
"remult": "^0.20.6",
"knex": "^2.5.1",
"remult": "^0.22.7",
"sqlite3": "^5.1.6",
"uuid": "^9.0.0"
},
"engines": {
Expand Down
17 changes: 9 additions & 8 deletions src/back-end/routes/story/join.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Application } from "express";
import { remult } from "remult";
import { Story } from "../../../models/story";
import { Vote } from "../../../models/vote";
import server from "../../server";
import { updateStory } from "./events";

Expand All @@ -23,18 +24,18 @@ const join = (app: Application) =>
console.log(`User ${remult.user.id} joining ${storyId}`);

try {
if (!story._votes?.find((v) => v.participant.id === remult.user?.id)) {
if (!story._votes) story._votes = [];

story._votes.push({
participant: req.body,
if (!story._votes?.find((v) => v.participantId === remult.user?.id)) {
await remult.repo(Vote).insert({
participantId: req.body.id,
participantName: req.body.name,
storyId,
vote: null,
});

await remult.repo(Story).update(story.id, story);
}

const updatedStory = await remult.repo(Story).findId(storyId);
const updatedStory = await remult
.repo(Story)
.findId(storyId, { useCache: false });

if (!updatedStory) {
throw new Error("No story");
Expand Down
35 changes: 10 additions & 25 deletions src/back-end/routes/story/vote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,37 +11,22 @@ const vote = (app: Application) => {
console.log(`Incoming vote for ${req.params.story}`);

const vote = req.body;
const story = await remult.repo(Story).findId(req.params.story);
const storyRepo = remult.repo(Story);
const story = await storyRepo.findId(req.params.story);

if (!story) return next(new Error("No such story"));

const votes: Vote[] = [];

if (!story._votes) {
votes.push(vote);
} else {
let updated = false;

for (const v of story._votes) {
if (v.participant?.id === vote.participant?.id) {
updated = true;
votes.push(vote);
} else {
votes.push(v);
}
}

if (!updated) {
votes.push(vote);
}
}

story._votes = votes;
const voteRepo = remult.repo(Vote);

try {
await remult.repo(Story).update(req.params.story, story);
await voteRepo.update(voteRepo.metadata.idMetadata.getId(vote), vote);
res.sendStatus(201);
updateStory(story);

const updatedStory = await storyRepo.findId(req.params.story, {
useCache: false,
});

updateStory(updatedStory);
} catch (ex) {
next(ex);
}
Expand Down
27 changes: 16 additions & 11 deletions src/back-end/server.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
import { UserInfo } from "remult";
import { remultExpress } from "remult/remult-express";
import { createKnexDataProvider } from "remult/remult-knex";
import { v4 } from "uuid";
import { Story } from "../models/story";
import { Vote } from "../models/vote";
import scales from "../scales";

const server = remultExpress({
entities: [Story],
entities: [Story, Vote],
dataProvider: createKnexDataProvider({
client: "sqlite3",
connection: {
filename: "./db/narf.sqlite3",
},
}),
async getUser(request) {
const user =
"narfClient" in (request.cookies ?? {})
Expand All @@ -20,20 +28,17 @@ const server = remultExpress({
if ((await storyRepo.count()) === 0) {
const [scale, opts] = scales.entries().next().value as [string, string[]];

await storyRepo.insert({
const story = await storyRepo.insert({
id: v4().replace(/[^-]/g, "0"),
owner: "test",
title: "Testing this thing",
scale,
_votes: [
{
participant: {
id: "test",
name: "Test Participant",
},
vote: opts[0],
},
],
});
await remult.repo(Vote).insert({
participantId: "test",
participantName: "Test Participant",
storyId: story.id,
vote: opts[0],
});
}
},
Expand Down
9 changes: 4 additions & 5 deletions src/front-end/scripts/components/estimate.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const Estimate = defineComponent({
},
you() {
return store.state.story.story?.votes?.find(
(v) => v.participant.id === store.state.session.id
(v) => v.participantId === store.state.session.id
);
},
},
Expand All @@ -49,10 +49,9 @@ const Estimate = defineComponent({
this.you ??
(() => {
return {
participant: {
id: this.$store.state.session.id,
name: this.$store.state.session.name,
},
participantId: this.$store.state.session.id,
participantName: this.$store.state.session.name,
storyId: this.$store.state.story.story?.id,
vote: option,
} as Vote;
})();
Expand Down
6 changes: 3 additions & 3 deletions src/front-end/scripts/components/participants.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ export default Participants;
<ul class="unstyled">
<li
v-for="v of $store.state.story.story?.votes"
:key="v.participant.id"
:key="v.participantId"
class="grid"
>
<span class="name">
{{ v.participant.name ?? "Anonymous" }}
<span v-if="v.participant.id === $store.state.session.id" class="you">
{{ v.participantName ?? "User" }}
<span v-if="v.participantId === $store.state.session.id" class="you">
(You)
</span>
</span>
Expand Down
9 changes: 0 additions & 9 deletions src/models/participant.ts

This file was deleted.

25 changes: 13 additions & 12 deletions src/models/story.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
import { Entity, Fields } from "remult";
import { Entity, Fields, Validators } from "remult";
import { v4 } from "uuid";
import scales from "../scales";
import { Vote } from "./vote";

@Entity("story", { allowApiCrud: true })
export class Story {
@Fields.string({
allowApiUpdate: false,
defaultValue: () => v4(),
})
id!: string;
@Fields.string({ allowApiUpdate: false, validate: Validators.unique })
id: string = v4();

@Fields.string({ allowApiUpdate: false })
owner!: string;
Expand All @@ -32,21 +29,25 @@ export class Story {
})
scale!: string;

@Fields.object<Story>({ includeInApi: false })
@Fields.object<Story>((options, remult) => {
options.includeInApi = false;
options.serverExpression = (e) =>
remult.repo(Vote).find({ where: { storyId: e.id } });
})
_votes?: Vote[];

@Fields.object<Story>((options, remult) => {
options.allowApiUpdate = false;
options.serverExpression = (s) => {
return s._votes?.map((v) => {
if (v.participant.id === remult.user?.id) {
options.serverExpression = (e) => {
return e._votes?.map((v) => {
if (v.participantId === remult.user?.id) {
return v;
}

return {
...v,
participant: { ...v.participant, id: "" },
vote: s.revealed ? v.vote : v.vote ? "❓" : null,
participantId: "",
vote: e.revealed ? v.vote : v.vote ? "❓" : null,
};
});
};
Expand Down
17 changes: 13 additions & 4 deletions src/models/vote.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
import { Fields } from "remult";
import Participant from "./participant";
import { Entity, Fields } from "remult";

@Entity<Vote>("vote", {
allowApiUpdate: (e, remult) => remult?.user?.id === e?.participantId,
id: (e) => [e.participantId, e.storyId],
})
export class Vote {
@Fields.object(() => Participant)
participant!: Participant;
@Fields.string()
storyId!: string;

@Fields.string()
participantId!: string;

@Fields.string()
participantName!: string;

@Fields.string({ allowNull: true })
vote: string | null = null;
}

0 comments on commit 4ec3573

Please sign in to comment.