Example #1
0
const local = classer('builder', function(h_input) {

	let {
		node: k_node,
	} = h_input;

	// destruct nodes under target namespaces
	let {
		volt: k_node_volt,
	} = k_node.$;

	// create new state for this property
	let h_context = context();

	// pretty print: indentation
	let s_indent_chr = '\t';
	let s_indent = s_indent_chr.repeat(1);

	//
	let s_head = '';
	let s_body = '';
	let s_tail = '';

	// each instruction is evaluated in series
	k_node_volt.instructions((k_instruction) => {

		// forward instruction to instruction builder
		duties.instruction(k_instruction, h_context, {
			head(s_add) {
				s_head += s_indent_chr+s_add+'\n';
			},
			body(s_add, n_indent_add=0) {
				// decrease indent before committing this string
				if(n_indent_add < 0) s_indent = s_indent.slice(0, s_indent_chr.length*n_indent_add);

				// commit string
				s_body += s_indent+s_add+'\n';

				// increase indent after adding this string
				if(n_indent_add > 0) s_indent += s_indent_chr.repeat(n_indent_add);

			},
			async(s_open, s_close='});') {
				s_body += s_indent+s_open+'\n';
				s_tail = `${s_indent}${s_close}\n${s_tail}`;
				s_indent += s_indent_chr;
			},
		});
	});

	// final async failure
	s_body += `${s_indent}return yield_(false, self);\n`;

	//
	let s_contents = s_head+s_body+s_tail;

	//
	let h_args = {
		util: evaluator({
			$$: {
				// proxy spaz select call by choosing graphs too
				select(...a_args) {
					return $$.select(...a_args).from(['graph:source', 'graph:reference', 'graph:output']);
				},
			},
		}),
	};

	//
	let a_arg_names = Object.keys(h_args);
	let a_arg_destructs = a_arg_names.map((s_arg_name) => {
		// ref arg struct
		let h_arg_struct = h_args[s_arg_name];

		// build destruct assignment code
		return `let {${
			Object.keys(h_arg_struct).join(', ')
		}} = ${s_arg_name};`;
	});

	let s_whole = `(function(${a_arg_names.join(',')}) {\n`
		+`${a_arg_destructs.map(s => s_indent_chr+s).join('\n')}\n${s_contents}\n})`;

	local.info(s_whole);

	({
		code: s_whole
	} = require('babel-core').transform(s_whole, {
		presets: ['es2015'],
	}));

	let f_property = eval(s_whole);

	//
	return f_property;
});
Example #2
0
const local = classer('plugins', (h_plugin_modules, h_util) => {

	//
	let h_router = {};

	// add all plugins from hash
	for(let p_namespace in h_plugin_modules) {
		h_router[p_namespace] = {};
	}

	//
	return function(p_function, a_args, f_okay) {

		// prep namespace uri
		let p_namespace;

		// prep user config hash
		let h_user_config = {};

		// parse function uri
		let [, p_prefix, s_querystring, s_function_name] = R_FUNCTION_URI.exec(p_function);

		// querystring-style uri
		if(s_function_name) {
			// no plugin exists in namespace
			if(!h_router.hasOwnProperty(p_prefix)) {
				debugger;
				throw 'no plugin is registered that matches namespace';
			}

			// set namespace
			p_namespace = p_prefix;
		}
		// no querystring, search for namespace
		else {
			// set default querystring
			s_querystring = '';

			// find which namespaces match
			let a_namespace_matches = Object.keys(h_plugin_modules).filter(p_ns => p_prefix.startsWith(p_ns));

			// no matching namespace
			if(!a_namespace_matches.length) {
				debugger;
				throw 'no plugin is registered that matches namespace';
			}
			// multiple namespaces
			else if(a_namespace_matches.length > 1) {
				debugger;
				throw 'multiple namespaces occupy same prefix';
			}
			// single namespace
			else {
				// set namespace
				p_namespace = a_namespace_matches[0];

				// extract function name
				s_function_name = p_function.substr(p_namespace.length);
			}
		}

		// prep plugin instance
		let k_plugin_instance;

		// ref plugin
		let h_plugin = h_router[p_namespace];

		// plugin not yet reserved
		if(!h_plugin) {
			// claim the namespace
			h_plugin = h_router[p_namespace] = {};
		}

		// user config instance does not yet exist
		if(!h_plugin.hasOwnProperty(s_querystring)) {
			// parse querystring using default options from qs module
			h_user_config =s_querystring.length? qs.parse(s_querystring): {};

			// lazily create instance with user config
			k_plugin_instance = h_plugin[s_querystring] = h_plugin_modules[p_namespace](h_user_config);

			// plugin did not return anything useful
			let s_instance_type = typeof k_plugin_instance;
			if('object' !== s_instance_type && 'function' !== s_instance_type) {
				debugger;
				throw 'plugin did not produce a routable datatype';
			}
		}
		// instance exists
		else {
			// ref instance
			k_plugin_instance = h_plugin[s_querystring];
		}

		// function does not exist
		if(!k_plugin_instance.hasOwnProperty(s_function_name)) {
			debugger;
			throw 'function not exists in plugin';
		}
		// function exists
		else {
			// apply function to input args
			k_plugin_instance[s_function_name](f_okay, ...a_args);
		}
	};
});
Example #3
0
const local = classer('compiler', (h_config) => {

	// destruct config
	let {
		code: s_program,
	} = h_config;

	// prep program hash
	let h_program;

	// parse program
	try {
		h_program = parser.parse(s_program);
	}
	catch(e_parse) {
		return {
			error: e_parse,
		};
	}

	// build model ttl
	let s_model = rapunzel({
		builder: new model_builder(h_program),
		config: {
			closing_delimiter: ' .',
		},
	});

	return {
		model: s_model,
	};
});
Example #4
0
const local = classer('router', (s_name, z_router, h_locals) => {

	// shuffle args
	if(!h_locals) {
		h_locals = z_router;
		z_router = undefined;
	}

	//
	return (...a_args) => {

		// prep route name & default return value
		let s_route;
		let w_return;

		// ref router type
		let s_router_type = typeof z_router;

		// router is string
		if('string' === s_router_type) {

			// split by decimal
			let a_properties = z_router.split(/\./g);

			// no need for recursion
			if(1 === a_properties.length) {
				// use that property name of 0th arg
				s_route = a_args[0][a_properties[0]];
			}
			// recurse
			else {
				// start with 0th arg
				let w_node = a_args[0];
				while(a_properties.length) {
					// shift property from each word
					w_node = w_node[a_properties.shift()];
				}

				// end at terminus
				s_route = w_node;
			}
		}
		// router is function
		else if('function' === s_router_type) {
			// prep route callback; set route value
			let f_set_route = (_s_route) => s_route = _s_route;

			// find which route to use
			w_return = z_router.apply(h_locals, [f_set_route, ...a_args]);
		}
		// router is void
		else if('undefined' === s_router_type) {
			// stringify arg value
			s_route = a_args[0]+'';
		}

		// route was set
		if(s_route) {
			// ref handler
			let k_route_handler = h_locals[s_route];

			// route does not exist
			if(!k_route_handler) {
				local.fail(`${s_name} cannot route "${s_route}"`);
			}

			// forward call to route handler
			return k_route_handler(...a_args);
		}
		// route not set; explicit return value
		else {
			return w_return;
		}
	};
}, {

/**
* public static:
**/

	// define how to route from an input to the local handlers
	group(s_group_name, w_router, h_handlers) {
		let h_output = {};

		// each handler
		for(let s_handler_name in h_handlers) {
			let h_handler = h_handlers[s_handler_name];

			// create handler interface
			h_output[s_handler_name] = local(`${s_group_name}.${s_handler_name}`, w_router, h_handler);
		}

		// render callee as output
		return h_output;
	},
});
Example #5
0
const local = classer('QueryPatterns', function(h_init) {

	/**
	* private:
	**/

	let h_prefixes = h_init.prefixes;
	let a_where = h_init.where;

	//
	let h_struct = rmprop({});
	let h_graph = {};
	let as_top_nodes = new Set();

	// each triple
	a_where.forEach((h_pattern) => {

		//
		switch(h_pattern.type) {

			// basic graph pattern
			case 'bgp':

				// each triple in basic graph pattern
				h_pattern.triples.forEach((h_triple) => {

					// ref subject
					let s_subject = h_triple.subject;

					// first triple using this subject
					if(!h_graph[s_subject]) {

						// create list to store triples sharing this subject
						h_graph[s_subject] = [];
					}

					// group triple into buckets by same subject
					h_graph[s_subject].push(h_triple);

					// only add non-blanknodes to top-level
					if(!s_subject.startsWith('_:')) {
						as_top_nodes.add(s_subject);
					}
				});
				break;

			// subquery
			case 'query':

				//
				break;
		}
	});

	// ------------------------------

	//
	const groups = function*(h_group, a_types, s_graph='') {
		let s_latent_graph = '';

		switch(h_group.type) {
			case 'graph':
				s_latent_graph = h_group.graph;
			case 'group':
			case 'union':
			case 'exists':
			case 'notexists':
				for(let i_group in h_group.patterns) {
					yield *groups(h_group.patterns[i_group], a_types, s_latent_graph);
				}

			case 'bgp':
			case 'query':
			case 'values':
				if(!a_types || -1 !== a_types.indexOf(h_group.type)) {
					yield [s_graph, h_group];
				}
				break;

			default:
				local.fail('group not yet caught: '+h_group.type);
				break;
		}
	};

	//
	const depth_first = function*(h_container) {

		// each triple in this node
		for(let h_triple of h_container) {

			// destructure triple
			let {subject: s_subject, predicate: s_predicate, object: s_object} = h_triple;

			// triple points to a blanknode
			if(s_object.startsWith('_:')) {

				// yield depth first triples down that path
				yield *depth_first(h_graph[s_object]);
			}

			// then yield this container triple
			yield [h_triple, s_subject, s_predicate, s_object];
		}
	};

	//
	const closure = function(s_target, h_context) {

		// ref visits
		let as_visits = h_context.visits;

		// traverse in a depth-first manner
		for(let [h_triple, s_subject, s_object, s_predicate] of operator.depth_first()) {

			// triple has been visited already
			if(as_visits.has(h_triple)) continue;

			//
			local.warn('testing for <'+s_target+'> in: '+arginfo(h_triple));

			// otherwise; mark this triple as visited
			as_visits.add(h_triple);

			// prep to remember this triple had a match
			let b_matched = false;

			// subject matches target
			if(s_subject === s_target) {
				b_matched = true;

				// close predicate
				closure(s_predicate, h_context);

				// close object
				closure(s_subject, h_context);
			}
			// predicate matches target
			else if(s_predicate === s_target) {
				b_matched = true;

				// close subject
				closure(s_subject, h_context);

				// close object
				closure(s_subject, h_context);
			}
			// object matches target
			else if(s_object === s_target) {
				b_matched = true;

				// close subject
				closure(s_subject, h_context);

				// close predicate
				closure(s_predicate, h_context);
			}

			// push triple to list
			if(b_matched) {
				local.good('+match');
				h_context.triples.push(h_triple);
			}
		}

		local.info('final triples of closure, '+arginfo(h_context.triples));

		// return triples list
		return h_context.triples;
	};


	//
	const bgp_closure = function(h_bgp, as_targets) {

		//
		let as_triples = new Set();

		//
		h_bgp.triples.forEach((h_triple) => {

			//
			if(as_targets.has(h_triple.subject)) {
				as_triples.add(h_triple);
			}

			if(as_targets.has(h_triple.predicate)) {
				as_triples.add(h_triple);
			}

			if(as_targets.has(h_triple.object)) {
				as_triples.add(h_triple);
			}
		});

		//
		return {
			type: 'bgp',
			triples: Array.from(as_triples),
		};
	};


	//
	const node_tree = function(s_node_id, h_forest) {

		// find this tree
		let h_tree = h_forest[s_node_id];

		// no tree!
		if(!h_tree) return s_node_id;

		// each branch in tree
		for(let s_predicate in h_tree) {

			// transform each leaf by pointing it to another tree
			h_tree[s_predicate] = h_tree[s_predicate].map((s_object) => {

				// only recurse on blanknodes; TODO: what about variables? 
				if(s_object.startsWith('_:')) {
					return node_tree(s_object, h_forest);
				}
				else {
					return s_object;
				}
			});
		}

		// return tree;
		return h_tree;
	};


	// 
	let operator = {

		// groups in a depth-first manner
		groups: function*(a_types) {

			// each top-level group
			for(let i_group in a_where) {
				let h_group = a_where[i_group];

				//
				yield *groups(h_group, a_types);
			}
		},

		// subqueries
		subqueries: function*() {

			// yield groups of subquery type
			yield *operator.groups(['query']);
		},

		// depth-first iteration
		depth_first: function*() {

			// each top level node
			for(let s_node_id of as_top_nodes) {

				// yield depth first triples
				yield *depth_first(h_graph[s_node_id]);
			}
		},

		// // depth-last iteration
		// depth_last: function*() {

		// 	// each top level node
		// 	for(let s_node_id of as_top_nodes) {

		// 		// yield depth first triples
		// 		yield *depth_last(h_graph[s_node_id]);
		// 	}
		// },

		// top-level iteration
		top_level: function*() {

			// each top level node
			for(let s_node_id of as_top_nodes) {

				// each triple pointed to by this subject
				for(let h_triple of h_graph[s_node_id]) {

					// destructure triple
					let {subject: s_subject, predicate: s_predicate, object: s_object} = h_triple;

					// yield top-level triples
					yield [h_triple, s_subject, s_predicate, s_object];
				}
			}
		},

		// obtains all triples that constrain any of the subject, predicate or object in the given triple
		constrained_by: function(h_triple) {

			// create list of targets to constrain from triple
			let as_targets = new Set([h_triple.subject, h_triple.predicate, h_triple.object]);

			// prep to store all patterns necessary for constraint
			let a_patterns = [];

			// each group in where block
			for(let [s_graph, h_group] of operator.groups()) {

				// graphs not yet supported
				if(s_graph) {
					local.fail('cannot constrain groups within GRAPH blocks');
				}

				// what is the group type?
				switch(h_group.type) {

					// basic graph pattern
					case 'bgp':

						// do bgp closure keeping only triples that constrain targets
						a_patterns.push(
							bgp_closure(h_group, as_targets)
						);
						break;

					// values block
					case 'values':

						// ref variables
						let a_vars = Object.keys(h_group.values[0]);

						debugger;

						// at least one of the variables is in targets
						if(a_vars.some((s_variable) => as_targets.has(s_variable))) {

							// keep entire values block
							a_patterns.push(h_group);

							// constrain all other variables
							if(a_vars.length > 1) {
								local.fail('cannot constrain multiple variable in VALUES block');
							}
						}
						break;

					// something else
					default:
						local.fail('cannot constrain '+h_group.type.toUpperCase()+' block');
						break;
				}

				debugger;
			}

			//
			return a_patterns;
		},

		// filter only triples that are closed by the given thing
		closure: function(s_thing) {

			// 
			return closure(s_thing, {
				visits: new Set(),
				triples: [],
			});
		},

		// create a tree to describe all properties of a subject
		tree: function(s_node_id) {

			// get statement forest
			let h_forest = operator.bgp_forest();

			// build node tree
			return node_tree(s_node_id, h_forest);
		},

		// create a tree of all statements in a bgp
		bgp_forest: function() {

			// prep hash for each node by id
			let h_forest = {};

			// 
			for(let s_subject in h_graph) {

				// ref triples list
				let a_triples = h_graph[s_subject];

				// each triple
				a_triples.forEach((h_triple) => {

					// ref node root
					let h_root = h_forest[s_subject];

					// node root does not yet exist
					if(!h_root) {

						// create node root
						h_root = h_forest[s_subject] = {};
					}

					// ref predicate
					let s_predicate = h_triple.predicate;

					// ref node branch
					let h_branch = h_root[s_predicate];

					// node branch does not yet exit
					if(!h_branch) {

						// create node branch
						h_branch = h_root[s_predicate] = [];
					}

					// push node leaf to node branch
					h_branch.push(h_triple.object);
				});
			}

			// return forest
			return h_forest;
		},
	};

	//
	return operator;
}, {

	/**
	* public static:
	**/

});
Example #6
0
const local = classer('engine', (h_config={}) => {

	// destruct config arg
	let {
		endpoint: s_endpoint,
		plugins: h_plugins,
	} = h_config;

	// open connection to SPARQL endpoint
	let $$ = spaz({
		engine: {
			endpoint: s_endpoint,
			http_methods: 'post',
		},
		prefixes: Object.assign({}, H_DEFAULT_PREFIXES, h_config.prefixes || {}, H_REQUIRED_PREFIXES),
	});

	// create plugin router
	let k_plugin_router = plugins(h_config.plugins || {}, $$);


	/**
	* operator:
	**/
	return classer.operator((s_sparql, f_okay) => {

		// new query id
		let s_query_id = i_query.toString(N_ID_RADIX);

		// parse sparql query
		let q_input;
		try {
			q_input = $$(s_sparql);
		}
		catch(e) {
			return f_okay({
				error: e+'',
			});
		}

		// extract graph patterns as a structured graph
		let k_patterns = q_input.patterns();

		// create graphs for this query instance; copy defaults
		let h_graphs = {};
		for(let s_key in H_GRAPH_GROUPS) {
			h_graphs[s_key] = H_GRAPH_GROUPS[s_key].slice(0);
		}

		// set unique graphs for this query
		A_UNIQUE_GRAPHS.forEach((s_graph_type) => {
			h_graphs[s_graph_type] = ['graph:'+s_graph_type+'_'+s_query_id];
		});

		// prep transfer hash
		let h_transfer = {
			$$,
			graphs: h_graphs,
			patterns: k_patterns,
			plugin_router: k_plugin_router,
		};

		// step through the query phases in series
		async.series([

			// relations
			(f_next) => {
				relations(h_transfer, () => {
					local.good('all done with relations');
					f_next();
				});
			},
		], () => {

			// all done evaluating phases of query
			local.good('=== all done evaluating phases of input query ===');

			// set the default `from` graphs
			q_input
				// content graphs
				.from(h_graphs.content)
				// input graph
				.from(h_graphs.input);

			// ref query's `order by` conditions
			let a_order = q_input.order();

			// no order clause!
			if(!a_order.length) {
				// execute input query and return results to callback
				return q_input.exec(f_okay);
			}
			// at least one order clause
			else {

				throw 'no order by clause handler yet';
				debugger;
				// // examine each order clause
				// a_order.forEach((h_order) => {

				// 	// clause contains function call
				// 	if(h_order.expression && 'functionCall' === h_order.expression.type) {

				// 		// set resolve to results filter function
				// 		h_transfer.resolve = f_filter_results;

				// 		// set expression
				// 		h_transfer.expression = h_order.expression;

				// 		// set extra args for function call
				// 		h_transfer.extra_args = a_extra_args;

				// 		// evaluate the function call
				// 		solve_query_function_call(h_transfer);
				// 	}
				// });
			}
		});

	}, {

	});
}, {

	/**
	* public static:
	**/

	// lazily load compiler
	compile(...a_args) {
		return require('../compiler/compiler.js').default(...a_args);
	},

});