Browse Source

refactor(nocodb): remove experiment stuff

pull/4237/head
Wing-Kam Wong 2 years ago
parent
commit
14823008e6
  1. 73607
      packages/nocodb/exp/cacheObj.json
  2. 37
      packages/nocodb/exp/compareObj.js
  3. 32
      packages/nocodb/exp/gql.js
  4. 6
      packages/nocodb/exp/http-client.env.json
  5. 603
      packages/nocodb/exp/queryLog.md
  6. 336
      packages/nocodb/exp/resolver_exp.js
  7. 365
      packages/nocodb/exp/resolver_exp_new.js
  8. 556
      packages/nocodb/exp/resolver_exp_old.js
  9. 79
      packages/nocodb/exp/test.http
  10. 17
      packages/nocodb/exp/test.js
  11. 334
      packages/nocodb/exp/testData/01_simple.js

73607
packages/nocodb/exp/cacheObj.json

File diff suppressed because it is too large Load Diff

37
packages/nocodb/exp/compareObj.js

@ -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;
}

32
packages/nocodb/exp/gql.js

@ -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);
});

6
packages/nocodb/exp/http-client.env.json

@ -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"
}
}

603
packages/nocodb/exp/queryLog.md

File diff suppressed because one or more lines are too long

336
packages/nocodb/exp/resolver_exp.js

@ -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
}

365
packages/nocodb/exp/resolver_exp_new.js

@ -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)
});
}
})

556
packages/nocodb/exp/resolver_exp_old.js

@ -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))

79
packages/nocodb/exp/test.http

@ -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"
}
###

17
packages/nocodb/exp/test.js

@ -1,17 +0,0 @@
const a = {
country:'abc',
countryId:2
}
a.__proto__ = {
list(){
return this.countryId + 1
}
}
console.log(a)
console.log(a.list())

334
packages/nocodb/exp/testData/01_simple.js

@ -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…
Cancel
Save