mirror of https://github.com/nocodb/nocodb
Wing-Kam Wong
2 years ago
11 changed files with 0 additions and 75972 deletions
File diff suppressed because it is too large
Load Diff
@ -1,37 +0,0 @@
|
||||
// refer : https://stackoverflow.com/a/6713782
|
||||
|
||||
module.exports = function compareObj(x, y) { |
||||
if (x === y) return true; |
||||
// if both x and y are null or undefined and exactly the same
|
||||
|
||||
if (!(x instanceof Object) || !(y instanceof Object)) return false; |
||||
// if they are not strictly equal, they both need to be Objects
|
||||
|
||||
if (x.constructor !== y.constructor) return false; |
||||
// they must have the exact same prototype chain, the closest we can do is
|
||||
// test there constructor.
|
||||
|
||||
for (var p in x) { |
||||
if (!x.hasOwnProperty(p)) continue; |
||||
// other properties were tested using x.constructor === y.constructor
|
||||
|
||||
if (!y.hasOwnProperty(p)) return false; |
||||
// allows to compare x[ p ] and y[ p ] when set to undefined
|
||||
|
||||
if (x[p] === y[p]) continue; |
||||
// if they have the same strict value or identity then they are equal
|
||||
|
||||
if (typeof (x[p]) !== "object") return false; |
||||
// Numbers, Strings, Functions, Booleans must be strictly equal
|
||||
|
||||
if (!compareObj(x[p], y[p])) return false; |
||||
// Objects and Arrays must be tested recursively
|
||||
} |
||||
|
||||
for (p in y) |
||||
if (y.hasOwnProperty(p) && !x.hasOwnProperty(p)) |
||||
return false; |
||||
// allows x[ p ] to be set to undefined
|
||||
|
||||
return true; |
||||
} |
@ -1,32 +0,0 @@
|
||||
const { |
||||
graphql, |
||||
GraphQLSchema, |
||||
GraphQLObjectType, |
||||
GraphQLString, |
||||
} = require( 'graphql'); |
||||
|
||||
var schema = new GraphQLSchema({ |
||||
query: new GraphQLObjectType({ |
||||
name: 'RootQueryType', |
||||
fields: { |
||||
hello: { |
||||
type: GraphQLString, |
||||
resolve() { |
||||
return 'world'; |
||||
}, |
||||
}, |
||||
}, |
||||
}), |
||||
}); |
||||
|
||||
|
||||
|
||||
var source = '{ hello }'; |
||||
|
||||
graphql({ schema, source }).then((result) => { |
||||
// Prints
|
||||
// {
|
||||
// data: { hello: "world" }
|
||||
// }
|
||||
console.log(result); |
||||
}); |
@ -1,6 +0,0 @@
|
||||
{ |
||||
"dev": { |
||||
"projectId": "dooku_bac0", |
||||
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InVzZXJAbm9jb2RiLmNvbSIsImZpcnN0bmFtZSI6bnVsbCwibGFzdG5hbWUiOm51bGwsImlkIjoxLCJyb2xlcyI6InVzZXIiLCJpYXQiOjE2NDA0MjA4MzN9.Ixh4PRNVoCV_nCq6amKB7EjRJO90_iMxF2LXaHDA6W4\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InVzZXJAbm9jb2RiLmNvbSIsImZpcnN0bmFtZSI6bnVsbCwibGFzdG5hbWUiOm51bGwsImlkIjoxLCJyb2xlcyI6InVzZXIiLCJpYXQiOjE2NDA0MjA4MzN9.Ixh4PRNVoCV_nCq6amKB7EjRJO90_iMxF2LXaHDA6W4\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InVzZXJAbm9jb2RiLmNvbSIsImZpcnN0bmFtZSI6bnVsbCwibGFzdG5hbWUiOm51bGwsImlkIjoxLCJyb2xlcyI6InVzZXIiLCJpYXQiOjE2NDA0MjA4MzN9.Ixh4PRNVoCV_nCq6amKB7EjRJO90_iMxF2LXaHDA6W4\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InVzZXJAbm9jb2RiLmNvbSIsImZpcnN0bmFtZSI6bnVsbCwibGFzdG5hbWUiOm51bGwsImlkIjoxLCJyb2xlcyI6InVzZXIiLCJpYXQiOjE2NDA0MjA4MzN9.Ixh4PRNVoCV_nCq6amKB7EjRJO90_iMxF2LXaHDA6W4\neyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6InVzZXJAbm9jb2RiLmNvbSIsImZpcnN0bmFtZSI6bnVsbCwibGFzdG5hbWUiOm51bGwsImlkIjoxLCJyb2xlcyI6InVzZXIiLCJpYXQiOjE2NDA0MjA4MzN9.Ixh4PRNVoCV_nCq6amKB7EjRJO90_iMxF2LXaHDA6W4" |
||||
} |
||||
} |
File diff suppressed because one or more lines are too long
@ -1,336 +0,0 @@
|
||||
const delay = t => new Promise(res => setTimeout(() => res(), t)) |
||||
|
||||
const time = 1000; |
||||
const knex = require('knex')({ |
||||
client: 'mysql2', |
||||
connection: { |
||||
user: 'root', |
||||
password: 'password', |
||||
database: 'sakila' |
||||
} |
||||
}); |
||||
|
||||
|
||||
class Country { |
||||
constructor(data) { |
||||
Object.assign(this, data) |
||||
} |
||||
|
||||
async cityList() { |
||||
return (await knex('city').select('*').where({ |
||||
country_id: this.country_id |
||||
}).limit(1)).map(c => new City(c)) |
||||
} |
||||
|
||||
async cityCount() { |
||||
return (await knex('city').count('city_id as count').where({ |
||||
country_id: this.country_id |
||||
}).first()).count |
||||
} |
||||
|
||||
async addressCount(args) { |
||||
|
||||
return await Promise.all(args.map(c => c.addressCount())) |
||||
|
||||
// return (await knex('city').count('city_id as count').where({
|
||||
// country_id: this.country_id
|
||||
// }).first()).count
|
||||
} |
||||
|
||||
async addressList(args) { |
||||
|
||||
return await Promise.all((await this.cityList()).map(c => c.addressList())) |
||||
|
||||
// return (await knex('city').count('city_id as count').where({
|
||||
// country_id: this.country_id
|
||||
// }).first()).count
|
||||
} |
||||
} |
||||
|
||||
|
||||
class Address { |
||||
constructor(data) { |
||||
Object.assign(this, data) |
||||
} |
||||
} |
||||
|
||||
class City { |
||||
constructor(data) { |
||||
Object.assign(this, data) |
||||
} |
||||
|
||||
async countryRead() { |
||||
return new Country((await knex('country').select('*').where({ |
||||
country_id: this.country_id |
||||
}).first())) |
||||
} |
||||
|
||||
/* async addressList() { |
||||
return (await knex('address').select('*').where({ |
||||
city_id: this.city_id |
||||
})).map(c => new Address(c)) |
||||
}*/ |
||||
|
||||
/* async addressCount() { |
||||
return (await knex('address').count('city_id as count').where({ |
||||
city_id: this.city_id |
||||
}).first()).count |
||||
}*/ |
||||
|
||||
|
||||
} |
||||
|
||||
|
||||
// const nestResolver = {
|
||||
// country: `INDIA`,
|
||||
// async cityCount() {
|
||||
// await delay(time)
|
||||
// return `12-${time}`
|
||||
// },
|
||||
// async cityList() {
|
||||
// await delay(time)
|
||||
// return {
|
||||
// city: `city 1-${time}`,
|
||||
// async addressCount() {
|
||||
// await delay(time)
|
||||
// return `2-${time}`
|
||||
// },
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
|
||||
|
||||
const rootAst = { |
||||
Country: { |
||||
name: 'Country', |
||||
type: 'Object', |
||||
fields: { |
||||
country_id: { |
||||
name: 'country_id', |
||||
type: 'number' |
||||
}, country: { |
||||
name: 'country', |
||||
type: 'string' |
||||
}, cityList: { |
||||
name: 'cityList', |
||||
type: 'array', |
||||
elementType: 'City', |
||||
nested: { |
||||
level: 1, dependsOn: ['country_id'] |
||||
} |
||||
}, cityCount: { |
||||
name: 'cityCount', |
||||
type: 'number', |
||||
nested: { |
||||
level: 1, dependsOn: ['country_id'] |
||||
} |
||||
}, addressCount: { |
||||
name: 'addressCount', |
||||
type: 'number', |
||||
nested: {level: 2, dependsOn: ['cityList', 'addressCount']} |
||||
} |
||||
} |
||||
}, City: { |
||||
name: 'City', |
||||
type: 'Object', |
||||
fields: { |
||||
city_id: { |
||||
name: 'city_id', |
||||
type: 'number' |
||||
}, country_id: { |
||||
name: 'country_id', |
||||
type: 'number' |
||||
}, city: { |
||||
name: 'city', |
||||
type: 'string' |
||||
}, addressList: { |
||||
name: 'addressList', |
||||
type: 'array', |
||||
elementType: 'City' |
||||
}, countryRead: { |
||||
name: 'countryRead', |
||||
type: 'Country' |
||||
}, addressCount: { |
||||
name: 'addressCount', |
||||
type: 'number' |
||||
} |
||||
} |
||||
}, Address: { |
||||
name: 'Address', |
||||
type: 'Object', |
||||
fields: { |
||||
address: { |
||||
name: 'address', |
||||
type: 'string' |
||||
} |
||||
} |
||||
}, |
||||
CountryList: { |
||||
type: 'array', |
||||
elementType: 'Country' |
||||
}, |
||||
} |
||||
|
||||
|
||||
const nestResolver = { |
||||
async Country() { |
||||
return new Country(await knex('country').first()) |
||||
}, |
||||
|
||||
async CountryList() { |
||||
return (await knex('country').limit(10)).map(c => new Country(c)) |
||||
} |
||||
} |
||||
|
||||
|
||||
const req = { |
||||
CountryList: { |
||||
country: 1, |
||||
cityList: { |
||||
addressCount: 1 |
||||
}, |
||||
addressCount: 1, |
||||
}, |
||||
} |
||||
|
||||
|
||||
const reqExecutor = async (reqObj, resObj, _ast) => { |
||||
|
||||
const res = {} |
||||
// const dependedFields = Object.keys(reqObj).map(k => (ast.fields && ast.fields[k] && ast.fields[k].nested && ast.fields[k].nested.dependsOn))
|
||||
/* const dependFields = new Set(); |
||||
for(const k of Object.keys(reqObj)){ |
||||
if(ast.fields && ast.fields[k] && ast.fields[k].nested && ast.fields[k].nested.dependsOn){ |
||||
dependFields.add(ast.fields[k].nested.dependsOn) |
||||
|
||||
} |
||||
}*/ |
||||
|
||||
function extractDependsOn(key, i = 0, prev, __ast) { |
||||
const ast = __ast || _ast |
||||
if (!prev || typeof prev !== 'object' || i >= _ast.fields[key].nested.dependsOn.length) { |
||||
if (typeof resObj[key] === 'function') { |
||||
return resObj[key](prev)//.call(res);
|
||||
// console.log(prefix + res[key])
|
||||
} else if (typeof resObj[key] === 'object') { |
||||
return Promise.resolve(resObj[key]) |
||||
// console.log(prefix + res[key])
|
||||
} else { |
||||
return Promise.resolve(resObj[key]) |
||||
// console.log(prefix + res[key])
|
||||
} |
||||
} |
||||
if (typeof prev[key] === 'function') { |
||||
return resObj[key](res)//.call(res);
|
||||
// console.log(prefix + res[key])
|
||||
} |
||||
|
||||
|
||||
if (!prev[_ast.fields[key].nested.dependsOn[i]]) |
||||
extractField(_ast.fields[key].nested.dependsOn[i], _ast) |
||||
prev[key] = prev[_ast.fields[key].nested.dependsOn[i]].then(next => { |
||||
// return extractDependsOn(key, ++i, next)
|
||||
|
||||
|
||||
if (Array.isArray(next)) { |
||||
return Promise.all(next.map(r => extractDependsOn(key, ++i, r, rootAst[_ast[ast.fields[key].nested.dependsOn[i]].elementType]))) |
||||
} else { |
||||
return extractDependsOn(reqObj[key], ++i, next, _ast[ast.fields[key].nested.dependsOn[i]]) |
||||
} |
||||
|
||||
}) |
||||
return prev[key] |
||||
} |
||||
|
||||
|
||||
function extractField(key, __ast) { |
||||
const ast = __ast || _ast |
||||
|
||||
if (!(ast.fields && ast.fields[key] && ast.fields[key].nested)) { |
||||
if (typeof resObj[key] === 'function') { |
||||
res[key] = resObj[key]()//.call(res);
|
||||
// console.log(prefix + res[key])
|
||||
} else if (typeof resObj[key] === 'object') { |
||||
res[key] = Promise.resolve(resObj[key]) |
||||
// console.log(prefix + res[key])
|
||||
} else { |
||||
res[key] = Promise.resolve(resObj[key]) |
||||
// console.log(prefix + res[key])
|
||||
} |
||||
} else { |
||||
extractDependsOn(key, 0, res) |
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
|
||||
for (const key of Object.keys(reqObj)) { |
||||
if (key in resObj) { |
||||
extractField(key); |
||||
} |
||||
|
||||
|
||||
if (reqObj[key] && typeof reqObj[key] === 'object') { |
||||
res[key] = res[key].then(res1 => { |
||||
if (Array.isArray(res1)) { |
||||
return Promise.all(res1.map(r => reqExecutor(reqObj[key], r, rootAst[_ast[key].elementType]))) |
||||
} else { |
||||
return reqExecutor(reqObj[key], res1, _ast[key]) |
||||
} |
||||
}) |
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
await Promise.all(Object.values(res)) |
||||
|
||||
const out = {}; |
||||
for (const [k, v] of Object.entries(res)) { |
||||
out[k] = await v |
||||
} |
||||
|
||||
|
||||
return out |
||||
} |
||||
|
||||
(async () => { |
||||
console.time('start') |
||||
console.log(JSON.stringify(await reqExecutor(req, nestResolver, rootAst), 0, 2)); |
||||
console.timeEnd('start') |
||||
})().catch(e => console.log(e)).finally(() => process.exit(0)) |
||||
|
||||
|
||||
const reqExecutorOld = async (reqObj, resObj, ast) => { |
||||
|
||||
const res = {} |
||||
|
||||
|
||||
await Promise.all(Object.keys(reqObj).map(async (key) => { |
||||
if (key in resObj && !(ast.fields && ast.fields[key] && ast.fields[key].dependsOn)) { |
||||
|
||||
if (typeof resObj[key] === 'function') { |
||||
res[key] = await resObj[key]()//.call(res);
|
||||
// console.log(prefix + res[key])
|
||||
} else if (typeof resObj[key] === 'object') { |
||||
res[key] = resObj[key] |
||||
// console.log(prefix + res[key])
|
||||
} else { |
||||
res[key] = resObj[key] |
||||
// console.log(prefix + res[key])
|
||||
} |
||||
await delay(100) |
||||
} |
||||
if (reqObj[key] && typeof reqObj[key] === 'object') { |
||||
if (Array.isArray(res[key])) { |
||||
res[key] = await Promise.all(res[key].map(r => reqExecutor(reqObj[key], r, rootAst[ast[key].elementType]))) |
||||
} else { |
||||
res[key] = await reqExecutor(reqObj[key], res[key], ast[key]) |
||||
} |
||||
} |
||||
|
||||
})) |
||||
|
||||
return res |
||||
} |
@ -1,365 +0,0 @@
|
||||
const {expect} = require('chai'); |
||||
require('mocha'); |
||||
const knex = require('knex')({ |
||||
client: 'mysql2', |
||||
connection: { "user": "root", |
||||
"password": "password", |
||||
"port":"3306", |
||||
"host":"localhost", |
||||
database: 'sakila' |
||||
} |
||||
}); |
||||
const delay = t => new Promise(res => setTimeout(() => res(), t)) |
||||
|
||||
const simpleInOut = require('./testData/01_simple') |
||||
const compareObj = require('./compareObj') |
||||
const Dataloader = require("dataloader"); |
||||
|
||||
const groupBy = (arr, field) => { |
||||
return (arr || []).reduce((obj, o) => { |
||||
obj[o[field]] = obj[o[field]] || [] |
||||
obj[o[field]].push(o) |
||||
return obj; |
||||
}, {}) |
||||
} |
||||
|
||||
|
||||
const cityListLoader = new Dataloader(async function (ids) { |
||||
const cities = await knex('city').select('*').whereIn('country_id', ids); |
||||
const gbObj = groupBy(cities, 'country_id') |
||||
return ids.map(id => (gbObj[id] || []).map(c => new City(c))) |
||||
}) |
||||
|
||||
|
||||
const addressCountLoader = new Dataloader(async function (ids) { |
||||
const cities = await knex('address').select('city_id').count('address_id as count') |
||||
.groupBy('city_id') |
||||
.whereIn('city_id', ids); |
||||
const gbObj = groupBy(cities, 'city_id') |
||||
return ids.map(id => (gbObj[id] && gbObj[id][0] && gbObj[id][0].count)) |
||||
}) |
||||
const cityCountLoader = new Dataloader(async function (ids) { |
||||
const cities = await knex('city').select('country').count('city_id as count') |
||||
.groupBy('country_id') |
||||
.whereIn('country_id', ids); |
||||
const gbObj = groupBy(cities, 'country_id') |
||||
return ids.map(id => (gbObj[id] && gbObj[id][0] && gbObj[id][0].count)) |
||||
}) |
||||
|
||||
const addressListLoader = new Dataloader(async function (ids) { |
||||
const addresses = await knex('address').select('*').whereIn('city_id', ids); |
||||
const gbObj = groupBy(addresses, 'city_id') |
||||
return ids.map(id => (gbObj[id] || []).map(c => new Address(c))) |
||||
}) |
||||
|
||||
const cityLoader = new Dataloader(async function (ids) { |
||||
const cities = await knex('city').select('*').whereIn('city_id', ids); |
||||
const gbObj = groupBy(cities, 'city_id') |
||||
return ids.map(id => gbObj[id] && gbObj[id][0] ? new City(gbObj[id][0]) : null) |
||||
}) |
||||
const countryLoader = new Dataloader(async function (ids) { |
||||
const countries = await knex('country').select('*').whereIn('country_id', ids); |
||||
const gbObj = groupBy(countries, 'country_id') |
||||
return ids.map(id => gbObj[id] && gbObj[id][0] ? new Country(gbObj[id][0]) : null) |
||||
}) |
||||
|
||||
class Country { |
||||
constructor(data) { |
||||
Object.assign(this, data) |
||||
} |
||||
|
||||
async cityList() { |
||||
return await cityListLoader.load(this.country_id) |
||||
} |
||||
|
||||
async cityCount() { |
||||
return cityCountLoader.load(this.country_id) |
||||
} |
||||
|
||||
} |
||||
|
||||
|
||||
class Address { |
||||
constructor(data) { |
||||
Object.assign(this, data) |
||||
} |
||||
|
||||
async City() { |
||||
return cityLoader.load(this.city_id) |
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
class City { |
||||
constructor(data) { |
||||
Object.assign(this, data) |
||||
} |
||||
|
||||
async Country() { |
||||
return countryLoader.load(this.country_id) |
||||
} |
||||
|
||||
async addressList() { |
||||
return addressListLoader.load(this.city_id) |
||||
} |
||||
|
||||
async addressCount() { |
||||
return addressCountLoader.load(this.city_id) |
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
const rootAst = { |
||||
Country: { |
||||
name: 'Country', |
||||
type: 'Object', |
||||
fields: { |
||||
country_id: { |
||||
name: 'country_id', |
||||
type: 'number' |
||||
}, country: { |
||||
name: 'country', |
||||
type: 'string' |
||||
}, |
||||
|
||||
cityList: { |
||||
name: 'cityList', |
||||
type: 'array', |
||||
elementType: 'City', |
||||
// nested: {
|
||||
// level: 1, path: ['country_id']
|
||||
// }
|
||||
}, |
||||
cityCount: { |
||||
name: 'cityCount', |
||||
type: 'number', |
||||
// nested: {
|
||||
// level: 1, path: ['country_id']
|
||||
// }
|
||||
}, |
||||
|
||||
|
||||
addressCount: { |
||||
name: 'addressCount', |
||||
type: 'number', |
||||
nested: {level: 2, path: ['cityList', 'addressCount']} |
||||
}, |
||||
addressList: { |
||||
type: 'number', |
||||
nested: {level: 2, path: ['cityList', 'addressList', 'address']} |
||||
}, |
||||
d: { |
||||
type: 'number', |
||||
nested: {level: 2, path: ['cityList', 'addressList', 'City', 'Country']} |
||||
} |
||||
} |
||||
}, City: { |
||||
name: 'City', |
||||
type: 'Object', |
||||
fields: { |
||||
city_id: { |
||||
name: 'city_id', |
||||
type: 'number' |
||||
}, country_id: { |
||||
name: 'country_id', |
||||
type: 'number' |
||||
}, city: { |
||||
name: 'city', |
||||
type: 'string' |
||||
}, addressList: { |
||||
name: 'addressList', |
||||
type: 'array', |
||||
elementType: 'Address' |
||||
}, countryRead: { |
||||
name: 'countryRead', |
||||
type: 'Country' |
||||
}, addressCount: { |
||||
name: 'addressCount', |
||||
type: 'number' |
||||
}, |
||||
Country: { |
||||
name: 'Country', |
||||
type: 'Country', |
||||
// nested: {
|
||||
// level: 1, path: ['country_id']
|
||||
// }
|
||||
}, |
||||
} |
||||
}, Address: { |
||||
name: 'Address', |
||||
type: 'Object', |
||||
fields: { |
||||
address: { |
||||
name: 'address', |
||||
type: 'string' |
||||
}, |
||||
City: { |
||||
name: 'City', |
||||
type: 'City', |
||||
// nested: {
|
||||
// level: 1,
|
||||
// path: ['city_id']
|
||||
// }
|
||||
}, |
||||
CountryName: { |
||||
name: 'Country', |
||||
type: 'Country', |
||||
nested: { |
||||
level: 1, |
||||
path: ['City', 'Country', 'country'] |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
CountryList: { |
||||
type: 'array', |
||||
elementType: 'Country' |
||||
}, |
||||
AddressList: { |
||||
type: 'array', |
||||
elementType: 'Address' |
||||
}, |
||||
} |
||||
|
||||
|
||||
const nestResolver = { |
||||
async Country() { |
||||
return new Country(await knex('country').first()) |
||||
}, |
||||
|
||||
async CountryList() { |
||||
return (await knex('country').limit(2)).map(c => new Country(c)) |
||||
}, |
||||
|
||||
async AddressList() { |
||||
return (await knex('address').limit(10)).map(c => new Address(c)) |
||||
} |
||||
} |
||||
|
||||
const flattenArray = (res) => { |
||||
return Array.isArray(res) ? res.flatMap(r => flattenArray(r)) : res |
||||
} |
||||
|
||||
|
||||
const execute = async (requestObj, resolverObj, ast, objTree = {}) => { |
||||
|
||||
const res = [] |
||||
// extract nested(lookup) recursively
|
||||
const extractNested = (path, o = {}, resolver) => { |
||||
if (path.length) { |
||||
const key = path[0] |
||||
if (!o[key]) { |
||||
|
||||
|
||||
if (typeof resolver[key] === 'function') { |
||||
o[path[0]] = resolver[key]()//.call(res);
|
||||
// console.log(prefix + o[path[0]])
|
||||
} else if (typeof resolver[key] === 'object') { |
||||
o[path[0]] = Promise.resolve(resolver[key]) |
||||
// console.log(prefix + o[path[0]])
|
||||
} else { |
||||
o[path[0]] = Promise.resolve(resolver[key]) |
||||
// console.log(prefix + o[path[0]])
|
||||
} |
||||
|
||||
|
||||
} else if (typeof o[key] === 'function') { |
||||
o[key] = o[key]() |
||||
} |
||||
|
||||
|
||||
return (o[path[0]] instanceof Promise ? o[path[0]] : Promise.resolve(o[path[0]])).then(res1 => { |
||||
|
||||
if (Array.isArray(res1)) { |
||||
return Promise.all(res1.map(r => extractNested(path.slice(1), r))) |
||||
} else { |
||||
return extractNested(path.slice(1), res1) |
||||
} |
||||
|
||||
}) |
||||
} else { |
||||
return Promise.resolve(o) |
||||
} |
||||
}; |
||||
|
||||
|
||||
// function for extracting field
|
||||
function extractField(key) { |
||||
if (!(ast && ast && ast[key] && ast[key].nested)) { |
||||
if (resolverObj) { |
||||
// resolve if it's resolver function
|
||||
if (typeof resolverObj[key] === 'function') { |
||||
res[key] = resolverObj[key]()//.call(res);
|
||||
// console.log(prefix + res[key])
|
||||
} else if (typeof resolverObj[key] === 'object') { |
||||
res[key] = Promise.resolve(resolverObj[key]) |
||||
// console.log(prefix + res[key])
|
||||
} else { |
||||
res[key] = Promise.resolve(resolverObj[key]) |
||||
// console.log(prefix + res[key])
|
||||
} |
||||
} |
||||
|
||||
objTree[key] = res[key] |
||||
|
||||
} else { |
||||
|
||||
// if nested extract the nested value
|
||||
res[key] = extractNested(ast[key].nested.path, objTree, resolverObj).then(res => { |
||||
return Promise.resolve(flattenArray(res)) |
||||
}) |
||||
|
||||
|
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
|
||||
for (const key of Object.keys(requestObj)) { |
||||
extractField(key); |
||||
|
||||
if (requestObj[key] && typeof requestObj[key] === 'object') { |
||||
res[key] = res[key].then(res1 => { |
||||
if (Array.isArray(res1)) { |
||||
return Promise.all(res1.map(r => execute(requestObj[key], r, rootAst[ast[key].elementType] && rootAst[ast[key].elementType].fields, objTree[key] = {}))) |
||||
} else { |
||||
return execute(requestObj[key], res1, ast[key].fields, objTree[key] = {}) |
||||
} |
||||
}) |
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
await Promise.all(Object.values(res)) |
||||
|
||||
const out = {}; |
||||
for (const [k, v] of Object.entries(res)) { |
||||
if (k in requestObj) |
||||
out[k] = await v |
||||
} |
||||
|
||||
|
||||
return out |
||||
} |
||||
|
||||
describe('Resolver', async () => { |
||||
for (const {name, in: input, out} of simpleInOut) { |
||||
it(`Resolver : ${name}`, async function () { |
||||
this.timeout(50000) |
||||
console.time(name) |
||||
const res = await execute(input, nestResolver, rootAst); |
||||
console.timeEnd(name) |
||||
console.log(JSON.stringify(res, 0, 2)) |
||||
expect(compareObj(out, res)).to.be.eq(true) |
||||
}); |
||||
} |
||||
}) |
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,556 +0,0 @@
|
||||
const delay = t => new Promise(res => setTimeout(() => res(), t)) |
||||
const Dataloader = require('dataloader') |
||||
const time = 1000; |
||||
const knex = require('knex')({ |
||||
client: 'mysql2', |
||||
connection: { |
||||
user: 'root', |
||||
password: 'password', |
||||
database: 'sakila' |
||||
} |
||||
}); |
||||
|
||||
|
||||
|
||||
|
||||
class Country { |
||||
constructor(data) { |
||||
Object.assign(this, data) |
||||
} |
||||
|
||||
async cityList() { |
||||
return (await knex('city').select('*').where({ |
||||
country_id: this.country_id |
||||
}).limit(1)).map(c => new City(c)) |
||||
} |
||||
|
||||
async cityCount() { |
||||
return (await knex('city').count('city_id as count').where({ |
||||
country_id: this.country_id |
||||
}).first()).count |
||||
} |
||||
|
||||
} |
||||
|
||||
|
||||
class Address { |
||||
constructor(data) { |
||||
Object.assign(this, data) |
||||
} |
||||
|
||||
async City() { |
||||
return new City(await knex('city').select('*').where({ |
||||
city_id: this.city_id |
||||
}).first()) |
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
class City { |
||||
constructor(data) { |
||||
Object.assign(this, data) |
||||
} |
||||
|
||||
async Country() { |
||||
return new Country((await knex('country').select('*').where({ |
||||
country_id: this.country_id |
||||
}).first())) |
||||
} |
||||
|
||||
async addressList() { |
||||
return (await knex('address').select('*').where({ |
||||
city_id: this.city_id |
||||
})).map(c => new Address(c)) |
||||
} |
||||
|
||||
async addressCount() { |
||||
return (await knex('address').count('city_id as count').where({ |
||||
city_id: this.city_id |
||||
}).first()).count |
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
|
||||
// const nestResolver = {
|
||||
// country: `INDIA`,
|
||||
// async cityCount() {
|
||||
// await delay(time)
|
||||
// return `12-${time}`
|
||||
// },
|
||||
// async cityList() {
|
||||
// await delay(time)
|
||||
// return {
|
||||
// city: `city 1-${time}`,
|
||||
// async addressCount() {
|
||||
// await delay(time)
|
||||
// return `2-${time}`
|
||||
// },
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
|
||||
|
||||
const rootAst = { |
||||
Country: { |
||||
name: 'Country', |
||||
type: 'Object', |
||||
fields: { |
||||
country_id: { |
||||
name: 'country_id', |
||||
type: 'number' |
||||
}, country: { |
||||
name: 'country', |
||||
type: 'string' |
||||
}, |
||||
|
||||
cityList: { |
||||
name: 'cityList', |
||||
type: 'array', |
||||
elementType: 'City', |
||||
// nested: {
|
||||
// level: 1, path: ['country_id']
|
||||
// }
|
||||
}, |
||||
cityCount: { |
||||
name: 'cityCount', |
||||
type: 'number', |
||||
// nested: {
|
||||
// level: 1, path: ['country_id']
|
||||
// }
|
||||
}, |
||||
|
||||
|
||||
addressCount: { |
||||
name: 'addressCount', |
||||
type: 'number', |
||||
nested: {level: 2, path: ['cityList', 'addressCount']} |
||||
}, |
||||
c: { |
||||
name: 'addressCount', |
||||
type: 'number', |
||||
nested: {level: 2, path: ['cityList', 'addressList','address']} |
||||
}, |
||||
d: { |
||||
name: 'addressCount', |
||||
type: 'number', |
||||
nested: {level: 2, path: ['cityList', 'addressList','City', 'Country']} |
||||
} |
||||
} |
||||
}, City: { |
||||
name: 'City', |
||||
type: 'Object', |
||||
fields: { |
||||
city_id: { |
||||
name: 'city_id', |
||||
type: 'number' |
||||
}, country_id: { |
||||
name: 'country_id', |
||||
type: 'number' |
||||
}, city: { |
||||
name: 'city', |
||||
type: 'string' |
||||
}, addressList: { |
||||
name: 'addressList', |
||||
type: 'array', |
||||
elementType: 'Address' |
||||
}, countryRead: { |
||||
name: 'countryRead', |
||||
type: 'Country' |
||||
}, addressCount: { |
||||
name: 'addressCount', |
||||
type: 'number' |
||||
}, |
||||
Country: { |
||||
name: 'Country', |
||||
type: 'Country', |
||||
// nested: {
|
||||
// level: 1, path: ['country_id']
|
||||
// }
|
||||
}, |
||||
} |
||||
}, Address: { |
||||
name: 'Address', |
||||
type: 'Object', |
||||
fields: { |
||||
address: { |
||||
name: 'address', |
||||
type: 'string' |
||||
}, |
||||
City: { |
||||
name: 'City', |
||||
type: 'City', |
||||
// nested: {
|
||||
// level: 1,
|
||||
// path: ['city_id']
|
||||
// }
|
||||
}, |
||||
Country: { |
||||
name: 'Country', |
||||
type: 'Country', |
||||
nested: { |
||||
level: 1, |
||||
path: ['City', 'Country','country'] |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
CountryList: { |
||||
type: 'array', |
||||
elementType: 'Country' |
||||
}, |
||||
AddressList: { |
||||
type: 'array', |
||||
elementType: 'Address' |
||||
}, |
||||
} |
||||
|
||||
|
||||
const nestResolver = { |
||||
async Country() { |
||||
return new Country(await knex('country').first()) |
||||
}, |
||||
|
||||
async CountryList() { |
||||
return (await knex('country').limit(2)).map(c => new Country(c)) |
||||
}, |
||||
|
||||
async AddressList() { |
||||
return (await knex('address').limit(10)).map(c => new Address(c)) |
||||
} |
||||
} |
||||
|
||||
|
||||
/* |
||||
|
||||
const reqExecutor = async (reqObj, resObj, _ast) => { |
||||
|
||||
const res = {} |
||||
// const dependedFields = Object.keys(reqObj).map(k => (ast.fields && ast.fields[k] && ast.fields[k].nested && ast.fields[k].nested.path))
|
||||
/!* const dependFields = new Set(); |
||||
for(const k of Object.keys(reqObj)){ |
||||
if(ast.fields && ast.fields[k] && ast.fields[k].nested && ast.fields[k].nested.path){ |
||||
dependFields.add(ast.fields[k].nested.path) |
||||
|
||||
} |
||||
}*!/ |
||||
|
||||
function extractDependsOn(key, i = 0, prev, __ast) { |
||||
const ast = __ast || _ast |
||||
if (!prev || typeof prev !== 'object' || i >= _ast.fields[key].nested.path.length) { |
||||
if (typeof resObj[key] === 'function') { |
||||
return resObj[key](prev)//.call(res);
|
||||
// console.log(prefix + res[key])
|
||||
} else if (typeof resObj[key] === 'object') { |
||||
return Promise.resolve(resObj[key]) |
||||
// console.log(prefix + res[key])
|
||||
} else { |
||||
return Promise.resolve(resObj[key]) |
||||
// console.log(prefix + res[key])
|
||||
} |
||||
} |
||||
if (typeof prev[key] === 'function') { |
||||
return resObj[key](res)//.call(res);
|
||||
// console.log(prefix + res[key])
|
||||
} |
||||
|
||||
|
||||
if (!prev[_ast.fields[key].nested.path[i]]) |
||||
extractField(_ast.fields[key].nested.path[i], _ast) |
||||
prev[key] = prev[_ast.fields[key].nested.path[i]].then(next => { |
||||
// return extractDependsOn(key, ++i, next)
|
||||
|
||||
|
||||
if (Array.isArray(next)) { |
||||
return Promise.all(next.map(r => extractDependsOn(key, ++i, r, rootAst[_ast[ast.fields[key].nested.path[i]].elementType]))) |
||||
} else { |
||||
return extractDependsOn(reqObj[key], ++i, next, _ast[ast.fields[key].nested.path[i]]) |
||||
} |
||||
|
||||
}) |
||||
return prev[key] |
||||
} |
||||
|
||||
|
||||
function extractField(key, __ast) { |
||||
const ast = __ast || _ast |
||||
|
||||
if (!(ast.fields && ast.fields[key] && ast.fields[key].nested)) { |
||||
if (typeof resObj[key] === 'function') { |
||||
res[key] = resObj[key]()//.call(res);
|
||||
// console.log(prefix + res[key])
|
||||
} else if (typeof resObj[key] === 'object') { |
||||
res[key] = Promise.resolve(resObj[key]) |
||||
// console.log(prefix + res[key])
|
||||
} else { |
||||
res[key] = Promise.resolve(resObj[key]) |
||||
// console.log(prefix + res[key])
|
||||
} |
||||
} else { |
||||
extractDependsOn(key, 0, res) |
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
|
||||
for (const key of Object.keys(reqObj)) { |
||||
if (key in resObj) { |
||||
extractField(key); |
||||
} |
||||
|
||||
|
||||
if (reqObj[key] && typeof reqObj[key] === 'object') { |
||||
res[key] = res[key].then(res1 => { |
||||
if (Array.isArray(res1)) { |
||||
return Promise.all(res1.map(r => reqExecutor(reqObj[key], r, rootAst[_ast[key].elementType]))) |
||||
} else { |
||||
return reqExecutor(reqObj[key], res1, _ast[key]) |
||||
} |
||||
}) |
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
await Promise.all(Object.values(res)) |
||||
|
||||
const out = {}; |
||||
for (const [k, v] of Object.entries(res)) { |
||||
out[k] = await v |
||||
} |
||||
|
||||
|
||||
return out |
||||
} |
||||
*/ |
||||
|
||||
/* |
||||
const reqExecutor = async (reqObj, resObj, ast) => { |
||||
|
||||
const res = {} |
||||
|
||||
|
||||
await Promise.all(Object.keys(reqObj).map(async (key) => { |
||||
if (key in resObj && !(ast.fields && ast.fields[key] && ast.fields[key].path)) { |
||||
|
||||
if (typeof resObj[key] === 'function') { |
||||
res[key] = await resObj[key]()//.call(res);
|
||||
// console.log(prefix + res[key])
|
||||
} else if (typeof resObj[key] === 'object') { |
||||
res[key] = resObj[key] |
||||
// console.log(prefix + res[key])
|
||||
} else { |
||||
res[key] = resObj[key] |
||||
// console.log(prefix + res[key])
|
||||
} |
||||
await delay(100) |
||||
} |
||||
if (reqObj[key] && typeof reqObj[key] === 'object') { |
||||
if (Array.isArray(res[key])) { |
||||
res[key] = await Promise.all(res[key].map(r => reqExecutor(reqObj[key], r, rootAst[ast[key].elementType]))) |
||||
} else { |
||||
res[key] = await reqExecutor(reqObj[key], res[key], ast[key]) |
||||
} |
||||
} |
||||
|
||||
})) |
||||
|
||||
return res |
||||
} |
||||
|
||||
*/ |
||||
|
||||
|
||||
const execute = async (requestObj, resolverObj, ast) => { |
||||
|
||||
const res = {} |
||||
// const dependedFields = Object.keys(reqObj).map(k => (ast.fields && ast.fields[k] && ast.fields[k].nested && ast.fields[k].nested.path))
|
||||
/* const dependFields = new Set(); |
||||
for(const k of Object.keys(reqObj)){ |
||||
if(ast.fields && ast.fields[k] && ast.fields[k].nested && ast.fields[k].nested.path){ |
||||
dependFields.add(ast.fields[k].nested.path) |
||||
|
||||
} |
||||
}*/ |
||||
|
||||
|
||||
// extract nested(lookup) recursively
|
||||
const extractNested = (path, o = {}, resolver) => { |
||||
if (path.length) { |
||||
const key = path[0] |
||||
if (!o[key]) { |
||||
|
||||
|
||||
if (typeof resolver[key] === 'function') { |
||||
o[path[0]] = resolver[key]()//.call(res);
|
||||
// console.log(prefix + o[path[0]])
|
||||
} else if (typeof resolver[key] === 'object') { |
||||
o[path[0]] = Promise.resolve(resolver[key]) |
||||
// console.log(prefix + o[path[0]])
|
||||
} else { |
||||
o[path[0]] = Promise.resolve(resolver[key]) |
||||
// console.log(prefix + o[path[0]])
|
||||
} |
||||
|
||||
|
||||
} else if (typeof o[key] === 'function') { |
||||
o[key] = o[key]() |
||||
} |
||||
|
||||
|
||||
return (o[path[0]] instanceof Promise ? o[path[0]] : Promise.resolve(o[path[0]])).then(res1 => { |
||||
|
||||
if (Array.isArray(res1)) { |
||||
return Promise.all(res1.map(r => extractNested(path.slice(1), r))) |
||||
} else { |
||||
return extractNested(path.slice(1), res1) |
||||
} |
||||
|
||||
}) |
||||
} else { |
||||
return Promise.resolve(o) |
||||
} |
||||
}; |
||||
|
||||
|
||||
// function for extracting field
|
||||
function extractField(key) { |
||||
if (!(ast && ast && ast[key] && ast[key].nested)) { |
||||
if (resolverObj) { |
||||
// resolve if it's resolver function
|
||||
if (typeof resolverObj[key] === 'function') { |
||||
res[key] = resolverObj[key]()//.call(res);
|
||||
// console.log(prefix + res[key])
|
||||
} else if (typeof resolverObj[key] === 'object') { |
||||
res[key] = Promise.resolve(resolverObj[key]) |
||||
// console.log(prefix + res[key])
|
||||
} else { |
||||
res[key] = Promise.resolve(resolverObj[key]) |
||||
// console.log(prefix + res[key])
|
||||
} |
||||
} |
||||
} else { |
||||
/* if (!res[ast[key].nested]) |
||||
extractField(ast[key].nested.path) |
||||
|
||||
|
||||
res[key] = res[ast.fields[key].nested.path].then(res => { |
||||
if (typeof resolverObj[key] === 'function') { |
||||
return resolverObj[key](res)//.call(res);
|
||||
// console.log(prefix + res[key])
|
||||
} else if (typeof resolverObj[key] === 'object') { |
||||
return Promise.resolve(resolverObj[key]) |
||||
// console.log(prefix + res[key])
|
||||
} else { |
||||
return Promise.resolve(resolverObj[key]) |
||||
// console.log(prefix + res[key])
|
||||
} |
||||
})*/ |
||||
// if nested extract the nested value
|
||||
res[key] = extractNested(ast[key].nested.path, res, resolverObj) |
||||
|
||||
|
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
|
||||
for (const key of Object.keys(requestObj)) { |
||||
// if (key in resolverObj) {
|
||||
extractField(key); |
||||
// }
|
||||
|
||||
|
||||
if (requestObj[key] && typeof requestObj[key] === 'object') { |
||||
res[key] = res[key].then(res1 => { |
||||
if (Array.isArray(res1)) { |
||||
return Promise.all(res1.map(r => execute(requestObj[key], r, rootAst[ast[key].elementType] && rootAst[ast[key].elementType].fields))) |
||||
} else { |
||||
return execute(requestObj[key], res1, ast[key].fields) |
||||
} |
||||
}) |
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
await Promise.all(Object.values(res)) |
||||
|
||||
const out = {}; |
||||
for (const [k, v] of Object.entries(res)) { |
||||
if(k in requestObj) |
||||
out[k] = await v |
||||
} |
||||
|
||||
|
||||
return out |
||||
} |
||||
|
||||
|
||||
const req = { |
||||
AddressList: { |
||||
// City: {
|
||||
// Country: 1
|
||||
// },
|
||||
Country: 1 |
||||
}, |
||||
CountryList: { |
||||
// cityList: {
|
||||
// addressCount: 1,
|
||||
// addressList: {
|
||||
// address: 1
|
||||
// }
|
||||
// },
|
||||
// c:1,
|
||||
// d:1,
|
||||
addressCount:1 |
||||
} |
||||
}; |
||||
|
||||
|
||||
const extractNested = (path, o = {}) => { |
||||
if (path.length) { |
||||
if (!o[path[0]]) { |
||||
o[path[0]] = Promise.resolve({}) |
||||
} |
||||
return o[path[0]].then(r => extractNested(path.slice(1), r)) |
||||
} else { |
||||
return Promise.resolve(o) |
||||
} |
||||
}; |
||||
|
||||
(async () => { |
||||
|
||||
console.time('start') |
||||
console.log(JSON.stringify(await execute(req, nestResolver, rootAst), 0, 2)); |
||||
console.timeEnd('start') |
||||
|
||||
|
||||
/* console.log(JSON.stringify(await extractNested(['a', 'b'], { |
||||
a: Promise.resolve({ |
||||
b: Promise.resolve({ |
||||
t: 1 |
||||
}) |
||||
}) |
||||
}), 0, 2))*/ |
||||
|
||||
|
||||
/* const o = {};*/ |
||||
|
||||
/* console.log(JSON.stringify(await extractNested(['a', 'b'], o), 0, 2)) |
||||
console.log(o) |
||||
console.log(JSON.stringify(await extractNested(['a', 'c'], o), 0, 2)) |
||||
console.log(JSON.stringify(await extractNested(['a', 'b', 'c'], o), 0, 2)) |
||||
console.log(JSON.stringify(await extractNested(['a', 'b'], o), 0, 2))*/ |
||||
|
||||
})().catch(e => console.log(e)).finally(() => process.exit(0)) |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,79 +0,0 @@
|
||||
GET http://localhost:8080/nc/{{projectId}}/api/v1/Film/v2 |
||||
Accept: application/json |
||||
Content-Type: application/json |
||||
xc-auth: {{token}} |
||||
|
||||
|
||||
|
||||
|
||||
### |
||||
|
||||
GET http://localhost:8080/nc/{{projectId}}/api/v1/Actor/v2/1 |
||||
Accept: application/json |
||||
Content-Type: application/json |
||||
xc-auth: {{token}} |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### |
||||
|
||||
|
||||
|
||||
GET http://localhost:8080/nc/{{projectId}}/api/v2/Country |
||||
Accept: application/json |
||||
Content-Type: application/json |
||||
xc-auth: {{token}} |
||||
|
||||
|
||||
|
||||
### |
||||
GET http://localhost:8080/nc/{{projectId}}/api/v2/Address?f=test123 |
||||
Accept: application/json |
||||
Content-Type: application/json |
||||
xc-auth: {{token}} |
||||
|
||||
|
||||
|
||||
### |
||||
|
||||
POST http://localhost:8080/nc/{{projectId}}/generateLookup1 |
||||
Accept: application/json |
||||
Content-Type: application/json |
||||
xc-auth: {{token}} |
||||
|
||||
|
||||
{ |
||||
|
||||
"type" : "Lookup" |
||||
|
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
### |
||||
|
||||
POST http://localhost:8080/nc/{{projectId}}/generate |
||||
Accept: application/json |
||||
Content-Type: application/json |
||||
xc-auth: {{token}} |
||||
|
||||
|
||||
{ |
||||
"table": "Address", |
||||
"type": "Formula", |
||||
"formula": "CONCAT(CountryName,'____sdsdsdsd')", |
||||
"alias": "test123" |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
### |
||||
|
||||
|
||||
|
||||
|
@ -1,17 +0,0 @@
|
||||
const a = { |
||||
country:'abc', |
||||
countryId:2 |
||||
} |
||||
|
||||
|
||||
|
||||
a.__proto__ = { |
||||
list(){ |
||||
return this.countryId + 1 |
||||
} |
||||
} |
||||
|
||||
|
||||
|
||||
console.log(a) |
||||
console.log(a.list()) |
@ -1,334 +0,0 @@
|
||||
module.exports = [{ |
||||
name: 'Simple', |
||||
in: { |
||||
CountryList: { |
||||
country: 1 |
||||
} |
||||
}, |
||||
out: { |
||||
"CountryList": [ |
||||
{ |
||||
"country": "Afghanistan" |
||||
}, |
||||
{ |
||||
"country": "Algeria" |
||||
} |
||||
] |
||||
} |
||||
},{ |
||||
name: 'Nested', |
||||
in: { |
||||
CountryList: { |
||||
country_id:1, |
||||
country:1, |
||||
cityList: { |
||||
city:1, |
||||
addressList:{ |
||||
address:1 |
||||
} |
||||
} |
||||
} |
||||
}, |
||||
out: { |
||||
"CountryList": [ |
||||
{ |
||||
"country_id": 1, |
||||
"country": "Afghanistan", |
||||
"cityList": [ |
||||
{ |
||||
"city": "Kabul", |
||||
"addressList": [ |
||||
{ |
||||
"address": "1168 Najafabad Parkway" |
||||
} |
||||
] |
||||
} |
||||
] |
||||
}, |
||||
{ |
||||
"country_id": 2, |
||||
"country": "Algeria", |
||||
"cityList": [ |
||||
{ |
||||
"city": "Batna", |
||||
"addressList": [ |
||||
{ |
||||
"address": "1924 Shimonoseki Drive" |
||||
} |
||||
] |
||||
}, |
||||
{ |
||||
"city": "Bchar", |
||||
"addressList": [ |
||||
{ |
||||
"address": "1031 Daugavpils Parkway" |
||||
} |
||||
] |
||||
}, |
||||
{ |
||||
"city": "Skikda", |
||||
"addressList": [ |
||||
{ |
||||
"address": "757 Rustenburg Avenue" |
||||
} |
||||
] |
||||
} |
||||
] |
||||
} |
||||
] |
||||
} |
||||
|
||||
}, { |
||||
name: 'Nested', |
||||
in: { |
||||
CountryList: { |
||||
country: 1, |
||||
cityList: { |
||||
city: 1 |
||||
} |
||||
} |
||||
}, |
||||
out: { |
||||
"CountryList": [ |
||||
{ |
||||
"country": "Afghanistan", |
||||
"cityList": [ |
||||
{ |
||||
"city": "Kabul" |
||||
} |
||||
] |
||||
}, |
||||
{ |
||||
"country": "Algeria", |
||||
"cityList": [ |
||||
{ |
||||
"city": "Batna" |
||||
}, |
||||
{ |
||||
"city": "Bchar" |
||||
}, |
||||
{ |
||||
"city": "Skikda" |
||||
} |
||||
] |
||||
} |
||||
] |
||||
} |
||||
}, { |
||||
name: 'Lookup', |
||||
in: { |
||||
CountryList: { |
||||
addressCount: 1 |
||||
}, |
||||
}, |
||||
out: { |
||||
"CountryList": [ |
||||
{ |
||||
"addressCount": [ |
||||
1 |
||||
] |
||||
}, |
||||
{ |
||||
"addressCount": [ |
||||
1, |
||||
1, |
||||
1 |
||||
] |
||||
} |
||||
] |
||||
} |
||||
|
||||
}, { |
||||
name: 'Nested and Lookup', |
||||
in: { |
||||
CountryList: { |
||||
cityList: { |
||||
city: 1 |
||||
}, |
||||
addressCount: 1 |
||||
}, |
||||
}, |
||||
out: { |
||||
"CountryList": [ |
||||
{ |
||||
"cityList": [ |
||||
{ |
||||
"city": "Kabul" |
||||
} |
||||
], |
||||
"addressCount": [ |
||||
1 |
||||
] |
||||
}, |
||||
{ |
||||
"cityList": [ |
||||
{ |
||||
"city": "Batna" |
||||
}, |
||||
{ |
||||
"city": "Bchar" |
||||
}, |
||||
{ |
||||
"city": "Skikda" |
||||
} |
||||
], |
||||
"addressCount": [ |
||||
1, |
||||
1, |
||||
1 |
||||
] |
||||
} |
||||
] |
||||
} |
||||
}, { |
||||
name: 'Deeply nested Lookup', |
||||
in: { |
||||
CountryList: { |
||||
addressList: 1 |
||||
}, |
||||
}, |
||||
out: { |
||||
"CountryList": [ |
||||
{ |
||||
"addressList": [ |
||||
"1168 Najafabad Parkway" |
||||
] |
||||
}, |
||||
{ |
||||
"addressList": [ |
||||
"1924 Shimonoseki Drive", |
||||
"1031 Daugavpils Parkway", |
||||
"757 Rustenburg Avenue" |
||||
] |
||||
} |
||||
] |
||||
} |
||||
}, |
||||
{ |
||||
name: 'Belongs relation', |
||||
in: { |
||||
AddressList: { |
||||
address: 1, |
||||
City: { |
||||
city: 1 |
||||
} |
||||
}, |
||||
}, |
||||
out: { |
||||
"AddressList": [ |
||||
{ |
||||
"address": "47 MySakila Drive", |
||||
"City": { |
||||
"city": "Lethbridge" |
||||
} |
||||
}, |
||||
{ |
||||
"address": "28 MySQL Boulevard", |
||||
"City": { |
||||
"city": "Woodridge" |
||||
} |
||||
}, |
||||
{ |
||||
"address": "23 Workhaven Lane", |
||||
"City": { |
||||
"city": "Lethbridge" |
||||
} |
||||
}, |
||||
{ |
||||
"address": "1411 Lillydale Drive", |
||||
"City": { |
||||
"city": "Woodridge" |
||||
} |
||||
}, |
||||
{ |
||||
"address": "1913 Hanoi Way", |
||||
"City": { |
||||
"city": "Sasebo" |
||||
} |
||||
}, |
||||
{ |
||||
"address": "1121 Loja Avenue", |
||||
"City": { |
||||
"city": "San Bernardino" |
||||
} |
||||
}, |
||||
{ |
||||
"address": "692 Joliet Street", |
||||
"City": { |
||||
"city": "Athenai" |
||||
} |
||||
}, |
||||
{ |
||||
"address": "1566 Inegl Manor", |
||||
"City": { |
||||
"city": "Myingyan" |
||||
} |
||||
}, |
||||
{ |
||||
"address": "53 Idfu Parkway", |
||||
"City": { |
||||
"city": "Nantou" |
||||
} |
||||
}, |
||||
{ |
||||
"address": "1795 Santiago de Compostela Way", |
||||
"City": { |
||||
"city": "Laredo" |
||||
} |
||||
} |
||||
] |
||||
} |
||||
}, { |
||||
name: 'Belongs relation with deep lookup', |
||||
in: { |
||||
AddressList: { |
||||
address: 1, |
||||
CountryName:1 |
||||
}, |
||||
}, |
||||
out: { |
||||
"AddressList": [ |
||||
{ |
||||
"address": "47 MySakila Drive", |
||||
"CountryName": "Canada" |
||||
}, |
||||
{ |
||||
"address": "28 MySQL Boulevard", |
||||
"CountryName": "Australia" |
||||
}, |
||||
{ |
||||
"address": "23 Workhaven Lane", |
||||
"CountryName": "Canada" |
||||
}, |
||||
{ |
||||
"address": "1411 Lillydale Drive", |
||||
"CountryName": "Australia" |
||||
}, |
||||
{ |
||||
"address": "1913 Hanoi Way", |
||||
"CountryName": "Japan" |
||||
}, |
||||
{ |
||||
"address": "1121 Loja Avenue", |
||||
"CountryName": "United States" |
||||
}, |
||||
{ |
||||
"address": "692 Joliet Street", |
||||
"CountryName": "Greece" |
||||
}, |
||||
{ |
||||
"address": "1566 Inegl Manor", |
||||
"CountryName": "Myanmar" |
||||
}, |
||||
{ |
||||
"address": "53 Idfu Parkway", |
||||
"CountryName": "Taiwan" |
||||
}, |
||||
{ |
||||
"address": "1795 Santiago de Compostela Way", |
||||
"CountryName": "United States" |
||||
} |
||||
] |
||||
} |
||||
} |
||||
] |
Loading…
Reference in new issue