import { Topology } from "./topology" import { Tag } from "./tag" import { Condition } from "./condition" import * as asyncModule from "async" import * as Leaf from "leaf-ts" import * as CoreLogic from "./coreLogic" import * as util from "util" import Pot = Type.Topology.Resolution.Pot import Graph = Type.Topology.Resolution.Graph export namespace Pot { export function solveCriteria( option: { topology: Topology graph: Graph pot: Pot data?: Type.Topology.Resolution.Data restriction?: Type.Topology.Resolution.Restriction debug?: boolean }, callback: Callback ) { let topology = option.topology let data = option.data || { pot: {}, pipe: {} } let pot = option.pot let graph = option.graph let queries = [] let outputs: T[] = [] let base = {} let pipes = pot.froms.map(name => graph.pipes[name]) let potData = data.pot[pot.name] = data.pot[pot.name] || {} asyncModule.each(pipes, (pipe, done) => { if (!pipe.from) { if (pipe.criteriaTemplate) { let criteria = Condition.realize(pipe.criteriaTemplate, {}) queries.push(criteria) } done() return } let prev = graph.pots[pipe.from] solve({ topology, graph, pot: prev, data, restriction: option.restriction, debug: option.debug }, (err, result) => { if (err) { done(err) return } try { base[prev.name] = result let pipeQueries = result.map(item => { return Condition.realize(pipe.criteriaTemplate, item) }) let query = Condition.or(pipeQueries) if (!pipe.criteriaTemplate) query = null let pipeRes = option.restriction.pipe[pipe.name] if (pipeRes && pipeRes.query) { query = Condition.and(pipeRes.query, query) } queries.push(query) let pipeData = option.data.pipe[pipe.name] = option.data.pipe[pipe.name] || {} pipeData.datas = result pipeData.pipeQueries = pipeQueries pipeData.query = query } catch (e) { done(e) return } done() }) }, (err) => { if (err) { callback(err) return } let criteria = Condition.and(...queries) if (option.restriction) { let restriction = option.restriction.pot[pot.name] if (restriction.query) { criteria = Condition.and(restriction.query, criteria) } } callback(null, criteria) }) } export function solve(option: { topology: Topology graph: Graph pot: Pot data?: Type.Topology.Resolution.Data restriction?: Type.Topology.Resolution.Restriction // force the offset and count for the resolve in model offset?: number count?: number debug?: boolean }, callback: Callback) { let topology = option.topology let data = option.data || { pot: {}, pipe: {}, } let pot = option.pot let graph = option.graph let queries = [] let outputs: T[] = [] let base = {} let pipes = pot.froms.map(name => graph.pipes[name]) let potData = data.pot[pot.name] = data.pot[pot.name] || {} if (pot.type == "source") { callback(null, potData && potData.srcs || []) return } asyncModule.each(pipes, (pipe, done) => { if (!pipe.from) { if (pipe.criteriaTemplate) { let criteria = Condition.realize(pipe.criteriaTemplate, {}) queries.push(criteria) } done() return } let prev = graph.pots[pipe.from] solve({ topology, graph, pot: prev, data, restriction: option.restriction, debug: option.debug }, (err, result) => { if (err) { done(err) return } base[prev.name] = result if (pot.type == "product") { let transform = pipe.transform || CoreLogic.identity let products = [] result.map(transform).filter(item => !Leaf.Util.isEmptyValue(item)).forEach(item => { if (Array.isArray(item)) { products.push(...item) } else { products.push(item) } }) outputs.push(...products) } else if (pot.type == "model") { let pipeQueries = result.map(item => { return Condition.realize(pipe.criteriaTemplate, item) }) let query = Condition.or(pipeQueries) // in case we shuold by pass but get no pot. if (!pipe.criteriaTemplate) query = null let pipeRes = option.restriction.pipe[pipe.name] if (pipeRes && pipeRes.query) { query = Condition.and(pipeRes.query, query) } option.data.pot[pot.name] = option.data.pot[pot.name] || {} let pipeData = option.data.pipe[pipe.name] = option.data.pipe[pipe.name] || {} pipeData.datas = result pipeData.pipeQueries = pipeQueries pipeData.query = query queries.push(query) } done() }) }, (err) => { if (err) { callback(err) return } if (pot.type == "model") { let criteria = Condition.and(...queries) let backend = topology.getBackend(pot.modelName) let qo: Type.Topology.Resolution.QueryOption = {} if (option.restriction) { let restriction = option.restriction.pot[pot.name] || {} qo = restriction.option || {} if (restriction.query) { criteria = Condition.and(restriction.query, criteria) } } let param = { criteria, ...qo } if (option.count) { param.count = option.count } if (option.offset) { param.offset = option.offset } let potData = option.data.pot[pot.name] = option.data.pot[pot.name] || {} potData.query = param.criteria potData.option = qo potData["queries"] = queries backend.some(param, (err, result) => { if (err) { callback(err) return } potData.datas = result callback(null, result) }) } else if (pot.type == "product") { potData.products = outputs callback(null, outputs) } else if (pot.type == "aggregation") { let agg = pot.aggregate(base) potData.aggregations = agg callback(null, agg) } else { throw new Error("Unknown pot type") } }) } }