detajs-sm
Version:
A small Deta Base wrapper with Typescript support.
401 lines (394 loc) • 13.4 kB
JavaScript
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;