UNPKG

type-arango

Version:

ArangoDB Foxx decorators and utilities for TypeScript

100 lines (85 loc) 3.06 kB
import {isFoxx, toArray} from '../utils' import {QueryOpt} from '../types' import {logger} from '../index' const is = isFoxx() const orders = ['ASC','DESC'] export const arango = is ? require('@arangodb') : null export const db = is ? arango.db : null export const operators = ['==', '!=', '<', '<=', '>', '>=', 'IN', 'NOT IN', 'LIKE', 'NOT LIKE', '=~', '!~', 'HAS'] function escape(val: any){ if(val === 'true') return true if(val === 'false') return false if(val === 'null') return null if(Array.isArray(val)) return '["'+clean(val).join('","')+'"]' switch(typeof val){ case 'string': return '"'+val+'"' case 'number': case 'boolean': return val default: throw {message:'INVALID_ESCAPING',val} } } function clean(val: any): any { if(Array.isArray(val)) return val.map(v => clean(v)) switch(typeof val){ default: case 'number': return val case 'string': const indexOf = val.indexOf(' ') return (indexOf > -1 ? val.substr(0, indexOf) : val).replace(/[^a-zA-Z0-9-_.\[*\]]/g, '') } } export function queryBuilder(collection: string, {filter,sort,limit,aggregate,keep,unset}: QueryOpt){ let q = ['FOR i IN '+collection] if(filter){ for(const f of toArray(filter)){ const entries = Object.entries(f).filter(([key]) => key !== '$') if(!entries.length) continue q.push( `FILTER (${entries.map(([key, value]: any) => ( // ['HAS', value] => FILTER value IN TO_ARRAY(i.key) Array.isArray(value) && value[0] === 'HAS' ? `${escape(value[1])} IN TO_ARRAY(i.${clean(key)})` // ['!=', value] => FILTER i.key != value : Array.isArray(value) && operators.includes(value[0]) ? `i.${clean(key)} ${value[0]} ${escape(value[1])}` // ['value1','value2'] => FILTER i.key IN [...values] : Array.isArray(value) ? `i.${clean(key)} IN ${escape(value)}` // value => FILTER i.key == value : `i.${clean(key)} == ${escape(value)}` ) ).join(` ${f.$ || '&&'} `)})` ) } } if(sort){ q.push('SORT i.'+(Array.isArray(sort) ? sort.map(s => { if(s.includes(' ')){ let [a,o] = s.split(' ') if(!orders.includes(o.toUpperCase())) o = orders[0] return clean(a)+' '+o } return clean(s) + ' ' + orders[0] }).join(', i.') : clean(sort))) } if(limit){ limit = clean(limit) q.push('LIMIT '+(Array.isArray(limit) ? limit.join(',') : limit)) } let ret = 'i' if(keep){ keep = clean(keep) ret = `KEEP(i, "${keep!.join('","')}")` } else if(unset){ unset = clean(unset) ret = `UNSET(i, "${unset!.join('","')}")` } if(aggregate){ q.push(`COLLECT AGGREGATE sum = SUM(${typeof aggregate === 'string' ? aggregate : 1})`) q.push(`RETURN sum`) } else q.push('RETURN '+ret) logger.info('Query %o', q.join(' ')) return q.join('\n') }