Skip to content

Instantly share code, notes, and snippets.

@Aryk
Created April 16, 2017 04:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Aryk/f1250a091dd115759a0992ac9fd027ec to your computer and use it in GitHub Desktop.
Save Aryk/f1250a091dd115759a0992ac9fd027ec to your computer and use it in GitHub Desktop.
Proposal and Ideas for redux-orm functionality
// Aryk: I wanted to be clear here and separate between ReduxOrmModelRevised and Model. ReduxOrmModelRevised is what
// I think should be in Redux-ORM library (or packaged as an add-on). Model (below) is application specific.
class ReduxOrmModelRevised extends ReduxOrmModel {
public static typeCastersByFieldName;
public static typeCasters = {
string: value => {
value = value.toString();
return trim(value) === '' ? null : value;
},
integer: value => parseInt(value, 10),
foreignKey: value => parseInt(value, 10),
float: value => parseFloat(value),
// '0' will convert to false.
boolean: value => Boolean(value === 'string' ? parseInt(value, 10) : value),
enum: (value, possibleValues) => {
if (possibleValues.indexOf(value) === -1) {
if (value === '') {
value = null;
} else {
throw Error(`Could not find ${value} in ${JSON.stringify(possibleValues)}.`);
}
}
return value;
},
};
// This is a temporary fix until this gets fixed: https://github.com/tommikaikkonen/redux-orm/issues/100.
public static markAccessed() {
this.session.markAccessed(this.modelName);
}
// Convenience wrapper, takes attribute names and adds `attrs()` per the spec. This function allows for
// subclassing and inheriting the fields from above.
public static setFields(attributes: object = {}, attributeKeys: string[] = []) {
const attributesDup = Object.assign({}, attributes);
if (attributeKeys.length > 0) {
Object.assign(attributesDup, fromPairs(attributeKeys.map(key => {
// Add a string primary key for new records so we can reference them.
const opts = key === 'id' ? {getDefault: (): foreignKeyTypeScriptType => uuidV1()} : undefined;
return [key, attr(opts)];
})));
}
this.fields = Object.assign({}, this.fields || {}, attributesDup);
}
/**
* Set types for casting on create and update calls.
* @param typeCastersByFieldName
*/
public static setTypes(typeCastersByFieldName: object) {
this.typeCastersByFieldName = Object.assign({}, this.typeCastersByFieldName, typeCastersByFieldName);
}
public static create(attrs) {
const userSpecifiedId = attrs[this.idAttribute];
if (userSpecifiedId && this.hasId(userSpecifiedId)) {
throw Error(`Record with ID: ${userSpecifiedId} already exists on ${this.modelName}.`);
}
return super.create(this.castValues(attrs));
}
public update(attrs) {
return super.update(this.getClass().castValues(attrs));
}
public static castValues(attrs) {
const newAttrs = {};
if (this.typeCastersByFieldName) {
Object.keys(this.typeCastersByFieldName).forEach(fieldName => {
let typeCaster = this.typeCastersByFieldName[fieldName];
let args = [];
if (isArray(typeCaster)) {
args = typeCaster.slice(1);
typeCaster = typeCaster[0];
}
if (typeCaster) {
const value = attrs[fieldName];
// Aryk: If it's null or undefined, we let them through so that we can assign any field to undefined/null.
if (value !== undefined && value !== null) {
newAttrs[fieldName] = this.typeCasters[typeCaster](value, ...args);
}
}
});
}
return Object.assign({}, attrs, newAttrs);
}
/**
* Refresh the model by providing a new state.
* @param state
* @returns {Model}
*/
public refresh(state) {
(this.getClass() as any).connect(ormSession(state));
this.refreshFromState();
return this;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment