@blitznocode/blitz-orm 0.6.4 → 0.7.0-beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,38 +1,3327 @@
1
- 'use strict';
2
-
3
- var radash = require('radash');
4
- var typedbDriver = require('typedb-driver');
5
- var immer = require('immer');
6
- var objectTraversal = require('object-traversal');
7
- var uuid = require('uuid');
8
-
9
- var lt={query:{noMetadata:!1,simplifiedLinks:!0,debugger:!1,returnNulls:!1},mutation:{}};var Ht=s=>{let r=[],c=new Map;return s.forEach(i=>{let{dbPath:f,contentType:d}=i,a=`${f}-${d}`;c.has(a)||(c.set(a,!0),r.push(i));}),r},bt=async(s,r,c)=>{let f=(()=>{let y="",l=[];y+=`
10
- `,Object.keys(r.entities).forEach($=>{let g=r.entities[$],{idFields:k,dataFields:O,linkFields:F,name:q}=g,T=[],L=[],A=[];if(g.extends){let S=r.entities[g.extends];S.dataFields&&S.dataFields.forEach(E=>{T.push(E.dbPath);}),S.linkFields&&S.linkFields.forEach(E=>{L.push(E.path);}),S.idFields&&S.idFields.forEach(E=>{A.push(E);});}y+=`${q} sub ${g.extends?g.extends:"entity"},
11
- `;let R=[];if(k&&k.length>0){let S=new Set(k),B=Array.from(S).map(I=>`${I}`).join(", ");A.includes(B)||(y+=` owns ${B} @key,
12
- `,R.push(B));}if(O&&O.length>0&&O.forEach(S=>{!T.includes(S.dbPath)&&!R.includes(S.dbPath)&&(y+=` owns ${S.dbPath},
13
- `),l.push({dbPath:S.dbPath,contentType:S.contentType});}),F&&F.length>0){let S=[];F.forEach(E=>{let{relation:B,plays:I}=E;!L.includes(E.path)&&!S.includes(`${B}:${I}`)&&(y+=` plays ${B}:${I},
14
- `,S.push(`${B}:${I}`));});}y=y.replace(/,\s*$/,`;
15
- `),y+=`
16
- `;}),Object.keys(r.relations).forEach($=>{let g=r.relations[$],{idFields:k,dataFields:O,roles:F,name:q,linkFields:T}=g,L=[],A=[],R=[],S=[];if(g.extends){let B=r.relations[g.extends];B.dataFields&&B.dataFields.forEach(I=>{L.push(I.dbPath);}),B.linkFields&&B.linkFields.forEach(I=>{A.push(I.dbPath);}),B.roles&&Object.values(B.roles).forEach(M=>{R.push(M.name);}),B.idFields&&B.idFields.forEach(I=>{S.push(I);});}y+=`${q} sub ${g.extends?g.extends:"relation"},
17
- `;let E=[];if(k&&k.length>0){let B=new Set(k),M=Array.from(B).map(P=>`${P}`).join(", ");S.includes(M)||(y+=` owns ${M} @key,
18
- `,E.push(M));}if(O&&O.length>0&&O.forEach(B=>{!L.includes(B.dbPath)&&!E.includes(B.dbPath)&&(y+=` owns ${B.dbPath},
19
- `),l.push({dbPath:B.dbPath,contentType:B.contentType});}),F&&Object.keys(F).forEach(B=>{R.includes(B)||(y+=` relates ${B},
20
- `);}),T&&T.length>0){let B=[];T.forEach(I=>{let{plays:M}=I;!A.includes(I.path)&&!B.includes(`${g}:${M}`)&&(y+=` plays ${I.relation}:${M},
21
- `,B.push(`${g}:${M}`));});}y=y.replace(/,\s*$/,`;
22
- `),y+=`
23
- `;});let t=`define
24
-
25
- `;return Ht(l).forEach($=>{t+=`${$.dbPath} sub attribute,
26
- `,$.contentType==="TEXT"||$.contentType==="ID"?t+=` value string;
27
- `:$.contentType==="EMAIL"?(t+=` value string,
28
- `,t+=` regex '^(?=.{1,64}@)[A-Za-z0-9_-]+(\\.[A-Za-z0-9_-]+)*@[^-][A-Za-z0-9-]+(\\.[A-Za-z0-9-]+)*(\\.[A-Za-z]{2,})$';
29
- `):$.contentType==="DATE"?t+=` value datetime;
30
- `:$.contentType==="BOOLEAN"?t+=` value boolean;
31
- `:$.contentType==="NUMBER"&&(t+=` value long;
32
- `);}),`${t}
33
-
34
- ${y}`})(),d=s.dbConnectors[0].id,a=c.typeDB.get(d)?.session,w=c.typeDB.get(d)?.client;if(!a){console.log("Session Status: ","NO SESSION");return}a.close();let[{dbName:b}]=s.dbConnectors;await(await w.databases.get(b)).delete(),await w.databases.create(b);let p=await w.session(s.dbConnectors[0].dbName,typedbDriver.SessionType.SCHEMA),u=await p.transaction(typedbDriver.TransactionType.WRITE);await u.query.define(f),await u.commit(),await u.close();let h=await p.transaction(typedbDriver.TransactionType.READ),o="match $a sub thing;";(await(await h.query.match(o)).collect()).forEach(async y=>{y.get("a");}),await h.close();};var wt=(s,r,c)=>c?r:`${s}\xB7${r}`,Et=s=>{let r=s.split("\xB7");return r[r.length-1]},X=(s,r)=>Object.values(Object.fromEntries(Object.entries(s).filter(([c,i])=>r(c,i))))[0],G=(s,r)=>Object.fromEntries(Object.entries(s).filter(([c,i])=>r(c,i))),Ft=s=>{let r=[],c=immer.produce(s,f=>objectTraversal.traverse(f,({key:d,value:a,meta:w})=>{if(w.depth===2&&(d&&(a.dataFields=a.dataFields?.map(b=>({...b,dbPath:wt(d,b.path,b.shared)}))),a.extends)){let b=f.entities[a.extends]||f.relations[a.extends];if(a.allExtends=[a.extends,...b.allExtends||[]],a.idFields=b.idFields?(a.idFields||[]).concat(b.idFields):a.idFields,a.dataFields=b.dataFields?(a.dataFields||[]).concat(b.dataFields.map(Q=>{let p=a.extends,u=s.entities[p]||s.relations[p];for(;!u.dataFields?.find(h=>h.path===Q.path);)p=u.extends,u=s.entities[p]||s.relations[p];return {...Q,dbPath:wt(p,Q.path,Q.shared)}})):a.dataFields,a.linkFields=b.linkFields?(a.linkFields||[]).concat(b.linkFields):a.linkFields,"roles"in b){let Q=a,p=b;Q.roles=Q.roles||{},Q.roles={...Q.roles,...p.roles},Object.keys(Q.roles).length===0&&(Q.roles={});}}},{traversalType:"breadth-first"}));return objectTraversal.traverse(s,({key:f,value:d,meta:a})=>{if(f==="linkFields"){let b=(()=>{if(!a.nodePath)throw new Error("No path");let[p,u]=a.nodePath.split(".");return {thing:u,thingType:p==="entities"?"entity":p==="relations"?"relation":""}})(),Q=Array.isArray(d)?d.map(p=>({...p,...b})):[{...d,...b}];r.push(...Q);}}),immer.produce(c,f=>objectTraversal.traverse(f,({value:d,key:a,meta:w})=>{if(w.depth===2&&d.idFields&&!d.id){d.name=a;let b=()=>{if(w.nodePath?.split(".")[0]==="entities")return "entity";if(w.nodePath?.split(".")[0]==="relations")return "relation";throw new Error("Unsupported node attributes")};d.thingType=b(),d.computedFields=[],d.virtualFields=[],"roles"in d&&Object.entries(d.roles).forEach(([p,u])=>{u.playedBy=r.filter(h=>h.relation===a&&h.plays===p)||[],u.name=p;}),"linkFields"in d&&d.linkFields&&d.linkFields?.forEach(p=>{if(p.target==="relation"){p.oppositeLinkFieldsPlayedBy=[{plays:p.path,thing:p.relation,thingType:"relation"}];return}let u=r.filter(o=>o.relation===p.relation&&o.plays!==p.plays)||[];p.oppositeLinkFieldsPlayedBy=u;let{filter:h}=p;p.oppositeLinkFieldsPlayedBy=p.oppositeLinkFieldsPlayedBy.filter(o=>o.target==="role"),h&&Array.isArray(h)&&(p.oppositeLinkFieldsPlayedBy=p.oppositeLinkFieldsPlayedBy.filter(o=>h.some(n=>o.thing===n.$role)),p.oppositeLinkFieldsPlayedBy=p.oppositeLinkFieldsPlayedBy.filter(o=>h.some(n=>o.thing===n.$thing))),h&&!Array.isArray(h)&&(p.oppositeLinkFieldsPlayedBy=p.oppositeLinkFieldsPlayedBy.filter(o=>o.$role===h.$role),p.oppositeLinkFieldsPlayedBy=p.oppositeLinkFieldsPlayedBy.filter(o=>o.thing===h.$thing));});}if(typeof d=="object"&&"playedBy"in d){if([...new Set(d.playedBy?.map(b=>b.thing))].length>1)throw new Error(`Unsupported: roleFields can be only played by one thing. Role: ${a} path:${w.nodePath}`);if(d.playedBy.length===0)throw new Error(`Unsupported: roleFields should be played at least by one thing. Role: ${a}, path:${w.nodePath}`)}if(w.depth===4&&(d.default||d.computedValue)){let[b,Q]=w.nodePath?.split(".")||[];d.isVirtual?f[b][Q].virtualFields.push(d.path):f[b][Q].computedFields.push(d.path);}}))},D=(s,r)=>{if(r.$entity){if(!(r.$entity in s.entities))throw new Error(`Missing entity '${r.$entity}' in the schema`);return s.entities[r.$entity]}if(r.$relation){if(!(r.$relation in s.relations))throw new Error(`Missing relation '${r.$relation}' in the schema`);return s.relations[r.$relation]}throw new Error(`Wrong schema or query for ${JSON.stringify(r)}`)},z=(s,r)=>{let c=s.dataFields?.map(n=>n.path)||[],i=s.linkFields?.map(n=>n.path)||[],f="roles"in s?radash.listify(s.roles,n=>n):[],d=[...c||[],...i||[],...f||[]],w=[...["$entity","$op","$id","$tempId","$bzId","$relation","$parentKey","$filter","$fields","$excludedFields"],...d];if(!r)return {fields:d,dataFields:c,roleFields:f,linkFields:i};let b=r.$fields?r.$fields.map(n=>{if(typeof n=="string")return n;if("$path"in n&&typeof n.$path=="string")return n.$path;throw new Error(" Wrongly structured query")}):radash.listify(r,n=>n),Q=r.$filter?radash.listify(r.$filter,n=>n.toString().startsWith("$")?void 0:n.toString()).filter(n=>n&&c?.includes(n)):[],p=r.$filter?radash.listify(r.$filter,n=>n.toString().startsWith("$")?void 0:n.toString()).filter(n=>n&&[...f||[],...i||[]].includes(n)):[],u=[...b,...Q].filter(n=>!w.includes(n)).filter(n=>n),h=r.$filter?G(r.$filter,(n,e)=>Q.includes(n)):{},o=r.$filter?G(r.$filter,(n,e)=>p.includes(n)):{};return {fields:d,dataFields:c,roleFields:f,linkFields:i,usedFields:b,usedLinkFields:i.filter(n=>b.includes(n)),usedRoleFields:f.filter(n=>b.includes(n)),unidentifiedFields:u,...Q.length?{localFilters:h}:{},...p.length?{nestedFilters:o}:{}}},Lt=(s,r)=>{let c=r.$localFilters&&radash.listify(r.$localFilters,(f,d)=>`has ${s.dataFields?.find(w=>w.path===f)?.dbPath} '${d}'`);return c?.length?`, ${c.join(",")}`:""},U=s=>s!==null,tt=(s,r)=>Object.values(s).reduce((c,i)=>(i.extends===r&&c.push(i.name),c),[]);var ee=(s,r)=>s.map(i=>{let f=[...i.conceptMaps],a=i.owner.asThing().type.label.name,w=r.entities[a]?r.entities[a]:r.relations[a];if(!w.idFields)throw new Error(`No idFields defined for ${a}`);let b=r.entities[a]?"entity":"relation",Q=f.map(u=>{let h=u.get("attribute")?.asAttribute();return h?[Et(h.type.label.name),h.value]:[]}),p=Object.fromEntries(Q);return {...p,[`$${b}`]:a,$id:p[w.idFields[0]]}}),ne=(s,r,c)=>s.flatMap(f=>f.conceptMaps.map(a=>{let w=new Map;return r.forEach(b=>{let Q=a.get(`${b}_id`)?.asAttribute().value.toString(),p=a.get(b),u=p?.isEntity()?p.asEntity().type.label.name:p?.asRelation().type.label.name,o={id:Q,entityName:(()=>u?(c.entities[u]??c.relations[u]).allExtends?.includes(b)?b:u:b)()};Q&&w.set(b,o);}),w})),ie=(s,r,c)=>s.flatMap(f=>f.conceptMaps.map(a=>{let w=a.get(`${r}_id`)?.asAttribute().value.toString(),b=a.get(`${c}_id`)?.asAttribute().value.toString();return {ownerId:w,path:c,roleId:b}})),re=(s,r)=>{let c=radash.listify(s.roles,(i,f)=>{if([...new Set(f.playedBy?.map(w=>w.thing))].length!==1)throw new Error("a role can be played by two entities throws the same relation");if(!f.playedBy)throw new Error("Role not being played by nobody");let d=f.playedBy[0].plays,a=tt(r.entities,d);return [d,...a]});return radash.unique(radash.flat(c))},J=async(s,r)=>{let{schema:c,bqlRequest:i,config:f,tqlRequest:d}=s,{rawTqlRes:a}=r;if(i){if(!a)throw new Error("TQL query not executed")}else throw new Error("BQL request not parsed");let{query:w}=i;if(!w){if(a.insertions?.length===0&&!d?.deletions){r.bqlRes={};return}let{mutation:h}=i;if(!h)throw new Error("TQL mutation not executed");let n=[...h.things,...h.edges].map(e=>{let y=a.insertions?.find(l=>l.get(`${e.$bzId}`))?.get(`${e.$bzId}`);if(e.$op==="create"||e.$op==="update"||e.$op==="link"){let l=y?.asThing().iid;return f.mutation?.noMetadata?radash.mapEntries(e,(t,m)=>[t.toString().startsWith("$")?Symbol.for(t):t,m]):{$dbId:l,...e,[e.path]:e.$id}}if(e.$op==="delete"||e.$op==="unlink")return e;if(e.$op!=="match")throw new Error(`Unsupported op ${e.$op}`)}).filter(e=>e);r.bqlRes=n;return}if(!a.entity)throw new Error("TQL query not executed");let b=ee(a.entity,c),Q=a.relations?.map(h=>{let o=c.relations[h.relation],n=re(o,c),e=ne(h.conceptMapGroups,[...n,o.name],c);return {name:h.relation,links:e}}),p=a.roles?.map(h=>({name:h.ownerPath,links:ie(h.conceptMapGroups,h.ownerPath,h.path)})),u=r.cache||{entities:new Map,relations:new Map,roleLinks:new Map};b.forEach(h=>{let o=h.$entity||h.$relation,n=h.$id,e=u.entities.get(o)||new Map;e.set(n,{...h,$show:!0}),u.entities.set(o,e);}),Q?.forEach(h=>{let o=h.name,n=u.relations.get(o)||[];n.push(...h.links),u.relations.set(o,n),h.links.forEach(e=>{[...e.entries()].forEach(([y,{entityName:l,id:t}])=>{let m=u.entities.get(l)||new Map,g={[c.entities[l]?.thingType||c.relations[l].thingType]:l,$id:t,...m.get(t)};m.set(t,g),u.entities.set(l,m);});});}),p?.forEach(h=>{let o=c.relations[h.name]||c.entities[h.name];h.links.forEach(n=>{let e=u.roleLinks.get(n.ownerId)||{},y=e[n.path];y?radash.isArray(y)?y.push(n.roleId):radash.isString(y)&&y!==n.roleId&&(y=[y,n.roleId]):y=n.roleId,e[n.path]=y,u.roleLinks.set(n.ownerId,e),o.roles[n.path].playedBy?.forEach(l=>{let t=u.entities.get(l.thing)||new Map,m={$entity:l.thing,$id:n.roleId,...t.get(n.roleId)};t.set(n.roleId,m),u.entities.set(l.thing,t);});});}),r.cache=u;};var oe=/((\/\/.*$)|(\/\*.*\*\/))/gm,se=/(\s*async\s*|\s*function\s*)+/,ae=/(?:function\s*[^(\s]*\s*|\s*=>\s*|^\s*)\(([^)]*)\)/,le=/[ ,\n\r\t]+/,Rt=s=>{let r=s.toString().replace(oe,"").replace(se,"").trim(),c=ae.exec(r);if(!c)return [];let i;for(let f of c.slice(1))if(f){i=f;break}return i?(i=i.replace(/\{\s*/g,"").replace(/\s*\}/g,""),i.split(le).filter(f=>f.trim()!=="")):[]};var et=({currentThing:s,fieldSchema:r,mandatoryDependencies:c=!1})=>{if(!r||!r.default||!r.default.value)throw new Error("Virtual field: No field schema found, or wrongly configured");let i=r.default.value,d=Rt(i).filter(w=>!(w in s));if(c&&d.length)throw new Error(`Virtual field: Missing arguments ${d.join(", ")}`);return "default"in r?r.default?.value(s):void 0};var de=(s,r)=>s.length===1&&typeof s[0]!="string"&&s[0].$id===r?s[0]:s,Mt=s=>typeof s=="string"||!!s.$show,Tt=(s,r)=>immer.produce(s,c=>objectTraversal.traverse(c,({value:i})=>{if(Array.isArray(i)||typeof i!="object"||i===null)return;i.$tempId&&(i.$tempId=`_:${i.$tempId}`),i.$fields&&delete i.$fields,i.$filter&&delete i.$filter,i.$show&&delete i.$show,i.$bzId&&delete i.$bzId,r.query?.noMetadata&&(i.$entity||i.$relation)&&(delete i.$entity,delete i.$relation,delete i.$id),Object.getOwnPropertySymbols(i).forEach(d=>{delete i[d];}),i.$excludedFields&&(i.$excludedFields.forEach(d=>{delete i[d];}),delete i.$excludedFields);})),dt=(s,r,c,i)=>s.map(([f,d])=>{if(!r||!r.includes(f))return null;if(!c.$fields||c.$fields.includes(i))return f;let a=c.$fields.find(w=>radash.isObject(w)&&w.$path===i);if(a){let w={...G(d,(Q,p)=>Q.startsWith("$"))},b=a.$fields?{...w,$fields:a.$fields}:w;if(a.$id){if(Array.isArray(a.$id))return a.$id.includes(f)?b:null;if(a.$id===f)return b}if(b.$fields&&b.$fields.includes("id")&&!b.$show){let Q="";return b.$fields.forEach(p=>{p==="id"?Q=b.$id:Q=b;}),Q}return b}return null}).filter(f=>f),pe=(s,r)=>{let c={};return r.forEach(i=>{c[i.$bzId]=i.$id;}),s.forEach(i=>{Object.keys(i).forEach(f=>{c[i[f]]&&f!=="$tempId"&&(i[f]=c[i[f]]);});}),s},fe=(s,r)=>{let c=r.map(f=>f.$bzId),i=!1;return s.forEach(f=>{Object.keys(f).forEach(d=>{c.includes(f[d])&&(i=!0);});}),i},qt=async(s,r)=>{let{bqlRequest:c,config:i,schema:f}=s,{cache:d}=r;if(!c)throw new Error("BQL request not parsed");let{query:a}=c;if(!a){let y=r.bqlRes[0]?r.bqlRes:[r.bqlRes],l=s.bqlRequest?.mutation?.things;if(fe(y,l)){let $=pe(y,l);r.bqlRes=$[1]?$:$[0];}let m=Tt(r.bqlRes,i);r.bqlRes=m;return}if(!d)return;let w="$entity"in a?a.$entity:a.$relation,b=d.entities.get(w.name);if(!b){r.bqlRes=null;return}let p=radash.listify(a.$filter,y=>y).some(y=>w.dataFields?.find(l=>l.path===y)?.validations?.unique),u=!Array.isArray(c.query)&&(c.query?.$id&&!Array.isArray(c.query?.$id)||p);if(Array.isArray(s.rawBqlRequest))throw new Error("Query arrays not implemented yet");let h=b,o=[...h].length?[...h].map(([y,l])=>({...s.rawBqlRequest,$id:y})):s.rawBqlRequest,n=immer.produce(o,y=>objectTraversal.traverse(y,({value:l})=>{let t=l;if(!t?.$entity&&!t?.$relation)return;let m="$entity"in t?t.$entity:t.$relation;if(m){let $=Array.isArray(t.$id)?t.$id:[t.$id],g="$relation"in t?f.relations[t.$relation]:f.entities[t.$entity],{dataFields:k,roleFields:O,fields:F}=z(g);i.query?.returnNulls&&(t.$fields?t.$fields.map(A=>typeof A=="string"?A:A.$path):F).forEach(A=>{t[A]=null;});let q=d.entities.get(m);if(!q)return;[...q].forEach(([L,A])=>{if($.includes(L)){let R=t.$fields?t.$fields:k,{virtualFields:S}=g;S?.forEach(M=>{if(R?.includes(M)&&(t[M]===void 0||t[M]===null)){let P=g.dataFields?.find(x=>x.path===M),C=et({currentThing:A,fieldSchema:P});t[M]=C;}}),radash.listify(A,(M,P)=>{M.startsWith("$")||R?.includes(M)&&(t[M]=P);});let E=d.roleLinks.get(L),B=t.$fields?t.$fields.filter(M=>typeof M=="string"):O,I=t.$fields?.filter(M=>typeof M=="object")?.map(M=>M.$path)||[];Object.entries(E||{}).forEach(([M,P])=>{if(![...B,...I].includes(M))return;if(!("roles"in g))throw new Error("No roles in schema");let C=Array.isArray(P)?[...new Set(P)]:[P],{cardinality:x,playedBy:v}=g.roles[M],j=[...new Set(v?.map(V=>V.thing))]?.flatMap(V=>{let Y=d.entities.get(V);return Y?dt([...Y],C,t,M):[]});if(j?.length){if(j.length===1&&j[0]===t.$id)return;if(x==="ONE"){t[M]=j[0];return}t[M]=j.filter(V=>typeof V=="string"||typeof V=="object"&&V?.$show);}});}});let T=g.linkFields;T&&T.forEach(L=>{let A=d.relations.get(L.relation),R=L.oppositeLinkFieldsPlayedBy;if(!A)return null;if(L.target==="relation"){let S=[...A].reduce((E,B)=>{let I=B.get(L.plays)?.id;if(I&&I===$[0]){let M=B.get(L.relation);if(!M)return E;E[M.entityName]||(E[M.entityName]=new Set),E[M.entityName].add(M.id);}return E},{});return Object.entries(S).map(([E,B])=>{let I=d.entities.get(E);if(!I)return null;let M=dt([...I],[...B.values()],t,L.path).filter(U).filter(Mt);if(M.length===0)return null;if(M&&M.length){if(L.cardinality==="ONE")return t[L.path]=M[0],null;t[L.path]=M;}return null}),null}return L.target==="role"&&R.forEach(S=>{if(!A)return;let E=[...A].reduce((B,I)=>{let M=I.get(L.plays)?.id;if(M&&M===$[0]){let P=I.get(S.plays);if(!P)return B;B[P.entityName]||(B[P.entityName]=new Set),B[P.entityName].add(P.id);}return B},{});Object.entries(E).forEach(([B,I])=>{let M=d.entities.get(B);if(!M)return;let P=dt([...M],[...I.values()],t,L.path).filter(U).filter(Mt);if(P.length!==0&&P&&P.length){if(L.cardinality==="ONE"){t[L.path]=P[0];return}t[L.path]=P;let C={},x=N=>(N.$path===L.path&&(C=N),N?.$fields?.forEach(x)),v="";a.$fields?.forEach(x),C&&(Array.isArray(C.$id)||(v=C.$id)),t[L.path]=de(P,v);}});}),null});}})),e=Tt(n,i);r.bqlRes=u?e[0]:e;};var nt=async s=>{let{schema:r,bqlRequest:c}=s;if(!c?.query)throw new Error("BQL query not parsed");let{query:i}=c,f="$entity"in i?i.$entity:i.$relation,d=f.defaultDBConnector.path||f.name;if(!d)throw new Error(`No thing path in ${JSON.stringify(f)}`);if(!f.idFields)throw new Error("No id fields");let[a]=f.idFields,w=`$${d}_id`,b=`, has ${a} ${w};`;i.$id&&(Array.isArray(i.$id)?b+=` ${w} like "${i.$id.join("|")}";`:b+=` ${w} "${i.$id}";`);let Q=Lt(f,i),p="roles"in f?radash.listify(f.roles,(n,e)=>({path:n,var:`$${n}`,schema:e})):[],u=`match $${d} isa ${d}, has attribute $attribute ${Q} ${b} get; group $${d};`,h=p.map(n=>{if(!n.schema.playedBy||[...new Set(n.schema.playedBy?.map(y=>y.thing))].length!==1)throw new Error("Unsupported: Role played by multiple linkfields or none");let e=n.schema.playedBy[0].thing;return {path:n.path,owner:d,request:`match $${d} (${n.path}: ${n.var} ) isa ${d} ${b} ${n.var} isa ${e}, has id ${n.var}_id; get; group $${d};`}}),o=f.linkFields?.flatMap(n=>{let e=`$${n.plays}_id`,y=`, has ${a} ${e};`;i.$id&&(Array.isArray(i.$id)?y+=` ${e} like "${i.$id.join("|")}";`:y+=` ${e} "${i.$id}";`);let l=`match $${n.plays} isa ${d}${Q} ${y}`,t=n.target==="relation",$=`$${n.relation}`,g=`${t?$:""} (${n.plays}: $${n.plays}`,k=n.oppositeLinkFieldsPlayedBy.map(R=>t?null:`${R.plays}: $${R.plays}`),O=[g,...k].filter(R=>R).join(",");if(r.relations[n.relation]===void 0)throw new Error(`Relation ${n.relation} not found in schema`);let F=r.relations[n.relation].defaultDBConnector.path||n.relation,q=`) isa ${F};`,T=n.oppositeLinkFieldsPlayedBy.map(R=>`$${t?R.thing:R.plays} isa ${R.thing}, has id $${t?R.thing:R.plays}_id;`).join(" "),L=`get; group $${n.plays};`,A=`${l} ${O} ${q} ${T} ${L}`;return {relation:F,entity:d,request:A}});s.tqlRequest={entity:u,...h?.length?{roles:h}:{},...o?.length?{relations:o}:{}};};var Ot=async s=>{let{rawBqlRequest:r,schema:c}=s;if(!("$entity"in r)&&!("$relation"in r))throw new Error("No entity specified in query");let i=D(c,r);if(!i)throw new Error(`Thing '${r}' not found in schema`);let{unidentifiedFields:f,localFilters:d,nestedFilters:a}=z(i,r);if(f&&f.length>0)throw new Error(`Unknown fields: [${f.join(",")}] in ${JSON.stringify(r)}`);s.bqlRequest={query:{...s.rawBqlRequest,...i.thingType==="entity"?{$entity:i}:{},...i.thingType==="relation"?{$relation:i}:{},...d?{$localFilters:d}:{},...a?{$nestedFilters:a}:{}}};};var it=async(s,r)=>{let c=r.dbConnectors[0].id,i=s.typeDB.get(c)?.session,f=s.typeDB.get(c)?.client;if(!i||!i.isOpen()){if(!f)throw new Error("Client not found");i=await f.session(r.dbConnectors[0].dbName,typedbDriver.SessionType.DATA),s.typeDB.set(c,{client:f,session:i});}return {client:f,session:i}};var rt=async(s,r)=>{let{dbHandles:c,bqlRequest:i,tqlRequest:f,config:d}=s;if(!i)throw new Error("BQL request not parsed");if(!f)throw new Error("TQL request not built");if(!f.entity)throw new Error("BQL request error, no entities");let{query:a}=i;if(!a)throw new Error("BQL request is not a query");let{session:w}=await it(c,d),b=await w.transaction(typedbDriver.TransactionType.READ);if(!b)throw new Error("Can't create transaction");let Q=b.query.getGroup(f.entity),p=f.roles?.map(e=>({...e,stream:b.query.getGroup(e.request)})),u=f.relations?.map(e=>({...e,stream:b.query.getGroup(e.request)})),h=await Q.collect(),o=await Promise.all(p?.map(async e=>({path:e.path,ownerPath:e.owner,conceptMapGroups:await e.stream.collect()}))||[]),n=await Promise.all(u?.map(async e=>({relation:e.relation,entity:e.entity,conceptMapGroups:await e.stream.collect()}))||[]);await b.close(),r.rawTqlRes={entity:h,...o?.length&&{roles:o},...n?.length&&{relations:n}};};var pt=async(s,r)=>{let{bqlRequest:c,schema:i}=s,{cache:f}=r;if(!c)throw new Error("BQL request not parsed");if(!f)throw new Error("Cache not initialized");let{query:d}=c;if(!d)return;let{$fields:a}=d;if(!("$entity"in d)&&!("$relation"in d))throw new Error("Node attributes not supported");let w="$entity"in d?d.$entity:d.$relation;if(!a||!Array.isArray(a))return;let b=a.filter(o=>typeof o!="string"&&o.$path),Q=w.linkFields?.filter(o=>b.findIndex(n=>n.$path===o.path)!==-1).flatMap(o=>o.oppositeLinkFieldsPlayedBy)||[],p="roles"in w?radash.listify(w.roles,(o,n)=>b.findIndex(e=>e.$path===o)!==-1?n:null).flatMap(o=>o?.playedBy).filter(o=>o):[],h=[...Q,...p]?.map(o=>{if(!o)return null;let{thing:n}=o,e=tt(i.entities,n);return [n,...e].map(y=>{let l=f.entities.get(y);if(!l)return null;let t=Array.from(l.values()).reduce((T,L)=>("$show"in L||T.push(L.$id),T),[]);if(t.length===0)return null;let m=i.entities[y]?{...i.entities[y],thingType:"entity"}:{...i.relations[y],thingType:"relation"},$=a.find(T=>typeof T=="object"&&T.$path===o.plays),g=$?.$id,k=g?Array.isArray(g)?g:[g]:[],O=$?.$filter,q={query:{$id:k.length?k.filter(T=>t.includes(T)):t,$fields:$?.$fields,...m.thingType==="entity"?{$entity:m}:{},...m.thingType==="relation"?{$relation:m}:{},...O?{$localFilters:O}:{}}};return {req:{...s,bqlRequest:q},res:r,pipeline:[nt,rt,J,pt]}}).filter(U)}).filter(U);if(h?.length)return radash.flat(h)};var At=async s=>{let{bqlRequest:r,schema:c}=s;if(!r)throw new Error("BQL request not parsed");let{mutation:i}=r;if(!i)throw new Error("BQL request is not a mutation");let f=o=>{let n=o.$op,e=`$${o.$bzId}`,y=D(c,o),{idFields:l,defaultDBConnector:t}=y,m=t?.path||o.$entity||o.$relation,$=o.$id,g=l?.[0],k=radash.listify(o,(E,B)=>{if(E.startsWith("$")||E===g||B===void 0||B===null)return "";let I=y.dataFields?.find(C=>C.path===E);if(!I?.path)return "";let P=I.dbPath;if(["TEXT","ID","EMAIL"].includes(I.contentType))return `has ${P} '${B}'`;if(["NUMBER","BOOLEAN"].includes(I.contentType))return `has ${P} ${B}`;if(I.contentType==="DATE"){if(Number.isNaN(B.valueOf()))throw new Error("Invalid format, Nan Date");return B instanceof Date?`has ${P} ${B.toISOString().replace("Z","")}`:`has ${P} ${new Date(B).toISOString().replace("Z","")}`}throw new Error(`Unsupported contentType ${I.contentType}`)}).filter(E=>E),O=`${e}-atts`,F=radash.listify(o,E=>{if(E.startsWith("$")||E===g)return "";let B=y.dataFields?.find(P=>P.path===E);if(!B?.path)return "";let M=B.dbPath;return `{${O} isa ${M};}`}).filter(E=>E),q=o[Symbol.for("isLocalId")],T=radash.isArray($)?`like '${$.join("|")}'`:`'${$}'`,L=!q&&$?[`has ${g} ${T}`]:[],A=[...L,...k].filter(E=>E).join(","),R=()=>{if(n==="delete"||n==="unlink"||n==="match")return `${e} isa ${[m,...L].filter(E=>E).join(",")};`;if(n==="update"){if(!F.length)throw new Error("update without attributes");return `${e} isa ${[m,...L].filter(E=>E).join(",")}, has ${O};
35
- ${F.join(" or ")};`}return ""},S=()=>n==="update"||n==="link"||n==="match"?`${e} isa ${[m,...L].filter(E=>E).join(",")};`:"";if(o.$entity||o.$relation)return {op:n,deletionMatch:R(),insertionMatch:S(),insertion:n==="create"?`${e} isa ${[m,A].filter(E=>E).join(",")};`:n==="update"&&k.length?`${e} ${k.join(",")};`:"",deletion:n==="delete"?`${e} isa ${m};`:n==="update"&&F.length?`${e} has ${O};`:""};throw new Error("in attributes")},d=o=>{let n=o.$op,e=D(c,o),y=`$${o.$bzId}`,l=o.$id,t=e.defaultDBConnector?.path||o.$relation,m="roles"in e?radash.listify(e.roles,S=>S):[],$=o.$relation&&"roles"in e&&radash.mapEntries(e.roles,(S,E)=>[S,E.dbConnector?.path||S]),g=radash.listify(o,(S,E)=>{if(!m.includes(S))return null;if(!("roles"in e))throw new Error("This should have roles! ");let B=$[S];return Array.isArray(E)?E.map(I=>({path:B,id:I})):{path:B,id:E}}).filter(S=>S).flat(),k=g.map(S=>{if(!S?.path)throw new Error("Object without path");return `${S.path}: $${S.id}`}),O=g.length>0?`( ${k.join(" , ")} )`:"",F=O?`${y} ${O} ${o[Symbol.for("edgeType")]==="linkField"||n==="delete"||n==="unlink"?`isa ${t}`:""}`:"",q=`${y} ${o[Symbol.for("edgeType")]==="linkField"||n==="delete"?`isa ${t}`:""}`,T=()=>F?n==="link"?`${F};`:n==="create"?`${F}, has id '${l}';`:"":"",L=()=>F&&n==="match"?`${F};`:"",A=()=>F?n==="delete"?`${F};`:n==="match"?`${F};`:"":"",R=()=>F?n==="delete"?`${q};`:n==="unlink"?`${y} ${O};`:"":"";return {deletionMatch:A(),insertionMatch:L(),deletion:R(),insertion:T(),op:""}},a=(o,n)=>{let e=n==="edges"?d:f;if(Array.isArray(o))return o.map(g=>{let{preDeletionBatch:k,insertionMatch:O,deletionMatch:F,insertion:q,deletion:T}=e(g);return radash.shake({preDeletionBatch:k,insertionMatch:O,deletionMatch:F,insertion:q,deletion:T},L=>!L)}).filter(g=>g);let{preDeletionBatch:y,insertionMatch:l,deletionMatch:t,insertion:m,deletion:$}=e(o);return radash.shake({preDeletionBatch:y,insertionMatch:l,deletionMatch:t,insertion:m,deletion:$},g=>!g)},w=a(i.things),b=Array.isArray(w)?w:[w],Q=a(i.edges,"edges"),p=Array.isArray(Q)?Q:[Q],u=[...b,...p],h=radash.shake({insertionMatches:u.map(o=>o.insertionMatch).join(" ").trim(),deletionMatches:u.map(o=>o.deletionMatch).join(" ").trim(),insertions:u.map(o=>o.insertion).join(" ").trim(),deletions:u.map(o=>o.deletion).join(" ").trim()},o=>!o);s.tqlRequest=h;};var Re=s=>{if(!s.startsWith("_:"))throw new Error("ID must start with '_:'.");let r=s.substring(2);if(!/^[a-zA-Z0-9-_]+$/.test(r))throw new Error("$tempId must contain only alphanumeric characters, hyphens, and underscores.");if(s.length>36)throw new Error("$tempId must not be longer than 36 characters.");return r},kt=async s=>{let{rawBqlRequest:r,schema:c}=s,f=(Q=>immer.produce(Q,p=>objectTraversal.traverse(p,({value:u,key:h,parent:o})=>{radash.isObject(u)&&(u=radash.shake(u,n=>n===void 0)),h==="$tempId"&&(o[h]=Re(u));})))(r),a=(Q=>immer.produce(Q,p=>objectTraversal.traverse(p,({value:u,meta:h,key:o})=>{if(radash.isObject(u)){if(u.$arrayOp)throw new Error("Array op not supported yet");if(o==="$filter"||h.nodePath?.includes(".$filter."))return;let n=u;if(n.$op==="create"&&n.$id)throw new Error("Can't write to computed field $id. Try writing to the id field directly.");let e=D(c,n),l=h.nodePath?.split(".")?.filter(F=>Number.isNaN(parseInt(F,10))).join(".");if(!e)throw new Error(`Schema not found for ${n.$entity||n.$relation}`);n.$bzId=n.$tempId??`T_${uuid.v4()}`,n[Symbol.for("schema")]=e,n[Symbol.for("dbId")]=e.defaultDBConnector.id;let{usedLinkFields:t,usedRoleFields:m}=z(e,n),$=t.map(F=>({fieldType:"linkField",path:F,schema:e.linkFields.find(q=>q.path===F)})),g=e.thingType==="relation"?m.map(F=>({fieldType:"roleField",path:F,schema:X(e.roles,q=>q===F)})):[];if($.some(F=>F.schema?.target==="role")&&$.some(F=>F.schema?.target==="relation"))throw new Error("Unsupported: Can't use a link field with target === 'role' and another with target === 'relation' in the same mutation.");let k=g.filter(F=>[...new Set(F.schema.playedBy?.map(q=>q.thing))].length!==1);if(k.length>1)throw new Error(`Field: ${k[0].path} - If a role can be played by multiple things, you must specify the thing in the mutation: ${JSON.stringify(k[0].schema.playedBy)}. Schema: ${JSON.stringify(k[0].schema)}`);let O=h.nodePath;if([...$,...g].forEach(F=>{let q=n[F.path];if(q===void 0)return;let T=F.schema;if(!T)throw new Error(`Field ${F.path} not found in schema`);let L=F.fieldType==="roleField"?T?.playedBy[0]:T,R=(()=>T&&"relation"in T&&L?.relation===n.$relation?"$self":L?.relation?L?.relation:"$self")(),S=R==="$self"?e:c.relations[R];if(X(S.roles,(C,x)=>C===F.path)?.playedBy?.length===0)throw new Error(`unused role: ${O}.${F.path}`);if(!T)throw new Error(`Field ${F.path} not found in schema`);let B=F.fieldType==="linkField"?T?.oppositeLinkFieldsPlayedBy:T?.playedBy;if(!B)throw new Error(`No opposite fields found for ${JSON.stringify(T)}`);if([...new Set(B?.map(C=>C.thing))].length>1)throw new Error(`Field: ${F.path} - If a role can be played by multiple things, you must specify the thing in the mutation: ${JSON.stringify(B)}. Schema: ${JSON.stringify(T)}`);if(T.cardinality==="ONE"&&Array.isArray(q))throw new Error("Can't have an array in a cardinality === ONE link field");if(T.cardinality==="MANY"&&q!==null&&!Array.isArray(q)&&!q.$arrayOp)throw new Error(`${F.fieldType==="linkField"?T.path:T.name} is a cardinality === MANY thing. Use an array or a $arrayOp object`);if(q?.$entity||q?.$relation)return;let[I]=B,M="plays"in T?"linkField":"roleField",P={[`$${I.thingType}`]:I.thing,[Symbol.for("relation")]:R,[Symbol.for("edgeType")]:M,[Symbol.for("parent")]:{path:O,...n.$id?{$id:n.$id}:{},...n.$tempId?{$tempId:n.$tempId}:{},...n.filter?{filter:n.filter}:{},links:B},[Symbol.for("role")]:I.plays,[Symbol.for("oppositeRole")]:"plays"in T?T.plays:void 0,[Symbol.for("relFieldSchema")]:T};if(radash.isObject(q)&&(n[F.path]={...P,...q}),Array.isArray(q))if(q.every(C=>radash.isObject(C)))n[F.path]=q.map(C=>({...P,...C}));else if(q.every(C=>typeof C=="string"))n[F.path]=q.map(C=>({...P,$op:n.$op==="create"?"link":"replace",$id:C}));else throw new Error(`Invalid array value for ${F.path}`);if(typeof q=="string"&&(n[F.path]={...P,$op:n.$op==="create"?"link":"replace",$id:q}),q===null){let C={...P,$op:"unlink"};n[F.path]=T.cardinality==="MANY"?[C]:C;}}),!l&&!n.$entity&&!n.$relation)throw new Error("Root things must specify $entity or $relation")}})))(f),b=(Q=>immer.produce(Q,p=>objectTraversal.traverse(p,({parent:u,key:h,value:o,meta:n})=>{if(radash.isObject(o)){if(Object.keys(o).length===0)throw new Error("Empty object!");if(h==="$filter"||n.nodePath?.includes(".$filter."))return;let e=o,y=n.nodePath?.split(".");if(e.$tempId&&!(e.$op===void 0||e.$op==="link"||e.$op==="create"||e.$op==="update"))throw new Error(`Invalid op ${e.$op} for tempId. TempIds can be created, or when created in another part of the same mutation. In the future maybe we can use them to catch stuff in the DB as well and group them under the same tempId.`);let l=y?.filter(N=>Number.isNaN(parseInt(N,10))).join("."),t=l?Array.isArray(u)?y?.slice(0,-1).join("."):n.nodePath:n.nodePath||"",m=D(c,e),{unidentifiedFields:$,dataFields:g,roleFields:k,linkFields:O}=z(m,e),F=immer.current(e)[Symbol.for("parent")],q=l&&F.path,L=(q?objectTraversal.getNodeByPath(p,q):p)?.$op;if(l&&!L)throw new Error("Error: Parent $op not detected");let A=e[Symbol.for("relFieldSchema")];e.$op==="replace"&&L==="create"&&(e.$op="link");let R=Object.keys(e).some(N=>g?.includes(N)),S=Object.keys(e).some(N=>[...k,...O].includes(N)),E=()=>{if(e.$op)return e.$op;if(l&&!e.$id&&!e.$tempId&&L!=="create"&&A.cardinality==="ONE")throw new Error(`Please specify if it is a create or an update. Path: ${n.nodePath}`);if(e.$tempId)return "create";if((e.$id||e.$filter)&&R)return "update";if((e.$id||e.$filter)&&l&&!R&&!S)return "link";if(!e.$filter&&!e.$id&&!e.$tempId)return "create";if((e.$id||e.$filter)&&!R&&S)return "match";throw new Error("Wrong op")};if(e.$op||(e.$op=E()),u||(e.$parentKey=""),typeof u=="object"&&(Array.isArray(u)&&(e[Symbol.for("index")]=h),e[Symbol.for("path")]=t,e[Symbol.for("isRoot")]=!l,e[Symbol.for("depth")]=l?.split(".").length),!e.$entity&&!e.$relation)throw new Error(`Node ${JSON.stringify(e)} without $entity/$relation`);let{idFields:B,computedFields:I,virtualFields:M}=m;if(!B)throw new Error("No idFields found");let[P]=B,C=radash.listify(e,(N,j)=>j!==void 0?N:void 0),x=C.filter(N=>M?.includes(N));if(x.length>0)throw new Error(`Virtual fields can't be sent to DB: "${x.join(",")}"`);if(I.filter(N=>!C.includes(N)).forEach(N=>{let j=m.dataFields?.find(_=>_.path===N),Y=m.linkFields?.find(_=>_.path===N)?.oppositeLinkFieldsPlayedBy[0],Ut="roles"in m?X(m.roles,(_,ke)=>_===N):void 0,$t=j||Y||Ut;if(!$t)throw new Error(`no field Def for ${N}`);if(N===P&&e.$op==="create"&&!e[N]){let _=et({currentThing:e,fieldSchema:$t,mandatoryDependencies:!0});e[N]=_,e.$id=_;}}),$.length>0)throw new Error(`Unknown fields: [${$.join(",")}] in ${JSON.stringify(e)}`)}})))(a);s.filledBqlRequest=b;};var Dt=async s=>{let{filledBqlRequest:r,schema:c}=s,i=p=>{let u=[],h=[],o=l=>{if(l.$id)return l.$id;let t=D(c,l),{idFields:m}=t;if(!m)throw new Error(`no idFields: ${JSON.stringify(l)}`);let[$]=m;if(!$)throw new Error(`no idField: ${JSON.stringify(l)}`);let g=t.dataFields?.find(F=>F.path===$),k=l.$op==="create"?g?.default?.value():null,O=l[$]||l.$id||k;if(!O)throw new Error(`no idValue: ${JSON.stringify(l)}`);return O},n=l=>{if(l.$op==="create"){let t=o(l);if(u.find(m=>m.$id===t))throw new Error(`Duplicate id ${t} for node ${JSON.stringify(l)}`);if(h.find(m=>m.$bzId===l.$bzId))throw new Error(`Duplicate $bzid ${l.$bzId} for node ${JSON.stringify(l)}`);u.push({...l,$id:t});return}l.$tempId&&l.$op==="match"||u.push(l);},e=l=>{if(l.$op==="create"){let t=o(l);if(u.find(m=>m.$id===t),h.find(m=>m.$bzId===l.$bzId))throw new Error(`Duplicate %bzId ${l.$bzIdd} for edge ${JSON.stringify(l)}`);h.push({...l,$id:t});return}h.push(l);};return objectTraversal.traverse(p,({value:l})=>{if(!radash.isObject(l))return;let t=l;if(t.$entity||t.$relation){if(!t.$op)throw new Error(`Operation should be defined at this step ${JSON.stringify(t)}`);if(!t.$bzId)throw new Error("[internal error] BzId not found");let m=D(c,t),{dataFields:$,roleFields:g,linkFields:k,usedFields:O}=z(m,t),F=()=>{if(t.$op==="create"||t.$op==="delete")return t.$op;if(t.$op==="update"){let T=O.filter(R=>$?.includes(R)),L=O.filter(R=>g?.includes(R)),A=O.filter(R=>k?.includes(R));if(T.length>0)return "update";if(L.length>0||A.length>0)return "match";throw new Error(`No fields on an $op:"update" for node ${JSON.stringify(t)}`)}return "match"},q={...t.$entity&&{$entity:t.$entity},...t.$relation&&{$relation:t.$relation},...t.$id&&{$id:t.$id},...t.$tempId&&{$tempId:t.$tempId},...t.$filter&&{$filter:t.$filter},...radash.shake(radash.pick(t,$||[""])),$op:F(),$bzId:t.$bzId,[Symbol.for("dbId")]:m.defaultDBConnector.id,[Symbol.for("path")]:t[Symbol.for("path")],[Symbol.for("parent")]:t[Symbol.for("parent")],[Symbol.for("isRoot")]:t[Symbol.for("isRoot")],[Symbol.for("isLocalId")]:t[Symbol.for("isLocalId")]||!1};if(n(q),t[Symbol.for("relation")]&&t[Symbol.for("edgeType")]==="linkField"){if((t.$op==="link"||t.$op==="unlink")&&(t.$id||t.$filter)){if(t.$tempId)throw new Error("can't specify a existing and a new element at once. Use an id/filter or a tempId");u.push({...t,$op:"match"});}let T=t[Symbol.for("relation")]===t.$relation,L=T?t.$bzId:uuid.v4(),R=t[Symbol.for("parent")].path,E=(R?objectTraversal.getNodeByPath(p,R):p).$bzId;if(!E)throw new Error("No parent id found");if(t[Symbol.for("relation")]==="$self")return;let B=()=>{if(t.$op==="delete")return T?"match":"delete";if(t.$op==="unlink")return T?"unlink":"delete";if(t.$op==="link"||t.$op==="create")return T?"link":"create";if(t.$op==="replace")throw new Error("Unsupported: Nested replaces not implemented yet");return "match"},I={$relation:t[Symbol.for("relation")],$bzId:L,...t.$tempId?{$tempId:t.$tempId}:{},$op:B(),...T?{}:{[t[Symbol.for("role")]]:t.$bzId},[t[Symbol.for("oppositeRole")]]:E,[Symbol.for("dbId")]:c.relations[t[Symbol.for("relation")]].defaultDBConnector.id,[Symbol.for("edgeType")]:"linkField",[Symbol.for("info")]:"normal linkField",[Symbol.for("path")]:t[Symbol.for("path")],[Symbol.for("parent")]:t[Symbol.for("parent")]};e(I),(t.$op==="unlink"||B()==="unlink")&&T&&e({$relation:t[Symbol.for("relation")],$bzId:L,$op:"match",[t[Symbol.for("oppositeRole")]]:E,[Symbol.for("dbId")]:c.relations[t[Symbol.for("relation")]].defaultDBConnector.id,[Symbol.for("edgeType")]:"linkField",[Symbol.for("info")]:"additional ownrelation unlink linkField",[Symbol.for("path")]:t[Symbol.for("path")],[Symbol.for("parent")]:t[Symbol.for("parent")]});}if(t.$relation){let T=G(t,(R,S)=>g.includes(R)),L=radash.mapEntries(T,(R,S)=>radash.isArray(S)?[R,S]:radash.isObject(S)?[R,S.$bzId]:[R,S]),A=G(l,(R,S)=>R.startsWith("$")||R.startsWith("Symbol"));if(Object.keys(T).filter(R=>!R.startsWith("$")).length>0){if(t.$op==="create"||t.$op==="delete"){let R=()=>{if(t.$op==="create")return "link";if(t.$op==="delete")return "match";throw new Error("Unsupported parent of edge op")},S=radash.mapEntries(L,(B,I)=>Array.isArray(I)?[B,I.map(M=>M.$bzId||M)]:[B,I.$bzId||I]),E={...A,$relation:t.$relation,$op:R(),...S,$bzId:t.$bzId,[Symbol.for("path")]:t[Symbol.for("path")],[Symbol.for("dbId")]:m.defaultDBConnector.id,[Symbol.for("info")]:"coming from created or deleted relation",[Symbol.for("edgeType")]:"roleField on C/D"};e(E);return}if(t.$op==="match"||t.$op==="update"&&Object.keys(T).length>0){let R=0;Object.entries(T).forEach(([S,E])=>{let B=radash.isArray(E)?E:[E],I=M=>M==="create"||M==="replace"?"link":M;B.forEach(M=>{let P=I(M.$op);if(P==="replace")throw new Error("Not supported yet: replace on roleFields");if(P==="unlink"&&R>0)throw R+=1,new Error("Not supported yet: Cannot unlink more than one role at a time, please split into two mutations");let C={...A,$relation:t.$relation,$op:P==="delete"?"unlink":P,[S]:M.$bzId,$bzId:t.$bzId,[Symbol.for("dbId")]:m.defaultDBConnector.id,[Symbol.for("parent")]:t[Symbol.for("parent")],[Symbol.for("path")]:t[Symbol.for("path")],[Symbol.for("info")]:"updating roleFields",[Symbol.for("edgeType")]:"roleField on L/U/R"};e(C);});});}}}}}),[u,h]};if(!r)throw new Error("Undefined filledBqlRequest");let [f,d]=i(r),a=f.reduce((p,u)=>{if(!u.$bzId)return [...p,u];let h=p.findIndex(o=>o.$bzId===u.$bzId);if(h===-1)return [...p,u];if(p[h].$op==="create"&&u.$op==="match")return p;if(p[h].$op==="match"&&(u.$op==="create"||u.$op==="match"))return [...p.slice(0,h),u,...p.slice(h+1)];throw new Error(`Unsupported operation combination for $tempId "${u.$tempId}". Existing: ${p[h].$op}. Current: ${u.$op}`)},[]),w=d.reduce((p,u)=>{let h=p.find(o=>(o.$id&&o.$id===u.$id||o.$bzId&&o.$bzId===u.$bzId)&&o.$relation===u.$relation&&o.$op===u.$op);if(h){let o={...h};return Object.keys(u).forEach(e=>{if(typeof e=="symbol"||e.startsWith("$"))return;let y=h[e],l=u[e];Array.isArray(y)&&Array.isArray(l)?o[e]=Array.from(new Set([...y,...l])):!Array.isArray(y)&&Array.isArray(l)?y!==void 0?o[e]=Array.from(new Set([y,...l])):o[e]=l:Array.isArray(y)&&!Array.isArray(l)?l!==void 0&&(o[e]=Array.from(new Set([...y,l]))):y||(o[e]=l);}),[...p.filter(e=>!((e.$id&&e.$id===u.$id||e.$bzId&&e.$bzId===u.$bzId)&&e.$relation===u.$relation&&e.$op===u.$op)),o]}return [...p,u]},[]);[...new Set(w.map(p=>p.$relation))];s.bqlRequest={mutation:{things:a,edges:w}};};var xt=async s=>{let{filledBqlRequest:r}=s;if(Array.isArray(r))return;let i=r,d=(e=>{if(Array.isArray(e)){let y=[],l=null,t=null;if(objectTraversal.traverse(e,({value:$,key:g,meta:k})=>{k.depth===2&&(g==="$relation"?l=$:g==="$entity"?t=$:g==="$id"&&typeof $=="string"&&y.push($));}),!l&&!t)throw new Error("Neither $relation nor $entity found in the blocks");let m={$id:y};return l&&(m.$relation=l),t&&(m.$entity=t),m}else if(radash.isObject(e)){let y={...e.$relation&&{$relation:e.$relation},...e.$entity&&{$entity:e.$entity},$id:e.$id||e.id};return objectTraversal.traverse(e,({key:l,value:t,meta:m})=>{if(l==="$op"&&t==="match"&&m.nodePath){let $=m.nodePath.split(".").slice(0,-1),g=y;$.forEach(k=>{g.$fields||(g.$fields=[]);let O=g.$fields.find(F=>F.$path===k);O||(O={$path:k},g.$fields.push(O)),g=O;});}}),y}return e})(r),a=await st(d,s.config,s.schema,s.dbHandles),w=(e,y)=>{let l=e.$id||e.id||e.$bzId;return `${e.$objectPath?l?e.$objectPath:e.$objectPath.split(".")[0]:"root"}${l?`-${l}`:""}.${y}`},Q=a?(e=>immer.produce(e,y=>objectTraversal.traverse(y,l=>{let{key:t,parent:m}=l;m&&t&&!t.includes("$")&&(Array.isArray(m[t])?m[t].forEach($=>{typeof $!="string"&&($.$objectPath=w(m,t));}):radash.isObject(m[t])&&(m[t].$objectPath=w(m,t)));})))(a):{},p={};(e=>immer.produce(e,y=>objectTraversal.traverse(y,l=>{let{key:t,parent:m}=l;if(m&&t&&m.$id&&!t.includes("$")){let $=w(m,t);if(Array.isArray(m[t])){let g=[];m[t].forEach(k=>{radash.isObject(k)?g.push(k.$id.toString()):g.push(k.toString());}),p[$]=g;}else {let g=m[t];radash.isObject(g)?p[$]=g.$id.toString():p[$]=g.toString();}}})))(Q);let h=(e,y)=>{let l=!1,t=Array.isArray(p[e])?"MANY":"ONE",m=Array.isArray(p[e])?p[e]:[p[e]];return m&&(l=(Array.isArray(y)?m.filter(g=>y.includes(g)):m.filter(g=>g===y)).length>0),{found:l,cardinality:t,isOccupied:!!p[e]}},o=(e,y)=>{let l=[],t=Array.isArray(p[e])?p[e]:[p[e]],m=y.map($=>$.$id);return t&&(l=t.filter($=>!m.includes($))),l};a&&(i=(e=>immer.produce(e,y=>objectTraversal.traverse(y,l=>{let{key:t,value:m,parent:$}=l;if($&&t&&!t.includes("$")&&(Array.isArray(m)||radash.isObject(m))&&!Array.isArray($)&&(Array.isArray($[t])?$[t].forEach(g=>{typeof g!="string"&&(g.$objectPath=w($,t));}):radash.isObject($[t])&&($[t].$objectPath=w($,t))),t&&$&&!t?.includes("$")&&(Array.isArray(m)||radash.isObject(m))&&!Array.isArray($)){let g=Array.isArray(m)?m:[m],k={},O=[],F=[],q=w($,t);g.forEach(L=>{let A=L.$id||L.id,{found:R,cardinality:S,isOccupied:E}=h(q,A);if(L.$op&&A)switch(L.$op){case"delete":if(!R)throw new Error(`[BQLE-Q-M-2] Cannot delete $id:"${A}" because it is not linked to $id:"${$.$id}"`);break;case"update":if(!R)throw new Error(`[BQLE-Q-M-2] Cannot update $id:"${A}" because it is not linked to $id:"${$.$id}"`);break;case"unlink":if(!R)throw new Error(`[BQLE-Q-M-2] Cannot unlink $id:"${A}" because it is not linked to $id:"${$.$id}"`);break;case"link":if(R)throw new Error(`[BQLE-Q-M-2] Cannot link $id:"${A}" because it is already linked to $id:"${$.$id}"`);break;case"replace":O.push(L),L.$op="link",R&&F.push(A);break;case"create":O.push(L);break;}else if(L.$op==="link"&&!R&&S==="ONE"&&E)throw new Error(`[BQLE-Q-M-2] Cannot link on:"${L.$objectPath}" because it is already occupied.`)}),O.length>0&&o(q,O).forEach(A=>{let R=g.find(E=>E.$id===A&&E.$op==="link"),[S]=O;if(S.$entity?k.$entity=S.$entity:S.$relation&&(k.$relation=S.$relation),!R&&!g.some(E=>E.$id===A)){let E={...k,$op:"unlink",$id:A,$bzId:`T_${uuid.v4()}`};Array.isArray(m)?m.push(E):g=[m,E];}else if(R){let E=g.findIndex(B=>B.$id===A&&B.$op==="link");E>-1&&g.splice(E,1);}});let T=g.filter(L=>!F.includes(L.$id));$[t]=radash.isObject(m)&&T.length===1?T[0]:T;}})))(i),s.filledBqlRequest=i);};var jt=async(s,r)=>{let{dbHandles:c,tqlRequest:i,bqlRequest:f,config:d}=s;if(!i)throw new Error("TQL request not built");if(!(i.deletions&&i.deletionMatches||i.insertions))throw new Error("TQL request error, no things");if(!f?.mutation)throw new Error("BQL mutation not parsed");let{session:a}=await it(c,d),w=await a.transaction(typedbDriver.TransactionType.WRITE);if(!w)throw new Error("Can't create transaction");let b=i.deletionMatches&&i.deletions&&`match ${i.deletionMatches} delete ${i.deletions}`,Q=i.insertions&&`${i.insertionMatches?`match ${i.insertionMatches}`:""} insert ${i.insertions}`;b&&w.query.delete(b);let p=Q&&w.query.insert(Q);try{let u=p?await p.collect():void 0;await w.commit(),await w.close(),r.rawTqlRes={insertions:u};}catch(u){throw await w.close(),new Error(`Transaction failed: ${u.message}`)}};var zt={query:[Ot,nt,rt,J,pt],mutation:[kt,xt,Dt,At,jt,J]},Ae=[qt],at=async(s,r,c={},i=!0)=>{for(let f of s){let d=await f(r,c);if(d&&Array.isArray(d))for(let a of d)await at(a.pipeline,a.req,a.res,!1);}return i?(await at(Ae,r,c,!1),r.config.query?.debugger===!0&&typeof c.bqlRes=="object"?{...c.bqlRes,$debugger:{tqlRequest:r.tqlRequest}}:c.bqlRes):c.bqlRes},st=(s,r,c,i)=>at(zt.query,{config:r,schema:c,rawBqlRequest:s,dbHandles:i},{}),Vt=(s,r,c,i)=>at(zt.mutation,{config:r,schema:c,rawBqlRequest:s,dbHandles:i},{});var mt=class{schema;config;dbHandles;constructor({schema:r,config:c}){this.schema=r,this.config=c;}init=async()=>{let r={typeDB:new Map},c=Ft(this.schema);await Promise.all(this.config.dbConnectors.map(async i=>{if(i.provider==="typeDB"&&i.dbName){let[f,d]=await radash.tryit(typedbDriver.TypeDB.coreDriver)(i.url);if(f){let a=`[BORM:${i.provider}:${i.dbName}:core] ${f.message??"Can't create TypeDB Client"}`;throw new Error(a)}try{let a=await d.session(i.dbName,typedbDriver.SessionType.DATA);r.typeDB.set(i.id,{client:d,session:a});}catch(a){let w=`[BORM:${i.provider}:${i.dbName}:session] ${(a.messageTemplate?._messageBody()||a.message)??"Can't create TypeDB Session"}`;throw new Error(w)}}if(i.provider==="typeDBCluster"&&i.dbName){let[f,d]=await radash.tryit(typedbDriver.TypeDB.enterpriseDriver)(i.addresses,i.credentials);if(f){let a=`[BORM:${i.provider}:${i.dbName}:core] ${f.message??"Can't create TypeDB Cluster Client"}`;throw new Error(a)}try{let a=await d.session(i.dbName,typedbDriver.SessionType.DATA);r.typeDB.set(i.id,{client:d,session:a});}catch(a){let w=`[BORM:${i.provider}:${i.dbName}:session] ${(a.messageTemplate?._messageBody()||a.message)??"Can't create TypeDB Session"}`;throw new Error(w)}}})),this.schema=c,this.dbHandles=r;};#t=async()=>{if(!this.dbHandles&&(await this.init(),!this.dbHandles))throw new Error("Can't init BormClient")};introspect=async()=>(await this.#t(),this.schema);define=async()=>(await this.#t(),bt(this.config,this.schema,this.dbHandles));query=async(r,c)=>{await this.#t();let i={...this.config,query:{...lt.query,...this.config.query,...c}};return st(r,i,this.schema,this.dbHandles)};mutate=async(r,c)=>{await this.#t();let i={...this.config,mutation:{...lt.mutation,...this.config.mutation,...c}};return Vt(r,i,this.schema,this.dbHandles)};close=async()=>{this.dbHandles&&this.dbHandles.typeDB.forEach(async({client:r,session:c})=>{console.log("Closing session"),await c.close(),console.log("Closing client"),await r.close();});}},Ii=mt;//! reads all the insertions and gets the first match. This means each id must be unique
36
- //! disabled as it has false positives
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var src_exports = {};
22
+ __export(src_exports, {
23
+ default: () => src_default
24
+ });
25
+ module.exports = __toCommonJS(src_exports);
26
+ var import_radash11 = require("radash");
27
+ var import_typedb_driver5 = require("typedb-driver");
28
+
29
+ // src/default.config.ts
30
+ var defaultConfig = {
31
+ query: {
32
+ noMetadata: false,
33
+ simplifiedLinks: true,
34
+ debugger: false,
35
+ returnNulls: false
36
+ },
37
+ mutation: {
38
+ noMetadata: false,
39
+ preQuery: true,
40
+ ignoreNonexistingThings: false
41
+ }
42
+ };
43
+
44
+ // src/define/index.ts
45
+ var import_typedb_driver = require("typedb-driver");
46
+ var removeDuplicateObjects = (arr) => {
47
+ const uniqueObjects = [];
48
+ const uniqueMap = /* @__PURE__ */ new Map();
49
+ arr.forEach((obj) => {
50
+ const { dbPath, contentType } = obj;
51
+ const key = `${dbPath}-${contentType}`;
52
+ if (!uniqueMap.has(key)) {
53
+ uniqueMap.set(key, true);
54
+ uniqueObjects.push(obj);
55
+ }
56
+ });
57
+ return uniqueObjects;
58
+ };
59
+ var bormDefine = async (config, schema, dbHandles) => {
60
+ const convertSchema = () => {
61
+ let output = "";
62
+ const usedAttributes = [];
63
+ output += "\n";
64
+ Object.keys(schema.entities).forEach((entityName) => {
65
+ const entity = schema.entities[entityName];
66
+ const { idFields, dataFields, linkFields, name } = entity;
67
+ const commonDataFields = [];
68
+ const commonLinkFields = [];
69
+ const commonIdFields = [];
70
+ if (entity.extends) {
71
+ const parentEntity = schema.entities[entity.extends];
72
+ if (parentEntity.dataFields) {
73
+ parentEntity.dataFields.forEach((dataField) => {
74
+ commonDataFields.push(dataField.dbPath);
75
+ });
76
+ }
77
+ if (parentEntity.linkFields) {
78
+ parentEntity.linkFields.forEach((linkField) => {
79
+ commonLinkFields.push(linkField.path);
80
+ });
81
+ }
82
+ if (parentEntity.idFields) {
83
+ parentEntity.idFields.forEach((idField) => {
84
+ commonIdFields.push(idField);
85
+ });
86
+ }
87
+ }
88
+ output += `${name} sub ${entity.extends ? entity.extends : "entity"},
89
+ `;
90
+ const idsAsData = [];
91
+ if (idFields && idFields.length > 0) {
92
+ const setIds = new Set(idFields);
93
+ const newIdFields = Array.from(setIds);
94
+ const idFieldsString = newIdFields.map((field) => `${field}`).join(", ");
95
+ if (!commonIdFields.includes(idFieldsString)) {
96
+ output += ` owns ${idFieldsString} @key,
97
+ `;
98
+ idsAsData.push(idFieldsString);
99
+ }
100
+ }
101
+ if (dataFields && dataFields.length > 0) {
102
+ dataFields.forEach((field) => {
103
+ if (!commonDataFields.includes(field.dbPath) && !idsAsData.includes(field.dbPath)) {
104
+ output += ` owns ${field.dbPath},
105
+ `;
106
+ }
107
+ usedAttributes.push({ dbPath: field.dbPath, contentType: field.contentType });
108
+ });
109
+ }
110
+ if (linkFields && linkFields.length > 0) {
111
+ const usedLinkFields = [];
112
+ linkFields.forEach((linkField) => {
113
+ const { relation, plays } = linkField;
114
+ if (!commonLinkFields.includes(linkField.path) && !usedLinkFields.includes(`${relation}:${plays}`)) {
115
+ output += ` plays ${relation}:${plays},
116
+ `;
117
+ usedLinkFields.push(`${relation}:${plays}`);
118
+ }
119
+ });
120
+ }
121
+ output = output.replace(/,\s*$/, ";\n");
122
+ output += "\n";
123
+ });
124
+ Object.keys(schema.relations).forEach((relationName) => {
125
+ const relation = schema.relations[relationName];
126
+ const { idFields, dataFields, roles, name, linkFields } = relation;
127
+ const commonDataFields = [];
128
+ const commonLinkFields = [];
129
+ const commonRoleFields = [];
130
+ const commonIdFields = [];
131
+ if (relation.extends) {
132
+ const parentRelation = schema.relations[relation.extends];
133
+ if (parentRelation.dataFields) {
134
+ parentRelation.dataFields.forEach((dataField) => {
135
+ commonDataFields.push(dataField.dbPath);
136
+ });
137
+ }
138
+ if (parentRelation.linkFields) {
139
+ parentRelation.linkFields.forEach((linkField) => {
140
+ commonLinkFields.push(linkField.dbPath);
141
+ });
142
+ }
143
+ if (parentRelation.roles) {
144
+ const roleFields = Object.values(parentRelation.roles);
145
+ roleFields.forEach((roleField) => {
146
+ commonRoleFields.push(roleField.name);
147
+ });
148
+ }
149
+ if (parentRelation.idFields) {
150
+ parentRelation.idFields.forEach((idField) => {
151
+ commonIdFields.push(idField);
152
+ });
153
+ }
154
+ }
155
+ output += `${name} sub ${relation.extends ? relation.extends : "relation"},
156
+ `;
157
+ const idsAsData = [];
158
+ if (idFields && idFields.length > 0) {
159
+ const setIds = new Set(idFields);
160
+ const newIdFields = Array.from(setIds);
161
+ const idFieldsString = newIdFields.map((field) => `${field}`).join(", ");
162
+ if (!commonIdFields.includes(idFieldsString)) {
163
+ output += ` owns ${idFieldsString} @key,
164
+ `;
165
+ idsAsData.push(idFieldsString);
166
+ }
167
+ }
168
+ if (dataFields && dataFields.length > 0) {
169
+ dataFields.forEach((field) => {
170
+ if (!commonDataFields.includes(field.dbPath) && !idsAsData.includes(field.dbPath)) {
171
+ output += ` owns ${field.dbPath},
172
+ `;
173
+ }
174
+ usedAttributes.push({ dbPath: field.dbPath, contentType: field.contentType });
175
+ });
176
+ }
177
+ if (roles) {
178
+ Object.keys(roles).forEach((roleName) => {
179
+ if (!commonRoleFields.includes(roleName)) {
180
+ output += ` relates ${roleName},
181
+ `;
182
+ }
183
+ });
184
+ }
185
+ if (linkFields && linkFields.length > 0) {
186
+ const usedLinkFields = [];
187
+ linkFields.forEach((linkField) => {
188
+ const { plays } = linkField;
189
+ if (!commonLinkFields.includes(linkField.path) && !usedLinkFields.includes(`${relation}:${plays}`)) {
190
+ output += ` plays ${linkField.relation}:${plays},
191
+ `;
192
+ usedLinkFields.push(`${relation}:${plays}`);
193
+ }
194
+ });
195
+ }
196
+ output = output.replace(/,\s*$/, ";\n");
197
+ output += "\n";
198
+ });
199
+ let attributes = "define\n\n";
200
+ const newUsedAttributes = removeDuplicateObjects(usedAttributes);
201
+ newUsedAttributes.forEach((attribute) => {
202
+ attributes += `${attribute.dbPath} sub attribute,
203
+ `;
204
+ if (attribute.contentType === "TEXT" || attribute.contentType === "ID") {
205
+ attributes += " value string;\n";
206
+ } else if (attribute.contentType === "EMAIL") {
207
+ attributes += " value string,\n";
208
+ attributes += " regex '^(?=.{1,64}@)[A-Za-z0-9_-]+(\\.[A-Za-z0-9_-]+)*@[^-][A-Za-z0-9-]+(\\.[A-Za-z0-9-]+)*(\\.[A-Za-z]{2,})$';\n";
209
+ } else if (attribute.contentType === "DATE") {
210
+ attributes += " value datetime;\n";
211
+ } else if (attribute.contentType === "BOOLEAN") {
212
+ attributes += " value boolean;\n";
213
+ } else if (attribute.contentType === "NUMBER") {
214
+ attributes += " value long;\n";
215
+ }
216
+ });
217
+ return `${attributes}
218
+
219
+ ${output}`;
220
+ };
221
+ const typeDBString = convertSchema();
222
+ const singleHandlerV0 = config.dbConnectors[0].id;
223
+ const session = dbHandles.typeDB.get(singleHandlerV0)?.session;
224
+ const client = dbHandles.typeDB.get(singleHandlerV0)?.client;
225
+ if (!session) {
226
+ console.log("Session Status: ", "NO SESSION");
227
+ return;
228
+ }
229
+ session.close();
230
+ const [{ dbName }] = config.dbConnectors;
231
+ const db = await client.databases.get(dbName);
232
+ await db.delete();
233
+ await client.databases.create(dbName);
234
+ const schemaSession = await client.session(config.dbConnectors[0].dbName, import_typedb_driver.SessionType.SCHEMA);
235
+ const schemaTransaction = await schemaSession.transaction(import_typedb_driver.TransactionType.WRITE);
236
+ await schemaTransaction.query.define(typeDBString);
237
+ await schemaTransaction.commit();
238
+ await schemaTransaction.close();
239
+ const getSchemaTransaction = await schemaSession.transaction(import_typedb_driver.TransactionType.READ);
240
+ const getSchemaQuery = "match $a sub thing;";
241
+ const getSchemaStream = await getSchemaTransaction.query.match(getSchemaQuery);
242
+ const schemaThings = await getSchemaStream.collect();
243
+ schemaThings.forEach(async (conceptMap) => {
244
+ const thing = conceptMap.get("a");
245
+ const { _label } = thing;
246
+ const { _name } = _label;
247
+ });
248
+ await getSchemaTransaction.close();
249
+ };
250
+
251
+ // src/helpers.ts
252
+ var import_immer = require("immer");
253
+ var import_object_traversal = require("object-traversal");
254
+ var import_radash = require("radash");
255
+ var getDbPath = (thing, attribute, shared) => shared ? attribute : `${thing}\xB7${attribute}`;
256
+ var oFind = (obj, fn) => Object.values(Object.fromEntries(Object.entries(obj).filter(([k, v]) => fn(k, v))))[0];
257
+ var oFilter = (obj, fn) => Object.fromEntries(Object.entries(obj).filter(([k, v]) => fn(k, v)));
258
+ var enrichSchema = (schema) => {
259
+ const allLinkedFields = [];
260
+ const withExtensionsSchema = (0, import_immer.produce)(
261
+ schema,
262
+ (draft) => (0, import_object_traversal.traverse)(
263
+ draft,
264
+ ({ key, value, meta }) => {
265
+ if (meta.depth !== 2) {
266
+ return;
267
+ }
268
+ if (key) {
269
+ value.dataFields = value.dataFields?.map((df) => ({
270
+ ...df,
271
+ dbPath: getDbPath(key, df.path, df.shared)
272
+ }));
273
+ }
274
+ if (value.extends) {
275
+ const extendedSchema = draft.entities[value.extends] || draft.relations[value.extends];
276
+ value.allExtends = [value.extends, ...extendedSchema.allExtends || []];
277
+ value;
278
+ value.idFields = extendedSchema.idFields ? (value.idFields || []).concat(extendedSchema.idFields) : value.idFields;
279
+ value.dataFields = extendedSchema.dataFields ? (value.dataFields || []).concat(
280
+ extendedSchema.dataFields.map((df) => {
281
+ let deepExtendedThing = value.extends;
282
+ let deepSchema = schema.entities[deepExtendedThing] || schema.relations[deepExtendedThing];
283
+ while (!deepSchema.dataFields?.find((deepDf) => deepDf.path === df.path)) {
284
+ deepExtendedThing = deepSchema.extends;
285
+ deepSchema = schema.entities[deepExtendedThing] || schema.relations[deepExtendedThing];
286
+ }
287
+ return {
288
+ ...df,
289
+ dbPath: getDbPath(deepExtendedThing, df.path, df.shared)
290
+ };
291
+ })
292
+ ) : value.dataFields;
293
+ value.linkFields = extendedSchema.linkFields ? (value.linkFields || []).concat(extendedSchema.linkFields) : value.linkFields;
294
+ if ("roles" in extendedSchema) {
295
+ const val = value;
296
+ const extendedRelationSchema = extendedSchema;
297
+ val.roles = val.roles || {};
298
+ val.roles = {
299
+ ...val.roles,
300
+ ...extendedRelationSchema.roles
301
+ };
302
+ if (Object.keys(val.roles).length === 0) {
303
+ val.roles = {};
304
+ }
305
+ }
306
+ }
307
+ },
308
+ { traversalType: "breadth-first" }
309
+ )
310
+ );
311
+ (0, import_object_traversal.traverse)(schema, ({ key, value, meta }) => {
312
+ if (key === "linkFields") {
313
+ const getThingTypes = () => {
314
+ if (!meta.nodePath) {
315
+ throw new Error("No path");
316
+ }
317
+ const [thingPath, thing] = meta.nodePath.split(".");
318
+ const thingType = thingPath === "entities" ? "entity" : thingPath === "relations" ? "relation" : "";
319
+ return {
320
+ thing,
321
+ thingType
322
+ };
323
+ };
324
+ const thingTypes = getThingTypes();
325
+ const withThing = !Array.isArray(value) ? [
326
+ {
327
+ ...value,
328
+ ...thingTypes
329
+ }
330
+ ] : value.map((x) => ({ ...x, ...thingTypes }));
331
+ allLinkedFields.push(...withThing);
332
+ }
333
+ });
334
+ const enrichedSchema = (0, import_immer.produce)(
335
+ withExtensionsSchema,
336
+ (draft) => (0, import_object_traversal.traverse)(draft, ({ value, key, meta }) => {
337
+ if (meta.depth === 2 && value.idFields && !value.id) {
338
+ value.name = key;
339
+ const thingType = () => {
340
+ if (meta.nodePath?.split(".")[0] === "entities") {
341
+ return "entity";
342
+ }
343
+ if (meta.nodePath?.split(".")[0] === "relations") {
344
+ return "relation";
345
+ }
346
+ throw new Error("Unsupported node attributes");
347
+ };
348
+ value.thingType = thingType();
349
+ value.computedFields = [];
350
+ value.virtualFields = [];
351
+ if ("roles" in value) {
352
+ const val = value;
353
+ Object.entries(val.roles).forEach(([roleKey, role]) => {
354
+ role.playedBy = allLinkedFields.filter((x) => x.relation === key && x.plays === roleKey) || [];
355
+ role.name = roleKey;
356
+ });
357
+ }
358
+ if ("linkFields" in value && value.linkFields) {
359
+ const val = value;
360
+ val.linkFields?.forEach((linkField) => {
361
+ if (linkField.target === "relation") {
362
+ linkField.oppositeLinkFieldsPlayedBy = [
363
+ {
364
+ plays: linkField.path,
365
+ thing: linkField.relation,
366
+ thingType: "relation"
367
+ }
368
+ ];
369
+ return;
370
+ }
371
+ const allOppositeLinkFields = allLinkedFields.filter((x) => x.relation === linkField.relation && x.plays !== linkField.plays) || [];
372
+ linkField.oppositeLinkFieldsPlayedBy = allOppositeLinkFields;
373
+ const { filter } = linkField;
374
+ linkField.oppositeLinkFieldsPlayedBy = linkField.oppositeLinkFieldsPlayedBy.filter(
375
+ (x) => x.target === "role"
376
+ );
377
+ if (filter && Array.isArray(filter)) {
378
+ linkField.oppositeLinkFieldsPlayedBy = linkField.oppositeLinkFieldsPlayedBy.filter(
379
+ (lf) => (
380
+ // @ts-expect-error - TODO description
381
+ filter.some((ft) => lf.thing === ft.$role)
382
+ )
383
+ );
384
+ linkField.oppositeLinkFieldsPlayedBy = linkField.oppositeLinkFieldsPlayedBy.filter(
385
+ (lf) => (
386
+ // @ts-expect-error - TODO description
387
+ filter.some((ft) => lf.thing === ft.$thing)
388
+ )
389
+ );
390
+ }
391
+ if (filter && !Array.isArray(filter)) {
392
+ linkField.oppositeLinkFieldsPlayedBy = linkField.oppositeLinkFieldsPlayedBy.filter(
393
+ // @ts-expect-error - TODO description
394
+ (lf) => lf.$role === filter.$role
395
+ );
396
+ linkField.oppositeLinkFieldsPlayedBy = linkField.oppositeLinkFieldsPlayedBy.filter(
397
+ // @ts-expect-error - TODO description
398
+ (lf) => lf.thing === filter.$thing
399
+ );
400
+ }
401
+ });
402
+ }
403
+ }
404
+ if (typeof value === "object" && "playedBy" in value) {
405
+ if ([...new Set(value.playedBy?.map((x) => x.thing))].length > 1) {
406
+ throw new Error(
407
+ `Unsupported: roleFields can be only played by one thing. Role: ${key} path:${meta.nodePath}`
408
+ );
409
+ }
410
+ if (value.playedBy.length === 0) {
411
+ throw new Error(
412
+ `Unsupported: roleFields should be played at least by one thing. Role: ${key}, path:${meta.nodePath}`
413
+ );
414
+ }
415
+ }
416
+ if (meta.depth === 4 && (value.default || value.computedValue)) {
417
+ const [type, thingId] = meta.nodePath?.split(".") || [];
418
+ if (value.isVirtual) {
419
+ draft[type][thingId].virtualFields.push(value.path);
420
+ } else {
421
+ draft[type][thingId].computedFields.push(value.path);
422
+ }
423
+ }
424
+ })
425
+ );
426
+ return enrichedSchema;
427
+ };
428
+ var getCurrentSchema = (schema, node) => {
429
+ if (node.$entity) {
430
+ if (!(node.$entity in schema.entities)) {
431
+ throw new Error(`Missing entity '${node.$entity}' in the schema`);
432
+ }
433
+ return schema.entities[node.$entity];
434
+ }
435
+ if (node.$relation) {
436
+ if (!(node.$relation in schema.relations)) {
437
+ throw new Error(`Missing relation '${node.$relation}' in the schema`);
438
+ }
439
+ return schema.relations[node.$relation];
440
+ }
441
+ throw new Error(`Wrong schema or query for ${JSON.stringify(node, null, 2)}`);
442
+ };
443
+ var getCurrentFields = (currentSchema, node) => {
444
+ const availableDataFields = currentSchema.dataFields?.map((x) => x.path) || [];
445
+ const availableLinkFields = currentSchema.linkFields?.map((x) => x.path) || [];
446
+ const availableRoleFields = "roles" in currentSchema ? (0, import_radash.listify)(currentSchema.roles, (k) => k) : [];
447
+ const availableFields = [
448
+ ...availableDataFields || [],
449
+ ...availableLinkFields || [],
450
+ ...availableRoleFields || []
451
+ ];
452
+ const reservedRootFields = [
453
+ "$entity",
454
+ "$op",
455
+ "$id",
456
+ "$tempId",
457
+ "$bzId",
458
+ "$relation",
459
+ "$parentKey",
460
+ "$filter",
461
+ "$fields",
462
+ "$excludedFields"
463
+ ];
464
+ const allowedFields = [...reservedRootFields, ...availableFields];
465
+ if (!node) {
466
+ return {
467
+ fields: availableFields,
468
+ dataFields: availableDataFields,
469
+ roleFields: availableRoleFields,
470
+ linkFields: availableLinkFields
471
+ };
472
+ }
473
+ const usedFields = node.$fields ? node.$fields.map((x) => {
474
+ if (typeof x === "string") {
475
+ return x;
476
+ }
477
+ if ("$path" in x && typeof x.$path === "string") {
478
+ return x.$path;
479
+ }
480
+ throw new Error(" Wrongly structured query");
481
+ }) : (0, import_radash.listify)(node, (k) => k);
482
+ const localFilterFields = !node.$filter ? [] : (0, import_radash.listify)(node.$filter, (k) => k.toString().startsWith("$") ? void 0 : k.toString()).filter(
483
+ (x) => x && availableDataFields?.includes(x)
484
+ );
485
+ const nestedFilterFields = !node.$filter ? [] : (0, import_radash.listify)(node.$filter, (k) => k.toString().startsWith("$") ? void 0 : k.toString()).filter(
486
+ (x) => x && [...availableRoleFields || [], ...availableLinkFields || []]?.includes(x)
487
+ );
488
+ const unidentifiedFields = [...usedFields, ...localFilterFields].filter((x) => !allowedFields.includes(x)).filter((x) => x);
489
+ const localFilters = !node.$filter ? {} : oFilter(node.$filter, (k, _v) => localFilterFields.includes(k));
490
+ const nestedFilters = !node.$filter ? {} : oFilter(node.$filter, (k, _v) => nestedFilterFields.includes(k));
491
+ return {
492
+ fields: availableFields,
493
+ dataFields: availableDataFields,
494
+ roleFields: availableRoleFields,
495
+ linkFields: availableLinkFields,
496
+ usedFields,
497
+ usedLinkFields: availableLinkFields.filter((x) => usedFields.includes(x)),
498
+ usedRoleFields: availableRoleFields.filter((x) => usedFields.includes(x)),
499
+ unidentifiedFields,
500
+ ...localFilterFields.length ? { localFilters } : {},
501
+ ...nestedFilterFields.length ? { nestedFilters } : {}
502
+ };
503
+ };
504
+ var notNull = (value) => {
505
+ return value !== null;
506
+ };
507
+
508
+ // src/pipeline/postprocess/parseTQLMutation.ts
509
+ var import_radash2 = require("radash");
510
+ var parseTQLMutation = async (req, res) => {
511
+ const { bqlRequest, config, tqlRequest } = req;
512
+ const { rawTqlRes } = res;
513
+ if (!bqlRequest) {
514
+ throw new Error("BQL request not parsed");
515
+ } else if (!rawTqlRes) {
516
+ throw new Error("TQL query not executed");
517
+ }
518
+ const { query } = bqlRequest;
519
+ if (!query) {
520
+ if (rawTqlRes.insertions?.length === 0 && !tqlRequest?.deletions) {
521
+ res.bqlRes = {};
522
+ return;
523
+ }
524
+ const { mutation } = bqlRequest;
525
+ if (!mutation) {
526
+ throw new Error("TQL mutation not executed");
527
+ }
528
+ const expected = [...mutation.things, ...mutation.edges];
529
+ const result = expected.map((exp) => {
530
+ const currentNode = rawTqlRes.insertions?.find((y) => y.get(`${exp.$bzId}`))?.get(`${exp.$bzId}`);
531
+ if (exp.$op === "create" || exp.$op === "update" || exp.$op === "link") {
532
+ const dbIdd = currentNode?.asThing().iid;
533
+ if (config.mutation?.noMetadata) {
534
+ return (0, import_radash2.mapEntries)(exp, (k, v) => [
535
+ k.toString().startsWith("$") ? Symbol.for(k) : k,
536
+ v
537
+ ]);
538
+ }
539
+ return { $dbId: dbIdd, ...exp, ...{ [exp.path]: exp.$id } };
540
+ }
541
+ if (exp.$op === "delete" || exp.$op === "unlink") {
542
+ return exp;
543
+ }
544
+ if (exp.$op === "match") {
545
+ return void 0;
546
+ }
547
+ throw new Error(`Unsupported op ${exp.$op}`);
548
+ }).filter((z) => z);
549
+ res.bqlRes = result;
550
+ return;
551
+ }
552
+ };
553
+
554
+ // src/pipeline/postprocess/fieldsOperator.ts
555
+ var import_radash3 = require("radash");
556
+
557
+ // src/pipeline/postprocess/buildBQLTree.ts
558
+ var import_immer2 = require("immer");
559
+ var import_object_traversal2 = require("object-traversal");
560
+ var import_radash4 = require("radash");
561
+
562
+ // src/engine/helpers.ts
563
+ var STRIP_COMMENTS = /((\/\/.*$)|(\/\*.*\*\/))/gm;
564
+ var STRIP_KEYWORDS = /(\s*async\s*|\s*function\s*)+/;
565
+ var ARGUMENT_NAMES = /(?:function\s*[^(\s]*\s*|\s*=>\s*|^\s*)\(([^)]*)\)/;
566
+ var ARGUMENT_SPLIT = /[ ,\n\r\t]+/;
567
+ var getParamNames = (func) => {
568
+ const fnStr = func.toString().replace(STRIP_COMMENTS, "").replace(STRIP_KEYWORDS, "").trim();
569
+ const matches = ARGUMENT_NAMES.exec(fnStr);
570
+ if (!matches) {
571
+ return [];
572
+ }
573
+ let match;
574
+ for (const matchGroup of matches.slice(1)) {
575
+ if (matchGroup) {
576
+ match = matchGroup;
577
+ break;
578
+ }
579
+ }
580
+ if (!match) {
581
+ return [];
582
+ }
583
+ match = match.replace(/\{\s*/g, "").replace(/\s*\}/g, "");
584
+ return match.split(ARGUMENT_SPLIT).filter((part) => part.trim() !== "");
585
+ };
586
+
587
+ // src/engine/compute.ts
588
+ var compute = ({
589
+ currentThing,
590
+ fieldSchema,
591
+ mandatoryDependencies = false
592
+ }) => {
593
+ if (!fieldSchema || !fieldSchema.default || !fieldSchema.default.value) {
594
+ throw new Error("Virtual field: No field schema found, or wrongly configured");
595
+ }
596
+ const fn = fieldSchema.default.value;
597
+ const args = getParamNames(fn);
598
+ const missingArgs = args.filter((arg) => !(arg in currentThing));
599
+ if (mandatoryDependencies && missingArgs.length) {
600
+ throw new Error(`Virtual field: Missing arguments ${missingArgs.join(", ")}`);
601
+ }
602
+ const computedValue = "default" in fieldSchema ? fieldSchema.default?.value(currentThing) : void 0;
603
+ return computedValue;
604
+ };
605
+
606
+ // src/pipeline/postprocess/buildBQLTree.ts
607
+ var isOne = (children, $id) => {
608
+ if (children.length === 1 && typeof children[0] !== "string" ? children[0].$id === $id : false) {
609
+ return children[0];
610
+ }
611
+ return children;
612
+ };
613
+ var isStringOrHasShow = (value) => {
614
+ return typeof value === "string" || !!value.$show;
615
+ };
616
+ var cleanOutput = (obj, config) => (0, import_immer2.produce)(
617
+ obj,
618
+ (draft) => (0, import_object_traversal2.traverse)(draft, ({ value }) => {
619
+ if (Array.isArray(value) || !(typeof value === "object") || value === null) {
620
+ return;
621
+ }
622
+ if (value.$tempId) {
623
+ value.$tempId = `_:${value.$tempId}`;
624
+ }
625
+ if (value.$fields) {
626
+ delete value.$fields;
627
+ }
628
+ if (value.$filter) {
629
+ delete value.$filter;
630
+ }
631
+ if (value.$show) {
632
+ delete value.$show;
633
+ }
634
+ if (value.$bzId) {
635
+ delete value.$bzId;
636
+ }
637
+ if (config.query?.noMetadata && (value.$entity || value.$relation)) {
638
+ delete value.$entity;
639
+ delete value.$relation;
640
+ delete value.$id;
641
+ }
642
+ const symbols = Object.getOwnPropertySymbols(value);
643
+ symbols.forEach((symbol) => {
644
+ delete value[symbol];
645
+ });
646
+ if (value.$excludedFields) {
647
+ value.$excludedFields.forEach((field) => {
648
+ delete value[field];
649
+ });
650
+ delete value.$excludedFields;
651
+ }
652
+ })
653
+ );
654
+ var filterChildrenEntities = (things, ids, node, path) => things.map(([id, entity]) => {
655
+ if (!ids) {
656
+ return null;
657
+ }
658
+ if (!ids.includes(id)) {
659
+ return null;
660
+ }
661
+ if (!node.$fields) {
662
+ return id;
663
+ }
664
+ if (node.$fields.includes(path)) {
665
+ return id;
666
+ }
667
+ const currentFieldConf = node.$fields.find((f) => (0, import_radash4.isObject)(f) && f.$path === path);
668
+ if (currentFieldConf) {
669
+ const onlyMetadataEntity = {
670
+ ...oFilter(entity, (k, _v) => k.startsWith("$"))
671
+ };
672
+ const withFieldsEntity = currentFieldConf.$fields ? {
673
+ ...onlyMetadataEntity,
674
+ $fields: currentFieldConf.$fields
675
+ } : onlyMetadataEntity;
676
+ if (currentFieldConf.$id) {
677
+ if (Array.isArray(currentFieldConf.$id)) {
678
+ if (currentFieldConf.$id.includes(id)) {
679
+ return withFieldsEntity;
680
+ }
681
+ return null;
682
+ }
683
+ if (currentFieldConf.$id === id) {
684
+ return withFieldsEntity;
685
+ }
686
+ }
687
+ if (withFieldsEntity.$fields && withFieldsEntity.$fields.includes("id") && !withFieldsEntity.$show) {
688
+ let returnVal = "";
689
+ withFieldsEntity.$fields.forEach((field) => {
690
+ if (field === "id") {
691
+ returnVal = withFieldsEntity.$id;
692
+ } else {
693
+ returnVal = withFieldsEntity;
694
+ }
695
+ });
696
+ return returnVal;
697
+ }
698
+ return withFieldsEntity;
699
+ }
700
+ return null;
701
+ }).filter((x) => x);
702
+ var replaceBzIds = (resItems, things) => {
703
+ const mapping = {};
704
+ things.forEach((thing) => {
705
+ mapping[thing.$bzId] = thing.$id;
706
+ });
707
+ resItems.forEach((item) => {
708
+ Object.keys(item).forEach((key) => {
709
+ if (mapping[item[key]] && key !== "$tempId") {
710
+ item[key] = mapping[item[key]];
711
+ }
712
+ });
713
+ });
714
+ return resItems;
715
+ };
716
+ var hasMatches = (resItems, things) => {
717
+ const bzIds = things.map((thing) => thing.$bzId);
718
+ let found = false;
719
+ resItems.forEach((item) => {
720
+ Object.keys(item).forEach((key) => {
721
+ if (bzIds.includes(item[key])) {
722
+ found = true;
723
+ }
724
+ });
725
+ });
726
+ return found;
727
+ };
728
+ var buildBQLTree = async (req, res) => {
729
+ const { bqlRequest, config, schema } = req;
730
+ const { cache } = res;
731
+ if (!bqlRequest) {
732
+ throw new Error("BQL request not parsed");
733
+ }
734
+ const { query } = bqlRequest;
735
+ if (!query) {
736
+ const resItems = res.bqlRes[0] ? res.bqlRes : [res.bqlRes];
737
+ const things = req.bqlRequest?.mutation?.things;
738
+ const matchesFound = hasMatches(resItems, things);
739
+ if (matchesFound) {
740
+ const replaced = replaceBzIds(resItems, things);
741
+ res.bqlRes = replaced[1] ? replaced : replaced[0];
742
+ }
743
+ const output = cleanOutput(res.bqlRes, config);
744
+ res.bqlRes = output;
745
+ return;
746
+ }
747
+ if (!cache) {
748
+ return;
749
+ }
750
+ const thingSchema = "$entity" in query ? query.$entity : query.$relation;
751
+ const entityMap = cache.entities.get(thingSchema.name);
752
+ if (!entityMap) {
753
+ res.bqlRes = null;
754
+ return;
755
+ }
756
+ const filterFields = (0, import_radash4.listify)(query.$filter, (x) => x);
757
+ const atLeastOneUnique = filterFields.some(
758
+ (x) => thingSchema.dataFields?.find((y) => y.path === x)?.validations?.unique
759
+ );
760
+ const monoOutput = !Array.isArray(bqlRequest.query) && (bqlRequest.query?.$id && !Array.isArray(bqlRequest.query?.$id) || atLeastOneUnique);
761
+ if (Array.isArray(req.rawBqlRequest)) {
762
+ throw new Error("Query arrays not implemented yet");
763
+ }
764
+ const rootThings = entityMap;
765
+ const structuredAnswer = [...rootThings].length ? [...rootThings].map(([id, _entity]) => ({
766
+ ...req.rawBqlRequest,
767
+ $id: id
768
+ })) : req.rawBqlRequest;
769
+ const bqlTree = (0, import_immer2.produce)(
770
+ structuredAnswer,
771
+ (draft) => (0, import_object_traversal2.traverse)(draft, ({ value: val }) => {
772
+ const value = val;
773
+ if (!value?.$entity && !value?.$relation) {
774
+ return;
775
+ }
776
+ const thingName = "$entity" in value ? value.$entity : value.$relation;
777
+ if (thingName) {
778
+ const currentIds = Array.isArray(value.$id) ? value.$id : [value.$id];
779
+ const currentSchema = "$relation" in value ? schema.relations[value.$relation] : schema.entities[value.$entity];
780
+ const { dataFields, roleFields, fields } = getCurrentFields(currentSchema);
781
+ if (config.query?.returnNulls) {
782
+ const queriedPaths = value.$fields ? value.$fields.map((x) => typeof x === "string" ? x : x.$path) : fields;
783
+ queriedPaths.forEach((path) => {
784
+ value[path] = null;
785
+ });
786
+ }
787
+ const currentEntities = cache.entities.get(thingName);
788
+ if (!currentEntities) {
789
+ return;
790
+ }
791
+ [...currentEntities].forEach(([id, entity]) => {
792
+ if (currentIds.includes(id)) {
793
+ const queriedDataFields = value.$fields ? value.$fields : dataFields;
794
+ const { virtualFields } = currentSchema;
795
+ virtualFields?.forEach((virtualField) => {
796
+ if (queriedDataFields?.includes(virtualField) && // @ts-expect-error - No need to compute if it was received somehow from the DB or if it is not a virtual field
797
+ (value[virtualField] === void 0 || value[virtualField] === null)) {
798
+ const fieldSchema = currentSchema.dataFields?.find((x) => x.path === virtualField);
799
+ const computedValue = compute({ currentThing: entity, fieldSchema });
800
+ value[virtualField] = computedValue;
801
+ }
802
+ });
803
+ (0, import_radash4.listify)(entity, (k, v) => {
804
+ if (k.startsWith("$")) {
805
+ return;
806
+ }
807
+ if (!queriedDataFields?.includes(k)) {
808
+ return;
809
+ }
810
+ value[k] = v;
811
+ });
812
+ const links = cache.roleLinks.get(id);
813
+ const flatRoleFields = value.$fields ? value.$fields.filter((x) => typeof x === "string") : roleFields;
814
+ const embeddedRoleFields = value.$fields?.filter((x) => typeof x === "object")?.map((y) => y.$path) || [];
815
+ Object.entries(links || {}).forEach(([rolePath, linkedIds]) => {
816
+ if (![...flatRoleFields, ...embeddedRoleFields].includes(rolePath)) {
817
+ return;
818
+ }
819
+ if (!("roles" in currentSchema)) {
820
+ throw new Error("No roles in schema");
821
+ }
822
+ const uniqueLinkedIds = !Array.isArray(linkedIds) ? [linkedIds] : [...new Set(linkedIds)];
823
+ const { cardinality, playedBy } = currentSchema.roles[rolePath];
824
+ const thingNames = [...new Set(playedBy?.map((x) => x.thing))];
825
+ const children = thingNames?.flatMap((x) => {
826
+ const thingEntities = cache.entities.get(x);
827
+ if (!thingEntities) {
828
+ return [];
829
+ }
830
+ return filterChildrenEntities([...thingEntities], uniqueLinkedIds, value, rolePath);
831
+ });
832
+ if (children?.length) {
833
+ if (children.length === 1 && children[0] === value.$id) {
834
+ return;
835
+ }
836
+ if (cardinality === "ONE") {
837
+ value[rolePath] = children[0];
838
+ return;
839
+ }
840
+ value[rolePath] = children.filter((x) => typeof x === "string" || typeof x === "object" && x?.$show);
841
+ }
842
+ });
843
+ }
844
+ });
845
+ const currentLinkFields = currentSchema.linkFields;
846
+ if (currentLinkFields) {
847
+ currentLinkFields.forEach((linkField) => {
848
+ const currentRelation = cache.relations.get(linkField.relation);
849
+ const tunnel = linkField.oppositeLinkFieldsPlayedBy;
850
+ if (!currentRelation) {
851
+ return null;
852
+ }
853
+ if (linkField.target === "relation") {
854
+ const linkedEntities = [...currentRelation].reduce((acc, relation) => {
855
+ const id = relation.get(linkField.plays)?.id;
856
+ if (id && id === currentIds[0]) {
857
+ const opposingRole = relation.get(linkField.relation);
858
+ if (!opposingRole) {
859
+ return acc;
860
+ }
861
+ if (!acc[opposingRole.entityName]) {
862
+ acc[opposingRole.entityName] = /* @__PURE__ */ new Set();
863
+ }
864
+ acc[opposingRole.entityName].add(opposingRole.id);
865
+ }
866
+ return acc;
867
+ }, {});
868
+ Object.entries(linkedEntities).map(([key, linkedEntityVal]) => {
869
+ const allCurrentLinkFieldThings = cache.entities.get(key);
870
+ if (!allCurrentLinkFieldThings) {
871
+ return null;
872
+ }
873
+ const children = filterChildrenEntities(
874
+ [...allCurrentLinkFieldThings],
875
+ [...linkedEntityVal.values()],
876
+ value,
877
+ linkField.path
878
+ ).filter(notNull).filter(isStringOrHasShow);
879
+ if (children.length === 0) {
880
+ return null;
881
+ }
882
+ if (children && children.length) {
883
+ if (linkField.cardinality === "ONE") {
884
+ value[linkField.path] = children[0];
885
+ return null;
886
+ }
887
+ value[linkField.path] = children;
888
+ }
889
+ return null;
890
+ });
891
+ return null;
892
+ }
893
+ if (linkField.target === "role") {
894
+ tunnel.forEach((t) => {
895
+ if (!currentRelation) {
896
+ return;
897
+ }
898
+ const linkedEntities = [...currentRelation].reduce((acc, relation) => {
899
+ const id = relation.get(linkField.plays)?.id;
900
+ if (id && id === currentIds[0]) {
901
+ const opposingRole = relation.get(t.plays);
902
+ if (!opposingRole) {
903
+ return acc;
904
+ }
905
+ if (!acc[opposingRole.entityName]) {
906
+ acc[opposingRole.entityName] = /* @__PURE__ */ new Set();
907
+ }
908
+ acc[opposingRole.entityName].add(opposingRole.id);
909
+ }
910
+ return acc;
911
+ }, {});
912
+ Object.entries(linkedEntities).forEach(([key, linkedEntityVal]) => {
913
+ const allCurrentLinkFieldThings = cache.entities.get(key);
914
+ if (!allCurrentLinkFieldThings) {
915
+ return;
916
+ }
917
+ const children = filterChildrenEntities(
918
+ [...allCurrentLinkFieldThings],
919
+ [...linkedEntityVal.values()],
920
+ value,
921
+ linkField.path
922
+ ).filter(notNull).filter(isStringOrHasShow);
923
+ if (children.length === 0) {
924
+ return;
925
+ }
926
+ if (children && children.length) {
927
+ if (linkField.cardinality === "ONE") {
928
+ value[linkField.path] = children[0];
929
+ return;
930
+ }
931
+ value[linkField.path] = children;
932
+ let filtered = {};
933
+ const filterFunc = (o) => {
934
+ if (o.$path === linkField.path) {
935
+ filtered = o;
936
+ }
937
+ return o?.$fields?.forEach(filterFunc);
938
+ };
939
+ let pathAndIdMatch = "";
940
+ query.$fields?.forEach(filterFunc);
941
+ if (filtered) {
942
+ if (!Array.isArray(filtered.$id)) {
943
+ pathAndIdMatch = filtered.$id;
944
+ }
945
+ }
946
+ value[linkField.path] = isOne(children, pathAndIdMatch);
947
+ }
948
+ });
949
+ });
950
+ }
951
+ return null;
952
+ });
953
+ }
954
+ }
955
+ })
956
+ );
957
+ const withoutFieldFilters = cleanOutput(bqlTree, config);
958
+ res.bqlRes = monoOutput ? withoutFieldFilters[0] : withoutFieldFilters;
959
+ };
960
+
961
+ // src/pipeline/preprocess/buildTQLMutation.ts
962
+ var import_radash5 = require("radash");
963
+ var buildTQLMutation = async (req) => {
964
+ const { bqlRequest, schema } = req;
965
+ if (!bqlRequest) {
966
+ throw new Error("BQL request not parsed");
967
+ }
968
+ const { mutation } = bqlRequest;
969
+ if (!mutation) {
970
+ throw new Error("BQL request is not a mutation");
971
+ }
972
+ const nodeToTypeQL = (node) => {
973
+ const op = node.$op;
974
+ const bzId = `$${node.$bzId}`;
975
+ const currentSchema = getCurrentSchema(schema, node);
976
+ const { idFields, defaultDBConnector } = currentSchema;
977
+ const thingDbPath = defaultDBConnector?.path || node.$entity || node.$relation;
978
+ const idValue = node.$id;
979
+ const idField = idFields?.[0];
980
+ const attributes = (0, import_radash5.listify)(node, (k, v) => {
981
+ if (k.startsWith("$") || k === idField || v === void 0 || v === null) {
982
+ return "";
983
+ }
984
+ const currentDataField = currentSchema.dataFields?.find((x) => x.path === k);
985
+ const fieldDbPath = currentDataField?.path;
986
+ if (!fieldDbPath) {
987
+ return "";
988
+ }
989
+ const dbField = currentDataField.dbPath;
990
+ if (["TEXT", "ID", "EMAIL"].includes(currentDataField.contentType)) {
991
+ return `has ${dbField} '${v}'`;
992
+ }
993
+ if (["NUMBER", "BOOLEAN"].includes(currentDataField.contentType)) {
994
+ return `has ${dbField} ${v}`;
995
+ }
996
+ if (currentDataField.contentType === "DATE") {
997
+ if (Number.isNaN(v.valueOf())) {
998
+ throw new Error("Invalid format, Nan Date");
999
+ }
1000
+ if (v instanceof Date) {
1001
+ return `has ${dbField} ${v.toISOString().replace("Z", "")}`;
1002
+ }
1003
+ return `has ${dbField} ${new Date(v).toISOString().replace("Z", "")}`;
1004
+ }
1005
+ throw new Error(`Unsupported contentType ${currentDataField.contentType}`);
1006
+ }).filter((x) => x);
1007
+ const attributesVar = `${bzId}-atts`;
1008
+ const matchAttributes = (0, import_radash5.listify)(node, (k) => {
1009
+ if (k.startsWith("$") || k === idField) {
1010
+ return "";
1011
+ }
1012
+ const currentDataField = currentSchema.dataFields?.find((x) => x.path === k);
1013
+ const fieldDbPath = currentDataField?.path;
1014
+ if (!fieldDbPath) {
1015
+ return "";
1016
+ }
1017
+ const dbField = currentDataField.dbPath;
1018
+ return `{${attributesVar} isa ${dbField};}`;
1019
+ }).filter((x) => x);
1020
+ const isLocalId = node[Symbol.for("isLocalId")];
1021
+ const idValueTQL = (0, import_radash5.isArray)(idValue) ? `like '${idValue.join("|")}'` : `'${idValue}'`;
1022
+ const idAttributes = !isLocalId && idValue ? (
1023
+ // if it is a relation, add only the id fields in the lines where we add the roles also so it does not get defined twice
1024
+ [`has ${idField} ${idValueTQL}`]
1025
+ ) : [];
1026
+ const allAttributes = [...idAttributes, ...attributes].filter((x) => x).join(",");
1027
+ const getDeletionMatchInNodes = () => {
1028
+ if (op === "delete" || op === "unlink" || op === "match") {
1029
+ return `${bzId} isa ${[thingDbPath, ...idAttributes].filter((x) => x).join(",")};`;
1030
+ }
1031
+ if (op === "update") {
1032
+ if (!matchAttributes.length) {
1033
+ throw new Error("update without attributes");
1034
+ }
1035
+ return `${bzId} isa ${[thingDbPath, ...idAttributes].filter((x) => x).join(",")}, has ${attributesVar};
1036
+ ${matchAttributes.join(" or ")};`;
1037
+ }
1038
+ return "";
1039
+ };
1040
+ const getInsertionMatchInNodes = () => {
1041
+ if (op === "update" || op === "link" || op === "match") {
1042
+ return `${bzId} isa ${[thingDbPath, ...idAttributes].filter((x) => x).join(",")};`;
1043
+ }
1044
+ return "";
1045
+ };
1046
+ if (node.$entity || node.$relation) {
1047
+ return {
1048
+ op,
1049
+ deletionMatch: getDeletionMatchInNodes(),
1050
+ insertionMatch: getInsertionMatchInNodes(),
1051
+ insertion: op === "create" ? `${bzId} isa ${[thingDbPath, allAttributes].filter((x) => x).join(",")};` : op === "update" && attributes.length ? `${bzId} ${attributes.join(",")};` : "",
1052
+ deletion: op === "delete" ? `${bzId} isa ${thingDbPath};` : op === "update" && matchAttributes.length ? `${bzId} has ${attributesVar};` : ""
1053
+ };
1054
+ }
1055
+ throw new Error("in attributes");
1056
+ };
1057
+ const edgeToTypeQL = (node) => {
1058
+ const op = node.$op;
1059
+ const currentSchema = getCurrentSchema(schema, node);
1060
+ const bzId = `$${node.$bzId}`;
1061
+ const idValue = node.$id;
1062
+ const relationDbPath = currentSchema.defaultDBConnector?.path || node.$relation;
1063
+ const roleFields = "roles" in currentSchema ? (0, import_radash5.listify)(currentSchema.roles, (k) => k) : [];
1064
+ const roleDbPaths = node.$relation && "roles" in currentSchema && (0, import_radash5.mapEntries)(currentSchema.roles, (k, v) => [k, v.dbConnector?.path || k]);
1065
+ const fromRoleFields = (0, import_radash5.listify)(node, (k, v) => {
1066
+ if (!roleFields.includes(k)) {
1067
+ return null;
1068
+ }
1069
+ if (!("roles" in currentSchema)) {
1070
+ throw new Error("This should have roles! ");
1071
+ }
1072
+ const roleDbPath = roleDbPaths[k];
1073
+ if (Array.isArray(v)) {
1074
+ return v.map((x) => ({ path: roleDbPath, id: x }));
1075
+ }
1076
+ return { path: roleDbPath, id: v };
1077
+ }).filter((x) => x).flat();
1078
+ const fromRoleFieldsTql = fromRoleFields.map((x) => {
1079
+ if (!x?.path) {
1080
+ throw new Error("Object without path");
1081
+ }
1082
+ return `${x.path}: $${x.id}`;
1083
+ });
1084
+ const roles = fromRoleFields.length > 0 ? `( ${fromRoleFieldsTql.join(" , ")} )` : "";
1085
+ const relationTql = !roles ? "" : `${bzId} ${roles} ${node[Symbol.for("edgeType")] === "linkField" || op === "delete" || op === "unlink" ? `isa ${relationDbPath}` : ""}`;
1086
+ const relationTqlWithoutRoles = `${bzId} ${node[Symbol.for("edgeType")] === "linkField" || op === "delete" ? `isa ${relationDbPath}` : ""}`;
1087
+ const getInsertionsInEdges = () => {
1088
+ if (!relationTql) {
1089
+ return "";
1090
+ }
1091
+ if (op === "link") {
1092
+ return `${relationTql};`;
1093
+ }
1094
+ if (op === "create") {
1095
+ return `${relationTql}, has id '${idValue}';`;
1096
+ }
1097
+ return "";
1098
+ };
1099
+ const getInsertionMatchInEdges = () => {
1100
+ if (!relationTql) {
1101
+ return "";
1102
+ }
1103
+ if (op === "match") {
1104
+ return `${relationTql};`;
1105
+ }
1106
+ return "";
1107
+ };
1108
+ const getDeletionMatchInEdges = () => {
1109
+ if (!relationTql) {
1110
+ return "";
1111
+ }
1112
+ if (op === "delete") {
1113
+ return `${relationTql};`;
1114
+ }
1115
+ if (op === "unlink") {
1116
+ }
1117
+ if (op === "match") {
1118
+ return `${relationTql};`;
1119
+ }
1120
+ return "";
1121
+ };
1122
+ const getDeletionsInEdges = () => {
1123
+ if (!relationTql) {
1124
+ return "";
1125
+ }
1126
+ if (op === "delete") {
1127
+ return `${relationTqlWithoutRoles};`;
1128
+ }
1129
+ if (op === "unlink") {
1130
+ return `${bzId} ${roles};`;
1131
+ }
1132
+ return "";
1133
+ };
1134
+ return {
1135
+ // preDeletionBatch: getPreDeletionBatch(),
1136
+ deletionMatch: getDeletionMatchInEdges(),
1137
+ insertionMatch: getInsertionMatchInEdges(),
1138
+ deletion: getDeletionsInEdges(),
1139
+ insertion: getInsertionsInEdges(),
1140
+ op: ""
1141
+ };
1142
+ };
1143
+ const toTypeQL = (nodes, mode) => {
1144
+ const typeQL = mode === "edges" ? edgeToTypeQL : nodeToTypeQL;
1145
+ if (Array.isArray(nodes)) {
1146
+ return nodes.map((x) => {
1147
+ const { preDeletionBatch: preDeletionBatch2, insertionMatch: insertionMatch2, deletionMatch: deletionMatch2, insertion: insertion2, deletion: deletion2 } = typeQL(x);
1148
+ return (0, import_radash5.shake)({ preDeletionBatch: preDeletionBatch2, insertionMatch: insertionMatch2, deletionMatch: deletionMatch2, insertion: insertion2, deletion: deletion2 }, (z) => !z);
1149
+ }).filter((y) => y);
1150
+ }
1151
+ const { preDeletionBatch, insertionMatch, deletionMatch, insertion, deletion } = typeQL(nodes);
1152
+ return (0, import_radash5.shake)({ preDeletionBatch, insertionMatch, deletionMatch, insertion, deletion }, (z) => !z);
1153
+ };
1154
+ const nodeOperations = toTypeQL(mutation.things);
1155
+ const arrayNodeOperations = Array.isArray(nodeOperations) ? nodeOperations : [nodeOperations];
1156
+ const edgeOperations = toTypeQL(mutation.edges, "edges");
1157
+ const arrayEdgeOperations = Array.isArray(edgeOperations) ? edgeOperations : [edgeOperations];
1158
+ const allOperations = [...arrayNodeOperations, ...arrayEdgeOperations];
1159
+ const tqlRequest = (0, import_radash5.shake)(
1160
+ {
1161
+ // preDeletionBatch: allOperations.flatMap((x) => x.preDeletionBatch).filter((y) => y !== undefined),
1162
+ insertionMatches: allOperations.map((x) => x.insertionMatch).join(" ").trim(),
1163
+ deletionMatches: allOperations.map((x) => x.deletionMatch).join(" ").trim(),
1164
+ insertions: allOperations.map((x) => x.insertion).join(" ").trim(),
1165
+ deletions: allOperations.map((x) => x.deletion).join(" ").trim()
1166
+ // ...(typeQLRelations?.length && { relations: typeQLRelations }),
1167
+ },
1168
+ (x) => !x
1169
+ );
1170
+ req.tqlRequest = tqlRequest;
1171
+ };
37
1172
 
38
- module.exports = Ii;
1173
+ // src/pipeline/preprocess/fill.ts
1174
+ var import_immer3 = require("immer");
1175
+ var import_object_traversal3 = require("object-traversal");
1176
+ var import_radash6 = require("radash");
1177
+ var import_uuid = require("uuid");
1178
+ var sanitizeTempId = (id) => {
1179
+ if (!id.startsWith("_:")) {
1180
+ throw new Error("ID must start with '_:'.");
1181
+ }
1182
+ const sanitizedId = id.substring(2);
1183
+ if (!/^[a-zA-Z0-9-_]+$/.test(sanitizedId)) {
1184
+ throw new Error("$tempId must contain only alphanumeric characters, hyphens, and underscores.");
1185
+ }
1186
+ if (id.length > 36) {
1187
+ throw new Error("$tempId must not be longer than 36 characters.");
1188
+ }
1189
+ return sanitizedId;
1190
+ };
1191
+ var fillBQLMutation = async (req) => {
1192
+ const { rawBqlRequest, schema } = req;
1193
+ const shakeBqlRequest = (blocks) => {
1194
+ return (0, import_immer3.produce)(
1195
+ blocks,
1196
+ (draft) => (0, import_object_traversal3.traverse)(draft, ({ value: val, key, parent }) => {
1197
+ if ((0, import_radash6.isObject)(val)) {
1198
+ val = (0, import_radash6.shake)(val, (att) => att === void 0);
1199
+ }
1200
+ if (key === "$tempId") {
1201
+ parent[key] = sanitizeTempId(val);
1202
+ }
1203
+ })
1204
+ );
1205
+ };
1206
+ const shakedBqlRequest = shakeBqlRequest(rawBqlRequest);
1207
+ const stringToObjects = (blocks) => {
1208
+ return (0, import_immer3.produce)(
1209
+ blocks,
1210
+ (draft) => (0, import_object_traversal3.traverse)(draft, ({ value: val, meta, key }) => {
1211
+ if ((0, import_radash6.isObject)(val)) {
1212
+ if (val.$arrayOp) {
1213
+ throw new Error("Array op not supported yet");
1214
+ }
1215
+ if (key === "$filter" || meta.nodePath?.includes(".$filter.")) {
1216
+ return;
1217
+ }
1218
+ const value = val;
1219
+ if (value.$op === "create" && value.$id) {
1220
+ throw new Error("Can't write to computed field $id. Try writing to the id field directly.");
1221
+ }
1222
+ const currentSchema = getCurrentSchema(schema, value);
1223
+ const nodePathArray = meta.nodePath?.split(".");
1224
+ const notRoot = nodePathArray?.filter((x) => Number.isNaN(parseInt(x, 10))).join(".");
1225
+ if (!currentSchema) {
1226
+ throw new Error(`Schema not found for ${value.$entity || value.$relation}`);
1227
+ }
1228
+ value.$bzId = value.$tempId ?? `T_${(0, import_uuid.v4)()}`;
1229
+ value[Symbol.for("schema")] = currentSchema;
1230
+ value[Symbol.for("dbId")] = currentSchema.defaultDBConnector.id;
1231
+ const { usedLinkFields, usedRoleFields } = getCurrentFields(currentSchema, value);
1232
+ const usedLinkFieldsMap = usedLinkFields.map(
1233
+ (linkFieldPath) => ({
1234
+ fieldType: "linkField",
1235
+ path: linkFieldPath,
1236
+ // @ts-expect-error - TODO description
1237
+ schema: currentSchema.linkFields.find((y) => y.path === linkFieldPath)
1238
+ })
1239
+ );
1240
+ const usedRoleFieldsMap = currentSchema.thingType === "relation" ? usedRoleFields.map(
1241
+ (roleFieldPath) => ({
1242
+ fieldType: "roleField",
1243
+ path: roleFieldPath,
1244
+ schema: oFind(currentSchema.roles, (k) => k === roleFieldPath)
1245
+ })
1246
+ ) : [];
1247
+ if (usedLinkFieldsMap.some((x) => x.schema?.target === "role") && usedLinkFieldsMap.some((x) => x.schema?.target === "relation")) {
1248
+ throw new Error(
1249
+ "Unsupported: Can't use a link field with target === 'role' and another with target === 'relation' in the same mutation."
1250
+ );
1251
+ }
1252
+ const multiplayedRoles = usedRoleFieldsMap.filter(
1253
+ (roleField) => [...new Set(roleField.schema.playedBy?.map((x) => x.thing))].length !== 1
1254
+ );
1255
+ if (multiplayedRoles.length > 1) {
1256
+ throw new Error(
1257
+ `Field: ${multiplayedRoles[0].path} - If a role can be played by multiple things, you must specify the thing in the mutation: ${JSON.stringify(
1258
+ multiplayedRoles[0].schema.playedBy
1259
+ )}. Schema: ${JSON.stringify(multiplayedRoles[0].schema)}`
1260
+ );
1261
+ }
1262
+ const currentPath = meta.nodePath;
1263
+ [...usedLinkFieldsMap, ...usedRoleFieldsMap]?.forEach((currentField) => {
1264
+ const currentValue = value[currentField.path];
1265
+ if (currentValue === void 0) {
1266
+ return;
1267
+ }
1268
+ const currentFieldSchema = currentField.schema;
1269
+ if (!currentFieldSchema) {
1270
+ throw new Error(`Field ${currentField.path} not found in schema`);
1271
+ }
1272
+ const currentEdgeSchema = (
1273
+ // @ts-expect-error - TODO description
1274
+ currentField.fieldType === "roleField" ? currentFieldSchema?.playedBy[0] : currentFieldSchema
1275
+ );
1276
+ const getCurrentRelation = () => {
1277
+ if (currentFieldSchema && "relation" in currentFieldSchema && currentEdgeSchema?.relation === value.$relation) {
1278
+ return "$self";
1279
+ }
1280
+ if (currentEdgeSchema?.relation) {
1281
+ return currentEdgeSchema?.relation;
1282
+ }
1283
+ return "$self";
1284
+ };
1285
+ const relation = getCurrentRelation();
1286
+ const relationSchema = relation === "$self" ? currentSchema : schema.relations[relation];
1287
+ const currentFieldRole = oFind(relationSchema.roles, (k, _v) => k === currentField.path);
1288
+ if (currentFieldRole?.playedBy?.length === 0) {
1289
+ throw new Error(`unused role: ${currentPath}.${currentField.path}`);
1290
+ }
1291
+ if (!currentFieldSchema) {
1292
+ throw new Error(`Field ${currentField.path} not found in schema`);
1293
+ }
1294
+ const oppositeFields = currentField.fieldType === "linkField" ? currentFieldSchema?.oppositeLinkFieldsPlayedBy : currentFieldSchema?.playedBy;
1295
+ if (!oppositeFields) {
1296
+ throw new Error(`No opposite fields found for ${JSON.stringify(currentFieldSchema)}`);
1297
+ }
1298
+ if ([...new Set(oppositeFields?.map((x) => x.thing))].length > 1) {
1299
+ throw new Error(
1300
+ `Field: ${currentField.path} - If a role can be played by multiple things, you must specify the thing in the mutation: ${JSON.stringify(
1301
+ oppositeFields
1302
+ )}. Schema: ${JSON.stringify(currentFieldSchema)}`
1303
+ );
1304
+ }
1305
+ if (currentFieldSchema.cardinality === "ONE") {
1306
+ if (Array.isArray(currentValue)) {
1307
+ throw new Error("Can't have an array in a cardinality === ONE link field");
1308
+ }
1309
+ }
1310
+ if (currentFieldSchema.cardinality === "MANY" && currentValue !== null && !Array.isArray(currentValue) && !currentValue.$arrayOp) {
1311
+ throw new Error(
1312
+ `${// @ts-expect-error - TODO description
1313
+ currentField.fieldType === "linkField" ? currentFieldSchema.path : currentFieldSchema.name} is a cardinality === MANY thing. Use an array or a $arrayOp object`
1314
+ );
1315
+ }
1316
+ if (currentValue?.$entity || currentValue?.$relation) {
1317
+ return;
1318
+ }
1319
+ const [childrenLinkField] = oppositeFields;
1320
+ const currentFieldType = "plays" in currentFieldSchema ? "linkField" : "roleField";
1321
+ const childrenThingObj = {
1322
+ [`$${childrenLinkField.thingType}`]: childrenLinkField.thing,
1323
+ [Symbol.for("relation")]: relation,
1324
+ [Symbol.for("edgeType")]: currentFieldType,
1325
+ [Symbol.for("parent")]: {
1326
+ path: currentPath,
1327
+ ...value.$id ? { $id: value.$id } : {},
1328
+ ...value.$tempId ? { $tempId: value.$tempId } : {},
1329
+ ...value.filter ? { filter: value.filter } : {},
1330
+ links: oppositeFields
1331
+ },
1332
+ [Symbol.for("role")]: childrenLinkField.plays,
1333
+ // this is the currentChildren
1334
+ // this is the parent
1335
+ [Symbol.for("oppositeRole")]: "plays" in currentFieldSchema ? currentFieldSchema.plays : void 0,
1336
+ // todo
1337
+ [Symbol.for("relFieldSchema")]: currentFieldSchema
1338
+ };
1339
+ if ((0, import_radash6.isObject)(currentValue)) {
1340
+ value[currentField.path] = {
1341
+ ...childrenThingObj,
1342
+ ...currentValue
1343
+ };
1344
+ }
1345
+ if (Array.isArray(currentValue)) {
1346
+ if (currentValue.every((x) => (0, import_radash6.isObject)(x))) {
1347
+ value[currentField.path] = currentValue.map((y) => {
1348
+ return {
1349
+ ...childrenThingObj,
1350
+ ...y
1351
+ };
1352
+ });
1353
+ } else if (currentValue.every((x) => typeof x === "string")) {
1354
+ value[currentField.path] = currentValue.map((y) => ({
1355
+ ...childrenThingObj,
1356
+ $op: value.$op === "create" ? "link" : "replace",
1357
+ $id: y
1358
+ }));
1359
+ } else {
1360
+ throw new Error(`Invalid array value for ${currentField.path}`);
1361
+ }
1362
+ }
1363
+ if (typeof currentValue === "string") {
1364
+ value[currentField.path] = {
1365
+ ...childrenThingObj,
1366
+ $op: value.$op === "create" ? "link" : "replace",
1367
+ // if the parent is being created, then is not a replace, is a new link
1368
+ $id: currentValue
1369
+ // todo: now all strings are ids and not tempIds, but in the future this might change
1370
+ };
1371
+ }
1372
+ if (currentValue === null) {
1373
+ const neutralObject = {
1374
+ ...childrenThingObj,
1375
+ $op: "unlink"
1376
+ // todo: embedded => delete
1377
+ };
1378
+ value[currentField.path] = currentFieldSchema.cardinality === "MANY" ? [neutralObject] : neutralObject;
1379
+ }
1380
+ });
1381
+ if (!notRoot && !value.$entity && !value.$relation) {
1382
+ throw new Error("Root things must specify $entity or $relation");
1383
+ }
1384
+ if (!notRoot) {
1385
+ }
1386
+ }
1387
+ })
1388
+ );
1389
+ };
1390
+ const withObjects = stringToObjects(shakedBqlRequest);
1391
+ const fill = (blocks) => {
1392
+ return (0, import_immer3.produce)(
1393
+ blocks,
1394
+ (draft) => (0, import_object_traversal3.traverse)(draft, ({ parent, key, value: val, meta }) => {
1395
+ if ((0, import_radash6.isObject)(val)) {
1396
+ if (Object.keys(val).length === 0) {
1397
+ throw new Error("Empty object!");
1398
+ }
1399
+ if (key === "$filter" || meta.nodePath?.includes(".$filter.")) {
1400
+ return;
1401
+ }
1402
+ const value = val;
1403
+ const nodePathArray = meta.nodePath?.split(".");
1404
+ if (value.$tempId) {
1405
+ if (!(value.$op === void 0 || value.$op === "link" || value.$op === "create" || value.$op === "update")) {
1406
+ throw new Error(
1407
+ `Invalid op ${value.$op} for tempId. TempIds can be created, or when created in another part of the same mutation. In the future maybe we can use them to catch stuff in the DB as well and group them under the same tempId.`
1408
+ );
1409
+ }
1410
+ }
1411
+ const notRoot = nodePathArray?.filter((x) => Number.isNaN(parseInt(x, 10))).join(".");
1412
+ const currentPath = !notRoot ? meta.nodePath || "" : Array.isArray(parent) ? nodePathArray?.slice(0, -1).join(".") : meta.nodePath;
1413
+ const currentSchema = getCurrentSchema(schema, value);
1414
+ const { unidentifiedFields, dataFields, roleFields, linkFields } = getCurrentFields(currentSchema, value);
1415
+ const parentMeta = (0, import_immer3.current)(value)[Symbol.for("parent")];
1416
+ const parentPath = notRoot && parentMeta.path;
1417
+ const parentNode = !parentPath ? draft : (0, import_object_traversal3.getNodeByPath)(draft, parentPath);
1418
+ const parentOp = parentNode?.$op;
1419
+ if (notRoot && !parentOp) {
1420
+ throw new Error("Error: Parent $op not detected");
1421
+ }
1422
+ const currentFieldSchema = value[Symbol.for("relFieldSchema")];
1423
+ if (value.$op === "replace") {
1424
+ if (parentOp === "create") {
1425
+ value.$op = "link";
1426
+ }
1427
+ }
1428
+ const hasUpdatedDataFields = Object.keys(value).some((x) => dataFields?.includes(x));
1429
+ const hasUpdatedChildren = Object.keys(value).some((x) => [...roleFields, ...linkFields]?.includes(x));
1430
+ const getOp = () => {
1431
+ if (value.$op) {
1432
+ return value.$op;
1433
+ }
1434
+ if (notRoot && !value.$id && !value.$tempId && parentOp !== "create" && currentFieldSchema.cardinality === "ONE") {
1435
+ throw new Error(`Please specify if it is a create or an update. Path: ${meta.nodePath}`);
1436
+ }
1437
+ if (value.$tempId) {
1438
+ return "create";
1439
+ }
1440
+ if ((value.$id || value.$filter) && hasUpdatedDataFields) {
1441
+ return "update";
1442
+ }
1443
+ if ((value.$id || value.$filter) && notRoot && !hasUpdatedDataFields && !hasUpdatedChildren) {
1444
+ return "link";
1445
+ }
1446
+ if (!value.$filter && !value.$id && !value.$tempId) {
1447
+ return "create";
1448
+ }
1449
+ if ((value.$id || value.$filter) && !hasUpdatedDataFields && hasUpdatedChildren) {
1450
+ return "match";
1451
+ }
1452
+ throw new Error("Wrong op");
1453
+ };
1454
+ if (!value.$op) {
1455
+ value.$op = getOp();
1456
+ }
1457
+ if (!parent) {
1458
+ value.$parentKey = "";
1459
+ }
1460
+ if (typeof parent === "object") {
1461
+ const ArParent = Array.isArray(parent);
1462
+ if (ArParent) {
1463
+ value[Symbol.for("index")] = key;
1464
+ }
1465
+ value[Symbol.for("path")] = currentPath;
1466
+ value[Symbol.for("isRoot")] = !notRoot;
1467
+ value[Symbol.for("depth")] = notRoot?.split(".").length;
1468
+ }
1469
+ if (!value.$entity && !value.$relation) {
1470
+ throw new Error(`Node ${JSON.stringify(value)} without $entity/$relation`);
1471
+ }
1472
+ const { idFields, computedFields, virtualFields } = currentSchema;
1473
+ if (!idFields) {
1474
+ throw new Error("No idFields found");
1475
+ }
1476
+ const [idField] = idFields;
1477
+ const filledFields = (0, import_radash6.listify)(value, (attKey, v) => v !== void 0 ? attKey : void 0);
1478
+ const virtualFilledFields = filledFields.filter((x) => virtualFields?.includes(x));
1479
+ if (virtualFilledFields.length > 0) {
1480
+ throw new Error(`Virtual fields can't be sent to DB: "${virtualFilledFields.join(",")}"`);
1481
+ }
1482
+ const missingComputedFields = computedFields.filter((x) => !filledFields.includes(x));
1483
+ missingComputedFields.forEach((fieldPath) => {
1484
+ const currentFieldDef = currentSchema.dataFields?.find((x) => x.path === fieldPath);
1485
+ const currentLinkDef = currentSchema.linkFields?.find((x) => x.path === fieldPath);
1486
+ const currentLinkedDef = currentLinkDef?.oppositeLinkFieldsPlayedBy[0];
1487
+ const currentRoleDef = "roles" in currentSchema ? oFind(currentSchema.roles, (k, _v) => k === fieldPath) : void 0;
1488
+ const currentDef = currentFieldDef || currentLinkedDef || currentRoleDef;
1489
+ if (!currentDef) {
1490
+ throw new Error(`no field Def for ${fieldPath}`);
1491
+ }
1492
+ if (fieldPath === idField && value.$op === "create" && !value[fieldPath]) {
1493
+ const defaultValue = compute({
1494
+ currentThing: value,
1495
+ fieldSchema: currentDef,
1496
+ //id is always a datafield.
1497
+ mandatoryDependencies: true
1498
+ //can't send to db without every dependency being there
1499
+ });
1500
+ value[fieldPath] = defaultValue;
1501
+ value.$id = defaultValue;
1502
+ }
1503
+ });
1504
+ if (unidentifiedFields.length > 0) {
1505
+ throw new Error(`Unknown fields: [${unidentifiedFields.join(",")}] in ${JSON.stringify(value)}`);
1506
+ }
1507
+ }
1508
+ })
1509
+ );
1510
+ };
1511
+ const filledBQLMutation = fill(withObjects);
1512
+ if (Array.isArray(filledBQLMutation)) {
1513
+ req.filledBqlRequest = filledBQLMutation;
1514
+ } else {
1515
+ req.filledBqlRequest = filledBQLMutation;
1516
+ }
1517
+ };
1518
+
1519
+ // src/pipeline/preprocess/parseBQLMutation.ts
1520
+ var import_object_traversal4 = require("object-traversal");
1521
+ var import_radash7 = require("radash");
1522
+ var import_uuid2 = require("uuid");
1523
+ var parseBQLMutation = async (req) => {
1524
+ const { filledBqlRequest, schema } = req;
1525
+ const listNodes = (blocks) => {
1526
+ const nodes = [];
1527
+ const edges = [];
1528
+ const getIdValue = (node) => {
1529
+ if (node.$id) {
1530
+ return node.$id;
1531
+ }
1532
+ const currentSchema = getCurrentSchema(schema, node);
1533
+ const { idFields } = currentSchema;
1534
+ if (!idFields) {
1535
+ throw new Error(`no idFields: ${JSON.stringify(node)}`);
1536
+ }
1537
+ const [idField] = idFields;
1538
+ if (!idField) {
1539
+ throw new Error(`no idField: ${JSON.stringify(node)}`);
1540
+ }
1541
+ const idDataField = currentSchema.dataFields?.find((x) => x.path === idField);
1542
+ const idDefaultValue = node.$op === "create" ? idDataField?.default?.value() : null;
1543
+ const idValue = node[idField] || node.$id || idDefaultValue;
1544
+ if (!idValue) {
1545
+ throw new Error(`no idValue: ${JSON.stringify(node)}`);
1546
+ }
1547
+ return idValue;
1548
+ };
1549
+ const toNodes = (node) => {
1550
+ if (node.$op === "create") {
1551
+ const idValue = getIdValue(node);
1552
+ if (nodes.find((x) => x.$id === idValue)) {
1553
+ throw new Error(`Duplicate id ${idValue} for node ${JSON.stringify(node)}`);
1554
+ }
1555
+ if (edges.find((x) => x.$bzId === node.$bzId)) {
1556
+ throw new Error(`Duplicate $bzid ${node.$bzId} for node ${JSON.stringify(node)}`);
1557
+ }
1558
+ nodes.push({ ...node, $id: idValue });
1559
+ return;
1560
+ }
1561
+ if (node.$tempId && node.$op === "match") {
1562
+ return;
1563
+ }
1564
+ nodes.push(node);
1565
+ };
1566
+ const toEdges = (edge) => {
1567
+ if (edge.$op === "create") {
1568
+ const idValue = getIdValue(edge);
1569
+ if (nodes.find((x) => x.$id === idValue)) {
1570
+ }
1571
+ if (edges.find((x) => x.$bzId === edge.$bzId)) {
1572
+ throw new Error(`Duplicate %bzId ${edge.$bzIdd} for edge ${JSON.stringify(edge)}`);
1573
+ }
1574
+ edges.push({ ...edge, $id: idValue });
1575
+ return;
1576
+ }
1577
+ edges.push(edge);
1578
+ };
1579
+ const listOp = ({ value: val }) => {
1580
+ if (!(0, import_radash7.isObject)(val)) {
1581
+ return;
1582
+ }
1583
+ const value = val;
1584
+ if (value.$entity || value.$relation) {
1585
+ if (!value.$op) {
1586
+ throw new Error(`Operation should be defined at this step ${JSON.stringify(value)}`);
1587
+ }
1588
+ if (!value.$bzId) {
1589
+ throw new Error("[internal error] BzId not found");
1590
+ }
1591
+ const currentThingSchema = getCurrentSchema(schema, value);
1592
+ const {
1593
+ dataFields: dataFieldPaths,
1594
+ roleFields: roleFieldPaths,
1595
+ linkFields: linkFieldPaths,
1596
+ usedFields
1597
+ } = getCurrentFields(currentThingSchema, value);
1598
+ const getChildOp = () => {
1599
+ if (value.$op === "create" || value.$op === "delete") {
1600
+ return value.$op;
1601
+ }
1602
+ if (value.$op === "update") {
1603
+ const usedDataFields = usedFields.filter((x) => dataFieldPaths?.includes(x));
1604
+ const usedRoleFields = usedFields.filter((x) => roleFieldPaths?.includes(x));
1605
+ const usedLinkFields = usedFields.filter((x) => linkFieldPaths?.includes(x));
1606
+ if (usedDataFields.length > 0) {
1607
+ return "update";
1608
+ }
1609
+ if (usedRoleFields.length > 0 || usedLinkFields.length > 0) {
1610
+ return "match";
1611
+ }
1612
+ throw new Error(`No fields on an $op:"update" for node ${JSON.stringify(value)}`);
1613
+ }
1614
+ return "match";
1615
+ };
1616
+ const dataObj = {
1617
+ ...value.$entity && { $entity: value.$entity },
1618
+ ...value.$relation && { $relation: value.$relation },
1619
+ ...value.$id && { $id: value.$id },
1620
+ ...value.$tempId && { $tempId: value.$tempId },
1621
+ ...value.$filter && { $filter: value.$filter },
1622
+ ...(0, import_radash7.shake)((0, import_radash7.pick)(value, dataFieldPaths || [""])),
1623
+ $op: getChildOp(),
1624
+ $bzId: value.$bzId,
1625
+ [Symbol.for("dbId")]: currentThingSchema.defaultDBConnector.id,
1626
+ // [Symbol.for('dependencies')]: value[Symbol.for('dependencies')],
1627
+ [Symbol.for("path")]: value[Symbol.for("path")],
1628
+ [Symbol.for("parent")]: value[Symbol.for("parent")],
1629
+ [Symbol.for("isRoot")]: value[Symbol.for("isRoot")],
1630
+ [Symbol.for("isLocalId")]: value[Symbol.for("isLocalId")] || false
1631
+ };
1632
+ toNodes(dataObj);
1633
+ if (value[Symbol.for("relation")] && value[Symbol.for("edgeType")] === "linkField") {
1634
+ if (value.$op === "link" || value.$op === "unlink") {
1635
+ if (value.$id || value.$filter) {
1636
+ if (value.$tempId) {
1637
+ throw new Error("can't specify a existing and a new element at once. Use an id/filter or a tempId");
1638
+ }
1639
+ nodes.push({ ...value, $op: "match" });
1640
+ }
1641
+ }
1642
+ const ownRelation = value[Symbol.for("relation")] === value.$relation;
1643
+ const linkTempId = ownRelation ? value.$bzId : (0, import_uuid2.v4)();
1644
+ const parentMeta = value[Symbol.for("parent")];
1645
+ const parentPath = parentMeta.path;
1646
+ const parentNode = !parentPath ? blocks : (0, import_object_traversal4.getNodeByPath)(blocks, parentPath);
1647
+ const parentId = parentNode.$bzId;
1648
+ if (!parentId) {
1649
+ throw new Error("No parent id found");
1650
+ }
1651
+ if (value[Symbol.for("relation")] === "$self") {
1652
+ return;
1653
+ }
1654
+ const getLinkObjOp = () => {
1655
+ if (value.$op === "delete") {
1656
+ if (ownRelation) {
1657
+ return "match";
1658
+ }
1659
+ return "delete";
1660
+ }
1661
+ if (value.$op === "unlink") {
1662
+ if (ownRelation) {
1663
+ return "unlink";
1664
+ }
1665
+ return "delete";
1666
+ }
1667
+ if (value.$op === "link" || value.$op === "create") {
1668
+ if (ownRelation) {
1669
+ return "link";
1670
+ }
1671
+ return "create";
1672
+ }
1673
+ if (value.$op === "replace") {
1674
+ throw new Error("Unsupported: Nested replaces not implemented yet");
1675
+ }
1676
+ return "match";
1677
+ };
1678
+ const edgeType1 = {
1679
+ $relation: value[Symbol.for("relation")],
1680
+ $bzId: linkTempId,
1681
+ ...value.$tempId ? { $tempId: value.$tempId } : {},
1682
+ $op: getLinkObjOp(),
1683
+ // roles
1684
+ ...!ownRelation ? { [value[Symbol.for("role")]]: value.$bzId } : {},
1685
+ [value[Symbol.for("oppositeRole")]]: parentId,
1686
+ [Symbol.for("dbId")]: schema.relations[value[Symbol.for("relation")]].defaultDBConnector.id,
1687
+ [Symbol.for("edgeType")]: "linkField",
1688
+ [Symbol.for("info")]: "normal linkField",
1689
+ [Symbol.for("path")]: value[Symbol.for("path")],
1690
+ [Symbol.for("parent")]: value[Symbol.for("parent")]
1691
+ };
1692
+ toEdges(edgeType1);
1693
+ if ((value.$op === "unlink" || getLinkObjOp() === "unlink") && ownRelation) {
1694
+ toEdges({
1695
+ $relation: value[Symbol.for("relation")],
1696
+ $bzId: linkTempId,
1697
+ $op: "match",
1698
+ [value[Symbol.for("oppositeRole")]]: parentId,
1699
+ [Symbol.for("dbId")]: schema.relations[value[Symbol.for("relation")]].defaultDBConnector.id,
1700
+ [Symbol.for("edgeType")]: "linkField",
1701
+ [Symbol.for("info")]: "additional ownrelation unlink linkField",
1702
+ [Symbol.for("path")]: value[Symbol.for("path")],
1703
+ [Symbol.for("parent")]: value[Symbol.for("parent")]
1704
+ });
1705
+ }
1706
+ }
1707
+ if (value.$relation) {
1708
+ const rolesObjFiltered = oFilter(value, (k, _v) => roleFieldPaths.includes(k));
1709
+ const rolesObjOnlyIds = (0, import_radash7.mapEntries)(rolesObjFiltered, (k, v) => {
1710
+ if ((0, import_radash7.isArray)(v)) {
1711
+ return [k, v];
1712
+ }
1713
+ if ((0, import_radash7.isObject)(v)) {
1714
+ return [k, v.$bzId];
1715
+ }
1716
+ return [k, v];
1717
+ });
1718
+ const objWithMetaDataOnly = oFilter(val, (k, _v) => {
1719
+ return k.startsWith("$") || k.startsWith("Symbol");
1720
+ });
1721
+ if (Object.keys(rolesObjFiltered).filter((x) => !x.startsWith("$")).length > 0) {
1722
+ if (value.$op === "create" || value.$op === "delete") {
1723
+ const getEdgeOp = () => {
1724
+ if (value.$op === "create") {
1725
+ return "link";
1726
+ }
1727
+ if (value.$op === "delete") {
1728
+ return "match";
1729
+ }
1730
+ throw new Error("Unsupported parent of edge op");
1731
+ };
1732
+ const rolesObjOnlyIdsGrouped = (0, import_radash7.mapEntries)(rolesObjOnlyIds, (k, v) => {
1733
+ if (Array.isArray(v)) {
1734
+ return [k, v.map((vNested) => vNested.$bzId || vNested)];
1735
+ }
1736
+ return [k, v.$bzId || v];
1737
+ });
1738
+ const edgeType2 = {
1739
+ ...objWithMetaDataOnly,
1740
+ $relation: value.$relation,
1741
+ $op: getEdgeOp(),
1742
+ ...rolesObjOnlyIdsGrouped,
1743
+ // override role fields by ids or tempIDs
1744
+ $bzId: value.$bzId,
1745
+ [Symbol.for("path")]: value[Symbol.for("path")],
1746
+ [Symbol.for("dbId")]: currentThingSchema.defaultDBConnector.id,
1747
+ [Symbol.for("info")]: "coming from created or deleted relation",
1748
+ [Symbol.for("edgeType")]: "roleField on C/D"
1749
+ };
1750
+ toEdges(edgeType2);
1751
+ return;
1752
+ }
1753
+ if (value.$op === "match" || value.$op === "update" && Object.keys(rolesObjFiltered).length > 0) {
1754
+ let totalUnlinks = 0;
1755
+ Object.entries(rolesObjFiltered).forEach(([role, operations]) => {
1756
+ const operationsArray = (0, import_radash7.isArray)(operations) ? operations : [operations];
1757
+ const getOp = (childOp) => {
1758
+ if (childOp === "create" || childOp === "replace") {
1759
+ return "link";
1760
+ }
1761
+ return childOp;
1762
+ };
1763
+ operationsArray.forEach((operation) => {
1764
+ if (!operation) {
1765
+ return;
1766
+ }
1767
+ const op = getOp(operation.$op);
1768
+ if (op === "replace") {
1769
+ throw new Error("Not supported yet: replace on roleFields");
1770
+ }
1771
+ if (op === "unlink" && totalUnlinks > 0) {
1772
+ totalUnlinks += 1;
1773
+ throw new Error(
1774
+ "Not supported yet: Cannot unlink more than one role at a time, please split into two mutations"
1775
+ );
1776
+ }
1777
+ const edgeType3 = {
1778
+ ...objWithMetaDataOnly,
1779
+ $relation: value.$relation,
1780
+ $op: op === "delete" ? "unlink" : op,
1781
+ [role]: operation.$bzId,
1782
+ $bzId: value.$bzId,
1783
+ [Symbol.for("dbId")]: currentThingSchema.defaultDBConnector.id,
1784
+ [Symbol.for("parent")]: value[Symbol.for("parent")],
1785
+ [Symbol.for("path")]: value[Symbol.for("path")],
1786
+ [Symbol.for("info")]: "updating roleFields",
1787
+ [Symbol.for("edgeType")]: "roleField on L/U/R"
1788
+ };
1789
+ toEdges(edgeType3);
1790
+ if (op === "unlink") {
1791
+ }
1792
+ });
1793
+ });
1794
+ }
1795
+ }
1796
+ }
1797
+ }
1798
+ };
1799
+ (0, import_object_traversal4.traverse)(blocks, listOp);
1800
+ return [nodes, edges];
1801
+ };
1802
+ if (!filledBqlRequest) {
1803
+ throw new Error("Undefined filledBqlRequest");
1804
+ }
1805
+ const [parsedThings, parsedEdges] = listNodes(filledBqlRequest);
1806
+ const mergedThings = parsedThings.reduce((acc, thing) => {
1807
+ if (!thing.$bzId) {
1808
+ return [...acc, thing];
1809
+ }
1810
+ const existingIndex = acc.findIndex((t) => t.$bzId === thing.$bzId);
1811
+ if (existingIndex === -1) {
1812
+ return [...acc, thing];
1813
+ }
1814
+ if (acc[existingIndex].$op === "create" && thing.$op === "match") {
1815
+ return acc;
1816
+ }
1817
+ if (acc[existingIndex].$op === "match" && (thing.$op === "create" || thing.$op === "match")) {
1818
+ return [...acc.slice(0, existingIndex), thing, ...acc.slice(existingIndex + 1)];
1819
+ }
1820
+ throw new Error(
1821
+ `Unsupported operation combination for $tempId "${thing.$tempId}". Existing: ${acc[existingIndex].$op}. Current: ${thing.$op}`
1822
+ );
1823
+ }, []);
1824
+ const mergedEdges = parsedEdges.reduce((acc, curr) => {
1825
+ const existingEdge = acc.find(
1826
+ (r) => (r.$id && r.$id === curr.$id || r.$bzId && r.$bzId === curr.$bzId) && r.$relation === curr.$relation && r.$op === curr.$op
1827
+ );
1828
+ if (existingEdge) {
1829
+ const newRelation = { ...existingEdge };
1830
+ Object.keys(curr).forEach((key) => {
1831
+ if (typeof key === "symbol" || key.startsWith("$")) {
1832
+ return;
1833
+ }
1834
+ const existingVal = existingEdge[key];
1835
+ const currVal = curr[key];
1836
+ if (Array.isArray(existingVal) && Array.isArray(currVal)) {
1837
+ newRelation[key] = Array.from(/* @__PURE__ */ new Set([...existingVal, ...currVal]));
1838
+ } else if (!Array.isArray(existingVal) && Array.isArray(currVal)) {
1839
+ if (existingVal !== void 0) {
1840
+ newRelation[key] = Array.from(/* @__PURE__ */ new Set([existingVal, ...currVal]));
1841
+ } else {
1842
+ newRelation[key] = currVal;
1843
+ }
1844
+ } else if (Array.isArray(existingVal) && !Array.isArray(currVal)) {
1845
+ if (currVal !== void 0) {
1846
+ newRelation[key] = Array.from(/* @__PURE__ */ new Set([...existingVal, currVal]));
1847
+ }
1848
+ } else if (!existingVal) {
1849
+ newRelation[key] = currVal;
1850
+ }
1851
+ });
1852
+ const newAcc = acc.filter(
1853
+ (r) => !((r.$id && r.$id === curr.$id || r.$bzId && r.$bzId === curr.$bzId) && r.$relation === curr.$relation && r.$op === curr.$op)
1854
+ );
1855
+ return [...newAcc, newRelation];
1856
+ }
1857
+ return [...acc, curr];
1858
+ }, []);
1859
+ const uniqueRelations = [...new Set(mergedEdges.map((x) => x.$relation))];
1860
+ const _checkCardinality = () => {
1861
+ const problematicEdges = {};
1862
+ uniqueRelations.forEach((relation) => {
1863
+ const cardinalityOneRoles = Object.keys(schema.relations[relation].roles).filter(
1864
+ (role) => schema.relations[relation].roles[role].cardinality === "ONE"
1865
+ );
1866
+ cardinalityOneRoles.forEach((oneRole) => {
1867
+ const idMapping = {};
1868
+ mergedEdges.forEach((edge) => {
1869
+ if (edge.$relation === relation && edge[oneRole]) {
1870
+ const oneId = edge[oneRole];
1871
+ const otherRole = Object.keys(edge).find(
1872
+ (role) => role !== "$relation" && role !== "$op" && role !== "$id" && role !== oneRole
1873
+ );
1874
+ if (otherRole) {
1875
+ const otherId = edge[otherRole];
1876
+ if (!idMapping[otherId]) {
1877
+ idMapping[otherId] = /* @__PURE__ */ new Set();
1878
+ }
1879
+ idMapping[otherId].add(oneId);
1880
+ }
1881
+ }
1882
+ });
1883
+ Object.entries(idMapping).forEach(([otherId, oneIds]) => {
1884
+ if (oneIds.size > 1) {
1885
+ throw new Error(
1886
+ `${relation} has illegal cardinality: The ${oneRole} role is linked to multiple ${Object.keys(
1887
+ idMapping[otherId]
1888
+ ).join(",")} roles.`
1889
+ );
1890
+ }
1891
+ });
1892
+ });
1893
+ });
1894
+ if (Object.keys(problematicEdges).length > 0) {
1895
+ let errorMessage = "";
1896
+ Object.entries(problematicEdges).forEach(([otherId, errorSet]) => {
1897
+ errorMessage += `"${otherId}" is connected to many entities. ${Array.from(errorSet).join(" ")}The relation's role is of cardinality ONE.
1898
+ `;
1899
+ });
1900
+ throw new Error(errorMessage);
1901
+ }
1902
+ };
1903
+ req.bqlRequest = {
1904
+ mutation: {
1905
+ things: mergedThings,
1906
+ edges: mergedEdges
1907
+ }
1908
+ };
1909
+ };
1910
+
1911
+ // src/pipeline/transaction/runTQLMutation.ts
1912
+ var import_typedb_driver3 = require("typedb-driver");
1913
+
1914
+ // src/pipeline/transaction/helpers.ts
1915
+ var import_typedb_driver2 = require("typedb-driver");
1916
+ var getSessionOrOpenNewOne = async (dbHandles, config) => {
1917
+ const singleHandlerV0 = config.dbConnectors[0].id;
1918
+ let session = dbHandles.typeDB.get(singleHandlerV0)?.session;
1919
+ const client = dbHandles.typeDB.get(singleHandlerV0)?.client;
1920
+ if (!session || !session.isOpen()) {
1921
+ if (!client) {
1922
+ throw new Error("Client not found");
1923
+ }
1924
+ session = await client.session(config.dbConnectors[0].dbName, import_typedb_driver2.SessionType.DATA);
1925
+ dbHandles.typeDB.set(singleHandlerV0, { client, session });
1926
+ }
1927
+ return { client, session };
1928
+ };
1929
+
1930
+ // src/pipeline/transaction/runTQLMutation.ts
1931
+ var runTQLMutation = async (req, res) => {
1932
+ const { dbHandles, tqlRequest, bqlRequest, config } = req;
1933
+ if (!tqlRequest) {
1934
+ throw new Error("TQL request not built");
1935
+ }
1936
+ if (!(tqlRequest.deletions && tqlRequest.deletionMatches || tqlRequest.insertions)) {
1937
+ throw new Error("TQL request error, no things");
1938
+ }
1939
+ if (!bqlRequest?.mutation) {
1940
+ throw new Error("BQL mutation not parsed");
1941
+ }
1942
+ const { session } = await getSessionOrOpenNewOne(dbHandles, config);
1943
+ const mutateTransaction = await session.transaction(import_typedb_driver3.TransactionType.WRITE);
1944
+ if (!mutateTransaction) {
1945
+ throw new Error("Can't create transaction");
1946
+ }
1947
+ const tqlDeletion = tqlRequest.deletionMatches && tqlRequest.deletions && `match ${tqlRequest.deletionMatches} delete ${tqlRequest.deletions}`;
1948
+ const tqlInsertion = tqlRequest.insertions && `${tqlRequest.insertionMatches ? `match ${tqlRequest.insertionMatches}` : ""} insert ${tqlRequest.insertions}`;
1949
+ if (tqlDeletion) {
1950
+ await mutateTransaction.query.delete(tqlDeletion);
1951
+ }
1952
+ const insertionsStream = tqlInsertion && mutateTransaction.query.insert(tqlInsertion);
1953
+ try {
1954
+ const insertionsRes = insertionsStream ? await insertionsStream.collect() : void 0;
1955
+ await mutateTransaction.commit();
1956
+ await mutateTransaction.close();
1957
+ res.rawTqlRes = { insertions: insertionsRes };
1958
+ } catch (e) {
1959
+ await mutateTransaction.close();
1960
+ throw new Error(`Transaction failed: ${e.message}`);
1961
+ }
1962
+ };
1963
+
1964
+ // src/pipeline/preprocess/buildTQLQuery.ts
1965
+ var separator = "___";
1966
+ var newBuildTQLQuery = async (req) => {
1967
+ const { enrichedBqlQuery } = req;
1968
+ if (!enrichedBqlQuery) {
1969
+ throw new Error("BQL query not enriched");
1970
+ }
1971
+ let tqlStr = "";
1972
+ const processFilters = ($filter, $var) => {
1973
+ let simpleHas = "";
1974
+ let orHas = "";
1975
+ for (const key in $filter) {
1976
+ const filterKey = $filter[key];
1977
+ if (Array.isArray(filterKey)) {
1978
+ for (let i = 0; i < filterKey.length; i++) {
1979
+ orHas += `{$${$var} has ${key} "${filterKey[i]}";}`;
1980
+ if (i < filterKey.length - 1) {
1981
+ orHas += "or";
1982
+ } else {
1983
+ orHas += ";";
1984
+ }
1985
+ }
1986
+ } else {
1987
+ simpleHas += `, has ${key} "${filterKey}"`;
1988
+ }
1989
+ }
1990
+ simpleHas += "; \n";
1991
+ tqlStr += simpleHas;
1992
+ tqlStr += orHas;
1993
+ };
1994
+ const processDataFields = (dataFields, $path) => {
1995
+ const postStrParts = [];
1996
+ const asMetaDataParts = [];
1997
+ const virtualMetaDataParts = [];
1998
+ let $asMetaData = "";
1999
+ let $virtualMetaData = "";
2000
+ for (let i = 0; i < dataFields.length; i++) {
2001
+ if (!dataFields[i].$isVirtual) {
2002
+ postStrParts.push(` ${dataFields[i].$dbPath}`);
2003
+ } else {
2004
+ virtualMetaDataParts.push(`${dataFields[i].$dbPath}`);
2005
+ }
2006
+ asMetaDataParts.push(`{${dataFields[i].$dbPath}:${dataFields[i].$as}}`);
2007
+ }
2008
+ const postStr = `${postStrParts.join(",")};
2009
+ `;
2010
+ $asMetaData = asMetaDataParts.join(",");
2011
+ $virtualMetaData = virtualMetaDataParts.join(",");
2012
+ const $metaData = `$metadata:{as:[${$asMetaData}],virtual:[${$virtualMetaData}]}`;
2013
+ tqlStr += `$${$path} as "${$path}.${$metaData}.$dataFields": `;
2014
+ tqlStr += postStr;
2015
+ };
2016
+ const processRoleFields = (roleFields, $path, dotPath) => {
2017
+ for (const roleField of roleFields) {
2018
+ const { $fields, $as, $justId, $idNotIncluded, $filterByUnique } = roleField;
2019
+ const $metaData = `$metadata:{as:${$as},justId:${$justId ? "T" : "F"},idNotIncluded:${$idNotIncluded},filterByUnique:${$filterByUnique}}`;
2020
+ tqlStr += `"${dotPath}.${$metaData}.${roleField.$var}":{
2021
+ `;
2022
+ tqlStr += " match \n";
2023
+ if (roleField.$filter) {
2024
+ tqlStr += ` $${$path}${separator}${roleField.$var} isa ${roleField.$thing}`;
2025
+ processFilters(roleField.$filter, `${$path}${separator}${roleField.$var}`);
2026
+ }
2027
+ tqlStr += ` $${$path} (${roleField.$var}: $${$path}${separator}${roleField.$var}) isa ${roleField.$intermediary};
2028
+ `;
2029
+ if ($fields) {
2030
+ tqlStr += " fetch \n";
2031
+ }
2032
+ const dataFields = $fields?.filter((f) => f.$fieldType === "data");
2033
+ if (dataFields && dataFields.length > 0) {
2034
+ processDataFields(dataFields, `${$path}${separator}${roleField.$var}`, `${$path}.${roleField.$var}`);
2035
+ }
2036
+ const linkFields = $fields?.filter((f) => f.$fieldType === "link");
2037
+ if (linkFields && linkFields.length > 0) {
2038
+ processLinkFields(linkFields, `${$path}${separator}${roleField.$var}`, `${$path}.${roleField.$var}`);
2039
+ }
2040
+ const roleFields2 = $fields?.filter((f) => f.$fieldType === "role");
2041
+ if (roleFields2 && roleFields2.length > 0) {
2042
+ processRoleFields(roleFields2, `${$path}${separator}${roleField.$var}`, `${$path}.${roleField.$var}`);
2043
+ }
2044
+ tqlStr += "}; \n";
2045
+ }
2046
+ };
2047
+ const processLinkFields = (linkFields, $path, dotPath) => {
2048
+ for (const linkField of linkFields) {
2049
+ const { $fields, $as, $justId, $idNotIncluded, $filterByUnique, $playedBy } = linkField;
2050
+ const $metaData = `$metadata:{as:${$as},justId:${$justId ? "T" : "F"},idNotIncluded:${$idNotIncluded},filterByUnique:${$filterByUnique}}`;
2051
+ tqlStr += `"${dotPath}.${$metaData}.${linkField.$var}":{
2052
+ `;
2053
+ tqlStr += " match \n";
2054
+ if (linkField.$filter) {
2055
+ tqlStr += ` $${$path}${separator}${linkField.$var} isa ${linkField.$thing}`;
2056
+ processFilters(linkField.$filter, `${$path}${separator}${linkField.$var}`);
2057
+ }
2058
+ if (linkField.$target === "role") {
2059
+ tqlStr += ` $${$path}_intermediary (${linkField.$plays}: $${$path}, ${$playedBy.plays}: $${$path}${separator}${linkField.$var}) isa ${linkField.$intermediary};
2060
+ `;
2061
+ } else {
2062
+ tqlStr += ` $${$path}${separator}${linkField.$var} (${linkField.$plays}: $${$path}) isa ${linkField.$thing};
2063
+ `;
2064
+ }
2065
+ if ($fields) {
2066
+ tqlStr += " fetch \n";
2067
+ }
2068
+ const dataFields = $fields?.filter((f) => f.$fieldType === "data");
2069
+ if (dataFields && dataFields.length > 0) {
2070
+ processDataFields(dataFields, `${$path}${separator}${linkField.$var}`);
2071
+ }
2072
+ const linkFields2 = $fields?.filter((f) => f.$fieldType === "link");
2073
+ if (linkFields2 && linkFields2.length > 0) {
2074
+ processLinkFields(linkFields2, `${$path}${separator}${linkField.$var}`, `${$path}.${linkField.$var}`);
2075
+ }
2076
+ const roleFields = $fields?.filter((f) => f.$fieldType === "role");
2077
+ if (roleFields && roleFields.length > 0) {
2078
+ processRoleFields(roleFields, `${$path}${separator}${linkField.$var}`, `${$path}.${linkField.$var}`);
2079
+ }
2080
+ tqlStr += "}; \n";
2081
+ }
2082
+ };
2083
+ const isBatched = enrichedBqlQuery.length > 1;
2084
+ const tqlStrings = [];
2085
+ const builder = (enrichedBqlQuery2) => {
2086
+ if (isBatched) {
2087
+ for (const query of enrichedBqlQuery2) {
2088
+ const { $path, $thing, $filter, $fields } = query;
2089
+ tqlStr += `match
2090
+ $${$path} isa ${$thing} `;
2091
+ if ($filter) {
2092
+ processFilters($filter, $path);
2093
+ } else {
2094
+ tqlStr += "; ";
2095
+ }
2096
+ if ($fields) {
2097
+ tqlStr += "fetch \n";
2098
+ }
2099
+ const dataFields = $fields?.filter((f) => f.$fieldType === "data");
2100
+ if (dataFields && dataFields.length > 0) {
2101
+ processDataFields(dataFields, $path);
2102
+ }
2103
+ const linkFields = $fields?.filter((f) => f.$fieldType === "link");
2104
+ if (linkFields && linkFields.length > 0) {
2105
+ processLinkFields(linkFields, $path, $path);
2106
+ }
2107
+ const roleFields = $fields?.filter((f) => f.$fieldType === "role");
2108
+ if (roleFields && roleFields.length > 0) {
2109
+ processRoleFields(roleFields, $path, $path);
2110
+ }
2111
+ tqlStrings.push(tqlStr);
2112
+ tqlStr = "";
2113
+ }
2114
+ } else {
2115
+ for (const query of enrichedBqlQuery2) {
2116
+ const { $path, $thing, $filter, $fields } = query;
2117
+ tqlStr += `match
2118
+ $${$path} isa ${$thing} `;
2119
+ if ($filter) {
2120
+ processFilters($filter, $path);
2121
+ } else {
2122
+ tqlStr += "; ";
2123
+ }
2124
+ if ($fields) {
2125
+ tqlStr += "fetch \n";
2126
+ }
2127
+ const dataFields = $fields?.filter((f) => f.$fieldType === "data");
2128
+ if (dataFields && dataFields.length > 0) {
2129
+ processDataFields(dataFields, $path);
2130
+ }
2131
+ const linkFields = $fields?.filter((f) => f.$fieldType === "link");
2132
+ if (linkFields && linkFields.length > 0) {
2133
+ processLinkFields(linkFields, $path, $path);
2134
+ }
2135
+ const roleFields = $fields?.filter((f) => f.$fieldType === "role");
2136
+ if (roleFields && roleFields.length > 0) {
2137
+ processRoleFields(roleFields, $path, $path);
2138
+ }
2139
+ }
2140
+ }
2141
+ };
2142
+ builder(enrichedBqlQuery);
2143
+ req.tqlRequest = isBatched ? tqlStrings : tqlStr;
2144
+ };
2145
+
2146
+ // src/pipeline/preprocess/enrichBQLQuery.ts
2147
+ var import_immer4 = require("immer");
2148
+ var import_object_traversal5 = require("object-traversal");
2149
+ var import_radash8 = require("radash");
2150
+ var getAllFields = (currentSchema) => {
2151
+ const dataFields = currentSchema.dataFields?.map((field) => field.path) || [];
2152
+ const linkFields = currentSchema.linkFields?.map((field) => field.path) || [];
2153
+ const roleFields = Object.keys(currentSchema.roles || {}) || [];
2154
+ const allFields = [...dataFields, ...linkFields, ...roleFields];
2155
+ return allFields;
2156
+ };
2157
+ var checkFilterByUnique = ($filter, currentSchema) => {
2158
+ const fields = Object.keys($filter || {});
2159
+ return fields.some((field) => {
2160
+ if (!Array.isArray($filter[field])) {
2161
+ const isIdField = currentSchema.idFields?.includes(field);
2162
+ const isUniqueDataField = currentSchema.dataFields?.some(
2163
+ (f) => (f.dbPath === field || f.path === field) && f?.validations?.unique
2164
+ );
2165
+ return isIdField || isUniqueDataField;
2166
+ }
2167
+ return false;
2168
+ });
2169
+ };
2170
+ var processFilter = ($filter, currentSchema) => {
2171
+ const dataFields = currentSchema.dataFields?.map((field) => ({ path: field.path, dbPath: field.dbPath })) || [];
2172
+ const linkFields = currentSchema.linkFields?.map((field) => ({ path: field.path, dbPath: field.dbPath })) || [];
2173
+ const roleFields = Object.keys(currentSchema.roles || {}).map((field) => ({ path: field, dbPath: field })) || [];
2174
+ const allFields = [...dataFields, ...linkFields, ...roleFields];
2175
+ return Object.entries($filter || {}).reduce((newFilter, [filterKey, filterValue]) => {
2176
+ const field = allFields.find((o) => o.path === filterKey);
2177
+ newFilter[field?.dbPath || filterKey] = filterValue;
2178
+ return newFilter;
2179
+ }, {});
2180
+ };
2181
+ var enrichBQLQuery = async (req) => {
2182
+ const { rawBqlRequest: rawBqlQuery, schema } = req;
2183
+ if (!Array.isArray(rawBqlQuery)) {
2184
+ if (!("$entity" in rawBqlQuery) && !("$relation" in rawBqlQuery) && (!("$thing" in rawBqlQuery) || !("$thingType" in rawBqlQuery))) {
2185
+ throw new Error("No entity specified in query");
2186
+ }
2187
+ } else {
2188
+ for (const item of rawBqlQuery) {
2189
+ if (!("$entity" in item) && !("$relation" in item) && (!("$thing" in item) || !("$thingType" in item))) {
2190
+ throw new Error("No entity specified in query");
2191
+ }
2192
+ }
2193
+ }
2194
+ const createDataField = (field, fieldStr, $justId, dbPath, isVirtual) => {
2195
+ return {
2196
+ $path: fieldStr,
2197
+ $dbPath: dbPath,
2198
+ $thingType: "attribute",
2199
+ $as: field.$as || fieldStr,
2200
+ $var: fieldStr,
2201
+ $fieldType: "data",
2202
+ $justId,
2203
+ $id: field.$id,
2204
+ $filter: field.$filter,
2205
+ $isVirtual: isVirtual,
2206
+ // ...(typeof field !== 'string' && { $fields: [...field.$fields, ...['id']] }),
2207
+ $filterProcessed: true
2208
+ };
2209
+ };
2210
+ const createLinkField = (field, fieldStr, linkField, $justId, dbPath) => {
2211
+ const { target, oppositeLinkFieldsPlayedBy } = linkField;
2212
+ return oppositeLinkFieldsPlayedBy.map((playedBy) => {
2213
+ const $thingType = target === "role" ? playedBy.thingType : "relation";
2214
+ const $thing = target === "role" ? playedBy.thing : linkField.relation;
2215
+ const node = { [`$${$thingType}`]: $thing };
2216
+ const currentSchema = getCurrentSchema(schema, node);
2217
+ const idNotIncluded = field?.$fields?.filter(
2218
+ (field2) => currentSchema?.idFields?.includes(field2) || currentSchema?.idFields?.includes(field2.$path)
2219
+ ).length === 0;
2220
+ let fields = [];
2221
+ if (typeof field !== "string") {
2222
+ if (field.$fields) {
2223
+ if (idNotIncluded) {
2224
+ fields = [...field.$fields, ...currentSchema.idFields];
2225
+ } else {
2226
+ fields = field.$fields;
2227
+ }
2228
+ } else {
2229
+ fields = getAllFields(currentSchema);
2230
+ }
2231
+ } else {
2232
+ fields = ["id"];
2233
+ }
2234
+ if (field.$excludedFields) {
2235
+ fields = fields.filter((f) => !field.$excludedFields.includes(f.$path));
2236
+ }
2237
+ return {
2238
+ $thingType,
2239
+ $plays: linkField.plays,
2240
+ $playedBy: playedBy,
2241
+ $path: playedBy.path,
2242
+ $dbPath: dbPath,
2243
+ $as: field.$as || fieldStr,
2244
+ $var: fieldStr,
2245
+ $thing,
2246
+ $fields: fields,
2247
+ $fieldType: "link",
2248
+ $target: target,
2249
+ $intermediary: playedBy.relation,
2250
+ $justId,
2251
+ $id: field.$id,
2252
+ $filter: processFilter(field.$filter, currentSchema),
2253
+ $idNotIncluded: idNotIncluded,
2254
+ $filterByUnique: checkFilterByUnique(field.$filter, currentSchema),
2255
+ $filterProcessed: true
2256
+ };
2257
+ });
2258
+ };
2259
+ const createRoleField = (field, fieldStr, roleField, $justId, dbPath) => {
2260
+ return roleField.playedBy.map((playedBy) => {
2261
+ const { thing, thingType, relation } = playedBy;
2262
+ const node = { [`$${thingType}`]: thing };
2263
+ const currentSchema = getCurrentSchema(schema, node);
2264
+ const idNotIncluded = field?.$fields?.filter(
2265
+ (field2) => currentSchema?.idFields?.includes(field2) || currentSchema?.idFields?.includes(field2.$path)
2266
+ ).length === 0;
2267
+ let fields = [];
2268
+ if (typeof field !== "string") {
2269
+ if (field.$fields) {
2270
+ if (idNotIncluded) {
2271
+ fields = [...field.$fields, ...currentSchema.idFields];
2272
+ } else {
2273
+ fields = field.$fields;
2274
+ }
2275
+ } else {
2276
+ fields = getAllFields(currentSchema);
2277
+ }
2278
+ } else {
2279
+ fields = ["id"];
2280
+ }
2281
+ if (field.$excludedFields) {
2282
+ fields = fields.filter((f) => !field.$excludedFields.includes(f.$path));
2283
+ }
2284
+ return {
2285
+ $thingType: thingType,
2286
+ $path: fieldStr,
2287
+ $dbPath: dbPath,
2288
+ $as: field.$as || fieldStr,
2289
+ $var: fieldStr,
2290
+ $thing: thing,
2291
+ $fields: fields,
2292
+ $fieldType: "role",
2293
+ $intermediary: relation,
2294
+ $justId,
2295
+ $id: field.$id,
2296
+ $filter: processFilter(field.$filter, currentSchema),
2297
+ $idNotIncluded: idNotIncluded,
2298
+ $filterByUnique: checkFilterByUnique(field.$filter, currentSchema),
2299
+ $playedBy: playedBy,
2300
+ $filterProcessed: true
2301
+ };
2302
+ });
2303
+ };
2304
+ const processField = (field, schema2) => {
2305
+ const fieldStr = typeof field === "string" ? field : field.$path;
2306
+ const justId = typeof field === "string";
2307
+ const isDataField = schema2.dataFields?.find((dataField) => dataField.path === fieldStr);
2308
+ const isLinkField = schema2.linkFields?.find((linkField) => linkField.path === fieldStr);
2309
+ const isRoleField = schema2.roles?.[fieldStr];
2310
+ if (isDataField) {
2311
+ return createDataField(field, fieldStr, justId, isDataField.dbPath, isDataField.isVirtual);
2312
+ } else if (isLinkField) {
2313
+ return createLinkField(field, fieldStr, isLinkField, justId, isLinkField.dbPath);
2314
+ } else if (isRoleField) {
2315
+ return createRoleField(field, fieldStr, isRoleField, justId, isRoleField.dbPath);
2316
+ }
2317
+ return null;
2318
+ };
2319
+ const parser = (blocks) => {
2320
+ return (0, import_immer4.produce)(
2321
+ blocks,
2322
+ (draft) => (0, import_object_traversal5.traverse)(draft, (context) => {
2323
+ const { value: val } = context;
2324
+ const value = val;
2325
+ if ((0, import_radash8.isObject)(value)) {
2326
+ if (value.$id) {
2327
+ const node = value.$entity || value.$relation ? value : { [`$${value.$thingType}`]: value.$thing };
2328
+ const currentSchema = getCurrentSchema(schema, node);
2329
+ value.$path = currentSchema.name;
2330
+ if (!Array.isArray(value.$id)) {
2331
+ value.$filterByUnique = true;
2332
+ }
2333
+ if (currentSchema?.idFields?.length === 1) {
2334
+ const [idField] = currentSchema.idFields;
2335
+ value.$filter = { ...value.$filter, ...{ [idField]: value.$id } };
2336
+ delete value.$id;
2337
+ } else {
2338
+ throw new Error("Multiple ids not yet enabled / composite ids");
2339
+ }
2340
+ } else if ("$entity" in value || "$relation" in value) {
2341
+ const currentSchema = getCurrentSchema(schema, value);
2342
+ value.$path = currentSchema.name;
2343
+ value.$as = currentSchema.name;
2344
+ }
2345
+ if (value.$entity) {
2346
+ value.$thing = value.$entity;
2347
+ value.$thingType = "entity";
2348
+ delete value.$entity;
2349
+ } else if (value.$relation) {
2350
+ value.$thing = value.$relation;
2351
+ value.$thingType = "relation";
2352
+ delete value.$relation;
2353
+ }
2354
+ if ((0, import_radash8.isObject)(value) && "$thing" in value) {
2355
+ const node = value.$entity || value.$relation ? value : { [`$${value.$thingType}`]: value.$thing };
2356
+ const currentSchema = getCurrentSchema(schema, node);
2357
+ if (value.$filter) {
2358
+ value.$filterByUnique = checkFilterByUnique(value.$filter, currentSchema);
2359
+ if (!value.$filterProcessed) {
2360
+ value.$filter = processFilter(value.$filter, currentSchema);
2361
+ }
2362
+ }
2363
+ if (value.$fields) {
2364
+ const idFieldIncluded = value.$fields.filter(
2365
+ (field) => currentSchema?.idFields?.includes(field) || currentSchema?.idFields?.includes(field.$path)
2366
+ ).length > 0;
2367
+ if (!idFieldIncluded) {
2368
+ value.$fields = [...value.$fields, ...currentSchema.idFields];
2369
+ value.$idNotIncluded = true;
2370
+ }
2371
+ const newFields = value.$fields?.flatMap((field) => {
2372
+ const processed = processField(field, currentSchema);
2373
+ if (Array.isArray(processed)) {
2374
+ return processed;
2375
+ } else {
2376
+ return [processed];
2377
+ }
2378
+ }).filter(Boolean);
2379
+ value.$fields = newFields;
2380
+ } else {
2381
+ const allFields = getAllFields(currentSchema);
2382
+ const newFields = allFields?.flatMap((field) => {
2383
+ const processed = processField(field, currentSchema);
2384
+ if (Array.isArray(processed)) {
2385
+ return processed;
2386
+ } else {
2387
+ return [processed];
2388
+ }
2389
+ }).filter(Boolean);
2390
+ value.$fields = newFields;
2391
+ }
2392
+ if (value.$excludedFields) {
2393
+ value.$fields = value.$fields.filter((f) => !value.$excludedFields.includes(f.$path));
2394
+ }
2395
+ }
2396
+ }
2397
+ })
2398
+ );
2399
+ };
2400
+ const enrichedBqlQuery = parser(Array.isArray(rawBqlQuery) ? rawBqlQuery : [rawBqlQuery]);
2401
+ req.enrichedBqlQuery = enrichedBqlQuery;
2402
+ };
2403
+
2404
+ // src/pipeline/transaction/runTQLQuery.ts
2405
+ var import_typedb_driver4 = require("typedb-driver");
2406
+ var import_radash9 = require("radash");
2407
+ var newRunTQLQuery = async (req, res) => {
2408
+ const { dbHandles, enrichedBqlQuery, tqlRequest, config } = req;
2409
+ if (!enrichedBqlQuery) {
2410
+ throw new Error("BQL request not parsed");
2411
+ }
2412
+ if (!tqlRequest) {
2413
+ throw new Error("TQL request not built");
2414
+ }
2415
+ const isBatched = Array.isArray(tqlRequest);
2416
+ if (isBatched) {
2417
+ const resArray = await (0, import_radash9.parallel)(tqlRequest.length, tqlRequest, async (queryString) => {
2418
+ const { session } = await getSessionOrOpenNewOne(dbHandles, config);
2419
+ const transaction = await session.transaction(import_typedb_driver4.TransactionType.READ);
2420
+ if (!transaction) {
2421
+ throw new Error("Can't create transaction");
2422
+ }
2423
+ const tqlStream = transaction.query.fetch(queryString);
2424
+ const tqlRes = await tqlStream.collect();
2425
+ await transaction.close();
2426
+ return tqlRes;
2427
+ });
2428
+ res.rawTqlRes = resArray;
2429
+ res.isBatched = true;
2430
+ } else {
2431
+ const { session } = await getSessionOrOpenNewOne(dbHandles, config);
2432
+ const transaction = await session.transaction(import_typedb_driver4.TransactionType.READ);
2433
+ if (!transaction) {
2434
+ throw new Error("Can't create transaction");
2435
+ }
2436
+ const tqlStream = transaction.query.fetch(tqlRequest);
2437
+ const tqlRes = await tqlStream.collect();
2438
+ await transaction.close();
2439
+ res.rawTqlRes = tqlRes;
2440
+ }
2441
+ };
2442
+
2443
+ // src/pipeline/postprocess/parseTQLQuery.ts
2444
+ var parseMetaData = (str) => {
2445
+ const asRegex = /as:([a-zA-Z0-9_\-·]+)/;
2446
+ const justIdRegex = /justId:([a-zA-Z0-9_\-·]+)/;
2447
+ const idNotIncludedRegex = /idNotIncluded:([a-zA-Z0-9_\-·]+)/;
2448
+ const filterByUniqueRegex = /filterByUnique:([a-zA-Z0-9_\-·]+)/;
2449
+ const asMatch = str.match(asRegex);
2450
+ const justIdMatch = str.match(justIdRegex);
2451
+ const idNotIncludedMatch = str.match(idNotIncludedRegex);
2452
+ const filterByUniqueMatch = str.match(filterByUniqueRegex);
2453
+ return {
2454
+ as: asMatch ? asMatch[1] : null,
2455
+ justId: justIdMatch ? justIdMatch[1] : null,
2456
+ idNotIncluded: idNotIncludedMatch ? idNotIncludedMatch[1] : null,
2457
+ filterByUnique: filterByUniqueMatch ? filterByUniqueMatch[1] : null
2458
+ };
2459
+ };
2460
+ var parseArrayMetadata = (str) => {
2461
+ try {
2462
+ const convertToJson = (str2) => {
2463
+ let jsonString = str2.replace("$metadata:", "");
2464
+ jsonString = jsonString.replace(/([a-zA-Z0-9_\-·]+)(?=:)/g, '"$1"');
2465
+ jsonString = jsonString.replace(/:(\s*)([a-zA-Z0-9_\-·]+)/g, (match, p1, p2) => {
2466
+ if (/^{.*}$/.test(p2)) {
2467
+ return `:${p2}`;
2468
+ } else {
2469
+ return `:${p1}"${p2}"`;
2470
+ }
2471
+ });
2472
+ jsonString = jsonString.replace(/\[([^\]]+)\]/g, (match, p1) => {
2473
+ return `[${p1.split(",").map((s) => {
2474
+ if (s.trim().startsWith("{") && s.trim().endsWith("}")) {
2475
+ return s.trim();
2476
+ } else {
2477
+ return `"${s.trim()}"`;
2478
+ }
2479
+ }).join(",")}]`;
2480
+ });
2481
+ return jsonString;
2482
+ };
2483
+ const converted = convertToJson(str);
2484
+ const parsed = JSON.parse(converted);
2485
+ return parsed;
2486
+ } catch (e) {
2487
+ console.error(e);
2488
+ return { as: [], virtual: [] };
2489
+ }
2490
+ };
2491
+ var parseTQLQuery = async (req, res) => {
2492
+ const { enrichedBqlQuery, rawBqlRequest, schema, config } = req;
2493
+ const { rawTqlRes, isBatched } = res;
2494
+ if (!enrichedBqlQuery) {
2495
+ throw new Error("BQL request not enriched");
2496
+ } else if (!rawTqlRes) {
2497
+ throw new Error("TQL query not executed");
2498
+ }
2499
+ const parseDataFields = (dataFields, currentSchema) => {
2500
+ const { $metaData } = dataFields;
2501
+ const { as: $as, virtual } = parseArrayMetadata($metaData);
2502
+ const mainDataFields = Object.entries(dataFields).filter(([key]) => key !== "type" && !key.includes("$")).map(([key, value]) => {
2503
+ const field = currentSchema.dataFields?.find((f) => f.path === key || f.dbPath === key);
2504
+ const isIdField = key === "id";
2505
+ const $asKey = Array.isArray($as) ? $as.find((o) => o[key])?.[key] : key;
2506
+ let fieldValue;
2507
+ if (field?.cardinality === "ONE") {
2508
+ fieldValue = value[0] ? value[0].value : config.query?.returnNulls ? null : void 0;
2509
+ if (isIdField && !config.query?.noMetadata) {
2510
+ return [
2511
+ [$asKey, fieldValue],
2512
+ ["$id", fieldValue]
2513
+ ].filter(([_, v]) => v !== void 0);
2514
+ }
2515
+ } else if (field?.cardinality === "MANY") {
2516
+ fieldValue = value.map((o) => o.value);
2517
+ }
2518
+ return [[$asKey, fieldValue]].filter(([_, v]) => v !== void 0);
2519
+ }).flat();
2520
+ const virtualFields = virtual.map((key) => {
2521
+ const $asKey = $as.find((o) => o[key])?.[key];
2522
+ const field = currentSchema.dataFields?.find((f) => f.isVirtual && f.dbPath === key);
2523
+ const computedValue = compute({ currentThing: Object.fromEntries(mainDataFields), fieldSchema: field });
2524
+ return [$asKey, computedValue];
2525
+ });
2526
+ return Object.fromEntries([...mainDataFields, ...virtualFields]);
2527
+ };
2528
+ const parseRoleFields = (roleFields) => {
2529
+ return roleFields.reduce((roleFieldsRes, roleField) => {
2530
+ const { $roleFields, $metaData, $cardinality } = roleField;
2531
+ const { as, justId, idNotIncluded, filterByUnique } = parseMetaData($metaData);
2532
+ const items = $roleFields.map((item) => {
2533
+ const { dataFields, currentSchema, linkFields, roleFields: roleFields2, schemaValue } = parseFields(item);
2534
+ const parsedDataFields = parseDataFields(dataFields, currentSchema);
2535
+ if (justId === "T") {
2536
+ return parsedDataFields.id;
2537
+ } else {
2538
+ const parsedLinkFields = parseLinkFields(linkFields);
2539
+ const parsedRoleFields = parseRoleFields(roleFields2);
2540
+ const resDataFields = { ...parsedDataFields };
2541
+ if (idNotIncluded === "true") {
2542
+ currentSchema?.idFields?.forEach((field) => delete resDataFields[field]);
2543
+ }
2544
+ return {
2545
+ ...resDataFields,
2546
+ ...parsedLinkFields,
2547
+ ...parsedRoleFields,
2548
+ ...!config.query?.noMetadata && { ...schemaValue }
2549
+ };
2550
+ }
2551
+ });
2552
+ if (items.length > 0) {
2553
+ roleFieldsRes[as] = $cardinality === "MANY" && filterByUnique === "false" ? items : items[0];
2554
+ } else if (config.query?.returnNulls) {
2555
+ roleFieldsRes[as] = null;
2556
+ }
2557
+ return roleFieldsRes;
2558
+ }, {});
2559
+ };
2560
+ const parseLinkFields = (linkFields) => {
2561
+ return linkFields.reduce((linkFieldsRes, linkField) => {
2562
+ const { $linkFields, $metaData, $cardinality } = linkField;
2563
+ const { as, justId, idNotIncluded, filterByUnique } = parseMetaData($metaData);
2564
+ const items = $linkFields.map((item) => {
2565
+ const { dataFields, currentSchema, linkFields: linkFields2, roleFields, schemaValue } = parseFields(item);
2566
+ const parsedDataFields = parseDataFields(dataFields, currentSchema);
2567
+ if (justId === "T") {
2568
+ return parsedDataFields.id;
2569
+ } else {
2570
+ const parsedLinkFields = parseLinkFields(linkFields2);
2571
+ const parsedRoleFields = parseRoleFields(roleFields);
2572
+ const resDataFields = { ...parsedDataFields };
2573
+ if (idNotIncluded === "true") {
2574
+ currentSchema.idFields?.forEach((field) => delete resDataFields[field]);
2575
+ }
2576
+ return {
2577
+ ...resDataFields,
2578
+ ...parsedLinkFields,
2579
+ ...parsedRoleFields,
2580
+ ...!config.query?.noMetadata && { ...schemaValue }
2581
+ };
2582
+ }
2583
+ });
2584
+ linkFieldsRes[as] = items.length > 0 ? $cardinality === "MANY" && filterByUnique === "false" ? items : items[0] : config.query?.returnNulls ? null : void 0;
2585
+ return linkFieldsRes;
2586
+ }, {});
2587
+ };
2588
+ const parseFields = (obj) => {
2589
+ const keys = Object.keys(obj);
2590
+ const dataFieldsKey = keys.find((key) => key.endsWith(".$dataFields"));
2591
+ if (!dataFieldsKey) {
2592
+ throw new Error("No datafields");
2593
+ }
2594
+ const dataFields = obj[dataFieldsKey];
2595
+ const metaDataKey = dataFieldsKey.split(".")[dataFieldsKey.split(".").length - 2];
2596
+ dataFields.$metaData = metaDataKey;
2597
+ if (dataFields.length === 0) {
2598
+ throw new Error("No datafields");
2599
+ }
2600
+ const dataFieldsThing = dataFields.type;
2601
+ const schemaValue = {
2602
+ $thing: dataFieldsThing.label,
2603
+ $thingType: dataFieldsThing.root
2604
+ };
2605
+ const node = { [`$${schemaValue.$thingType}`]: schemaValue.$thing };
2606
+ const currentSchema = getCurrentSchema(schema, node);
2607
+ const linkFields = keys.filter(
2608
+ (key) => !key.endsWith(".$dataFields") && currentSchema.linkFields?.some((o) => o.path === key.split(".").pop())
2609
+ ).map((key) => ({
2610
+ $linkFields: obj[key],
2611
+ $key: key.split(".").pop(),
2612
+ $metaData: key.split(".")[key.split(".").length - 2],
2613
+ $cardinality: currentSchema?.linkFields?.find((o) => o.path === key.split(".").pop())?.cardinality
2614
+ }));
2615
+ const roleFields = keys.filter((key) => !key.endsWith(".$dataFields") && currentSchema.roles?.[key.split(".").pop()]).map((key) => ({
2616
+ $roleFields: obj[key],
2617
+ $key: key.split(".").pop(),
2618
+ $metaData: key.split(".")[key.split(".").length - 2],
2619
+ // @ts-expect-error todo
2620
+ $cardinality: currentSchema.roles[key.split(".").pop()].cardinality
2621
+ }));
2622
+ return { dataFields, schemaValue, currentSchema, linkFields, roleFields };
2623
+ };
2624
+ const realParse = (tqlRes) => {
2625
+ return tqlRes.map((resItem) => {
2626
+ const { dataFields, currentSchema, linkFields, roleFields, schemaValue } = parseFields(resItem);
2627
+ const parsedDataFields = parseDataFields(dataFields, currentSchema);
2628
+ const parsedLinkFields = parseLinkFields(linkFields);
2629
+ const parsedRoleFields = parseRoleFields(roleFields);
2630
+ const idNotIncluded = rawBqlRequest?.$fields?.every(
2631
+ // @ts-expect-error todo
2632
+ (field) => !currentSchema?.idFields?.includes(field) && !currentSchema?.idFields?.includes(field.$path)
2633
+ );
2634
+ const finalObj = {
2635
+ ...parsedLinkFields,
2636
+ ...parsedRoleFields,
2637
+ ...!config.query?.noMetadata ? { ...schemaValue } : {},
2638
+ ...!config.query?.noMetadata && rawBqlRequest.$id ? { $id: Array.isArray(rawBqlRequest.$id) ? parsedDataFields["id"] : rawBqlRequest.$id } : {},
2639
+ ...idNotIncluded ? Object.fromEntries(
2640
+ Object.entries(parsedDataFields).filter(([key]) => !currentSchema?.idFields?.includes(key))
2641
+ ) : parsedDataFields
2642
+ };
2643
+ return finalObj;
2644
+ });
2645
+ };
2646
+ const parser = (tqlRes) => {
2647
+ const processResponse = (resItems) => {
2648
+ const parsedItems = realParse(resItems);
2649
+ return rawBqlRequest.$id && !Array.isArray(rawBqlRequest.$id) || enrichedBqlQuery[0].$filterByUnique ? parsedItems[0] ?? null : parsedItems.length === 0 ? null : parsedItems;
2650
+ };
2651
+ return isBatched ? tqlRes.map(processResponse) : processResponse(tqlRes);
2652
+ };
2653
+ const parsedTqlRes = parser(rawTqlRes);
2654
+ res.bqlRes = parsedTqlRes;
2655
+ };
2656
+
2657
+ // src/pipeline/preprocess/newPreQuery.ts
2658
+ var import_object_traversal6 = require("object-traversal");
2659
+ var import_radash10 = require("radash");
2660
+ var import_immer5 = require("immer");
2661
+ var import_uuid3 = require("uuid");
2662
+ var newPreQuery = async (req) => {
2663
+ const { filledBqlRequest, config, schema } = req;
2664
+ const getFieldKeys = (block, noDataFields) => {
2665
+ return Object.keys(block).filter((key) => {
2666
+ if (!key.startsWith("$")) {
2667
+ if (noDataFields) {
2668
+ const currentSchema = getCurrentSchema(schema, block);
2669
+ if (!currentSchema.dataFields?.find((field) => field.path === key)) {
2670
+ return true;
2671
+ } else {
2672
+ return false;
2673
+ }
2674
+ } else {
2675
+ return true;
2676
+ }
2677
+ } else {
2678
+ return false;
2679
+ }
2680
+ });
2681
+ };
2682
+ if (!filledBqlRequest) {
2683
+ throw new Error("[BQLE-M-0] No filledBqlRequest found");
2684
+ }
2685
+ console.log("filledBql: ", JSON.stringify(filledBqlRequest, null, 2));
2686
+ if (config.mutation?.preQuery === false) {
2687
+ return;
2688
+ }
2689
+ const ops = [];
2690
+ (0, import_object_traversal6.traverse)(filledBqlRequest, ({ parent, key, value }) => {
2691
+ if (parent && key && !key.includes("$") && (0, import_radash10.isObject)(parent)) {
2692
+ const values = Array.isArray(parent[key]) ? parent[key] : [parent[key]];
2693
+ values.forEach((val) => {
2694
+ if ((0, import_radash10.isObject)(val)) {
2695
+ if (parent.$op !== "create") {
2696
+ if (!ops.includes(val.$op)) {
2697
+ ops.push(val.$op);
2698
+ }
2699
+ } else {
2700
+ if (val.$op === "delete" || val.$op === "unlink") {
2701
+ throw new Error(`Cannot ${val.$op} under a create`);
2702
+ }
2703
+ }
2704
+ }
2705
+ });
2706
+ } else if (!parent && (0, import_radash10.isObject)(value)) {
2707
+ if (!ops.includes(value.$op)) {
2708
+ ops.push(value.$op);
2709
+ }
2710
+ }
2711
+ });
2712
+ if (!ops.includes("delete") && !ops.includes("unlink") && !ops.includes("replace") && !ops.includes("update") && !ops.includes("link")) {
2713
+ return;
2714
+ }
2715
+ const convertMutationToQuery = (blocks) => {
2716
+ const processBlock = (block, root) => {
2717
+ const $fields = [];
2718
+ const filteredBlock = {};
2719
+ const toRemoveFromRoot = ["$op", "$bzId", "$parentKey"];
2720
+ const toRemove = ["$relation", "$entity", "$id", ...toRemoveFromRoot];
2721
+ for (const k in block) {
2722
+ if (toRemoveFromRoot.includes(k)) {
2723
+ continue;
2724
+ }
2725
+ if (toRemove.includes(k) && !root) {
2726
+ continue;
2727
+ }
2728
+ if (!k.includes("$") && ((0, import_radash10.isObject)(block[k]) || Array.isArray(block[k]))) {
2729
+ const v = block[k];
2730
+ if (Array.isArray(v) && v.length > 0) {
2731
+ v.forEach((opBlock) => {
2732
+ $fields.push({
2733
+ $path: k,
2734
+ ...processBlock(opBlock)
2735
+ // $as: opBlock.$bzId,
2736
+ // $as: `${k}_${includedKeys}`,
2737
+ });
2738
+ });
2739
+ } else {
2740
+ $fields.push({
2741
+ $path: k,
2742
+ ...processBlock(v)
2743
+ // $as: v.$bzId,
2744
+ });
2745
+ }
2746
+ } else {
2747
+ filteredBlock[k] = block[k];
2748
+ }
2749
+ }
2750
+ return {
2751
+ ...filteredBlock,
2752
+ $fields
2753
+ // $as: block.$bzId,
2754
+ };
2755
+ };
2756
+ return blocks.map((block) => processBlock(block, true));
2757
+ };
2758
+ const preQueryReq = convertMutationToQuery(Array.isArray(filledBqlRequest) ? filledBqlRequest : [filledBqlRequest]);
2759
+ const preQueryRes = await queryPipeline(preQueryReq, req.config, req.schema, req.dbHandles);
2760
+ const getObjectPath = (parent, key) => {
2761
+ const idField = parent.$id || parent.id || parent.$bzId;
2762
+ if (parent.$objectPath) {
2763
+ const { $objectPath } = parent;
2764
+ const root = $objectPath?.beforePath || "root";
2765
+ const ids = Array.isArray($objectPath.ids) ? `[${$objectPath.ids}]` : $objectPath.ids;
2766
+ const final2 = `${root}.${ids}___${$objectPath.key}`;
2767
+ const new$objectPath = {
2768
+ beforePath: final2,
2769
+ ids: idField,
2770
+ key
2771
+ };
2772
+ return new$objectPath;
2773
+ } else {
2774
+ return {
2775
+ beforePath: "root",
2776
+ ids: idField,
2777
+ key
2778
+ };
2779
+ }
2780
+ };
2781
+ const objectPathToKey = ($objectPath, hardId) => {
2782
+ const root = $objectPath?.beforePath || "root";
2783
+ const ids = hardId ? hardId : Array.isArray($objectPath?.ids) ? `[${$objectPath?.ids}]` : $objectPath?.ids;
2784
+ const final2 = `${root}.${ids}___${$objectPath?.key}`;
2785
+ return final2;
2786
+ };
2787
+ const convertManyPaths = (input) => {
2788
+ if (input.includes("[") && input.includes("]")) {
2789
+ const [prefix, itemsWithBrackets, suffix] = input.split(/[[\]]/);
2790
+ const items = itemsWithBrackets.split(",");
2791
+ return items.map((item) => `${prefix}${item}${suffix}`);
2792
+ } else {
2793
+ return [input];
2794
+ }
2795
+ };
2796
+ const cache = {};
2797
+ const cachePaths = (blocks) => {
2798
+ return (0, import_immer5.produce)(
2799
+ blocks,
2800
+ (draft) => (0, import_object_traversal6.traverse)(draft, (context) => {
2801
+ const { key, parent } = context;
2802
+ if (parent && key && parent.$id && !key.includes("$")) {
2803
+ const newObjPath = getObjectPath(parent, key);
2804
+ const cacheKey = objectPathToKey(newObjPath);
2805
+ if (Array.isArray(parent[key])) {
2806
+ const cacheArray = [];
2807
+ parent[key].forEach((val) => {
2808
+ if ((0, import_radash10.isObject)(val)) {
2809
+ val.$objectPath = newObjPath;
2810
+ cacheArray.push(val.$id.toString());
2811
+ } else if (val) {
2812
+ cacheArray.push(val.toString());
2813
+ }
2814
+ });
2815
+ cache[cacheKey] = { $objectPath: newObjPath, $ids: cacheArray };
2816
+ } else {
2817
+ const val = parent[key];
2818
+ if ((0, import_radash10.isObject)(val)) {
2819
+ cache[cacheKey] = { $objectPath: newObjPath, $ids: [val.$id.toString()] };
2820
+ val.$objectPath = newObjPath;
2821
+ } else if (val) {
2822
+ cache[cacheKey] = { $objectPath: newObjPath, $ids: [val.toString()] };
2823
+ }
2824
+ }
2825
+ }
2826
+ })
2827
+ );
2828
+ };
2829
+ cachePaths(preQueryRes || {});
2830
+ const fillObjectPaths = (blocks) => {
2831
+ return (0, import_immer5.produce)(
2832
+ blocks,
2833
+ (draft) => (0, import_object_traversal6.traverse)(draft, (context) => {
2834
+ const { key, value, parent } = context;
2835
+ if (parent && key && !key.includes("$") && (Array.isArray(value) || (0, import_radash10.isObject)(value)) && !Array.isArray(parent)) {
2836
+ if (Array.isArray(parent[key])) {
2837
+ parent[key].forEach(
2838
+ (o) => {
2839
+ if (typeof o !== "string") {
2840
+ o.$objectPath = getObjectPath(parent, key);
2841
+ o.$parentIsCreate = parent.$op === "create";
2842
+ o.$grandChildOfCreate = parent.$parentIsCreate || parent.$grandChildOfCreate;
2843
+ }
2844
+ }
2845
+ );
2846
+ } else if ((0, import_radash10.isObject)(parent[key])) {
2847
+ parent[key].$parentIsCreate = parent.$op === "create";
2848
+ parent[key].$grandChildOfCreate = parent.$parentIsCreate || parent.$grandChildOfCreate;
2849
+ parent[key].$objectPath = getObjectPath(parent, key);
2850
+ }
2851
+ }
2852
+ })
2853
+ );
2854
+ };
2855
+ const bqlWithObjectPaths = fillObjectPaths(filledBqlRequest);
2856
+ const splitBzIds = (blocks) => {
2857
+ const processBlocks = (operationBlocks, parentOperationBlock) => {
2858
+ let processIds = [];
2859
+ operationBlocks.forEach((operationBlock) => {
2860
+ const fieldCount = Object.keys(operationBlock).filter((key) => !key.startsWith("$")).length;
2861
+ if (Array.isArray(operationBlock.$id) && fieldCount > 0) {
2862
+ const splitBlocksById = operationBlock.$id.map((id) => {
2863
+ return { ...operationBlock, $id: id };
2864
+ });
2865
+ processIds = [...processIds, ...splitBlocksById];
2866
+ } else {
2867
+ processIds.push(operationBlock);
2868
+ }
2869
+ });
2870
+ let newOperationBlocks = [];
2871
+ const fieldsWithoutMultiples = [];
2872
+ const fieldsWithMultiples = processIds.filter((operationBlock) => {
2873
+ const ops2 = ["delete", "update", "unlink"];
2874
+ const isCorrectOp = ops2.includes(operationBlock.$op || "");
2875
+ const fieldCount = Object.keys(operationBlock).filter((key) => !key.startsWith("$")).length;
2876
+ const isMultiple = !operationBlock.$id || Array.isArray(operationBlock.$id) && fieldCount > 0 || operationBlock.$filter;
2877
+ if (isMultiple && isCorrectOp) {
2878
+ return true;
2879
+ } else {
2880
+ fieldsWithoutMultiples.push(operationBlock);
2881
+ }
2882
+ });
2883
+ if (fieldsWithMultiples.length > 0) {
2884
+ fieldsWithMultiples.forEach((opBlock) => {
2885
+ const getAllKeyCombinations = (obj) => {
2886
+ const allKeys = Object.keys(obj);
2887
+ const combinableKeys = allKeys.filter((key) => !key.startsWith("$"));
2888
+ const allCombinations2 = [];
2889
+ const generateCombinations = (index, currentObj) => {
2890
+ if (index === combinableKeys.length) {
2891
+ const fullObj = { ...currentObj };
2892
+ allKeys.forEach((key) => {
2893
+ if (key.startsWith("$")) {
2894
+ fullObj[key] = obj[key];
2895
+ }
2896
+ });
2897
+ allCombinations2.push(fullObj);
2898
+ return;
2899
+ }
2900
+ const newObjInclude = { ...currentObj, [combinableKeys[index]]: obj[combinableKeys[index]] };
2901
+ generateCombinations(index + 1, newObjInclude);
2902
+ generateCombinations(index + 1, currentObj);
2903
+ };
2904
+ generateCombinations(0, {});
2905
+ return allCombinations2;
2906
+ };
2907
+ const allCombinations = getAllKeyCombinations(opBlock).filter(
2908
+ (opBlock2) => !(opBlock2.$op === "update" && Object.keys(opBlock2).filter((key) => !key.startsWith("$")).length === 0)
2909
+ );
2910
+ let included = [];
2911
+ const emptyObjCKey = objectPathToKey(opBlock.$objectPath);
2912
+ const cacheR = cache[emptyObjCKey];
2913
+ let remaining = cacheR ? cache[emptyObjCKey].$ids : [];
2914
+ const combinationsFromCache = allCombinations.map((combination, index) => {
2915
+ const _currentSchema = getCurrentSchema(schema, combination);
2916
+ const combinableKeys = Object.keys(combination).filter(
2917
+ (fieldKey) => !fieldKey.includes("$") && !_currentSchema.dataFields?.some((o) => o.path === fieldKey)
2918
+ );
2919
+ const cachesFound = combinableKeys.map((key) => {
2920
+ const multiples = Array.isArray(combination[key]) ? combination[key].length > 1 ? combination[key].filter(
2921
+ (opBlock2) => !opBlock2.$id || Array.isArray(opBlock2.$id) || opBlock2.$filter
2922
+ ) : combination[key] : [combination[key]];
2923
+ const processedMultiples = multiples.map((multiple) => {
2924
+ const cKey = objectPathToKey(multiple.$objectPath);
2925
+ const getIdsToKey = (searchKey) => {
2926
+ const ids = [];
2927
+ const searchSegments = searchKey.split(".");
2928
+ const starting = searchSegments.slice(0, searchSegments.length - 1).join(".");
2929
+ const ending = searchSegments.slice(searchSegments.length - 1, searchSegments.length)[0].split("___")[1];
2930
+ for (const key2 in cache) {
2931
+ if (key2.startsWith(starting) && key2.endsWith(ending)) {
2932
+ const searchSegments2 = key2.split(".");
2933
+ const id = searchSegments2.slice(searchSegments2.length - 1, searchSegments2.length)[0].split("___")[0];
2934
+ ids.push(id);
2935
+ }
2936
+ }
2937
+ return ids;
2938
+ };
2939
+ const idsToKey = getIdsToKey(cKey);
2940
+ return { idsToKey, key, multiple };
2941
+ });
2942
+ return processedMultiples;
2943
+ }).filter((key) => key !== void 0);
2944
+ const findCommonIds = (data) => {
2945
+ const preppedArray = data.map((operations) => {
2946
+ const ids = operations.map((operation) => {
2947
+ return operation.idsToKey;
2948
+ });
2949
+ return ids;
2950
+ });
2951
+ const findCommonElements = (arr) => {
2952
+ if (arr.length > 0) {
2953
+ const flatArray = arr.reduce((acc, val) => acc.concat(val), []);
2954
+ return flatArray.reduce((acc, subArr) => {
2955
+ if (!acc) {
2956
+ return subArr;
2957
+ }
2958
+ return subArr.filter((item) => acc.includes(item));
2959
+ });
2960
+ } else {
2961
+ return [];
2962
+ }
2963
+ };
2964
+ return findCommonElements(preppedArray);
2965
+ };
2966
+ const commonIds = findCommonIds(cachesFound);
2967
+ const filteredCommonIds = commonIds.filter((id) => !included.includes(id));
2968
+ included = [...included, ...filteredCommonIds];
2969
+ remaining = remaining.filter((id) => !filteredCommonIds.includes(id));
2970
+ if (index === allCombinations.length - 1 && remaining.length > 0) {
2971
+ const newOp = {
2972
+ ...combination,
2973
+ $id: remaining
2974
+ };
2975
+ return newOp;
2976
+ } else if (filteredCommonIds.length > 0) {
2977
+ const newOp = {
2978
+ ...combination,
2979
+ $id: filteredCommonIds
2980
+ };
2981
+ return newOp;
2982
+ }
2983
+ }).filter((combination) => combination !== void 0);
2984
+ const returnFields = combinationsFromCache.length === 0 && !parentOperationBlock?.$id ? fieldsWithMultiples : combinationsFromCache;
2985
+ newOperationBlocks = [...fieldsWithoutMultiples, ...returnFields].map(processOperationBlock);
2986
+ });
2987
+ } else {
2988
+ newOperationBlocks = processIds.map(processOperationBlock);
2989
+ }
2990
+ return newOperationBlocks;
2991
+ };
2992
+ const processOperationBlock = (operationBlock) => {
2993
+ const newBlock = { ...operationBlock, $bzId: `T_${(0, import_uuid3.v4)()}` };
2994
+ const currentSchema = getCurrentSchema(schema, operationBlock);
2995
+ Object.keys(operationBlock).filter((fieldKey) => !fieldKey.includes("$") && !currentSchema.dataFields?.some((o) => o.path === fieldKey)).forEach((fieldKey) => {
2996
+ const operationBlocks = Array.isArray(operationBlock[fieldKey]) ? operationBlock[fieldKey] : [operationBlock[fieldKey]];
2997
+ const newOperationBlocks = processBlocks(operationBlocks, operationBlock);
2998
+ newBlock[fieldKey] = newOperationBlocks;
2999
+ });
3000
+ return newBlock;
3001
+ };
3002
+ let newBlocks = [];
3003
+ blocks.forEach((block) => {
3004
+ newBlocks = [...newBlocks, ...processBlocks([block])];
3005
+ });
3006
+ const splitBlocks = newBlocks.map(processOperationBlock);
3007
+ return splitBlocks;
3008
+ };
3009
+ const splitBql = splitBzIds(Array.isArray(bqlWithObjectPaths) ? bqlWithObjectPaths : [bqlWithObjectPaths]);
3010
+ const processReplaces = (blocks) => {
3011
+ return blocks.map((block) => {
3012
+ const fields = getFieldKeys(block, true);
3013
+ const newBlock = { ...block };
3014
+ fields.forEach((field) => {
3015
+ const opBlocks = Array.isArray(block[field]) ? block[field] : [block[field]];
3016
+ const newOpBlocks = [];
3017
+ opBlocks.forEach((opBlock) => {
3018
+ if (opBlock.$op === "replace") {
3019
+ const cacheKey = objectPathToKey(opBlock.$objectPath);
3020
+ const cacheKeys = convertManyPaths(cacheKey);
3021
+ const foundKeys = cacheKeys.map((cacheKey2) => {
3022
+ return cache[cacheKey2];
3023
+ });
3024
+ const cacheFound = foundKeys.length === cacheKeys.length;
3025
+ const linksToNotInclude = [];
3026
+ if (cacheFound) {
3027
+ foundKeys.forEach((foundKey) => {
3028
+ if (foundKey) {
3029
+ const unlinkIds = [];
3030
+ foundKey.$ids.filter((id) => {
3031
+ linksToNotInclude.push(id);
3032
+ return id !== opBlock.$id;
3033
+ }).forEach((id) => {
3034
+ unlinkIds.push(id);
3035
+ });
3036
+ newOpBlocks.push({ ...opBlock, $op: "unlink", $id: unlinkIds, $bzId: `T_${(0, import_uuid3.v4)()}` });
3037
+ }
3038
+ });
3039
+ }
3040
+ if (Array.isArray(opBlock.$id) ? !opBlock.$id.every((id) => linksToNotInclude.includes(id)) : (
3041
+ // @ts-expect-error todo
3042
+ !linksToNotInclude.includes(opBlock.$id)
3043
+ )) {
3044
+ newOpBlocks.push({ ...opBlock, $op: "link", $bzId: `T_${(0, import_uuid3.v4)()}` });
3045
+ }
3046
+ } else {
3047
+ newOpBlocks.push(opBlock);
3048
+ }
3049
+ });
3050
+ newBlock[field] = processReplaces(newOpBlocks);
3051
+ });
3052
+ return newBlock;
3053
+ });
3054
+ };
3055
+ const processedReplaces = fillObjectPaths(processReplaces(fillObjectPaths(splitBql)));
3056
+ const throwErrors = (blocks) => {
3057
+ return (0, import_immer5.produce)(
3058
+ blocks,
3059
+ (draft) => (0, import_object_traversal6.traverse)(draft, (context) => {
3060
+ const { key, value, parent } = context;
3061
+ if (key && parent && !key?.includes("$") && (Array.isArray(value) || (0, import_radash10.isObject)(value)) && !Array.isArray(parent)) {
3062
+ const values = Array.isArray(value) ? value : [value];
3063
+ values.forEach((thing) => {
3064
+ const parentSchema = getCurrentSchema(schema, parent);
3065
+ const findCardinality = () => {
3066
+ const dataFieldFound = parentSchema.dataFields?.find((field) => field.path === thing.$objectPath.key);
3067
+ if (dataFieldFound) {
3068
+ return dataFieldFound.cardinality;
3069
+ }
3070
+ const linkFieldFound = parentSchema.linkFields?.find((field) => field.path === thing.$objectPath.key);
3071
+ if (linkFieldFound) {
3072
+ return linkFieldFound.cardinality;
3073
+ }
3074
+ const roleFieldFound = parentSchema.roles?.[thing.$objectPath.key];
3075
+ if (linkFieldFound) {
3076
+ return roleFieldFound.cardinality;
3077
+ }
3078
+ };
3079
+ const cacheFound = cache[objectPathToKey(thing.$objectPath)];
3080
+ const processArrayIdsFound = (arrayOfIds, cacheOfIds) => {
3081
+ return arrayOfIds.every((id) => cacheOfIds.includes(id));
3082
+ };
3083
+ const isOccupied = thing.$id ? Array.isArray(thing.$id) ? (
3084
+ // @ts-expect-error todo
3085
+ processArrayIdsFound(thing.$id, cacheFound.$ids)
3086
+ ) : (
3087
+ // @ts-expect-error todo
3088
+ cacheFound?.$ids.includes(thing.$id)
3089
+ ) : cacheFound;
3090
+ const cardinality = findCardinality();
3091
+ if (thing.$op === "link" && isOccupied && cardinality === "ONE") {
3092
+ throw new Error(
3093
+ `[BQLE-Q-M-2] Cannot link on:"${objectPathToKey(thing.$objectPath)}" because it is already occupied.`
3094
+ );
3095
+ }
3096
+ if (thing.$op) {
3097
+ switch (thing.$op) {
3098
+ case "delete":
3099
+ if (!isOccupied) {
3100
+ if (!config.mutation?.ignoreNonexistingThings) {
3101
+ throw new Error(
3102
+ `[BQLE-Q-M-2] Cannot delete $id:"${thing.$id}" because it is not linked to $id:"${parent.$id}"`
3103
+ );
3104
+ } else {
3105
+ }
3106
+ }
3107
+ break;
3108
+ case "update":
3109
+ if (!isOccupied) {
3110
+ if (!config.mutation?.ignoreNonexistingThings) {
3111
+ throw new Error(
3112
+ `[BQLE-Q-M-2] Cannot update $id:"${thing.$id}" because it is not linked to $id:"${parent.$id}"`
3113
+ );
3114
+ }
3115
+ }
3116
+ break;
3117
+ case "unlink":
3118
+ if (!isOccupied) {
3119
+ if (!config.mutation?.ignoreNonexistingThings) {
3120
+ throw new Error(
3121
+ `[BQLE-Q-M-2] Cannot unlink $id:"${thing.$id}" because it is not linked to $id:"${parent.$id}"`
3122
+ );
3123
+ }
3124
+ }
3125
+ break;
3126
+ case "link":
3127
+ if (isOccupied) {
3128
+ throw new Error(
3129
+ `[BQLE-Q-M-2] Cannot link $id:"${thing.$id}" because it is already linked to $id:"${parent.$id}"`
3130
+ );
3131
+ }
3132
+ break;
3133
+ default:
3134
+ break;
3135
+ }
3136
+ }
3137
+ });
3138
+ }
3139
+ })
3140
+ );
3141
+ };
3142
+ throwErrors(processedReplaces);
3143
+ const fillPaths = (blocks) => {
3144
+ return (0, import_immer5.produce)(
3145
+ blocks,
3146
+ (draft) => (0, import_object_traversal6.traverse)(draft, (context) => {
3147
+ const { parent, key, value, meta } = context;
3148
+ if ((0, import_radash10.isObject)(value)) {
3149
+ value[Symbol.for("path")] = meta.nodePath;
3150
+ delete value.$objectPath;
3151
+ delete value.$parentIsCreate;
3152
+ }
3153
+ if (key && parent && !key?.includes("$") && (Array.isArray(value) || (0, import_radash10.isObject)(value)) && !Array.isArray(parent)) {
3154
+ const values = Array.isArray(value) ? value : [value];
3155
+ values.forEach((val) => {
3156
+ if ((0, import_radash10.isObject)(val)) {
3157
+ val[Symbol.for("parent")] = {
3158
+ // @ts-expect-error todo
3159
+ ...value[Symbol.for("parent")],
3160
+ path: parent[Symbol.for("path")]
3161
+ };
3162
+ }
3163
+ });
3164
+ }
3165
+ })
3166
+ );
3167
+ };
3168
+ const final = fillPaths(processedReplaces);
3169
+ console.log("final", JSON.stringify(final, null, 2));
3170
+ req.filledBqlRequest = final;
3171
+ };
3172
+
3173
+ // src/pipeline/pipeline.ts
3174
+ var Pipelines = {
3175
+ query: [enrichBQLQuery, newBuildTQLQuery, newRunTQLQuery, parseTQLQuery],
3176
+ mutation: [
3177
+ fillBQLMutation,
3178
+ newPreQuery,
3179
+ parseBQLMutation,
3180
+ buildTQLMutation,
3181
+ runTQLMutation,
3182
+ parseTQLMutation,
3183
+ buildBQLTree
3184
+ ]
3185
+ };
3186
+ var runPipeline = async (pipeline, req, res = {}, root = true) => {
3187
+ for (const operation of pipeline) {
3188
+ const next = await operation(req, res);
3189
+ if (next && Array.isArray(next)) {
3190
+ for (const nextPipeline of next) {
3191
+ await runPipeline(nextPipeline.pipeline, nextPipeline.req, nextPipeline.res, false);
3192
+ }
3193
+ }
3194
+ }
3195
+ if (root) {
3196
+ if (req.config.query?.debugger === true && typeof res.bqlRes === "object") {
3197
+ return { ...res.bqlRes, $debugger: { tqlRequest: req.tqlRequest } };
3198
+ }
3199
+ return res.bqlRes;
3200
+ }
3201
+ return res.bqlRes;
3202
+ };
3203
+ var queryPipeline = (bqlRequest, bormConfig, bormSchema, dbHandles) => runPipeline(
3204
+ Pipelines.query,
3205
+ {
3206
+ config: bormConfig,
3207
+ schema: bormSchema,
3208
+ rawBqlRequest: bqlRequest,
3209
+ dbHandles
3210
+ },
3211
+ {}
3212
+ );
3213
+ var mutationPipeline = (bqlRequest, bormConfig, bormSchema, dbHandles) => runPipeline(
3214
+ Pipelines.mutation,
3215
+ {
3216
+ config: bormConfig,
3217
+ schema: bormSchema,
3218
+ rawBqlRequest: bqlRequest,
3219
+ dbHandles
3220
+ },
3221
+ {}
3222
+ );
3223
+
3224
+ // src/index.ts
3225
+ var BormClient = class {
3226
+ schema;
3227
+ config;
3228
+ dbHandles;
3229
+ constructor({ schema, config }) {
3230
+ this.schema = schema;
3231
+ this.config = config;
3232
+ }
3233
+ init = async () => {
3234
+ const dbHandles = { typeDB: /* @__PURE__ */ new Map() };
3235
+ const enrichedSchema = enrichSchema(this.schema);
3236
+ await Promise.all(
3237
+ this.config.dbConnectors.map(async (dbc) => {
3238
+ if (dbc.provider === "typeDB" && dbc.dbName) {
3239
+ const [clientErr, client] = await (0, import_radash11.tryit)(import_typedb_driver5.TypeDB.coreDriver)(dbc.url);
3240
+ if (clientErr) {
3241
+ const message = `[BORM:${dbc.provider}:${dbc.dbName}:core] ${// clientErr.messageTemplate?._messageBody() ?? "Can't create TypeDB Client"
3242
+ clientErr.message ?? "Can't create TypeDB Client"}`;
3243
+ throw new Error(message);
3244
+ }
3245
+ try {
3246
+ const session = await client.session(dbc.dbName, import_typedb_driver5.SessionType.DATA);
3247
+ dbHandles.typeDB.set(dbc.id, { client, session });
3248
+ } catch (sessionErr) {
3249
+ const message = `[BORM:${dbc.provider}:${dbc.dbName}:session] ${// eslint-disable-next-line no-underscore-dangle
3250
+ (sessionErr.messageTemplate?._messageBody() || sessionErr.message) ?? "Can't create TypeDB Session"}`;
3251
+ throw new Error(message);
3252
+ }
3253
+ }
3254
+ if (dbc.provider === "typeDBCluster" && dbc.dbName) {
3255
+ const [clientErr, client] = await (0, import_radash11.tryit)(import_typedb_driver5.TypeDB.enterpriseDriver)(dbc.addresses, dbc.credentials);
3256
+ if (clientErr) {
3257
+ const message = `[BORM:${dbc.provider}:${dbc.dbName}:core] ${// clientErr.messageTemplate?._messageBody() ?? "Can't create TypeDB Client"
3258
+ clientErr.message ?? "Can't create TypeDB Cluster Client"}`;
3259
+ throw new Error(message);
3260
+ }
3261
+ try {
3262
+ const session = await client.session(dbc.dbName, import_typedb_driver5.SessionType.DATA);
3263
+ dbHandles.typeDB.set(dbc.id, { client, session });
3264
+ } catch (sessionErr) {
3265
+ const message = `[BORM:${dbc.provider}:${dbc.dbName}:session] ${// eslint-disable-next-line no-underscore-dangle
3266
+ (sessionErr.messageTemplate?._messageBody() || sessionErr.message) ?? "Can't create TypeDB Session"}`;
3267
+ throw new Error(message);
3268
+ }
3269
+ }
3270
+ })
3271
+ );
3272
+ this.schema = enrichedSchema;
3273
+ this.dbHandles = dbHandles;
3274
+ };
3275
+ #enforceConnection = async () => {
3276
+ if (!this.dbHandles) {
3277
+ await this.init();
3278
+ if (!this.dbHandles) {
3279
+ throw new Error("Can't init BormClient");
3280
+ }
3281
+ }
3282
+ };
3283
+ introspect = async () => {
3284
+ await this.#enforceConnection();
3285
+ return this.schema;
3286
+ };
3287
+ define = async () => {
3288
+ await this.#enforceConnection();
3289
+ return bormDefine(this.config, this.schema, this.dbHandles);
3290
+ };
3291
+ /// no types yet, but we can do "as ..." after getting the type fro the schema
3292
+ query = async (query, queryConfig) => {
3293
+ await this.#enforceConnection();
3294
+ const qConfig = {
3295
+ ...this.config,
3296
+ query: { ...defaultConfig.query, ...this.config.query, ...queryConfig }
3297
+ };
3298
+ return queryPipeline(query, qConfig, this.schema, this.dbHandles);
3299
+ };
3300
+ mutate = async (mutation, mutationConfig) => {
3301
+ await this.#enforceConnection();
3302
+ const mConfig = {
3303
+ ...this.config,
3304
+ mutation: {
3305
+ ...defaultConfig.mutation,
3306
+ ...this.config.mutation,
3307
+ ...mutationConfig
3308
+ }
3309
+ };
3310
+ return mutationPipeline(mutation, mConfig, this.schema, this.dbHandles);
3311
+ };
3312
+ close = async () => {
3313
+ if (!this.dbHandles) {
3314
+ return;
3315
+ }
3316
+ this.dbHandles.typeDB.forEach(async ({ client, session }) => {
3317
+ console.log("Closing session");
3318
+ await session.close();
3319
+ console.log("Closing client");
3320
+ await client.close();
3321
+ });
3322
+ };
3323
+ };
3324
+ var src_default = BormClient;
3325
+ //! reads all the insertions and gets the first match. This means each id must be unique
3326
+ //! disabled as it has false positives
3327
+ //# sourceMappingURL=index.js.map