@rest-api/react-models
Version:
[](https://www.npmjs.com/package/@rest-api/react-models) [](https://codecov.io/gh/hector7/rest-
392 lines (391 loc) • 17.2 kB
JavaScript
"use strict";
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.Schema = exports.fieldIsSchema = void 0;
const BasicRestModel_1 = __importDefault(require("./restmodels/basic/BasicRestModel"));
const BasicIdRestModel_1 = __importDefault(require("./restmodels/basic/BasicIdRestModel"));
function fieldIsExtendedFormat(property) {
return property !== null && property.hasOwnProperty('type');
}
function isBasicModel(property) {
return property.constructor === BasicIdRestModel_1.default || property.constructor === BasicRestModel_1.default;
}
function fieldIsSchema(property) {
return property && typeof property === 'object' && property.constructor === Schema;
}
exports.fieldIsSchema = fieldIsSchema;
class Schema {
constructor(schema, subSchema) {
this.updateSchema = schema => {
const ownKeys = this.keys;
const targetKeys = Object.keys(schema);
const matchingKeys = ownKeys.filter(k => targetKeys.indexOf(k) >= 0);
return new Schema(Object.assign(Object.assign({}, this._schema), matchingKeys
.map(k => ({ k, v: schema[k] }))
.reduce((o, next) => {
o[next.k] = next.v;
return o;
}, {})), new Schema(schema).deleteFields(...matchingKeys));
};
this.deleteFields = (...fields) => {
let schema = Object.assign({}, this._schema);
fields.forEach(f => {
const _a = schema, _b = f, toBeDelete = _a[_b], other = __rest(_a, [typeof _b === "symbol" ? _b : _b + ""]);
schema = other;
});
if (this._subSchema)
return new Schema(schema, this._subSchema.deleteFields(...fields));
return new Schema(schema);
};
this._schema = schema;
this._subSchema = subSchema;
}
get RealType() {
throw ('This getter is only for typing reasons');
}
get PopulatedType() {
throw ('This getter is only for typing reasons');
}
get FullPopulatedType() {
throw ('This getter is only for typing reasons');
}
static getSchema(schema) {
return new Schema(schema);
}
_fieldIsAnIdModel(property) {
return isBasicModel(property);
}
fieldIsExtendedFormatWithModel(property) {
if (fieldIsExtendedFormat(property)) {
return this._fieldIsAnIdModel(property.type);
}
return false;
}
fieldIsSchema(property) {
return fieldIsSchema(property);
}
isItemFromProperty(item, property, nullable, idOnly = false) {
if (this._fieldIsAnIdModel(property)) {
if (idOnly)
return this.isItemFromProperty(item, property.idType, nullable);
return property.model.schema.validate(item);
}
if (this.fieldIsSchema(property))
return property.validate(item);
if (item === null) {
return nullable;
}
return (item.constructor === property);
}
getErrorFromItemProperty(item, property, nullable, idOnly = false) {
if (this._fieldIsAnIdModel(property)) {
if (idOnly)
return this.getErrorFromItemProperty(item, property.idType, nullable);
return property.model.schema.getValidateError(item);
}
if (this.fieldIsSchema(property))
return property.getValidateError(item);
if (item === null && !nullable) {
return `Received null, not marked as nullable.`;
}
if (item.constructor !== property) {
return `Received: \n ${JSON.stringify(item, null, 2)}\nExpected:\n ${property.name}`;
}
throw new Error('Called getErrorFromItemProperty and not errors found.');
}
get keys() {
if (this._subSchema)
return Object.keys(this._schema).concat(this._subSchema.keys);
return Object.keys(this._schema);
}
/**
*
* @param f field to update
* @param fx function in order to convert the field
*/
updateField(f, fx) {
const schema = new Schema({}, this);
schema.functionToConvert = { key: f, fx };
return schema;
}
/** @internal */
_useUpdatedSteps(state, item) {
let r = item;
if (this._subSchema) {
r = this._subSchema._useUpdatedSteps(state, item);
}
if (this.functionToConvert !== undefined) {
r[this.functionToConvert.key] = this.functionToConvert.fx(r[this.functionToConvert.key]);
}
return r;
}
/** @internal */
_isPopulated(state, item) {
let key;
for (key in this._schema) {
if (item !== null && item.hasOwnProperty(key)) {
// check arrays and required property.
const gField = this._schema[key];
const isArray = fieldIsExtendedFormat(gField) ? Array.isArray(gField.type) : Array.isArray(gField);
const field = Array.isArray(gField) ? gField[0] : gField;
const type = fieldIsExtendedFormat(field) ? field.type : field;
const idOnly = this.fieldIsExtendedFormatWithModel(field) ? field.idOnly === true : false;
const nullable = fieldIsExtendedFormat(field) ? field.nullable === true : false;
if (this._fieldIsAnIdModel(type)) {
if (idOnly) {
if (isArray) {
const array = item[key];
for (let i = 0; i < array.length; i++) {
if (!nullable || (nullable && array[i] !== null)) {
const getByIdResult = type._reducer.getById(state, array[i]);
if (!getByIdResult)
return false;
}
}
}
else {
if ((!nullable || (nullable && item[key] !== null)) && !type._reducer.getById(state, item[key]))
return false;
}
}
}
else if (this.fieldIsSchema(type)) {
if (isArray) {
const array = item[key];
for (let i = 0; i < array.length; i++) {
const getByIdResult = type._isPopulated(state, array[i]);
if (!getByIdResult)
return false;
}
}
else {
if (!type._isPopulated(state, item[key]))
return false;
}
}
}
}
return true;
}
/** @internal */
_convertToPopulated(state, item) {
let key;
let result = Object.assign({}, item);
for (key in this._schema) {
if (item !== null && item.hasOwnProperty(key)) {
// check arrays and required property.
const gField = this._schema[key];
const isArray = fieldIsExtendedFormat(gField) ? Array.isArray(gField.type) : Array.isArray(gField);
const field = Array.isArray(gField) ? gField[0] : gField;
const type = fieldIsExtendedFormat(field) ? field.type : field;
const idOnly = this.fieldIsExtendedFormatWithModel(field) ? field.idOnly === true : false;
const nullable = fieldIsExtendedFormat(field) ? field.nullable === true : false;
if (this._fieldIsAnIdModel(type)) {
if (idOnly) {
if (isArray) {
result[key] = item[key].map((object) => {
if (!nullable || (nullable && object !== null)) {
const getByIdResult = type._reducer.getById(state, object);
return getByIdResult ? type.model.schema._convertToPopulated(state, getByIdResult) : { [type._id]: object };
}
else {
return object;
}
});
}
else {
if (!nullable || (nullable && item[key] !== null)) {
const getByIdResult = type._reducer.getById(state, item[key]);
result[key] = getByIdResult ? type.model.schema._convertToPopulated(state, getByIdResult) : { [type._id]: item[key] };
}
}
}
}
else if (this.fieldIsSchema(type)) {
if (isArray) {
result[key] = item[key].map((object) => {
return type._convertToPopulated(state, object);
});
}
else {
result[key] = type._convertToPopulated(state, item[key]);
}
}
}
}
return result;
}
_getModelValuesToPopulate(item, callback) {
let key;
for (key in this._schema) {
if (item !== null && item.hasOwnProperty(key)) {
// check arrays and required property.
const gField = this._schema[key];
const isArray = fieldIsExtendedFormat(gField) ? Array.isArray(gField.type) : Array.isArray(gField);
const field = Array.isArray(gField) ? gField[0] : gField;
const type = fieldIsExtendedFormat(field) ? field.type : field;
const idOnly = this.fieldIsExtendedFormatWithModel(field) ? field.idOnly === true : false;
const nullable = fieldIsExtendedFormat(field) ? field.nullable === true : false;
if (this._fieldIsAnIdModel(type)) {
if (idOnly) {
if (isArray) {
item[key].forEach((object, idx) => {
if (!nullable || (nullable && object !== null)) {
callback(type, object);
}
});
}
else if (!nullable || (nullable && item[key] !== null)) {
callback(type, item[key]);
}
}
}
else if (this.fieldIsSchema(type)) {
if (isArray) {
item[key].forEach((object, idx) => {
type._getModelValuesToPopulate(object, callback);
});
}
else {
type._getModelValuesToPopulate(item[key], callback);
}
}
}
}
}
validate(str) {
if (process.env.NODE_ENV === 'production')
return true;
if (typeof str !== 'object') {
return false;
}
let key;
for (key in this._schema) {
// check arrays and required property.
const gField = this._schema[key];
const isArray = fieldIsExtendedFormat(gField) ? Array.isArray(gField.type) : Array.isArray(gField);
const field = Array.isArray(gField) ? gField[0] : gField;
const type = fieldIsExtendedFormat(field) ? field.type : field;
const required = fieldIsExtendedFormat(gField) && gField.required === true;
const idOnly = this.fieldIsExtendedFormatWithModel(field) ? field.idOnly === true : false;
const nullable = fieldIsExtendedFormat(field) ? field.nullable === true : false;
if (required && (str === null || !str.hasOwnProperty(key)))
return false;
if (str !== null && str.hasOwnProperty(key)) {
if (isArray) {
if (str[key] === null) {
if (!nullable) {
return false;
}
}
else {
if (!Array.isArray(str[key])) {
return false;
}
for (let i = 0; i < str[key].length; i++) {
if (!this.isItemFromProperty(str[key][i], type, nullable, idOnly))
return false;
}
}
}
else {
if (!this.isItemFromProperty(str[key], type, nullable, idOnly)) {
return false;
}
}
}
}
if (this._subSchema)
return this._subSchema.validate(str);
return true;
}
getValidateError(str) {
if (typeof str !== 'object') {
return `Expected Object, found:
${JSON.stringify(str, null, 2)}`;
}
let key;
for (key in this._schema) {
// check arrays and required property.
const gField = this._schema[key];
const isArray = fieldIsExtendedFormat(gField) ? Array.isArray(gField.type) : Array.isArray(gField);
const field = Array.isArray(gField) ? gField[0] : gField;
const type = fieldIsExtendedFormat(field) ? field.type : field;
const required = fieldIsExtendedFormat(gField) && gField.required === true;
const idOnly = this.fieldIsExtendedFormatWithModel(field) ? field.idOnly === true : false;
const nullable = fieldIsExtendedFormat(field) ? field.nullable === true : false;
if (required && (str === null || !str.hasOwnProperty(key)))
return { [key]: 'Marked as required, not found' };
if (str !== null && str.hasOwnProperty(key)) {
if (isArray) {
if (str[key] === null) {
if (!nullable) {
return { [key]: 'Received null, not marked as nullable' };
}
}
else {
if (!Array.isArray(str[key])) {
return { [key]: 'Is not an array' };
}
for (let i = 0; i < str[key].length; i++) {
if (!this.isItemFromProperty(str[key][i], type, nullable, idOnly))
return { [key]: this.getErrorFromItemProperty(str[key][i], type, nullable, idOnly) };
}
}
}
else {
if (!this.isItemFromProperty(str[key], type, nullable, idOnly)) {
return { [key]: this.getErrorFromItemProperty(str[key], type, nullable, idOnly) };
}
}
}
}
if (this._subSchema)
return this._subSchema.getValidateError(str);
throw new Error('Called getValidateError and not errors found. Check first errors with validate function.');
}
getValidateErrorPretty(str) {
let error = this.getValidateError(str);
let keys = [];
while (typeof error !== 'string') {
const k = Object.keys(error)[0];
keys.push(k);
error = error[k];
}
return `Validate error on path "${keys.join('.')}"\n${error}`;
}
getValidateArrayError(str) {
if (Array.isArray(str)) {
for (let i = 0; i < str.length; i++) {
if (!this.validate(str[i]))
return this.getValidateErrorPretty(str[i]);
}
throw new Error('Called getValidateArrayError and not errors found. Check first errors with validateArray function.');
}
return `Expected Array, found:
${JSON.stringify(str, null, 2)}`;
}
validateArray(str) {
if (process.env.NODE_ENV === 'production')
return true;
if (Array.isArray(str)) {
return str.every(r => this.validate(r));
}
return false;
}
}
exports.Schema = Schema;
exports.default = Schema.getSchema;