Skip to content

Instantly share code, notes, and snippets.

@oitee
Last active December 12, 2021 13:41
Show Gist options
  • Save oitee/ed396afeba5b122349be3d4cda1bd90f to your computer and use it in GitHub Desktop.
Save oitee/ed396afeba5b122349be3d4cda1bd90f to your computer and use it in GitHub Desktop.
Database server that stores key-value pairs
export default class KVStore {
#data;
constructor() {
this.#data = new Map();
}
/**
* Given a key, returns its value
* @param {any} key
* @returns {any}
*/
get(key) {
return this.#data.get(key);
}
/**
* Updates/Inserts a given key-value pair
* @param {any} key
* @param {any} value
*/
set(key, value) {
this.#data.set(key, value);
}
/**
* Returns all keys in the store
* @returns array
*/
getAllKeys() {
return this.#data.keys();
}
}
import launchServer from "./server.js";
launchServer(4000);
{
"name": "penguin",
"version": "1.0.0",
"description": "",
"main": "src/launcher.js",
"directories": {
"test": "test"
},
"scripts": {
"test": "NODE_OPTIONS=--experimental-vm-modules jest --coverage=true -i",
"start": "node src/launcher.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/oitee/penguin.git"
},
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/oitee/penguin/issues"
},
"homepage": "https://github.com/oitee/penguin#readme",
"devDependencies": {
"jest": "^27.4.4",
"node-fetch": "^3.1.0"
},
"jest": {
"testMatch": [
"**/test/**.js"
],
"testTimeout": 60000,
"modulePathIgnorePatterns": [],
"setupFilesAfterEnv": []
},
"type": "module"
}
import KVStore from "./kv_store.js";
import http from "http";
import url from "url";
/**
* Handler for setting keys in the store
* @param {KVStore} store
* @param {Object} response
* @param {Object} queryParameters
* @returns Object
*/
function setKeys(store, response, queryParameters) {
if (!queryParameters || Object.keys(queryParameters).length <= 0) {
return buildResponse(
response,
400,
`Invalid request: Query parameters empty`
);
}
for (let key in queryParameters) {
store.set(key, queryParameters[key]);
}
return buildResponse(
response,
200,
`Inserted the following keys: ${Object.keys(queryParameters)}`
);
}
/**
* Handler for getting value of a given key
* @param {KVStore} store
* @param {Object} response
* @param {Object} queryParameters
* @returns Object
*/
function getKey(store, response, queryParameters) {
if (!queryParameters || !queryParameters.key) {
return buildResponse(response, 400, `Invalid request: Key cannot be empty`);
}
const result = store.get(queryParameters.key);
if (typeof result === "string") {
return buildResponse(response, 200, `The value is: ${result}`);
}
return buildResponse(
response,
404,
`The key "${queryParameters.key}" does not exist`
);
}
/**
* Creates a new store and returns a corresponding
* server handler that encapsulates the store
* @returns function
*/
function generateServerHandler() {
const store = new KVStore();
return (request, response) => {
let requestUrl = url.parse(request.url, true);
let urlPath = requestUrl.pathname;
switch (urlPath) {
case "/set":
return setKeys(store, response, requestUrl.query);
case "/get":
return getKey(store, response, requestUrl.query);
default:
return buildResponse(
response,
404,
`Invalid Request: Route not defined`
);
}
};
}
/**
* Given a status and a message, adds a json-ified content to the
* response object and ends the response
* @param {Object} response
* @param {number} statusCode
* @param {string} message
* @returns Object
*/
function buildResponse(response, statusCode, message) {
const responseBody = { status: statusCode === 200 };
if (message) {
responseBody.message = message;
}
response.statusCode = statusCode;
response.setHeader("Content-Type", "application/json");
return response.end(JSON.stringify(responseBody));
}
/**
* Given a port, creates an http server
* @param {number} port
* @returns Object
*/
export default function launchServer(port) {
const serverHandler = generateServerHandler();
const server = http.createServer(serverHandler);
return server.listen(port, () => console.log(`Listening on port: ${port}...`));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment