diff --git a/packages/skin-database/data/KeyValue.ts b/packages/skin-database/data/KeyValue.ts new file mode 100644 index 00000000..e6332b22 --- /dev/null +++ b/packages/skin-database/data/KeyValue.ts @@ -0,0 +1,28 @@ +import { knex } from "../db"; + +export default class KeyValue { + static async get(key: string): Promise { + const result = await knex("key_value").where({key}).first("value"); + return JSON.parse(result.value); + } + + static async set(key: string, value: any): Promise { + const {count} = (await knex("key_value").where({key}).count({count: '*'}).first() as {count: number}); + if(count) { + return await KeyValue.update(key, value); + } else { + return await KeyValue.insert(key, value); + } + } + + static async update(key: string, value: any): Promise { + const json = JSON.stringify(value); + await knex("key_value").where({key}).update({value: json}); + } + + static async insert(key: string, value: any): Promise { + const json = JSON.stringify(value); + await knex("key_value").insert({key, value: json}); + } + +} \ No newline at end of file diff --git a/packages/skin-database/migrations/20220203100031_key_value_store.ts b/packages/skin-database/migrations/20220203100031_key_value_store.ts new file mode 100644 index 00000000..6c2816fc --- /dev/null +++ b/packages/skin-database/migrations/20220203100031_key_value_store.ts @@ -0,0 +1,18 @@ +import * as Knex from "knex"; + + +export async function up(knex: Knex): Promise { + await knex.raw( + `CREATE TABLE "key_value" ( + "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, + "key" TEXT NOT NULL UNIQUE, + value TEXT NOT_NULL + );` + ); +} + + +export async function down(knex: Knex): Promise { + await knex.raw(`DROP TABLE "key_value"`); +} + diff --git a/packages/skin-database/tasks/tweetMilestones.ts b/packages/skin-database/tasks/tweetMilestones.ts index f1ba1f49..55092de0 100644 --- a/packages/skin-database/tasks/tweetMilestones.ts +++ b/packages/skin-database/tasks/tweetMilestones.ts @@ -1,6 +1,7 @@ import { getTwitterClient } from "../twitter"; import fs from "fs"; import DiscordEventHandler from "../api/DiscordEventHandler"; +import KeyValue from "../data/KeyValue"; const MAX_CALL_COUNT = 2; @@ -51,6 +52,7 @@ function tweetUrl(tweet: { id_str: string }) { } const JSON_FILE_NAME = "./popularTweets.json"; +const KEY = "tweet_milestones"; // Sort key/value entries by key largest to smallest function sortEntries(a: [string, never], b: [string, never]): number { @@ -65,6 +67,11 @@ export async function popularTweets(handler: DiscordEventHandler) { const currentJSON = fs.readFileSync(JSON_FILE_NAME, "utf8"); const current: { [bracket: string]: string[] } = JSON.parse(currentJSON); + const kvCurrent = await KeyValue.get(KEY); + if(JSON.stringify(kvCurrent) === JSON.stringify(current)) { + console.warn("KV value does not match!") + } + for (const tweet of tweets) { let notified = false; for (const [_bracket, seen] of Object.entries(current).sort(sortEntries)) { @@ -85,6 +92,7 @@ export async function popularTweets(handler: DiscordEventHandler) { notified = true; } + await KeyValue.set(KEY, current); fs.writeFileSync(JSON_FILE_NAME, JSON.stringify(current, null, 2)); } }