Source: components/traits/Eloquent.js

import React from 'react';
import Trait from './Trait';

import { studly_case } from '../../helpers';

import { difference, intersection } from 'lodash';

/** */
class Eloquent extends Trait{
	/** */
	constructor(targetClass){
		super(targetClass);
	}

	/** */
	static query_props = ['find', 'where', 'all', 'first'];

	/** */
	static pagination_props = ['per_page'];

	/** */
	static get reserved_props(){
		return [...this.query_props, ...this.pagination_props, 'order_by', 'sort_by'];
	}

	/** */
	static get_non_reserved_props(props){
		const ret = difference(Object.keys(props), this.reserved_props);
		const val = {};
		for(const i in ret){
			val[ret[i]] = props[ret[i]];
		}
		return val;
	}

	/** */
	get_non_reserved_props(){
		return this.constructor.get_non_reserved_props(this.props);
	}

	/** */
	get non_reserved_props(){
		return this.get_non_reserved_props();
	}

	/** */
	get_query_prop(){
		const i = intersection(this.constructor.query_props, Object.keys(this.props));
		return i.length ? i[0] : null;
	}

	/** */
	get query_prop(){
		return this.get_query_prop();
	}

	/** */
	get is_query(){
		return !!this.get_query_prop();
	}

	/** */
	get_query_endpoint(){
		const q = this.get_query_prop();
		let where_prop;
		if(q == 'where'){
			if(Array.isArray(this.props.where)){
				where_prop = this.props.where.join('|');
			}
			else where_prop = this.props.where;
		}
		const map = {
			find: `/api/${this.singular}/${this.props.find}`,
			where: `/api/${this.plural}/where/${where_prop}`,
			all: `/api/${this.plural}`,
			first: `/api/${this.singular}`,
		}
		const qs_object = {};
		if(this.props.per_page) qs_object.per_page = this.props.per_page;
		const qs_string = qs.stringify(qs_object);
		return map[q] + `?${qs_string}`;
	}

	/** */
	queryRender(){
		const q = this.get_query_endpoint();
		return <Shell url={q} Model={this.constructor} {...this.non_reserved_props} />
	}

	/** */
	render(){
		if(this.is_query){
			return this.queryRender();
		}

		let renderAs = this.props.renderAs || this.props.render || 'Default';
		let renderName = `render${studly_case(renderAs)}`;
		if(typeof renderAs === 'function'){
			return renderAs(this.props);
		}

		if(typeof this[renderName] === 'function'){
			return this[renderName]();
		}

		// return the default render method.
		return this.renderDefault();
	}

	/** */
	renderDebug(){
		return (<div><code>{this.constructor.name} | {this.props.id}</code></div>);
	}

}

window.Eloquent = Eloquent;

export default Eloquent;