qb-record
Version:
A lightweight abstraction layer for Quick Base
473 lines • 16.9 kB
JavaScript
/*!
* Package Name: qb-record
* Package Description: A lightweight abstraction layer for Quick Base
* Version: 5.0.23
* Build Timestamp: 2023-11-15T14:41:08.263Z
* Package Homepage: https://github.com/tflanagan/node-qb-record
* Git Location: git@github.com:tflanagan/node-qb-record.git
* Authored By: Tristian Flanagan <contact@tristianflanagan.com> (https://github.com/tflanagan)
* License: Apache-2.0
*
* Copyright 2016 Tristian Flanagan
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.replaceUndefinedWithString = exports.QBRecord = void 0;
/* Dependencies */
const deepmerge_1 = __importDefault(require("deepmerge"));
const rfc4122_1 = __importDefault(require("rfc4122"));
const quickbase_1 = require("quickbase");
const qb_field_1 = require("qb-field");
/* Globals */
const VERSION = require('../package.json').version;
const IS_BROWSER = typeof (window) !== 'undefined';
const rfc4122 = new rfc4122_1.default();
/* Main Class */
class QBRecord {
constructor(options) {
this.CLASS_NAME = 'QBRecord';
this._tableId = '';
this._fids = {};
this._fields = [];
this._data = {};
this.id = rfc4122.v4();
const _a = options || {}, { quickbase } = _a, classOptions = __rest(_a, ["quickbase"]);
if (quickbase_1.QuickBase.IsQuickBase(quickbase)) {
this._qb = quickbase;
}
else {
this._qb = new quickbase_1.QuickBase(deepmerge_1.default.all([
QBRecord.defaults.quickbase,
quickbase || {}
]));
}
const settings = (0, deepmerge_1.default)(QBRecord.defaults, classOptions);
this.setTableId(settings.tableId)
.setFids(settings.fids)
// @ts-ignore - my typescript skills fail me for now, tests are fine though
.set('recordid', settings.recordid)
// @ts-ignore - my typescript skills fail me for now, tests are fine though
.set('primaryKey', settings.primaryKey);
return this;
}
clear() {
this._data = {};
this._fields = [];
return this;
}
delete({ requestOptions } = {}) {
return __awaiter(this, void 0, void 0, function* () {
const recordid = this.get('recordid');
if (recordid) {
const results = yield this._qb.deleteRecords({
tableId: this.getTableId(),
where: `{'${this.getFid('recordid')}'.EX.'${recordid}'}`,
requestOptions
});
if (results.numberDeleted !== 0) {
this.clear();
}
return results;
}
else {
this.clear();
return {
numberDeleted: 0
};
}
});
}
get(field) {
return this._data[field];
}
getFid(field, byId = false) {
const fids = this.getFids();
let id = -1;
if (byId !== true) {
if (fids.hasOwnProperty(field)) {
id = fids[field];
}
}
else {
id = '';
field = +field;
Object.entries(fids).some(([name, fid]) => {
if (fid === field) {
id = name;
return true;
}
return false;
});
}
return id;
}
getFids() {
return this._fids;
}
getField(id, returnIndex = false) {
const fields = this.getFields();
let result = undefined;
for (let i = 0; result === undefined && i < fields.length; ++i) {
if (fields[i].getFid() === id) {
result = returnIndex ? i : fields[i];
}
}
return result;
}
getFields() {
return this._fields;
}
getTableId() {
return this._tableId;
}
getTempToken({ requestOptions } = {}) {
return __awaiter(this, void 0, void 0, function* () {
yield this._qb.getTempTokenDBID({
dbid: this.getTableId(),
requestOptions
});
});
}
load({ clist, query, requestOptions } = {}) {
return __awaiter(this, void 0, void 0, function* () {
const where = [];
let fids = this.getFids();
let select = [];
if (query) {
where.push(`(${query})`);
}
if (this.get('recordid')) {
where.push(`{'${this.getFid('recordid')}'.EX.'${this.get('recordid')}'}`);
}
else if (this.get('primaryKey')) {
where.push(`{'${this.getFid('primaryKey')}'.EX.'${this.get('primaryKey')}'}`);
}
if (clist) {
if (typeof (clist) === 'string') {
select = clist.split('.').map((val) => +val);
}
else {
select = clist;
}
fids = select.reduce((fids, fid) => {
let name = this.getFid(fid, true);
if (!name) {
name = fid;
this.setFid(fid, fid);
}
fids[name] = fid;
return fids;
}, {});
}
else {
select = Object.entries(fids).map((fid) => {
return fid[1];
});
}
const results = yield this._qb.runQuery({
tableId: this.getTableId(),
where: where.join('AND'),
select: select,
requestOptions
});
results.fields.forEach((field) => {
let result = this.getField(field.id);
if (!result) {
result = new qb_field_1.QBField({
quickbase: this._qb,
tableId: this.getTableId(),
fid: field.id
});
this._fields.push(result);
}
Object.entries(field).forEach(([attribute, property]) => {
result.set(attribute, property);
});
});
if (results.metadata.totalRecords === 0) {
throw new Error('Record not found');
}
const record = results.data[0];
Object.entries(fids).forEach(([name, fid]) => {
this.set(name, record[fid].value);
});
return this._data;
});
}
loadSchema({ requestOptions } = {}) {
return __awaiter(this, void 0, void 0, function* () {
const results = yield this._qb.getFields({
tableId: this.getTableId(),
requestOptions
});
results.forEach((field) => {
let result = this.getField(field.id);
if (result === undefined) {
result = new qb_field_1.QBField({
quickbase: this._qb,
tableId: this.getTableId(),
fid: field.id
});
this._fields.push(result);
}
Object.entries(field).forEach(([property, value]) => {
result.set(property, value);
});
});
return this.getFields();
});
}
save({ fidsToSave, mergeFieldId, requestOptions } = {}) {
return __awaiter(this, void 0, void 0, function* () {
const fids = this.getFids();
const names = Object.entries(fids).map(([name]) => name);
const mergeField = mergeFieldId || this.getFid('primaryKey');
const { headers, data: results } = yield this._qb.upsert({
tableId: this.getTableId(),
mergeFieldId: mergeField,
data: [names.filter((name) => {
const fid = fids[name];
const filtered = !fidsToSave || fidsToSave.indexOf(fid) !== -1 || fidsToSave.indexOf(name) !== -1 || fid === mergeField;
if (!filtered) {
return false;
}
const field = this.getField(fid);
if (field && [
'lookup',
'summary',
'formula'
].indexOf(field.get('mode') || '') !== -1) {
return false;
}
return true;
}).reduce((record, name) => {
const fid = fids[name];
if (fid) {
record[fid] = {
value: (0, exports.replaceUndefinedWithString)(this.get(name))
};
}
return record;
}, {})],
fieldsToReturn: names.map((name) => {
return fids[name];
}).filter((val, i, arr) => {
return arr.indexOf(val) === i;
}),
requestOptions,
returnAxios: true
});
const error = typeof (results.metadata.lineErrors) !== 'undefined' ? results.metadata.lineErrors[1] : false;
if (error) {
throw new quickbase_1.QuickBaseError(207, 'A partial success response was returned', error.join('\n'), headers['qb-api-ray']);
}
const record = results.data[0];
names.forEach((name) => {
let value = undefined;
const fid = fids[name];
if (fid) {
const field = record[fid];
if (field) {
value = field.value;
}
}
this.set(name, value);
});
return this._data;
});
}
set(field, value) {
this._data[field] = value;
return this;
}
setTableId(tableId) {
this._tableId = tableId;
return this;
}
setFid(name, id) {
this._fids[name] = +id;
return this;
}
setFids(fields) {
Object.entries(fields).forEach(([name, fid]) => {
this.setFid(name, fid);
});
return this;
}
setFields(fields) {
this._fields = fields;
return this;
}
/**
* Rebuild the QBRecord instance from serialized JSON
*
* @param json QBRecord serialized JSON
*/
fromJSON(json) {
if (typeof (json) === 'string') {
json = JSON.parse(json);
}
if (typeof (json) !== 'object') {
throw new TypeError('json argument must be type of object or a valid JSON string');
}
if (json.quickbase) {
this._qb = new quickbase_1.QuickBase(json.quickbase);
}
if (json.tableId) {
this.setTableId(json.tableId);
}
if (json.fids) {
this.setFids(json.fids);
}
if (json.recordid) {
// @ts-ignore - my typescript skills fail me for now, tests are fine though
this.set('recordid', json.recordid);
}
if (json.primaryKey) {
// @ts-ignore - my typescript skills fail me for now, tests are fine though
this.set('primaryKey', json.primaryKey);
}
if (json.fields) {
json.fields.forEach((fieldJSON) => {
this._fields.push(qb_field_1.QBField.fromJSON(fieldJSON));
});
}
if (json.data) {
Object.entries(json.data).forEach(([property, value]) => {
this.set(property, value);
});
}
return this;
}
/**
* Serialize the QBRecord instance into JSON
*/
toJSON(fidsToConvert) {
return {
quickbase: this._qb.toJSON(),
tableId: this.getTableId(),
fids: this.getFids(),
recordid: this.get('recordid'),
primaryKey: this.get('primaryKey'),
fields: this.getFields().map((field) => {
return field.toJSON();
}),
data: Object.entries(this._data).filter(([name]) => {
return !fidsToConvert || fidsToConvert.indexOf(name) !== -1;
}).reduce((data, [name, value]) => {
data[name] = value;
return data;
}, {})
};
}
/**
* Create a new QBRecord instance from serialized JSON
*
* @param json QBRecord serialized JSON
*/
static fromJSON(json) {
if (typeof (json) === 'string') {
json = JSON.parse(json);
}
if (typeof (json) !== 'object') {
throw new TypeError('json argument must be type of object or a valid JSON string');
}
const newRecord = new QBRecord();
return newRecord.fromJSON(json);
}
/**
* Test if a variable is a `qb-record` object
*
* @param obj A variable you'd like to test
*/
static IsQBRecord(obj) {
return (obj || {}).CLASS_NAME === QBRecord.CLASS_NAME;
}
/**
* Returns a new QBRecord instance built off of `options`, that inherits configuration data from the passed in `data` argument.
*
* @param options QBRecord instance options
* @param data Quick Base Record data
*/
static NewRecord(options, data) {
const newRecord = new QBRecord(options);
if (data) {
Object.entries(data).forEach(([property, value]) => {
newRecord.set(property, value);
});
}
return newRecord;
}
;
}
exports.QBRecord = QBRecord;
QBRecord.CLASS_NAME = 'QBRecord';
QBRecord.VERSION = VERSION;
/**
* The default settings of a `QuickBase` instance
*/
QBRecord.defaults = {
quickbase: {
realm: IS_BROWSER ? window.location.host.split('.')[0] : ''
},
tableId: (() => {
if (IS_BROWSER) {
const tableId = window.location.pathname.match(/^\/db\/(?!main)(.*)$/);
if (tableId) {
return tableId[1];
}
}
return '';
})(),
fids: {
recordid: 3,
primaryKey: 3
},
recordid: undefined,
primaryKey: undefined
};
/* Helpers */
const replaceUndefinedWithString = (val) => {
return val === null || val === undefined || (typeof val === 'number' && isNaN(val)) ? '' : val;
};
exports.replaceUndefinedWithString = replaceUndefinedWithString;
/* Export to Browser */
if (IS_BROWSER) {
window.QBRecord = exports;
}
//# sourceMappingURL=qb-record.js.map