Compare commits
15 commits
1cd1e51273
...
2baefce4b1
Author | SHA1 | Date | |
---|---|---|---|
2baefce4b1 | |||
64affde372 | |||
7151c77d15 | |||
6dfb8ce705 | |||
6648294566 | |||
eaaf62483c | |||
fe924df3d2 | |||
f767ab8483 | |||
aaed9e854d | |||
6de8f5bcdb | |||
2c42cf9dc8 | |||
146e05751d | |||
1906580fb4 | |||
37177e391d | |||
361ab5e8f4 |
5 changed files with 70 additions and 3 deletions
|
@ -8,7 +8,7 @@ on:
|
|||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
jobs:
|
||||
prettier:
|
||||
boot-test:
|
||||
runs-on: docker
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
|
49
index.js
49
index.js
|
@ -68,6 +68,55 @@ async function get_counter_value(ns_name, key) {
|
|||
}
|
||||
}
|
||||
|
||||
async function counter_increment(ns_name, key, offset, create = false) {
|
||||
var nsid = await get_namespace_id(ns_name);
|
||||
return await sql.begin(async (sql) => {
|
||||
if (offset == 0) return true;
|
||||
if (create) {
|
||||
var existence_res =
|
||||
await sql`SELECT value FROM keys WHERE name = ${key} AND namespace_id = ${nsid}`;
|
||||
if (existence_res.length == 0) {
|
||||
if (
|
||||
!(await add_counter({
|
||||
namespace: ns_name,
|
||||
key: key,
|
||||
value: 1,
|
||||
enable_reset: false,
|
||||
update_lowerbound: 0,
|
||||
update_upperbound: 1,
|
||||
}))
|
||||
)
|
||||
return null;
|
||||
else return 1; // We know the key value will be 1 here, just return it explicitly (Ending early to save some SQL calls)
|
||||
}
|
||||
}
|
||||
var sql_res = await sql`UPDATE keys SET value = value + ${offset} WHERE
|
||||
namespace_id = ${nsid} AND
|
||||
name = ${key} AND
|
||||
${offset < 0 ? sql`update_lowerbound <= ${offset}` : sql`update_upperbound >= ${offset}`}
|
||||
RETURNING value`;
|
||||
if (sql_res.length == 1) return parseInt(sql_res[0].value);
|
||||
else return null;
|
||||
});
|
||||
}
|
||||
|
||||
app.get("/hit/:ns/:key", async function (req, res) {
|
||||
var counter_res = await counter_increment(
|
||||
req.params.ns,
|
||||
req.params.key,
|
||||
1,
|
||||
true,
|
||||
);
|
||||
return res
|
||||
.status(counter_res == null ? 403 : 200)
|
||||
.json({ value: counter_res });
|
||||
});
|
||||
app.get("/hit/:key", async function (req, res) {
|
||||
var counter_res = await counter_increment("default", req.params.key, 1, true);
|
||||
return res
|
||||
.status(counter_res == null ? 403 : 200)
|
||||
.json({ value: counter_res });
|
||||
});
|
||||
app.get("/get/:ns/:key", async function (req, res) {
|
||||
var e = await get_counter_value(req.params.ns, req.params.key);
|
||||
return res.status(e == null ? 404 : 200).json({ value: e });
|
||||
|
|
|
@ -5,8 +5,8 @@ CREATE TABLE IF NOT EXISTS namespaces(
|
|||
);
|
||||
CREATE TABLE IF NOT EXISTS keys(
|
||||
id SERIAL PRIMARY KEY,
|
||||
namespace_id INTEGER REFERENCES namespaces (id) ON DELETE RESTRICT,
|
||||
name TEXT UNIQUE NOT NULL,
|
||||
namespace_id INTEGER REFERENCES namespaces (id) ON DELETE RESTRICT NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
-- Someone might want to store huge numbers in here, so... why not?
|
||||
value BIGINT NOT NULL DEFAULT 0,
|
||||
enable_reset BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
|
|
10
migrations/0002-no-globally-unique-keys.sql
Normal file
10
migrations/0002-no-globally-unique-keys.sql
Normal file
|
@ -0,0 +1,10 @@
|
|||
-- 0002-no-globally-unique-keys.sql
|
||||
-- This makes keys with the same name be able to exist in different namespaces, while still preventing duplicates in the same namespace.
|
||||
BEGIN;
|
||||
-- Delete the "unique" constraint
|
||||
ALTER TABLE keys DROP CONSTRAINT IF EXISTS keys_name_key;
|
||||
-- Avoid duplicate constraints.
|
||||
ALTER TABLE keys DROP CONSTRAINT IF EXISTS keys_name_namespace_id_key;
|
||||
-- Make sure that name and namespace_id together still have to be unique
|
||||
ALTER TABLE keys ADD UNIQUE (name, namespace_id);
|
||||
COMMIT;
|
8
migrations/0003-keys-namespace-id-not-null.sql
Normal file
8
migrations/0003-keys-namespace-id-not-null.sql
Normal file
|
@ -0,0 +1,8 @@
|
|||
-- Make sure that keys.namespace_id isn't able to be null
|
||||
BEGIN;
|
||||
-- Remove all null keys.namespace_id values. Nuking data like this is reckless, but it's the only option.
|
||||
DROP FROM keys WHERE namespace_id = NULL;
|
||||
-- Delete before adding to avoid conflicts
|
||||
ALTER TABLE keys ALTER COLUMN namespace_id DROP NOT NULL;
|
||||
ALTER TABLE keys ALTER COLUMN namespace_id SET NOT NULL;
|
||||
COMMIT;
|
Loading…
Reference in a new issue