Skip to content

Instantly share code, notes, and snippets.

@morlay
Last active August 29, 2015 14:26
Show Gist options
  • Save morlay/9cb4a83dd36ac02b3c1f to your computer and use it in GitHub Desktop.
Save morlay/9cb4a83dd36ac02b3c1f to your computer and use it in GitHub Desktop.
import isFunction from 'lodash.isFunction';
import isArray from 'lodash.isArray';
import Immutable from 'immutable';
import isTypeObject from './isTypeObject';
import isTypeArray from './isTypeArray';
import SchemaRecord from './../models/SchemaRecord';
export default function completeSchema(schema) {
schema = schema.asMutable();
if (isTypeObject(schema)) {
return schema.update('properties', (schemaProps)=> {
return schemaProps.map(updateSchemaItem);
}
);
}
function updateSchemaItem(schemaItem) {
if (isTypeObject(schemaItem)) {
const factory = schemaItem.get('factory');
return Immutable.fromJS({
factory: isFunction(factory) ? factory : SchemaRecord.createFactory(SchemaRecord(schemaItem.toJS()))
});
}
if (isTypeArray(schemaItem)) {
const isItemTypeObject = isTypeObject(schemaItem.get('items'));
if (isItemTypeObject) {
schemaItem = schemaItem.update('items', updateSchemaItem);
}
return schemaItem.set('factory', schemaListFactory(schemaItem, isItemTypeObject));
}
return schemaItem;
}
function schemaListFactory(arraySchema = {}, isItemTypeObject = false) {
return (values)=> {
if (!(values instanceof Immutable.List)) {
values = Immutable.List(isArray(values) ? values : undefined);
}
return values.update((list)=> {
return list.map((listItem)=> {
if (isItemTypeObject) {
return arraySchema.getIn(['items', 'factory'])(listItem);
}
return listItem;
});
});
};
}
return schema;
}
import immutable from 'immutable';
export default function isTypeArray(schema = {}) {
return immutable.Map.isMap(schema.get('items'));
}
import immutable from 'immutable';
export default function isTypeObject(schema = {}) {
return immutable.Map.isMap(schema.get('properties'));
}
import Immutable from 'immutable';
import _ from 'lodash'
import jsen from 'jsen'
import isTypeArray from './../libs/isTypeArray';
import updateData from './../libs/updateData';
import completeSchema from './../libs/completeSchema';
function SchemaRecord(schema = {}) {
if (!(this instanceof SchemaRecord)) {
return new SchemaRecord(schema);
}
schema = Immutable.fromJS(schema);
schema = completeSchema(schema);
const DefinedRecord = Immutable.Record(updateData(schema), schema.id);
function SchemaRecordType(values = {}) {
DefinedRecord.call(this, updateData(schema, values));
}
SchemaRecordType.prototype = Object.create(DefinedRecord.prototype);
SchemaRecordType.prototype.constructor = SchemaRecordType;
SchemaRecordType.prototype._factories = schema.get('properties')
.map((schemaItem)=> {
return schemaItem.get('factory', null);
})
.toObject();
SchemaRecordType.getSchema = SchemaRecordType.prototype.getSchema = function () {
return schema;
};
SchemaRecordType.setSchema = SchemaRecordType.prototype.setSchema = function (newSchema) {
schema = schema.merge(newSchema);
};
SchemaRecordType.createFactory = SchemaRecordType.prototype.createFactory = function (Model) {
if (new Model() instanceof SchemaRecordType) {
schema = schema.merge({'factory': SchemaRecord.createFactory(Model)});
}
};
SchemaRecordType.prototype.set = function (key, val) {
const factories = this._factories;
const factory = factories && factories[key];
return Object.getPrototypeOf(SchemaRecordType.prototype).set.call(this, key, factory ? factory(val) : val);
};
SchemaRecordType.getMeta = SchemaRecordType.prototype.getMeta = function (key) {
return getMetaFromSchema(schema, key);
};
SchemaRecordType.getMetaIn = SchemaRecordType.prototype.getMetaIn = function (keyPath) {
if (keyPath) {
keyPath = [].concat(keyPath);
return keyPath.reduce(getMetaFromSchema, schema);
}
};
SchemaRecordType.prototype.validate = function () {
return this.reduce((valid, value, key)=> {
return this.getValidator(key)(value) && valid;
}, true);
};
SchemaRecordType.prototype.setValidateError = function (key, errorKeyword) {
const validate = this.getValidator(key);
if (errorKeyword && validate) {
const errors = validate.errors;
errors.push({
keyword: errorKeyword,
path: ''
});
validate.errors = errors;
}
return this;
};
SchemaRecordType.prototype._validators = schema.get('properties')
.map((schemaItem)=> {
return createValidator(schemaItem)
});
SchemaRecordType.prototype.getValidator = function (key) {
if (!this._validators.has(key)) {
throw new Error(`${key} is not in ${String(this)}`)
}
return this._validators.get(key);
};
SchemaRecordType.prototype.getErrorMsg = function (key) {
const validate = this.getValidator(key);
if (validate.errors.length) {
const errorMsg = this.getMeta(key).get('errorMsg', Immutable.fromJS({}));
const displayErrorList = [];
validate.errors.forEach((errorItem)=> {
const msg = errorMsg.get(errorItem.keyword);
if (msg) {
displayErrorList.push(msg);
}
});
if (displayErrorList.length) {
return displayErrorList.join('; ')
}
return errorMsg.get('default') || '未知错误';
}
return null;
};
return SchemaRecordType;
}
SchemaRecord.createFactory = function (Model) {
const factory = function (values) {
return new Model(values);
};
factory.type = Model;
return factory;
};
function getMetaFromSchema(schema, key) {
if (key) {
const fieldSchema = schema.getIn(['properties', key]);
if (fieldSchema) {
if (isTypeArray(fieldSchema)) {
return getItemSchema(fieldSchema.get('items'));
}
return getItemSchema(fieldSchema);
}
}
return schema;
}
function getItemSchema(itemSchema = {}) {
if (itemSchema.has('factory')) {
return itemSchema.get('factory').type.getMeta();
}
return itemSchema;
}
function createValidator(itemSchema = {}) {
let options = {};
if (itemSchema.has('formats')) {
options.formats = itemSchema.get('formats').toObject();
itemSchema = itemSchema.remove('formats');
}
const validate = jsen(itemSchema.toJS(), options);
function customValidate(value) {
validate(value);
let errors = validate.errors;
if (itemSchema.has('required')) {
if (_.isEmpty(value)) {
errors = [{
'keyword': 'required',
'path': ''
}]
}
}
return (customValidate.errors = errors) && errors.length === 0;
}
return customValidate;
}
export default SchemaRecord;
import isTypeObject from './isTypeObject';
import isFunction from 'lodash.isFunction';
export default function updateData(schema = {}, data = {}) {
if (isTypeObject(schema)) {
return schema
.get('properties')
.map((schemaItem, key)=> {
const factory = schemaItem.get('factory');
let values = data && data[key];
return isFunction(factory) ? factory(values) : (values || schemaItem.get('default', null));
})
.toObject();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment