Last active
February 16, 2023 03:12
-
-
Save petrosmm/4b9818eecda6df6bf8d2b7e82c2993a3 to your computer and use it in GitHub Desktop.
route builder sample for directus; used when item in questions are linked but self-referencing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env node | |
// basic commands | |
// cls && tsc cli.ts --esModuleInterop true --outDir build && node build/cli.js | |
// REM && pause | |
import fetch from "node-fetch"; | |
import _ from "lodash"; | |
import Enumerable from "node-enumerable"; | |
interface RootResult { | |
data: DataResult[]; | |
} | |
interface DataResult { | |
uuid: string; | |
url: string; | |
title: string; | |
parentUuid: string; | |
parent_page_to: DataResult[]; | |
routePieces: string[]; | |
routePiecesAll: string[]; | |
localUuid: string; | |
localUuidPieces: string[]; | |
} | |
let initialResults: DataResult[] = []; | |
let results: DataResult[] = []; | |
export const main = async (): Promise<void> => { | |
var path = `/items/pages?fields=uuid,url,title,parent_page_to.url,parent_page_to.title,parent_page_to.uuid`; | |
var host = "http://localhost:8055"; | |
let rawResult = (await fetch(new URL(host + path).href, { | |
method: `get`, | |
// body: JSON.stringify({ email, password, mode: `json` }), | |
headers: { | |
"Content-Type": `application/json`, | |
}, | |
}) as unknown as Response).json(); | |
rawResult.then((p: RootResult) => { | |
purgeDupes(p); | |
}).then(() => { | |
flattenItems(initialResults); | |
deNestItems(initialResults); | |
emancipateChildren(results) | |
.then(() => { | |
results.forEach((item, index) => { | |
item.routePiecesAll = item.routePiecesAll ?? []; | |
item.parentUuid = item.parentUuid ?? null; | |
item.localUuid = generateUUID(); | |
item.localUuidPieces = item.localUuidPieces ?? []; | |
}); | |
var duplicateIds = []; | |
results.forEach((item, index) => { | |
let multipleResults = results.filter(p => p.uuid == item.uuid); | |
if (multipleResults.length > 1) { | |
// delete item; | |
let hasProperItem = multipleResults.some(p => (p.parentUuid == null || p.parentUuid == undefined)); | |
if (hasProperItem) { | |
let _result = results.filter(p => p.uuid !== undefined | |
&& p.uuid == multipleResults[0]?.uuid | |
&& (p.parentUuid == undefined || p.parentUuid == null))[0]; | |
duplicateIds.push(_result.localUuid); | |
} | |
} | |
}); | |
duplicateIds = Array.from(new Set(duplicateIds)); | |
results = results.filter(p => !(duplicateIds.includes(p.localUuid))); | |
results = Enumerable.from(results) | |
.orderBy(p => p?.parentUuid == null ? 0 : 1) | |
.thenBy(p => p?.parent_page_to?.length > 0 ? 2 : 3) | |
.toArray(); | |
traverseAncestors(results); | |
populateRoutes(results); | |
displayResults(results); | |
}); | |
// end | |
}); | |
}; | |
if (require.main === module) { | |
main().catch((error) => { | |
console.error(error); | |
process.exit(1); | |
}); | |
} else { | |
throw new Error(`This should be the main module.`); | |
} | |
function purgeDupes(input: RootResult) { | |
return new Promise<void>((resolve, reject) => { | |
initialResults = input.data; | |
initialResults.forEach((value, index) => { | |
purgeEachNested(value, null /* value.url */, value.uuid); | |
}); | |
resolve(); | |
}); | |
} | |
function purgeEachNested(value: DataResult, _parentUrl: string, _parentUuid: string) { | |
let childPages = value.parent_page_to?.length > 0 ? value.parent_page_to : []; | |
_.remove(initialResults, p => p.uuid == value.uuid && p.parent_page_to?.length == 0); | |
childPages.forEach(child => { | |
child.parentUuid = _parentUuid; | |
// recursive | |
purgeEachNested(child, null /* child.parentUrl */, child.parentUuid); | |
}); | |
} | |
function flattenItems(items: DataResult[]) { | |
return new Promise<void>((resolve, reject) => { | |
items.forEach(p => { | |
flattenEachNested(p); | |
}); | |
resolve(); | |
}); | |
} | |
function flattenEachNested(value: DataResult) { | |
let childPages = value.parent_page_to?.length > 0 ? value.parent_page_to : []; | |
childPages.forEach(child => { | |
// recursive | |
flattenEachNested(child); | |
}); | |
} | |
function deNestItems(items: DataResult[]) { | |
return new Promise<void>((resolve, reject) => { | |
items.forEach(item => { | |
deNestEachItem(item); | |
}); | |
resolve(); | |
}); | |
} | |
function deNestEachItem(value: DataResult) { | |
let childPages = value.parent_page_to?.length > 0 ? value.parent_page_to : []; | |
results.push(value); | |
childPages.forEach(child => { | |
// recursive | |
deNestEachItem(child); | |
}); | |
} | |
function emancipateChildren(items: DataResult[]) { | |
return new Promise<void>((resolve, reject) => { | |
items.forEach(item => { | |
delete item?.parent_page_to; | |
}); | |
resolve(); | |
}); | |
} | |
class lookup { | |
static byLocalUuid(input: string): DataResult { | |
return results.find(p => p.localUuid == input); | |
} | |
static byUuid(input: string): DataResult { | |
return results.find(p => p.uuid == input); | |
} | |
} | |
function displayResults(results: DataResult[]) { | |
console.log('\r\n\r\n' + 'starting result display'); | |
results.forEach((item, index) => { | |
console.log(item); | |
}); | |
} | |
/** @deprecated */ | |
function splice( | |
input: DataResult[], | |
// predicate: (value: T, index: number, array: DataResult[]) => value is DataResult | |
predicate: (p: DataResult) => boolean | |
) { | |
while (input.findIndex(predicate) > -1) { | |
let index = input.findIndex(predicate); | |
let result = input.splice(index, 1); | |
results.push(result[0]); | |
} | |
return results; | |
} | |
function generateUUID() { // Public Domain/MIT | |
let d = new Date().getTime();//Timestamp | |
let d2 = ((typeof performance !== 'undefined') && performance.now && (performance.now() * 1000)) || 0;//Time in microseconds since page-load or 0 if unsupported | |
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { | |
let r = Math.random() * 16;//random number between 0 and 16 | |
if (d > 0) {//Use timestamp until depleted | |
r = (d + r) % 16 | 0; | |
d = Math.floor(d / 16); | |
} else {//Use microseconds since page-load if supported | |
r = (d2 + r) % 16 | 0; | |
d2 = Math.floor(d2 / 16); | |
} | |
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16); | |
}); | |
} | |
function traverseAncestors(items: DataResult[]) { | |
items.forEach(item => { | |
traverseAncestorsEach(item, item.localUuid); | |
}); | |
} | |
function traverseAncestorsEach(value: DataResult, carryUuid: string) { | |
let target = value as DataResult; | |
do { | |
let parent = lookup.byUuid(target.parentUuid); | |
if (parent == null) { | |
target = null; | |
} else { | |
value.localUuidPieces.unshift(parent.localUuid); | |
target = parent; | |
} | |
} while (target != null); | |
} | |
function populateRoutes(items: DataResult[]) { | |
return new Promise<void>((resolve, reject) => { | |
// populate uuids | |
items.forEach(item => { | |
if (item.localUuidPieces.length > 0) { | |
item.localUuidPieces.forEach(_p => { | |
let _route = lookup.byLocalUuid(_p).url; | |
item.routePiecesAll.push(_route); | |
}); | |
item.routePiecesAll.push(item.url); | |
} | |
}); | |
results = items; | |
resolve(); | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment