UNPKG

detajs-sm

Version:

A small Deta Base wrapper with Typescript support.

401 lines (394 loc) 13.4 kB
var fetch = require('cross-fetch'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var fetch__default = /*#__PURE__*/_interopDefaultLegacy(fetch); exports.BaseUtilsActions = void 0; (function(BaseUtilsActions) { BaseUtilsActions[BaseUtilsActions["Set"] = 0] = "Set"; BaseUtilsActions[BaseUtilsActions["Increment"] = 1] = "Increment"; BaseUtilsActions[BaseUtilsActions["Append"] = 2] = "Append"; BaseUtilsActions[BaseUtilsActions["Prepend"] = 3] = "Prepend"; BaseUtilsActions[BaseUtilsActions["Delete"] = 4] = "Delete"; })(exports.BaseUtilsActions || (exports.BaseUtilsActions = {})); class BaseAction { constructor(action, value){ this.action = action; this.value = value; } } class BaseUtils { trim() { return new BaseAction(4); } increment(value = 1) { return new BaseAction(1, value); } append(values) { return new BaseAction(2, values); } prepend(values) { return new BaseAction(3, values); } } // ==== https://github.com/deta/deta-javascript/blob/main/src/utils/date.ts class Day { /** * addSeconds returns new Day object * by adding provided number of seconds. * * @param {number} seconds * @returns {Day} */ addSeconds(seconds) { this.date = new Date(this.date.getTime() + 1000 * seconds); return this; } /** * getEpochSeconds returns number of seconds after epoch. * * @returns {number} */ getEpochSeconds() { return Math.floor(this.date.getTime() / 1000.0); } /** * Day constructor * * @param {Date} [date] */ constructor(date){ this.date = date || new Date(); } } /** * getTTL computes and returns ttl value based on expireIn and expireAt params. * expireIn and expireAt are optional params. * * @param {number} [expireIn] * @param {Date | number} [expireAt] * @returns {TTLResponse} */ function getTTL(expireIn, expireAt) { // NOTE: `var == undefined` is same with `var == null` if (expireIn == null && expireAt == null) { return {}; } if (expireIn != null && expireAt != null) { return { error: new Error("can't set both expireIn and expireAt options") }; } if (expireIn) { if (!(typeof expireIn === "number")) { return { error: new Error("option expireIn should have a value of type number") }; } return { ttl: new Day().addSeconds(expireIn).getEpochSeconds() }; } if (!(typeof expireAt === "number" || expireAt instanceof Date)) { return { error: new Error("option expireAt should have a value of type number or Date") }; } if (expireAt instanceof Date) { return { ttl: new Day(expireAt).getEpochSeconds() }; } return { ttl: expireAt }; } function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _asyncToGenerator(fn) { return function() { var self = this, args = arguments; return new Promise(function(resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } function _extends() { _extends = Object.assign || function(target) { for(var i = 1; i < arguments.length; i++){ var source = arguments[i]; for(var key in source){ if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } const BASE_URL = "https://database.deta.sh/v1"; class _Base { request(url, method, headers) { var _this = this; return _asyncToGenerator(function*() { let response = undefined; let status = 0; let error = null; try { const r = yield fetch__default["default"](_this.baseUrl + `${url}`, _extends({}, headers, { method, headers: { "Content-Type": "application/json", "X-API-Key": _this.projectKey } })); response = yield r.json(); status = r.status; if (!r.ok && status !== 404) { const errJson = yield r.json(); error = new Error(`${status} | ${errJson.errors.length > 0 ? errJson.errors[0] : "Unknown error..."}`); } } catch (e) { error = new Error(String(e)); } if (!response) { throw new Error("Response is empty, maybe something is wrong?"); } return { response, status, error }; })(); } /** * Store multiple items to the database. * * @param items Array / list of items to store to the database. * @returns {Promise<PutResponse>} */ putMany(items) { var _this = this; return _asyncToGenerator(function*() { const { response , error } = yield _this.request("/items", "PUT", { body: JSON.stringify({ items }) }); if (error) throw error; return response; })(); } /** * Store an item in the database. * * It overwrite the item if the key already exists. * * @param item Item object to store / save to the database. * @param key Key of the item to save. * @param options Put options. * @returns {Promise<string>} */ put(item, key, options) { var _this = this; return _asyncToGenerator(function*() { const { ttl , error: ttlError } = getTTL(options == null ? void 0 : options.expireIn, options == null ? void 0 : options.expireAt); if (ttlError) throw ttlError; const _key = key ? key.trim() : undefined; const finalItem = _extends({}, item, key ? { key: _key } : {}, ttl ? { __expires: ttl } : {}); const response = yield _this.putMany([ finalItem ]); if (response.processed.items.length == 0) { throw new Error("Failed to save item to Base because of internal processing."); } return response.processed.items[0].key; })(); } /** * Get / retrieve a stored item from the database with the given key. * * @param key The key of the item to get. * @returns {Promise<T | null>} */ get(key) { var _this = this; return _asyncToGenerator(function*() { if (key === "") { throw new Error("Key cannot be empty."); } const { response , status , error } = yield _this.request(`/items/${key}`, "GET"); if (status === 404) { return null; } if (error) throw error; return response; })(); } /** * Delete an item from the database with the given key. * * @param key The key of the item to delete / remove. * @returns {Promise<null>} */ delete(key) { var _this = this; return _asyncToGenerator(function*() { if (key === "") { throw new Error("Key cannot be empty."); } // API Always returns 200 reegardless if an item with the key exists or not. const { error } = yield _this.request(`/items/${key}`, "DELETE"); if (error) throw error; return null; })(); } /** * Insert a single item into a Base. * * It will raise an error if the key already exists in the database. * Note: `insert` is roughly 2x slower than `put` * * @param item The item to save / store to the database. * @param key Key of the item if not included with the item object. * @param options Insert options. * @returns {Promise<GetResponse>} */ insert(item, key, options) { var _this = this; return _asyncToGenerator(function*() { const { ttl , error: ttlError } = getTTL(options == null ? void 0 : options.expireIn, options == null ? void 0 : options.expireAt); if (ttlError) throw ttlError; const _key = key ? key.trim() : undefined; const finalItem = _extends({}, item, key ? { key: _key } : {}, ttl ? { __expires: ttl } : {}); const { response , error } = yield _this.request("/items", "POST", { body: JSON.stringify({ item: finalItem }) }); if (error) throw error; return response; })(); } /** * Update an existing item from the database. * * @param updates A json object describing the updates on the item. * @param key The key of the item to be updated. * @returns {Promise<null>} */ update(updates, key) { var _this = this; return _asyncToGenerator(function*() { if (key === "") { throw new Error("Key cannot be empty."); } const payload = { set: {}, append: {}, prepend: {}, increment: {}, delete: [] }; for (const [key, v] of Object.entries(updates)){ if (v instanceof BaseAction) { switch(v.action){ case exports.BaseUtilsActions.Delete: payload.delete.push(v.value); break; case exports.BaseUtilsActions.Increment: payload.increment[key] = v.value; break; case exports.BaseUtilsActions.Append: payload.append[key] = v.value; break; case exports.BaseUtilsActions.Prepend: payload.prepend[key] = v.value; break; } continue; } payload.set[key] = v; } const { error } = yield _this.request(`/items/${key}`, "PATCH", { body: JSON.stringify(payload) }); if (error) throw error; return null; })(); } /** * * @param query A single or a list of query objects. If omitted, will fetch all items in the database (up to 1mn) * @param options * @returns {Promise<FetchResponse<T>>} */ fetch(query = {}, options) { var _this = this; return _asyncToGenerator(function*() { var _response_paging, _response_paging1; const payload = { query: Array.isArray(query) ? query : [ query ], limit: options == null ? void 0 : options.limit, last: options == null ? void 0 : options.last }; const { response , error } = yield _this.request("/query", "POST", { body: JSON.stringify(payload) }); if (error) throw error; return { items: response.items, count: (_response_paging = response.paging) == null ? void 0 : _response_paging.size, last: (_response_paging1 = response.paging) == null ? void 0 : _response_paging1.last }; })(); } constructor(name, projectKey, projectId){ this.name = name; this.projectKey = projectKey; this.baseUrl = `${BASE_URL}/${projectId}/${name}`; this.util = new BaseUtils(); } } class _Deta { Base(name) { return new _Base(name, this.projectKey, this.projectId); } constructor(projectKey){ const _projectKey = projectKey ? projectKey : process.env.DETA_PROJECT_KEY; if (_projectKey === undefined) throw new Error("DETA_PROJECT_KEY is not defined. Please pass a projectKey or set DETA_PROJECT_KEY env variable."); const v = _projectKey.split("_"); if (v.length != 2) { throw new Error("Invalid project key."); } this.projectId = v[0]; this.projectKey = _projectKey; } } const Deta = (projectKey)=>{ return new _Deta(projectKey); }; exports.BaseAction = BaseAction; exports.BaseUtils = BaseUtils; exports.Day = Day; exports.Deta = Deta; exports._Base = _Base; exports._Deta = _Deta; exports.getTTL = getTTL;