@thomasfosterau/effect-rdf 0.0.0-stage → 0.1.0
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/LICENSE +21 -0
- package/README.md +2251 -2
- package/dist/Algebra-CGG4oae3.mjs +433 -0
- package/dist/Algebra-CGG4oae3.mjs.map +1 -0
- package/dist/Algebra-uGsIEOUA.d.mts +446 -0
- package/dist/Ast-CPRZmBvk.mjs +552 -0
- package/dist/Ast-CPRZmBvk.mjs.map +1 -0
- package/dist/Ast-vcw2W-lf.d.mts +827 -0
- package/dist/Bindings-Ck3m7JRC.mjs +249 -0
- package/dist/Bindings-Ck3m7JRC.mjs.map +1 -0
- package/dist/Bindings-DiKpBd7f.d.mts +153 -0
- package/dist/ClientErrors-CpXdFX5u.mjs +128 -0
- package/dist/ClientErrors-CpXdFX5u.mjs.map +1 -0
- package/dist/ClientErrors-D4IZHUM-.d.mts +101 -0
- package/dist/ClientFormats-CXomkXLV.mjs +73 -0
- package/dist/ClientFormats-CXomkXLV.mjs.map +1 -0
- package/dist/ClientFormats-Dm57ZPwR.d.mts +36 -0
- package/dist/Csv2Json-DynEcwCh.mjs +194 -0
- package/dist/Csv2Json-DynEcwCh.mjs.map +1 -0
- package/dist/Csv2Json-aXNVDoXQ.d.mts +40 -0
- package/dist/Csv2Rdf-8maXP6mt.d.mts +41 -0
- package/dist/Csv2Rdf-DuSEkaKE.mjs +161 -0
- package/dist/Csv2Rdf-DuSEkaKE.mjs.map +1 -0
- package/dist/Dataset-BlmlcI7J.mjs +782 -0
- package/dist/Dataset-BlmlcI7J.mjs.map +1 -0
- package/dist/Dataset-DS3ESOcO.d.mts +426 -0
- package/dist/Dataset.d.mts +2 -0
- package/dist/Dataset.mjs +1 -0
- package/dist/Datatype-CxMpamHC.d.mts +212 -0
- package/dist/Datatype-DQvkNkiH.mjs +1001 -0
- package/dist/Datatype-DQvkNkiH.mjs.map +1 -0
- package/dist/Dialect-8ChFj5EX.d.mts +113 -0
- package/dist/Dialect-CzVH38uo.mjs +165 -0
- package/dist/Dialect-CzVH38uo.mjs.map +1 -0
- package/dist/DocumentLoader-D3lZREnB.mjs +346 -0
- package/dist/DocumentLoader-D3lZREnB.mjs.map +1 -0
- package/dist/DocumentLoader-ZUCEVrW5.d.mts +178 -0
- package/dist/DublinCore-AnwqxRx6.mjs +137 -0
- package/dist/DublinCore-AnwqxRx6.mjs.map +1 -0
- package/dist/DublinCore-Dq-tVA5d.d.mts +119 -0
- package/dist/Engine-CYPB3g4h.d.mts +144 -0
- package/dist/Engine-DF8PN7g-.mjs +872 -0
- package/dist/Engine-DF8PN7g-.mjs.map +1 -0
- package/dist/Errors-CMdV1RhU.mjs +37 -0
- package/dist/Errors-CMdV1RhU.mjs.map +1 -0
- package/dist/Errors-u2bDjUeM.d.mts +30 -0
- package/dist/Evaluator-DEsU4d1o.d.mts +50 -0
- package/dist/Evaluator-DOY2-guC.mjs +281 -0
- package/dist/Evaluator-DOY2-guC.mjs.map +1 -0
- package/dist/Exif-CpqniYQd.d.mts +78 -0
- package/dist/Exif-DjkCfEB-.mjs +89 -0
- package/dist/Exif-DjkCfEB-.mjs.map +1 -0
- package/dist/Expression-BIMMvduQ.mjs +230 -0
- package/dist/Expression-BIMMvduQ.mjs.map +1 -0
- package/dist/Expression-W8A9cyX7.d.mts +89 -0
- package/dist/Extract-Bop85jES.mjs +220 -0
- package/dist/Extract-Bop85jES.mjs.map +1 -0
- package/dist/Extract-C_pCvuTC.d.mts +88 -0
- package/dist/Federation-BcNrozc1.d.mts +52 -0
- package/dist/Federation-CHScBkaK.mjs +130 -0
- package/dist/Federation-CHScBkaK.mjs.map +1 -0
- package/dist/Functions-AvjNcId_.mjs +1346 -0
- package/dist/Functions-AvjNcId_.mjs.map +1 -0
- package/dist/Functions-OQJZP-F6.d.mts +111 -0
- package/dist/Generator-C52mmq01.d.mts +50 -0
- package/dist/Generator-D3utCJC7.mjs +205 -0
- package/dist/Generator-D3utCJC7.mjs.map +1 -0
- package/dist/Grammar-CPlSxGH6.mjs +200 -0
- package/dist/Grammar-CPlSxGH6.mjs.map +1 -0
- package/dist/Grammar-CRhnRoCu.d.mts +148 -0
- package/dist/Grammar-D6jZdJQ3.d.mts +169 -0
- package/dist/Grammar-mQ8CgE1M.mjs +258 -0
- package/dist/Grammar-mQ8CgE1M.mjs.map +1 -0
- package/dist/GraphStore-DhUa4nFO.d.mts +45 -0
- package/dist/GraphStore-DvbqwKy1.mjs +212 -0
- package/dist/GraphStore-DvbqwKy1.mjs.map +1 -0
- package/dist/Iri-BB8Ks-BF.d.mts +84 -0
- package/dist/Iri-Cr92gsQV.mjs +232 -0
- package/dist/Iri-Cr92gsQV.mjs.map +1 -0
- package/dist/Iri.d.mts +2 -0
- package/dist/Iri.mjs +1 -0
- package/dist/Isomorphism-B6qTY-xy.d.mts +28 -0
- package/dist/Isomorphism-BmqxhKyJ.mjs +232 -0
- package/dist/Isomorphism-BmqxhKyJ.mjs.map +1 -0
- package/dist/Isomorphism-DInKnWIy.mjs +390 -0
- package/dist/Isomorphism-DInKnWIy.mjs.map +1 -0
- package/dist/Isomorphism-DvSfZXLR.d.mts +37 -0
- package/dist/Isomorphism.d.mts +2 -0
- package/dist/Isomorphism.mjs +1 -0
- package/dist/JsonLd-DOwS2FHg.mjs +2836 -0
- package/dist/JsonLd-DOwS2FHg.mjs.map +1 -0
- package/dist/JsonLd-DobFrQNa.d.mts +242 -0
- package/dist/JsonLdError-C9J-BxfG.mjs +106 -0
- package/dist/JsonLdError-C9J-BxfG.mjs.map +1 -0
- package/dist/JsonLdError-DSOfHkOy.d.mts +43 -0
- package/dist/LanguageTag-BCu8rcmX.d.mts +38 -0
- package/dist/LanguageTag-BcOpMGZ4.mjs +89 -0
- package/dist/LanguageTag-BcOpMGZ4.mjs.map +1 -0
- package/dist/LanguageTag.d.mts +2 -0
- package/dist/LanguageTag.mjs +1 -0
- package/dist/Lexical-Cg0JHrf6.mjs +243 -0
- package/dist/Lexical-Cg0JHrf6.mjs.map +1 -0
- package/dist/Lexical-D3zySYVS.d.mts +163 -0
- package/dist/Manifest-B6xf6mUc.mjs +148 -0
- package/dist/Manifest-B6xf6mUc.mjs.map +1 -0
- package/dist/Manifest-DQUMRBFr.d.mts +98 -0
- package/dist/Mapping-BgG74x3U.d.mts +63 -0
- package/dist/Mapping-Dc1ZGirk.mjs +259 -0
- package/dist/Mapping-Dc1ZGirk.mjs.map +1 -0
- package/dist/Mcp-1DwTTKOK.mjs +48 -0
- package/dist/Mcp-1DwTTKOK.mjs.map +1 -0
- package/dist/Mcp-d-pX9erx.d.mts +25 -0
- package/dist/Message-CK_DGQuu.mjs +95 -0
- package/dist/Message-CK_DGQuu.mjs.map +1 -0
- package/dist/Message-fIvTJSXM.d.mts +49 -0
- package/dist/Metadata-BbffwGDZ.mjs +445 -0
- package/dist/Metadata-BbffwGDZ.mjs.map +1 -0
- package/dist/Metadata-CEt3yc1-.d.mts +901 -0
- package/dist/Metadata-D4HsQNXr.mjs +1273 -0
- package/dist/Metadata-D4HsQNXr.mjs.map +1 -0
- package/dist/Metadata-nzS7QKRj.d.mts +350 -0
- package/dist/Model-DaMmxurZ.d.mts +293 -0
- package/dist/Model-DlPzRYhF.mjs +528 -0
- package/dist/Model-DlPzRYhF.mjs.map +1 -0
- package/dist/N3-BzyV-KIH.mjs +974 -0
- package/dist/N3-BzyV-KIH.mjs.map +1 -0
- package/dist/N3-DSLnonDn.d.mts +100 -0
- package/dist/NQuads-C1VBOJ3-.mjs +117 -0
- package/dist/NQuads-C1VBOJ3-.mjs.map +1 -0
- package/dist/NQuads-FjFZikFg.d.mts +76 -0
- package/dist/NTriples-D-kLSEAf.mjs +120 -0
- package/dist/NTriples-D-kLSEAf.mjs.map +1 -0
- package/dist/NTriples-D34OspfW.d.mts +76 -0
- package/dist/Namespace-ClTUO_ya.d.mts +42 -0
- package/dist/Namespace-DHFIsORd.mjs +75 -0
- package/dist/Namespace-DHFIsORd.mjs.map +1 -0
- package/dist/Namespace.d.mts +2 -0
- package/dist/Namespace.mjs +1 -0
- package/dist/Namespaces-Bz85vpjW.mjs +235 -0
- package/dist/Namespaces-Bz85vpjW.mjs.map +1 -0
- package/dist/Namespaces-C1jW6EDo.d.mts +178 -0
- package/dist/Optimizer-BWWQRQPY.mjs +168 -0
- package/dist/Optimizer-BWWQRQPY.mjs.map +1 -0
- package/dist/Optimizer-DUpUow6k.d.mts +26 -0
- package/dist/Options-BLBGL4HE.mjs +72 -0
- package/dist/Options-BLBGL4HE.mjs.map +1 -0
- package/dist/Options-BommQwP9.d.mts +127 -0
- package/dist/Packet-CA76wVX3.mjs +197 -0
- package/dist/Packet-CA76wVX3.mjs.map +1 -0
- package/dist/Packet-Cy5g6XuW.d.mts +130 -0
- package/dist/Parser-p1Gyr0QN.d.mts +85 -0
- package/dist/Parser-xARsOWXk.mjs +1317 -0
- package/dist/Parser-xARsOWXk.mjs.map +1 -0
- package/dist/Path-B20Yp8KE.mjs +284 -0
- package/dist/Path-B20Yp8KE.mjs.map +1 -0
- package/dist/Path-DRB8e-Zn.d.mts +181 -0
- package/dist/Pdf-B9RZn--8.d.mts +77 -0
- package/dist/Pdf-CKK6dkZn.mjs +89 -0
- package/dist/Pdf-CKK6dkZn.mjs.map +1 -0
- package/dist/PdfA-CUjSuntT.d.mts +109 -0
- package/dist/PdfA-CleOhuL6.mjs +124 -0
- package/dist/PdfA-CleOhuL6.mjs.map +1 -0
- package/dist/Photoshop-CiHo80qV.mjs +233 -0
- package/dist/Photoshop-CiHo80qV.mjs.map +1 -0
- package/dist/Photoshop-udKZ0I3N.d.mts +204 -0
- package/dist/PrefixMap-BHFPDLO-.mjs +103 -0
- package/dist/PrefixMap-BHFPDLO-.mjs.map +1 -0
- package/dist/PrefixMap-BMlXrWNd.d.mts +64 -0
- package/dist/PrefixMap.d.mts +2 -0
- package/dist/PrefixMap.mjs +1 -0
- package/dist/Processor-CMmecFsb.mjs +198 -0
- package/dist/Processor-CMmecFsb.mjs.map +1 -0
- package/dist/Processor-FJPvO0CB.d.mts +435 -0
- package/dist/Protocol-BA7OkNgp.mjs +202 -0
- package/dist/Protocol-BA7OkNgp.mjs.map +1 -0
- package/dist/Protocol-DlSoiIKB.d.mts +108 -0
- package/dist/ProtocolErrors-Ckfejnl6.d.mts +84 -0
- package/dist/ProtocolErrors-czDPVcX5.mjs +129 -0
- package/dist/ProtocolErrors-czDPVcX5.mjs.map +1 -0
- package/dist/Query-D9A6LOpP.mjs +364 -0
- package/dist/Query-D9A6LOpP.mjs.map +1 -0
- package/dist/Query-KqSkTYyG.d.mts +96 -0
- package/dist/QueryBuilder-BLK9Vfbz.mjs +674 -0
- package/dist/QueryBuilder-BLK9Vfbz.mjs.map +1 -0
- package/dist/QueryBuilder-DUqh4ECe.d.mts +529 -0
- package/dist/RdfJs-D6-49XB5.mjs +86 -0
- package/dist/RdfJs-D6-49XB5.mjs.map +1 -0
- package/dist/RdfJs-DXFqdWrd.d.mts +76 -0
- package/dist/RdfJs.d.mts +2 -0
- package/dist/RdfJs.mjs +1 -0
- package/dist/RdfJson-5aKPDlPS.d.mts +297 -0
- package/dist/RdfJson-BNocgW4f.mjs +548 -0
- package/dist/RdfJson-BNocgW4f.mjs.map +1 -0
- package/dist/RdfXml-DJ9G4gOq.mjs +1014 -0
- package/dist/RdfXml-DJ9G4gOq.mjs.map +1 -0
- package/dist/RdfXml-_N7yxWEp.d.mts +149 -0
- package/dist/Rdfs-BRVPsAjc.d.mts +84 -0
- package/dist/Rdfs-CyY2wVHI.mjs +167 -0
- package/dist/Rdfs-CyY2wVHI.mjs.map +1 -0
- package/dist/Rdfs.d.mts +2 -0
- package/dist/Rdfs.mjs +1 -0
- package/dist/Reasoner-BxYhx9s7.d.mts +94 -0
- package/dist/Reasoner-Cw90zrjv.mjs +798 -0
- package/dist/Reasoner-Cw90zrjv.mjs.map +1 -0
- package/dist/Reification-BmN4EfnM.d.mts +40 -0
- package/dist/Reification-dpqQvjDE.mjs +82 -0
- package/dist/Reification-dpqQvjDE.mjs.map +1 -0
- package/dist/Reification.d.mts +2 -0
- package/dist/Reification.mjs +1 -0
- package/dist/Report-XHs8htzK.mjs +121 -0
- package/dist/Report-XHs8htzK.mjs.map +1 -0
- package/dist/Report-hcXsc_19.d.mts +115 -0
- package/dist/Resource-B1cI8FyJ.d.mts +218 -0
- package/dist/Resource-sIEeNh15.mjs +374 -0
- package/dist/Resource-sIEeNh15.mjs.map +1 -0
- package/dist/Resource.d.mts +2 -0
- package/dist/Resource.mjs +1 -0
- package/dist/Results-BVNEC-Wt.d.mts +277 -0
- package/dist/Results-peJjGA2V.mjs +621 -0
- package/dist/Results-peJjGA2V.mjs.map +1 -0
- package/dist/ResultsStream-BhF0OcNn.mjs +639 -0
- package/dist/ResultsStream-BhF0OcNn.mjs.map +1 -0
- package/dist/ResultsStream-toYMXrOe.d.mts +100 -0
- package/dist/SemAct-CDchtk49.d.mts +96 -0
- package/dist/SemAct-CmyT4yI8.mjs +118 -0
- package/dist/SemAct-CmyT4yI8.mjs.map +1 -0
- package/dist/Serialization-DP9H5bYQ.mjs +514 -0
- package/dist/Serialization-DP9H5bYQ.mjs.map +1 -0
- package/dist/Serialization-Df8iVauT.d.mts +392 -0
- package/dist/Serialization.d.mts +2 -0
- package/dist/Serialization.mjs +1 -0
- package/dist/ServerFormats-CrRnjjf6.mjs +64 -0
- package/dist/ServerFormats-CrRnjjf6.mjs.map +1 -0
- package/dist/ServerFormats-DjC9NsO_.d.mts +36 -0
- package/dist/ServiceDescription-BERsvg-k.d.mts +54 -0
- package/dist/ServiceDescription-Dq5hxeGy.mjs +97 -0
- package/dist/ServiceDescription-Dq5hxeGy.mjs.map +1 -0
- package/dist/ShExC-Ctf-06CL.d.mts +67 -0
- package/dist/ShExC-DJbB19i3.mjs +1181 -0
- package/dist/ShExC-DJbB19i3.mjs.map +1 -0
- package/dist/ShExError-BeYFD9rv.d.mts +61 -0
- package/dist/ShExError-CVtq2NnM.mjs +64 -0
- package/dist/ShExError-CVtq2NnM.mjs.map +1 -0
- package/dist/ShExJ-C1u_wgyD.d.mts +531 -0
- package/dist/ShExJ-COiPd9Xw.mjs +532 -0
- package/dist/ShExJ-COiPd9Xw.mjs.map +1 -0
- package/dist/ShExR-ByR4mCh-.mjs +480 -0
- package/dist/ShExR-ByR4mCh-.mjs.map +1 -0
- package/dist/ShExR-CqONNNBz.d.mts +40 -0
- package/dist/ShapeMap-C422pxKl.d.mts +140 -0
- package/dist/ShapeMap-CsgKxB2G.mjs +181 -0
- package/dist/ShapeMap-CsgKxB2G.mjs.map +1 -0
- package/dist/Shapes-18GjfyBV.mjs +597 -0
- package/dist/Shapes-18GjfyBV.mjs.map +1 -0
- package/dist/Shapes-BQFDFc4Q.d.mts +306 -0
- package/dist/Sparql-BiYFMSpl.mjs +29 -0
- package/dist/Sparql-BiYFMSpl.mjs.map +1 -0
- package/dist/Sparql-DecpWTPh.d.mts +97 -0
- package/dist/SparqlClient-C_CjXbwj.mjs +333 -0
- package/dist/SparqlClient-C_CjXbwj.mjs.map +1 -0
- package/dist/SparqlClient-UPc88SHy.d.mts +290 -0
- package/dist/SparqlServer-CbUW-pVj.d.mts +71 -0
- package/dist/SparqlServer-Db7w7Cll.mjs +308 -0
- package/dist/SparqlServer-Db7w7Cll.mjs.map +1 -0
- package/dist/SqlStore-BBqFx-Wl.mjs +684 -0
- package/dist/SqlStore-BBqFx-Wl.mjs.map +1 -0
- package/dist/SqlStore-CCJo5I-e.d.mts +117 -0
- package/dist/Store-D0jmVfb3.d.mts +166 -0
- package/dist/Store-DH3Ow1GO.mjs +162 -0
- package/dist/Store-DH3Ow1GO.mjs.map +1 -0
- package/dist/Structure-BjMo4Bkc.mjs +334 -0
- package/dist/Structure-BjMo4Bkc.mjs.map +1 -0
- package/dist/Structure-n4CmDiab.d.mts +63 -0
- package/dist/Table-BGgm9nbM.mjs +538 -0
- package/dist/Table-BGgm9nbM.mjs.map +1 -0
- package/dist/Table-C3reiVrb.d.mts +261 -0
- package/dist/Term-B_4ezyXq.d.mts +619 -0
- package/dist/Term-CFLG1qu4.mjs +991 -0
- package/dist/Term-CFLG1qu4.mjs.map +1 -0
- package/dist/Term.d.mts +2 -0
- package/dist/Term.mjs +1 -0
- package/dist/TermCodec-CDZiEztW.mjs +397 -0
- package/dist/TermCodec-CDZiEztW.mjs.map +1 -0
- package/dist/TermCodec-_03bDXr0.d.mts +209 -0
- package/dist/TermCodec.d.mts +2 -0
- package/dist/TermCodec.mjs +1 -0
- package/dist/TermJson-BOPe0yve.d.mts +232 -0
- package/dist/TermJson-FAg3lvjl.mjs +142 -0
- package/dist/TermJson-FAg3lvjl.mjs.map +1 -0
- package/dist/TermJson.d.mts +2 -0
- package/dist/TermJson.mjs +1 -0
- package/dist/TermSchema-Bn9CoaYA.mjs +30 -0
- package/dist/TermSchema-Bn9CoaYA.mjs.map +1 -0
- package/dist/TermSchema-DBO6MroX.d.mts +6 -0
- package/dist/Testing-B-aPCpmu.mjs +63 -0
- package/dist/Testing-B-aPCpmu.mjs.map +1 -0
- package/dist/Testing-CF6s8P3O.d.mts +53 -0
- package/dist/Tiff-CR-2QeSI.d.mts +148 -0
- package/dist/Tiff-DlsOlZPM.mjs +169 -0
- package/dist/Tiff-DlsOlZPM.mjs.map +1 -0
- package/dist/Tools-7MdRKccr.d.mts +583 -0
- package/dist/Tools-ryxphZbI.mjs +329 -0
- package/dist/Tools-ryxphZbI.mjs.map +1 -0
- package/dist/Translate-B0YKKANS.d.mts +37 -0
- package/dist/Translate-gzWPq0Ia.mjs +308 -0
- package/dist/Translate-gzWPq0Ia.mjs.map +1 -0
- package/dist/Translation-DC9rLm2y.mjs +1535 -0
- package/dist/Translation-DC9rLm2y.mjs.map +1 -0
- package/dist/Translation-K4L9XBqX.d.mts +103 -0
- package/dist/TriG-BkqtqZ6Y.mjs +125 -0
- package/dist/TriG-BkqtqZ6Y.mjs.map +1 -0
- package/dist/TriG-xDjdDatp.d.mts +86 -0
- package/dist/Turtle-Bv1_bisW.d.mts +85 -0
- package/dist/Turtle-CZVUOtwl.mjs +133 -0
- package/dist/Turtle-CZVUOtwl.mjs.map +1 -0
- package/dist/ValidationReport-DBdJshW5.mjs +285 -0
- package/dist/ValidationReport-DBdJshW5.mjs.map +1 -0
- package/dist/ValidationReport-Dx3WxY0h.d.mts +192 -0
- package/dist/Validator-227ff9Rn.d.mts +179 -0
- package/dist/Validator-BzXMKDeJ.mjs +1162 -0
- package/dist/Validator-BzXMKDeJ.mjs.map +1 -0
- package/dist/Validator-Dl8cih5V.d.mts +207 -0
- package/dist/Validator-DmUfMbpL.mjs +568 -0
- package/dist/Validator-DmUfMbpL.mjs.map +1 -0
- package/dist/Vocab-DceKywpq.mjs +168 -0
- package/dist/Vocab-DceKywpq.mjs.map +1 -0
- package/dist/Vocab-Df-L-IwZ.d.mts +46 -0
- package/dist/Vocab-Do56UgBX.d.mts +81 -0
- package/dist/Vocab-TfpWG1Ne.mjs +118 -0
- package/dist/Vocab-TfpWG1Ne.mjs.map +1 -0
- package/dist/Vocab.d.mts +2 -0
- package/dist/Vocab.mjs +1 -0
- package/dist/Vocabulary-C6-GPOy4.d.mts +22 -0
- package/dist/Vocabulary-CnQl-_Z4.mjs +179 -0
- package/dist/Vocabulary-CnQl-_Z4.mjs.map +1 -0
- package/dist/Xml-B7iihYCS.mjs +976 -0
- package/dist/Xml-B7iihYCS.mjs.map +1 -0
- package/dist/Xml-CmfHS7SW.d.mts +267 -0
- package/dist/Xmp-D7CKA7MZ.d.mts +111 -0
- package/dist/Xmp-DCGN9pOD.mjs +307 -0
- package/dist/Xmp-DCGN9pOD.mjs.map +1 -0
- package/dist/XmpBasic-CP38jpR_.mjs +73 -0
- package/dist/XmpBasic-CP38jpR_.mjs.map +1 -0
- package/dist/XmpBasic-Cmbe53rQ.d.mts +64 -0
- package/dist/XmpMM-BfL_TgJF.mjs +73 -0
- package/dist/XmpMM-BfL_TgJF.mjs.map +1 -0
- package/dist/XmpMM-Dqm3IX8p.d.mts +63 -0
- package/dist/XmpRights-BKPtoI5L.mjs +73 -0
- package/dist/XmpRights-BKPtoI5L.mjs.map +1 -0
- package/dist/XmpRights-CaALZQz2.d.mts +63 -0
- package/dist/Xsd-Cdgx5zRB.mjs +405 -0
- package/dist/Xsd-Cdgx5zRB.mjs.map +1 -0
- package/dist/Xsd-D2elNhSm.d.mts +187 -0
- package/dist/Xsd.d.mts +2 -0
- package/dist/Xsd.mjs +1 -0
- package/dist/accessors-CEjaojuQ.mjs +28 -0
- package/dist/accessors-CEjaojuQ.mjs.map +1 -0
- package/dist/codec-Lb2T96rv.d.mts +20 -0
- package/dist/codec-QNo7IdJF.mjs +389 -0
- package/dist/codec-QNo7IdJF.mjs.map +1 -0
- package/dist/csvw/Csv2Json.d.mts +2 -0
- package/dist/csvw/Csv2Json.mjs +1 -0
- package/dist/csvw/Csv2Rdf.d.mts +2 -0
- package/dist/csvw/Csv2Rdf.mjs +1 -0
- package/dist/csvw/Datatype.d.mts +2 -0
- package/dist/csvw/Datatype.mjs +1 -0
- package/dist/csvw/Metadata.d.mts +2 -0
- package/dist/csvw/Metadata.mjs +1 -0
- package/dist/csvw/Processor.d.mts +2 -0
- package/dist/csvw/Processor.mjs +1 -0
- package/dist/csvw/Report.d.mts +2 -0
- package/dist/csvw/Report.mjs +1 -0
- package/dist/csvw/Table.d.mts +2 -0
- package/dist/csvw/Table.mjs +1 -0
- package/dist/csvw/index.d.mts +8 -0
- package/dist/csvw/index.mjs +8 -0
- package/dist/index-Cms2TYfC.d.mts +16 -0
- package/dist/index-Ct8xFmRs.d.mts +7 -0
- package/dist/index-D4QFwOjm.d.mts +28 -0
- package/dist/index.d.mts +18 -0
- package/dist/index.mjs +17 -0
- package/dist/jsonld/DocumentLoader.d.mts +2 -0
- package/dist/jsonld/DocumentLoader.mjs +1 -0
- package/dist/jsonld/JsonLd.d.mts +2 -0
- package/dist/jsonld/JsonLd.mjs +1 -0
- package/dist/jsonld/JsonLdError.d.mts +2 -0
- package/dist/jsonld/JsonLdError.mjs +1 -0
- package/dist/jsonld/index.d.mts +4 -0
- package/dist/jsonld/index.mjs +4 -0
- package/dist/lists-D-OpQ0Ir.mjs +77 -0
- package/dist/lists-D-OpQ0Ir.mjs.map +1 -0
- package/dist/loop-D5-gNx9K.mjs +21 -0
- package/dist/loop-D5-gNx9K.mjs.map +1 -0
- package/dist/loop-DZ2hXlr_.mjs +21 -0
- package/dist/loop-DZ2hXlr_.mjs.map +1 -0
- package/dist/n3/Isomorphism.d.mts +2 -0
- package/dist/n3/Isomorphism.mjs +1 -0
- package/dist/n3/Mapping.d.mts +2 -0
- package/dist/n3/Mapping.mjs +1 -0
- package/dist/n3/Model.d.mts +2 -0
- package/dist/n3/Model.mjs +1 -0
- package/dist/n3/N3.d.mts +2 -0
- package/dist/n3/N3.mjs +1 -0
- package/dist/n3/Reasoner.d.mts +2 -0
- package/dist/n3/Reasoner.mjs +2 -0
- package/dist/n3/Vocab.d.mts +2 -0
- package/dist/n3/Vocab.mjs +1 -0
- package/dist/n3/index.d.mts +7 -0
- package/dist/n3/index.mjs +7 -0
- package/dist/ntriples/Grammar.d.mts +2 -0
- package/dist/ntriples/Grammar.mjs +1 -0
- package/dist/ntriples/Lexical.d.mts +2 -0
- package/dist/ntriples/Lexical.mjs +1 -0
- package/dist/ntriples/NQuads.d.mts +2 -0
- package/dist/ntriples/NQuads.mjs +1 -0
- package/dist/ntriples/NTriples.d.mts +2 -0
- package/dist/ntriples/NTriples.mjs +1 -0
- package/dist/ntriples/index.d.mts +5 -0
- package/dist/ntriples/index.mjs +5 -0
- package/dist/rdfjson/RdfJson.d.mts +2 -0
- package/dist/rdfjson/RdfJson.mjs +1 -0
- package/dist/rdfjson/index.d.mts +2 -0
- package/dist/rdfjson/index.mjs +1 -0
- package/dist/rdfxml/RdfXml.d.mts +2 -0
- package/dist/rdfxml/RdfXml.mjs +1 -0
- package/dist/rdfxml/Xml.d.mts +2 -0
- package/dist/rdfxml/Xml.mjs +1 -0
- package/dist/rdfxml/index.d.mts +3 -0
- package/dist/rdfxml/index.mjs +3 -0
- package/dist/rolldown-runtime-D8jQpDG7.mjs +12 -0
- package/dist/serialize-96KBvKaf.mjs +1463 -0
- package/dist/serialize-96KBvKaf.mjs.map +1 -0
- package/dist/serialize-DsoXdM6n.d.mts +37 -0
- package/dist/shacl/Message.d.mts +2 -0
- package/dist/shacl/Message.mjs +1 -0
- package/dist/shacl/Path.d.mts +2 -0
- package/dist/shacl/Path.mjs +1 -0
- package/dist/shacl/Shapes.d.mts +2 -0
- package/dist/shacl/Shapes.mjs +1 -0
- package/dist/shacl/Sparql.d.mts +2 -0
- package/dist/shacl/Sparql.mjs +1 -0
- package/dist/shacl/ValidationReport.d.mts +2 -0
- package/dist/shacl/ValidationReport.mjs +1 -0
- package/dist/shacl/Validator.d.mts +2 -0
- package/dist/shacl/Validator.mjs +1 -0
- package/dist/shacl/Vocabulary.d.mts +2 -0
- package/dist/shacl/Vocabulary.mjs +1 -0
- package/dist/shacl/index.d.mts +9 -0
- package/dist/shacl/index.mjs +8 -0
- package/dist/shex/SemAct.d.mts +2 -0
- package/dist/shex/SemAct.mjs +1 -0
- package/dist/shex/ShExC.d.mts +2 -0
- package/dist/shex/ShExC.mjs +1 -0
- package/dist/shex/ShExError.d.mts +2 -0
- package/dist/shex/ShExError.mjs +1 -0
- package/dist/shex/ShExJ.d.mts +2 -0
- package/dist/shex/ShExJ.mjs +2 -0
- package/dist/shex/ShExR.d.mts +2 -0
- package/dist/shex/ShExR.mjs +1 -0
- package/dist/shex/ShapeMap.d.mts +2 -0
- package/dist/shex/ShapeMap.mjs +1 -0
- package/dist/shex/Structure.d.mts +2 -0
- package/dist/shex/Structure.mjs +2 -0
- package/dist/shex/Validator.d.mts +2 -0
- package/dist/shex/Validator.mjs +4 -0
- package/dist/shex/index.d.mts +9 -0
- package/dist/shex/index.mjs +9 -0
- package/dist/sparql/Algebra.d.mts +2 -0
- package/dist/sparql/Algebra.mjs +1 -0
- package/dist/sparql/Ast.d.mts +2 -0
- package/dist/sparql/Ast.mjs +1 -0
- package/dist/sparql/Bindings.d.mts +2 -0
- package/dist/sparql/Bindings.mjs +1 -0
- package/dist/sparql/ClientErrors.d.mts +2 -0
- package/dist/sparql/ClientErrors.mjs +1 -0
- package/dist/sparql/ClientFormats.d.mts +2 -0
- package/dist/sparql/ClientFormats.mjs +1 -0
- package/dist/sparql/Engine.d.mts +2 -0
- package/dist/sparql/Engine.mjs +1 -0
- package/dist/sparql/Errors.d.mts +2 -0
- package/dist/sparql/Errors.mjs +1 -0
- package/dist/sparql/Expression.d.mts +2 -0
- package/dist/sparql/Expression.mjs +1 -0
- package/dist/sparql/Federation.d.mts +2 -0
- package/dist/sparql/Federation.mjs +1 -0
- package/dist/sparql/Functions.d.mts +2 -0
- package/dist/sparql/Functions.mjs +1 -0
- package/dist/sparql/Generator.d.mts +2 -0
- package/dist/sparql/Generator.mjs +1 -0
- package/dist/sparql/GraphStore.d.mts +2 -0
- package/dist/sparql/GraphStore.mjs +1 -0
- package/dist/sparql/Optimizer.d.mts +2 -0
- package/dist/sparql/Optimizer.mjs +1 -0
- package/dist/sparql/Options.d.mts +2 -0
- package/dist/sparql/Options.mjs +1 -0
- package/dist/sparql/Parser.d.mts +2 -0
- package/dist/sparql/Parser.mjs +1 -0
- package/dist/sparql/Protocol.d.mts +2 -0
- package/dist/sparql/Protocol.mjs +1 -0
- package/dist/sparql/ProtocolErrors.d.mts +2 -0
- package/dist/sparql/ProtocolErrors.mjs +1 -0
- package/dist/sparql/QueryBuilder.d.mts +2 -0
- package/dist/sparql/QueryBuilder.mjs +1 -0
- package/dist/sparql/Results.d.mts +2 -0
- package/dist/sparql/Results.mjs +1 -0
- package/dist/sparql/ResultsStream.d.mts +2 -0
- package/dist/sparql/ResultsStream.mjs +1 -0
- package/dist/sparql/ServerFormats.d.mts +2 -0
- package/dist/sparql/ServerFormats.mjs +1 -0
- package/dist/sparql/ServiceDescription.d.mts +2 -0
- package/dist/sparql/ServiceDescription.mjs +1 -0
- package/dist/sparql/SparqlClient.d.mts +2 -0
- package/dist/sparql/SparqlClient.mjs +1 -0
- package/dist/sparql/SparqlServer.d.mts +2 -0
- package/dist/sparql/SparqlServer.mjs +1 -0
- package/dist/sparql/Store.d.mts +2 -0
- package/dist/sparql/Store.mjs +1 -0
- package/dist/sparql/TermSchema.d.mts +3 -0
- package/dist/sparql/TermSchema.mjs +2 -0
- package/dist/sparql/Testing.d.mts +2 -0
- package/dist/sparql/Testing.mjs +1 -0
- package/dist/sparql/Translate.d.mts +2 -0
- package/dist/sparql/Translate.mjs +1 -0
- package/dist/sparql/ai/Mcp.d.mts +2 -0
- package/dist/sparql/ai/Mcp.mjs +1 -0
- package/dist/sparql/ai/Tools.d.mts +2 -0
- package/dist/sparql/ai/Tools.mjs +1 -0
- package/dist/sparql/ai/index.d.mts +3 -0
- package/dist/sparql/ai/index.mjs +3 -0
- package/dist/sparql/index.d.mts +30 -0
- package/dist/sparql/index.mjs +29 -0
- package/dist/sparql/shacl/Evaluator.d.mts +2 -0
- package/dist/sparql/shacl/Evaluator.mjs +1 -0
- package/dist/sparql/shacl/Query.d.mts +2 -0
- package/dist/sparql/shacl/Query.mjs +1 -0
- package/dist/sparql/shacl/index.d.mts +3 -0
- package/dist/sparql/shacl/index.mjs +3 -0
- package/dist/sparql/sql/Dialect.d.mts +2 -0
- package/dist/sparql/sql/Dialect.mjs +1 -0
- package/dist/sparql/sql/SqlStore.d.mts +2 -0
- package/dist/sparql/sql/SqlStore.mjs +1 -0
- package/dist/sparql/sql/Translation.d.mts +2 -0
- package/dist/sparql/sql/Translation.mjs +1 -0
- package/dist/sparql/sql/index.d.mts +4 -0
- package/dist/sparql/sql/index.mjs +4 -0
- package/dist/stringMap-D5YIpYtR.mjs +38 -0
- package/dist/stringMap-D5YIpYtR.mjs.map +1 -0
- package/dist/tokens-C6BzeodQ.mjs +24 -0
- package/dist/tokens-C6BzeodQ.mjs.map +1 -0
- package/dist/turtle/Grammar.d.mts +3 -0
- package/dist/turtle/Grammar.mjs +3 -0
- package/dist/turtle/Manifest.d.mts +2 -0
- package/dist/turtle/Manifest.mjs +1 -0
- package/dist/turtle/TriG.d.mts +2 -0
- package/dist/turtle/TriG.mjs +1 -0
- package/dist/turtle/Turtle.d.mts +2 -0
- package/dist/turtle/Turtle.mjs +1 -0
- package/dist/turtle/index.d.mts +5 -0
- package/dist/turtle/index.mjs +5 -0
- package/dist/xmp/DublinCore.d.mts +2 -0
- package/dist/xmp/DublinCore.mjs +1 -0
- package/dist/xmp/Exif.d.mts +2 -0
- package/dist/xmp/Exif.mjs +1 -0
- package/dist/xmp/Extract.d.mts +2 -0
- package/dist/xmp/Extract.mjs +1 -0
- package/dist/xmp/Metadata.d.mts +2 -0
- package/dist/xmp/Metadata.mjs +1 -0
- package/dist/xmp/Namespaces.d.mts +2 -0
- package/dist/xmp/Namespaces.mjs +1 -0
- package/dist/xmp/Packet.d.mts +2 -0
- package/dist/xmp/Packet.mjs +1 -0
- package/dist/xmp/Pdf.d.mts +2 -0
- package/dist/xmp/Pdf.mjs +1 -0
- package/dist/xmp/PdfA.d.mts +2 -0
- package/dist/xmp/PdfA.mjs +1 -0
- package/dist/xmp/Photoshop.d.mts +2 -0
- package/dist/xmp/Photoshop.mjs +1 -0
- package/dist/xmp/Tiff.d.mts +2 -0
- package/dist/xmp/Tiff.mjs +1 -0
- package/dist/xmp/Xmp.d.mts +2 -0
- package/dist/xmp/Xmp.mjs +3 -0
- package/dist/xmp/XmpBasic.d.mts +2 -0
- package/dist/xmp/XmpBasic.mjs +1 -0
- package/dist/xmp/XmpMM.d.mts +2 -0
- package/dist/xmp/XmpMM.mjs +1 -0
- package/dist/xmp/XmpRights.d.mts +2 -0
- package/dist/xmp/XmpRights.mjs +1 -0
- package/dist/xmp/index.d.mts +15 -0
- package/dist/xmp/index.mjs +15 -0
- package/package.json +195 -3
- package/src/Dataset.ts +1085 -0
- package/src/Iri.ts +322 -0
- package/src/Isomorphism.ts +319 -0
- package/src/LanguageTag.ts +98 -0
- package/src/Namespace.ts +100 -0
- package/src/PrefixMap.ts +117 -0
- package/src/RdfJs.ts +146 -0
- package/src/Rdfs.ts +241 -0
- package/src/Reification.ts +103 -0
- package/src/Resource.ts +873 -0
- package/src/Serialization.ts +775 -0
- package/src/Term.ts +1300 -0
- package/src/TermCodec.ts +505 -0
- package/src/TermJson.ts +313 -0
- package/src/Vocab.ts +161 -0
- package/src/Xsd.ts +573 -0
- package/src/csvw/Csv2Json.ts +265 -0
- package/src/csvw/Csv2Rdf.ts +268 -0
- package/src/csvw/Datatype.ts +589 -0
- package/src/csvw/Metadata.ts +1523 -0
- package/src/csvw/Processor.ts +276 -0
- package/src/csvw/Report.ts +135 -0
- package/src/csvw/Table.ts +759 -0
- package/src/csvw/index.ts +22 -0
- package/src/csvw/internal/dateFormat.ts +202 -0
- package/src/csvw/internal/json.ts +104 -0
- package/src/csvw/internal/numberFormat.ts +369 -0
- package/src/csvw/internal/object.ts +23 -0
- package/src/csvw/internal/uriTemplate.ts +130 -0
- package/src/csvw/internal/url.ts +93 -0
- package/src/csvw/internal/vocab.ts +282 -0
- package/src/index.ts +40 -0
- package/src/internal/arbitrary.ts +148 -0
- package/src/internal/loop.ts +24 -0
- package/src/internal/pending.ts +20 -0
- package/src/internal/textDecoder.ts +183 -0
- package/src/jsonld/DocumentLoader.ts +512 -0
- package/src/jsonld/JsonLd.ts +847 -0
- package/src/jsonld/JsonLdError.ts +105 -0
- package/src/jsonld/index.ts +13 -0
- package/src/jsonld/internal/compact.ts +852 -0
- package/src/jsonld/internal/context.ts +781 -0
- package/src/jsonld/internal/expand.ts +614 -0
- package/src/jsonld/internal/flatten.ts +243 -0
- package/src/jsonld/internal/frame.ts +559 -0
- package/src/jsonld/internal/iri.ts +52 -0
- package/src/jsonld/internal/json.ts +19 -0
- package/src/jsonld/internal/linkHeader.ts +60 -0
- package/src/jsonld/internal/rdf.ts +481 -0
- package/src/jsonld/internal/util.ts +367 -0
- package/src/n3/Isomorphism.ts +476 -0
- package/src/n3/Mapping.ts +332 -0
- package/src/n3/Model.ts +696 -0
- package/src/n3/N3.ts +237 -0
- package/src/n3/Reasoner.ts +568 -0
- package/src/n3/Vocab.ts +111 -0
- package/src/n3/index.ts +21 -0
- package/src/n3/internal/builtins.ts +668 -0
- package/src/n3/internal/guards.ts +23 -0
- package/src/n3/internal/lists.ts +106 -0
- package/src/n3/internal/loop.ts +28 -0
- package/src/n3/internal/parser.ts +1032 -0
- package/src/n3/internal/writer.ts +344 -0
- package/src/ntriples/Grammar.ts +317 -0
- package/src/ntriples/Lexical.ts +321 -0
- package/src/ntriples/NQuads.ts +140 -0
- package/src/ntriples/NTriples.ts +143 -0
- package/src/ntriples/index.ts +14 -0
- package/src/ntriples/internal/codec.ts +229 -0
- package/src/ntriples/internal/lineParser.ts +326 -0
- package/src/ntriples/internal/loop.ts +14 -0
- package/src/rdfjson/RdfJson.ts +806 -0
- package/src/rdfjson/index.ts +9 -0
- package/src/rdfjson/internal/json.ts +19 -0
- package/src/rdfxml/RdfXml.ts +1408 -0
- package/src/rdfxml/Xml.ts +419 -0
- package/src/rdfxml/index.ts +11 -0
- package/src/rdfxml/internal/chars.ts +73 -0
- package/src/rdfxml/internal/loop.ts +24 -0
- package/src/rdfxml/internal/parser.ts +1265 -0
- package/src/shacl/Message.ts +102 -0
- package/src/shacl/Path.ts +483 -0
- package/src/shacl/Shapes.ts +913 -0
- package/src/shacl/Sparql.ts +128 -0
- package/src/shacl/ValidationReport.ts +438 -0
- package/src/shacl/Validator.ts +1156 -0
- package/src/shacl/Vocabulary.ts +180 -0
- package/src/shacl/index.ts +22 -0
- package/src/shacl/internal/compare.ts +128 -0
- package/src/shacl/internal/regex.ts +56 -0
- package/src/shex/SemAct.ts +197 -0
- package/src/shex/ShExC.ts +415 -0
- package/src/shex/ShExError.ts +71 -0
- package/src/shex/ShExJ.ts +893 -0
- package/src/shex/ShExR.ts +640 -0
- package/src/shex/ShapeMap.ts +385 -0
- package/src/shex/Structure.ts +467 -0
- package/src/shex/Validator.ts +395 -0
- package/src/shex/index.ts +24 -0
- package/src/shex/internal/engine.ts +682 -0
- package/src/shex/internal/iterate.ts +14 -0
- package/src/shex/internal/json.ts +12 -0
- package/src/shex/internal/lexer.ts +56 -0
- package/src/shex/internal/nodeConstraint.ts +368 -0
- package/src/shex/internal/shexcLexer.ts +387 -0
- package/src/shex/internal/shexcParser.ts +1312 -0
- package/src/shex/internal/tokens.ts +41 -0
- package/src/shex/internal/xpathRegex.ts +290 -0
- package/src/sparql/Algebra.ts +914 -0
- package/src/sparql/Ast.ts +1344 -0
- package/src/sparql/Bindings.ts +272 -0
- package/src/sparql/ClientErrors.ts +156 -0
- package/src/sparql/ClientFormats.ts +70 -0
- package/src/sparql/Engine.ts +699 -0
- package/src/sparql/Errors.ts +30 -0
- package/src/sparql/Expression.ts +360 -0
- package/src/sparql/Federation.ts +187 -0
- package/src/sparql/Functions.ts +689 -0
- package/src/sparql/Generator.ts +426 -0
- package/src/sparql/GraphStore.ts +341 -0
- package/src/sparql/Optimizer.ts +230 -0
- package/src/sparql/Options.ts +191 -0
- package/src/sparql/Parser.ts +173 -0
- package/src/sparql/Protocol.ts +342 -0
- package/src/sparql/ProtocolErrors.ts +113 -0
- package/src/sparql/QueryBuilder.ts +953 -0
- package/src/sparql/Results.ts +844 -0
- package/src/sparql/ResultsStream.ts +771 -0
- package/src/sparql/ServerFormats.ts +75 -0
- package/src/sparql/ServiceDescription.ts +130 -0
- package/src/sparql/SparqlClient.ts +947 -0
- package/src/sparql/SparqlServer.ts +528 -0
- package/src/sparql/Store.ts +311 -0
- package/src/sparql/TermSchema.ts +20 -0
- package/src/sparql/Testing.ts +114 -0
- package/src/sparql/Translate.ts +407 -0
- package/src/sparql/ai/Mcp.ts +43 -0
- package/src/sparql/ai/Tools.ts +481 -0
- package/src/sparql/ai/index.ts +11 -0
- package/src/sparql/index.ts +64 -0
- package/src/sparql/internal/evaluator.ts +947 -0
- package/src/sparql/internal/hash.ts +418 -0
- package/src/sparql/internal/json.ts +12 -0
- package/src/sparql/internal/lexer.ts +488 -0
- package/src/sparql/internal/loop.ts +24 -0
- package/src/sparql/internal/parser.ts +2215 -0
- package/src/sparql/internal/prefetch.ts +46 -0
- package/src/sparql/internal/stringMap.ts +39 -0
- package/src/sparql/internal/textResults.ts +226 -0
- package/src/sparql/internal/values.ts +550 -0
- package/src/sparql/shacl/Evaluator.ts +478 -0
- package/src/sparql/shacl/Query.ts +574 -0
- package/src/sparql/shacl/index.ts +12 -0
- package/src/sparql/sql/Dialect.ts +246 -0
- package/src/sparql/sql/SqlStore.ts +1080 -0
- package/src/sparql/sql/Translation.ts +1898 -0
- package/src/sparql/sql/index.ts +17 -0
- package/src/sparql/sql/internal/encoding.ts +313 -0
- package/src/turtle/Grammar.ts +286 -0
- package/src/turtle/Manifest.ts +215 -0
- package/src/turtle/TriG.ts +158 -0
- package/src/turtle/Turtle.ts +166 -0
- package/src/turtle/index.ts +14 -0
- package/src/turtle/internal/loop.ts +23 -0
- package/src/turtle/internal/parse.ts +112 -0
- package/src/turtle/internal/parser.ts +1303 -0
- package/src/turtle/internal/serialize.ts +79 -0
- package/src/turtle/internal/streamWriter.ts +128 -0
- package/src/turtle/internal/writer.ts +898 -0
- package/src/xmp/DublinCore.ts +147 -0
- package/src/xmp/Exif.ts +109 -0
- package/src/xmp/Extract.ts +351 -0
- package/src/xmp/Metadata.ts +703 -0
- package/src/xmp/Namespaces.ts +228 -0
- package/src/xmp/Packet.ts +297 -0
- package/src/xmp/Pdf.ts +99 -0
- package/src/xmp/PdfA.ts +280 -0
- package/src/xmp/Photoshop.ts +275 -0
- package/src/xmp/Tiff.ts +196 -0
- package/src/xmp/Xmp.ts +430 -0
- package/src/xmp/XmpBasic.ts +90 -0
- package/src/xmp/XmpMM.ts +82 -0
- package/src/xmp/XmpRights.ts +83 -0
- package/src/xmp/index.ts +36 -0
- package/src/xmp/internal/accessors.ts +72 -0
- package/src/xmp/internal/xml.ts +63 -0
|
@@ -0,0 +1,1080 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A SQL storage backend for the SPARQL engine, built on Effect's SQL
|
|
3
|
+
* abstraction (`effect/sql`).
|
|
4
|
+
*
|
|
5
|
+
* The store keeps a dictionary of interned terms (RDF 1.2 triple terms
|
|
6
|
+
* included, referencing their components) and a table of quads of term ids
|
|
7
|
+
* indexed in four orders (`spog`, `posg`, `ospg`, `gspo`). It implements the
|
|
8
|
+
* `QuadStore` service of `@thomasfosterau/effect-rdf/sparql` — streaming pattern
|
|
9
|
+
* matching, statistics, updates, named graph management and transactions
|
|
10
|
+
* (mapped to `SqlClient.withTransaction`) — and a `QueryCapability` that
|
|
11
|
+
* translates SPARQL algebra to SQL (see `Translation`), so that the engine
|
|
12
|
+
* runs whole queries (or the largest translatable subtrees) in the database.
|
|
13
|
+
*
|
|
14
|
+
* The store is driver-agnostic: `layer` runs over whichever `SqlClient`
|
|
15
|
+
* the context provides, in the SQLite (3.35 or later) or PostgreSQL dialect
|
|
16
|
+
* (`Dialect.fromClient`). A backend for one driver (a ready store layer that
|
|
17
|
+
* also provides that driver's `SqlClient`) is a package of its own,
|
|
18
|
+
* `@thomasfosterau/effect-sparql-<driver>`.
|
|
19
|
+
*
|
|
20
|
+
* @since 0.1.0
|
|
21
|
+
*/
|
|
22
|
+
import * as Arr from 'effect/Array';
|
|
23
|
+
import * as Context from 'effect/Context';
|
|
24
|
+
import * as Effect from 'effect/Effect';
|
|
25
|
+
import * as Layer from 'effect/Layer';
|
|
26
|
+
import * as Option from 'effect/Option';
|
|
27
|
+
import * as Predicate from 'effect/Predicate';
|
|
28
|
+
import * as Result from 'effect/Result';
|
|
29
|
+
import * as MutableHashMap from 'effect/MutableHashMap';
|
|
30
|
+
import * as MutableHashSet from 'effect/MutableHashSet';
|
|
31
|
+
import * as Order from 'effect/Order';
|
|
32
|
+
import * as Migrator from 'effect/sql/Migrator';
|
|
33
|
+
import * as SqlClient from 'effect/sql/SqlClient';
|
|
34
|
+
import * as SqlError from 'effect/sql/SqlError';
|
|
35
|
+
import * as Stream from 'effect/Stream';
|
|
36
|
+
import * as Term from '../../Term.ts';
|
|
37
|
+
import type * as Algebra from '../Algebra.ts';
|
|
38
|
+
import * as B from '../Bindings.ts';
|
|
39
|
+
import * as Store from '../Store.ts';
|
|
40
|
+
import * as Dialect from './Dialect.ts';
|
|
41
|
+
import * as Enc from './internal/encoding.ts';
|
|
42
|
+
import * as Translation from './Translation.ts';
|
|
43
|
+
|
|
44
|
+
// -----------------------------------------------------------------------------
|
|
45
|
+
// Models
|
|
46
|
+
// -----------------------------------------------------------------------------
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* An event reported to `SqlStoreOptions.onQuery` for every algebra node the
|
|
50
|
+
* engine offers to the store: either it was translated to SQL and executed,
|
|
51
|
+
* or it was declined (and evaluated by the engine).
|
|
52
|
+
*
|
|
53
|
+
* @since 0.1.0
|
|
54
|
+
* @category models
|
|
55
|
+
*/
|
|
56
|
+
export type QueryEvent =
|
|
57
|
+
| {
|
|
58
|
+
readonly _tag: 'Executed';
|
|
59
|
+
readonly operation: Algebra.Operation;
|
|
60
|
+
readonly sql: string;
|
|
61
|
+
readonly params: ReadonlyArray<unknown>;
|
|
62
|
+
readonly rows: number;
|
|
63
|
+
}
|
|
64
|
+
| {
|
|
65
|
+
readonly _tag: 'Declined';
|
|
66
|
+
readonly operation: Algebra.Operation;
|
|
67
|
+
readonly reason: string;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Options of the SQL store.
|
|
72
|
+
*
|
|
73
|
+
* @since 0.1.0
|
|
74
|
+
* @category models
|
|
75
|
+
*/
|
|
76
|
+
export interface SqlStoreOptions {
|
|
77
|
+
/** The SQL dialect; detected from the `SqlClient` by default. */
|
|
78
|
+
readonly dialect?: Dialect.Dialect | undefined;
|
|
79
|
+
/** The prefix of the table names (default `rdf_`). */
|
|
80
|
+
readonly tablePrefix?: string | undefined;
|
|
81
|
+
/** Whether to create / migrate the schema when the store is built (default `true`). */
|
|
82
|
+
readonly migrate?: boolean | undefined;
|
|
83
|
+
/** Whether to translate SPARQL algebra to SQL (default `true`). */
|
|
84
|
+
readonly translate?: boolean | undefined;
|
|
85
|
+
/** The number of quads per insert / delete statement (default 500). */
|
|
86
|
+
readonly batchSize?: number | undefined;
|
|
87
|
+
/** The number of quads per page of `match` (default 5000). */
|
|
88
|
+
readonly pageSize?: number | undefined;
|
|
89
|
+
/** Debug hook: called for every algebra node offered to the store. */
|
|
90
|
+
readonly onQuery?: ((event: QueryEvent) => void) | undefined;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* The SQL store: a `QuadStore` with native SPARQL-to-SQL evaluation and some
|
|
95
|
+
* SQL-specific extras.
|
|
96
|
+
*
|
|
97
|
+
* @since 0.1.0
|
|
98
|
+
* @category models
|
|
99
|
+
*/
|
|
100
|
+
export interface SqlStoreShape extends Store.QuadStoreShape {
|
|
101
|
+
readonly dialect: Dialect.Dialect;
|
|
102
|
+
readonly tables: Dialect.Tables;
|
|
103
|
+
/** The native algebra evaluation (also available as `query`). */
|
|
104
|
+
readonly capability: Store.QueryCapability;
|
|
105
|
+
/**
|
|
106
|
+
* Translates an algebra tree for the given evaluation context, resolving
|
|
107
|
+
* constants against the dictionary (for inspection and debugging).
|
|
108
|
+
*/
|
|
109
|
+
readonly compile: (
|
|
110
|
+
op: Algebra.Operation,
|
|
111
|
+
context?: Partial<Pick<Store.EvaluationContext, 'dataset' | 'activeGraph'>>,
|
|
112
|
+
) => Effect.Effect<Result.Result<Translation.CompiledQuery, string>, Store.StoreError>;
|
|
113
|
+
/** The number of terms in the dictionary. */
|
|
114
|
+
readonly termCount: Effect.Effect<number, Store.StoreError>;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* The SQL store service.
|
|
119
|
+
*
|
|
120
|
+
* @since 0.1.0
|
|
121
|
+
* @category services
|
|
122
|
+
*/
|
|
123
|
+
export class SqlStore extends Context.Service<SqlStore, SqlStoreShape>()(
|
|
124
|
+
'@thomasfosterau/effect-rdf/sparql/sql/SqlStore',
|
|
125
|
+
) {}
|
|
126
|
+
|
|
127
|
+
// -----------------------------------------------------------------------------
|
|
128
|
+
// Helpers
|
|
129
|
+
// -----------------------------------------------------------------------------
|
|
130
|
+
|
|
131
|
+
const storeError = (message: string) => (cause: unknown) =>
|
|
132
|
+
cause instanceof Store.StoreError
|
|
133
|
+
? cause
|
|
134
|
+
: new Store.StoreError({
|
|
135
|
+
message: `${message}: ${Predicate.isError(cause) ? cause.message : String(cause)}`,
|
|
136
|
+
cause,
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
const chunks = <A>(items: ReadonlyArray<A>, size: number): Array<ReadonlyArray<A>> =>
|
|
140
|
+
Array.from({ length: Math.ceil(items.length / size) }, (_, i) =>
|
|
141
|
+
items.slice(i * size, (i + 1) * size),
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
/** The distinct values of `items`, in order of first occurrence. */
|
|
145
|
+
const distinct = <A extends string | number>(items: Iterable<A>): Array<A> =>
|
|
146
|
+
Arr.fromIterable(MutableHashSet.fromIterable(items));
|
|
147
|
+
|
|
148
|
+
const num = (v: unknown): number => (Predicate.isNumber(v) ? v : Number(v));
|
|
149
|
+
// The text columns come back as strings; a count or other numeric cell as a number (or a bigint);
|
|
150
|
+
// a missing cell is nullish and reads as the empty string.
|
|
151
|
+
const str = (v: unknown): string =>
|
|
152
|
+
Predicate.isString(v)
|
|
153
|
+
? v
|
|
154
|
+
: Predicate.isNumber(v) || Predicate.isBigInt(v) || Predicate.isBoolean(v)
|
|
155
|
+
? `${v}`
|
|
156
|
+
: '';
|
|
157
|
+
|
|
158
|
+
const depth = (t: Term.GroundTerm): number =>
|
|
159
|
+
Term.isTriple(t) ? 1 + Math.max(depth(t.subject), depth(t.predicate), depth(t.object)) : 0;
|
|
160
|
+
|
|
161
|
+
const CACHE_LIMIT = 200_000;
|
|
162
|
+
|
|
163
|
+
const DEFAULT_DATASET: Store.DatasetSpec = { defaultGraph: 'default', namedGraphs: 'all' };
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* The schema migrations of the store (for `effect/sql/Migrator`): a record of
|
|
167
|
+
* `<id>_<name>` to migration effect.
|
|
168
|
+
*
|
|
169
|
+
* @since 0.1.0
|
|
170
|
+
* @category schema
|
|
171
|
+
*/
|
|
172
|
+
export const migrations = (dialect: Dialect.Dialect, tables: Dialect.Tables) => ({
|
|
173
|
+
'1_create_rdf_store': Effect.gen(function* () {
|
|
174
|
+
const sql = yield* SqlClient.SqlClient;
|
|
175
|
+
yield* Effect.forEach(dialect.schema(tables), (statement) => sql.unsafe(statement), {
|
|
176
|
+
concurrency: 1,
|
|
177
|
+
discard: true,
|
|
178
|
+
});
|
|
179
|
+
}),
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Creates or migrates the store's schema.
|
|
184
|
+
*
|
|
185
|
+
* @since 0.1.0
|
|
186
|
+
* @category schema
|
|
187
|
+
*/
|
|
188
|
+
export const migrate = (
|
|
189
|
+
options: Pick<SqlStoreOptions, 'dialect' | 'tablePrefix'> = {},
|
|
190
|
+
): Effect.Effect<void, Store.StoreError, SqlClient.SqlClient> =>
|
|
191
|
+
Effect.gen(function* () {
|
|
192
|
+
const sql = yield* SqlClient.SqlClient;
|
|
193
|
+
const dialect = options.dialect ?? (yield* Dialect.fromClient(sql));
|
|
194
|
+
const tables = Dialect.tables(options.tablePrefix);
|
|
195
|
+
yield* Migrator.make({})({
|
|
196
|
+
loader: Migrator.fromRecord(migrations(dialect, tables)),
|
|
197
|
+
table: tables.migrations,
|
|
198
|
+
});
|
|
199
|
+
}).pipe(Effect.mapError(storeError('Migration failed')));
|
|
200
|
+
|
|
201
|
+
// -----------------------------------------------------------------------------
|
|
202
|
+
// Constructor
|
|
203
|
+
// -----------------------------------------------------------------------------
|
|
204
|
+
|
|
205
|
+
interface DecodeState {
|
|
206
|
+
readonly known: MutableHashMap.MutableHashMap<number, Term.GroundTerm>;
|
|
207
|
+
readonly triples: MutableHashMap.MutableHashMap<number, Enc.ComponentIds>;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/** Term ids by term key. */
|
|
211
|
+
type Ids = MutableHashMap.MutableHashMap<string, number>;
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* The term with id `id` of a decode state that `complete` has filled: every
|
|
215
|
+
* id is known, so a missing one is a defect.
|
|
216
|
+
*/
|
|
217
|
+
const termOf = (state: DecodeState, id: number): Term.GroundTerm => {
|
|
218
|
+
const known = MutableHashMap.get(state.known, id);
|
|
219
|
+
if (Option.isSome(known)) return known.value;
|
|
220
|
+
const comps = MutableHashMap.get(state.triples, id);
|
|
221
|
+
if (Option.isNone(comps)) throw new Store.StoreError({ message: `Unknown term id ${id}` });
|
|
222
|
+
const [s, p, o] = comps.value;
|
|
223
|
+
const t = Term.triple(
|
|
224
|
+
termAs(state, s, isSubject, 'subject'),
|
|
225
|
+
termAs(state, p, Term.isNamedNode, 'predicate'),
|
|
226
|
+
termOf(state, o),
|
|
227
|
+
);
|
|
228
|
+
MutableHashMap.set(state.known, id, t);
|
|
229
|
+
return t;
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* The term with id `id`, which the store only ever wrote in a position of
|
|
234
|
+
* kind `T` (so another kind is a defect).
|
|
235
|
+
*/
|
|
236
|
+
const termAs = <T extends Term.GroundTerm>(
|
|
237
|
+
state: DecodeState,
|
|
238
|
+
id: number,
|
|
239
|
+
is: Predicate.Refinement<Term.GroundTerm, T>,
|
|
240
|
+
position: string,
|
|
241
|
+
): T => {
|
|
242
|
+
const t = termOf(state, id);
|
|
243
|
+
if (is(t)) return t;
|
|
244
|
+
throw new Store.StoreError({ message: `Term id ${id} cannot be a ${position}` });
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
// A ground term is a subject unless it is a literal, and a graph name unless it is also not a
|
|
248
|
+
// triple term (the fewest checks, as these run for every decoded quad).
|
|
249
|
+
const isSubject = (t: Term.GroundTerm): t is Term.Subject => !Term.isLiteral(t);
|
|
250
|
+
|
|
251
|
+
const isGraphName = (t: Term.GroundTerm): t is Term.NamedNode | Term.BlankNode =>
|
|
252
|
+
!Term.isLiteral(t) && !Term.isTriple(t);
|
|
253
|
+
|
|
254
|
+
/** The dictionary key of a `id, kind, value, datatype, lang, dir` result row. */
|
|
255
|
+
const rowKeyOf = (r: ReadonlyArray<unknown>) =>
|
|
256
|
+
Enc.rowKey({
|
|
257
|
+
kind: num(r[1]),
|
|
258
|
+
value: str(r[2]),
|
|
259
|
+
datatype: str(r[3]),
|
|
260
|
+
lang: str(r[4]),
|
|
261
|
+
dir: str(r[5]),
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
/** A term to intern, its dictionary row and the row's key. */
|
|
265
|
+
interface Encoded {
|
|
266
|
+
readonly term: Term.GroundTerm;
|
|
267
|
+
readonly row: Enc.TermRow;
|
|
268
|
+
readonly key: string;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/** A dictionary row and its id, if it has one. */
|
|
272
|
+
interface Found {
|
|
273
|
+
readonly encoded: Encoded;
|
|
274
|
+
readonly id: Option.Option<number>;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const withKey = (term: Term.GroundTerm, row: Enc.TermRow): Encoded => ({
|
|
278
|
+
term,
|
|
279
|
+
row,
|
|
280
|
+
key: Enc.rowKey(row),
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* The dictionary rows of one depth level of terms; a triple term whose
|
|
285
|
+
* components have no id yet is left out.
|
|
286
|
+
*/
|
|
287
|
+
const encodeLevel = (
|
|
288
|
+
level: MutableHashMap.MutableHashMap<string, Term.GroundTerm>,
|
|
289
|
+
ids: Ids,
|
|
290
|
+
): Array<Encoded> =>
|
|
291
|
+
Arr.filterMap(MutableHashMap.values(level), (t): Result.Result<Encoded, void> => {
|
|
292
|
+
if (!Term.isTriple(t)) return Result.succeed(withKey(t, Enc.encode(t)));
|
|
293
|
+
const s = MutableHashMap.get(ids, t.subject.key);
|
|
294
|
+
const p = MutableHashMap.get(ids, t.predicate.key);
|
|
295
|
+
const o = MutableHashMap.get(ids, t.object.key);
|
|
296
|
+
return Option.isSome(s) && Option.isSome(p) && Option.isSome(o)
|
|
297
|
+
? Result.succeed(withKey(t, Enc.encode(t, [s.value, p.value, o.value])))
|
|
298
|
+
: Result.failVoid;
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
const newState = (): DecodeState => ({
|
|
302
|
+
known: MutableHashMap.empty(),
|
|
303
|
+
triples: MutableHashMap.empty(),
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
const isResolved = (state: DecodeState, c: number) =>
|
|
307
|
+
Option.isSome(MutableHashMap.get(state.known, c)) ||
|
|
308
|
+
Option.isSome(MutableHashMap.get(state.triples, c));
|
|
309
|
+
|
|
310
|
+
/** The id of a term or graph (`0` for the default graph), if it has one. */
|
|
311
|
+
const idIn = (ids: Ids, t: Term.GroundTerm | Term.DefaultGraph): Option.Option<number> =>
|
|
312
|
+
Term.isDefaultGraph(t) ? Option.some(0) : MutableHashMap.get(ids, t.key);
|
|
313
|
+
|
|
314
|
+
/** The `s, p, o, g` ids of a quad, if all its terms have one. */
|
|
315
|
+
const quadRow = (
|
|
316
|
+
ids: Ids,
|
|
317
|
+
q: Term.Quad,
|
|
318
|
+
): Result.Result<readonly [number, number, number, number], void> => {
|
|
319
|
+
const s = MutableHashMap.get(ids, q.subject.key);
|
|
320
|
+
const p = MutableHashMap.get(ids, q.predicate.key);
|
|
321
|
+
const o = MutableHashMap.get(ids, q.object.key);
|
|
322
|
+
const g = idIn(ids, q.graph);
|
|
323
|
+
return Option.isSome(s) && Option.isSome(p) && Option.isSome(o) && Option.isSome(g)
|
|
324
|
+
? Result.succeed([s.value, p.value, o.value, g.value] as const)
|
|
325
|
+
: Result.failVoid;
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
const INDEXES = [
|
|
329
|
+
['s', 'p', 'o', 'g'],
|
|
330
|
+
['p', 'o', 's', 'g'],
|
|
331
|
+
['o', 's', 'p', 'g'],
|
|
332
|
+
['g', 's', 'p', 'o'],
|
|
333
|
+
] as const;
|
|
334
|
+
|
|
335
|
+
/** The number of leading columns of an index that are bound. */
|
|
336
|
+
const boundPrefix = (idx: ReadonlyArray<string>, bound: MutableHashSet.MutableHashSet<string>) => {
|
|
337
|
+
const i = idx.findIndex((c) => !MutableHashSet.has(bound, c));
|
|
338
|
+
return i < 0 ? idx.length : i;
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
/** The index whose longest prefix of columns is bound (the first on a tie). */
|
|
342
|
+
interface BestIndex {
|
|
343
|
+
readonly best: ReadonlyArray<string>;
|
|
344
|
+
readonly prefix: number;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
const indexFor = (bound: MutableHashSet.MutableHashSet<string>): ReadonlyArray<string> => {
|
|
348
|
+
const first: BestIndex = { best: INDEXES[0], prefix: -1 };
|
|
349
|
+
return Arr.reduce(INDEXES, first, (acc, idx): BestIndex => {
|
|
350
|
+
const n = boundPrefix(idx, bound);
|
|
351
|
+
return n > acc.prefix ? { best: idx, prefix: n } : acc;
|
|
352
|
+
}).best;
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
/** Where an output column of a compiled query starts in its result rows. */
|
|
356
|
+
interface ColumnAt {
|
|
357
|
+
readonly column: Translation.OutputColumn;
|
|
358
|
+
readonly at: number;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
const columnLayout = (columns: ReadonlyArray<Translation.OutputColumn>): ReadonlyArray<ColumnAt> =>
|
|
362
|
+
Arr.mapAccum(columns, 0, (at, column) => [
|
|
363
|
+
at + (column.type === 'int' ? 1 : 6),
|
|
364
|
+
{ column, at },
|
|
365
|
+
])[1];
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Creates a SQL store over the `SqlClient` service.
|
|
369
|
+
*
|
|
370
|
+
* @since 0.1.0
|
|
371
|
+
* @category constructors
|
|
372
|
+
*/
|
|
373
|
+
export const make = (
|
|
374
|
+
options: SqlStoreOptions = {},
|
|
375
|
+
): Effect.Effect<SqlStoreShape, Store.StoreError, SqlClient.SqlClient> =>
|
|
376
|
+
Effect.gen(function* () {
|
|
377
|
+
const sql = yield* SqlClient.SqlClient;
|
|
378
|
+
const dialect =
|
|
379
|
+
options.dialect ??
|
|
380
|
+
(yield* Effect.mapError(Dialect.fromClient(sql), storeError('Unsupported database')));
|
|
381
|
+
const tables = Dialect.tables(options.tablePrefix);
|
|
382
|
+
if (options.migrate !== false) yield* migrate({ dialect, tablePrefix: options.tablePrefix });
|
|
383
|
+
|
|
384
|
+
const T = tables.terms;
|
|
385
|
+
const Qt = tables.quads;
|
|
386
|
+
const Gt = tables.graphs;
|
|
387
|
+
const batchSize = Math.max(1, Math.min(options.batchSize ?? 500, 1000));
|
|
388
|
+
const pageSize = Math.max(1, options.pageSize ?? 5000);
|
|
389
|
+
const onQuery = options.onQuery;
|
|
390
|
+
const ph = dialect.placeholder;
|
|
391
|
+
|
|
392
|
+
// Caches of the (append-only) dictionary, only filled outside transactions.
|
|
393
|
+
const idCache: Ids = MutableHashMap.empty();
|
|
394
|
+
const termCache = MutableHashMap.empty<number, Term.GroundTerm>();
|
|
395
|
+
|
|
396
|
+
const inTransaction = Effect.map(Effect.serviceOption(sql.transactionService), Option.isSome);
|
|
397
|
+
|
|
398
|
+
const run = (text: string, params: ReadonlyArray<unknown> = []) =>
|
|
399
|
+
sql.unsafe(text, params).values;
|
|
400
|
+
const exec = (text: string, params: ReadonlyArray<unknown> = []) =>
|
|
401
|
+
Effect.asVoid(sql.unsafe(text, params).raw);
|
|
402
|
+
|
|
403
|
+
// --- term dictionary ------------------------------------------------------
|
|
404
|
+
|
|
405
|
+
const lookupRows = (rows: ReadonlyArray<Encoded>) => {
|
|
406
|
+
const found: Ids = MutableHashMap.empty();
|
|
407
|
+
const values = distinct(rows.map((r) => r.row.value));
|
|
408
|
+
return Effect.as(
|
|
409
|
+
Effect.forEach(
|
|
410
|
+
chunks(values, 500),
|
|
411
|
+
(chunk) => {
|
|
412
|
+
const list = chunk
|
|
413
|
+
.map((_, i) => dialect.valueKey(dialect.castText(ph(i + 1))))
|
|
414
|
+
.join(', ');
|
|
415
|
+
return Effect.map(
|
|
416
|
+
run(
|
|
417
|
+
`SELECT id, kind, value, datatype, lang, dir FROM ${T} WHERE ${dialect.valueKey('value')} IN (${list})`,
|
|
418
|
+
chunk,
|
|
419
|
+
),
|
|
420
|
+
(result) =>
|
|
421
|
+
result.forEach((r) => {
|
|
422
|
+
MutableHashMap.set(found, rowKeyOf(r), num(r[0]));
|
|
423
|
+
}),
|
|
424
|
+
);
|
|
425
|
+
},
|
|
426
|
+
{ concurrency: 1, discard: true },
|
|
427
|
+
),
|
|
428
|
+
found,
|
|
429
|
+
);
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
/** Inserts dictionary rows; returns the ids of the rows that were new. */
|
|
433
|
+
const insertRows = (rows: ReadonlyArray<Encoded>) =>
|
|
434
|
+
Effect.gen(function* () {
|
|
435
|
+
const inserted: Ids = MutableHashMap.empty();
|
|
436
|
+
yield* Effect.forEach(
|
|
437
|
+
chunks(rows, 500),
|
|
438
|
+
Effect.fnUntraced(function* (chunk) {
|
|
439
|
+
const params: Array<unknown> = [];
|
|
440
|
+
const tuples = chunk.map(({ row: r }) => {
|
|
441
|
+
const base = params.length;
|
|
442
|
+
// An absent component or number is SQL `NULL`.
|
|
443
|
+
params.push(
|
|
444
|
+
r.kind,
|
|
445
|
+
r.value,
|
|
446
|
+
r.datatype,
|
|
447
|
+
r.lang,
|
|
448
|
+
r.dir,
|
|
449
|
+
Option.getOrNull(r.sub),
|
|
450
|
+
Option.getOrNull(r.pre),
|
|
451
|
+
Option.getOrNull(r.obj),
|
|
452
|
+
r.cls,
|
|
453
|
+
Option.getOrNull(r.num),
|
|
454
|
+
);
|
|
455
|
+
return `(${Array.from({ length: 10 }, (_, i) => {
|
|
456
|
+
const p = ph(base + i + 1);
|
|
457
|
+
return i >= 1 && i <= 4
|
|
458
|
+
? dialect.castText(p)
|
|
459
|
+
: i === 9
|
|
460
|
+
? dialect.castDouble(p)
|
|
461
|
+
: dialect.castId(p);
|
|
462
|
+
}).join(', ')})`;
|
|
463
|
+
});
|
|
464
|
+
const result = yield* run(
|
|
465
|
+
`INSERT INTO ${T} (kind, value, datatype, lang, dir, sub, pre, obj, cls, num) VALUES ${tuples.join(', ')} ON CONFLICT DO NOTHING RETURNING id, kind, value, datatype, lang, dir`,
|
|
466
|
+
params,
|
|
467
|
+
);
|
|
468
|
+
result.forEach((r) => {
|
|
469
|
+
MutableHashMap.set(inserted, rowKeyOf(r), num(r[0]));
|
|
470
|
+
});
|
|
471
|
+
}),
|
|
472
|
+
{ concurrency: 1, discard: true },
|
|
473
|
+
);
|
|
474
|
+
const classes = distinct(rows.map((r) => r.row.cls));
|
|
475
|
+
if (Arr.isReadonlyArrayNonEmpty(classes)) {
|
|
476
|
+
yield* exec(
|
|
477
|
+
`INSERT INTO ${tables.classes} (cls) VALUES ${classes.map((c) => `(${c})`).join(', ')} ON CONFLICT DO NOTHING`,
|
|
478
|
+
);
|
|
479
|
+
}
|
|
480
|
+
return inserted;
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
/**
|
|
484
|
+
* The ids of dictionary rows (none for a row not in the dictionary). With
|
|
485
|
+
* `create`, rows are inserted first (new rows come back with their ids) and
|
|
486
|
+
* the rest looked up.
|
|
487
|
+
*/
|
|
488
|
+
const findIds = (rows: ReadonlyArray<Encoded>, create: boolean) =>
|
|
489
|
+
Effect.gen(function* () {
|
|
490
|
+
if (!create) {
|
|
491
|
+
const found = yield* lookupRows(rows);
|
|
492
|
+
return rows.map((encoded): Found => ({
|
|
493
|
+
encoded,
|
|
494
|
+
id: MutableHashMap.get(found, encoded.key),
|
|
495
|
+
}));
|
|
496
|
+
}
|
|
497
|
+
const inserted = yield* insertRows(rows);
|
|
498
|
+
const first = rows.map((encoded): Found => ({
|
|
499
|
+
encoded,
|
|
500
|
+
id: MutableHashMap.get(inserted, encoded.key),
|
|
501
|
+
}));
|
|
502
|
+
const existing = first.filter(({ id }) => Option.isNone(id)).map(({ encoded }) => encoded);
|
|
503
|
+
if (Arr.isReadonlyArrayEmpty(existing)) return first;
|
|
504
|
+
const more = yield* lookupRows(existing);
|
|
505
|
+
return first.map((f): Found =>
|
|
506
|
+
Option.isSome(f.id)
|
|
507
|
+
? f
|
|
508
|
+
: { encoded: f.encoded, id: MutableHashMap.get(more, f.encoded.key) },
|
|
509
|
+
);
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* The dictionary ids of terms (by key). With `create`, missing terms are
|
|
514
|
+
* interned; otherwise they are absent from the result.
|
|
515
|
+
*/
|
|
516
|
+
const resolveTerms = (terms: Iterable<Term.GroundTerm>, create: boolean) =>
|
|
517
|
+
Effect.gen(function* () {
|
|
518
|
+
const cacheable = !(yield* inTransaction);
|
|
519
|
+
const result: Ids = MutableHashMap.empty();
|
|
520
|
+
// The terms to look up by depth (components before the triple terms using them).
|
|
521
|
+
const levels = MutableHashMap.empty<
|
|
522
|
+
number,
|
|
523
|
+
MutableHashMap.MutableHashMap<string, Term.GroundTerm>
|
|
524
|
+
>();
|
|
525
|
+
const levelAt = (d: number) => {
|
|
526
|
+
const found = MutableHashMap.get(levels, d);
|
|
527
|
+
if (Option.isSome(found)) return found.value;
|
|
528
|
+
const level = MutableHashMap.empty<string, Term.GroundTerm>();
|
|
529
|
+
MutableHashMap.set(levels, d, level);
|
|
530
|
+
return level;
|
|
531
|
+
};
|
|
532
|
+
const add = (t: Term.GroundTerm): void => {
|
|
533
|
+
if (Option.isSome(MutableHashMap.get(result, t.key))) return;
|
|
534
|
+
const cached = MutableHashMap.get(idCache, t.key);
|
|
535
|
+
if (Option.isSome(cached)) {
|
|
536
|
+
MutableHashMap.set(result, t.key, cached.value);
|
|
537
|
+
return;
|
|
538
|
+
}
|
|
539
|
+
const level = levelAt(depth(t));
|
|
540
|
+
if (Option.isSome(MutableHashMap.get(level, t.key))) return;
|
|
541
|
+
MutableHashMap.set(level, t.key, t);
|
|
542
|
+
if (Term.isTriple(t)) {
|
|
543
|
+
add(t.subject);
|
|
544
|
+
add(t.predicate);
|
|
545
|
+
add(t.object);
|
|
546
|
+
}
|
|
547
|
+
};
|
|
548
|
+
Arr.fromIterable(terms).forEach((t) => add(t));
|
|
549
|
+
const depths = Arr.sort(MutableHashMap.keys(levels), Order.Number);
|
|
550
|
+
yield* Effect.forEach(
|
|
551
|
+
depths,
|
|
552
|
+
Effect.fnUntraced(function* (d) {
|
|
553
|
+
const rows = encodeLevel(levelAt(d), result);
|
|
554
|
+
if (Arr.isReadonlyArrayEmpty(rows)) return;
|
|
555
|
+
const found = yield* findIds(rows, create);
|
|
556
|
+
found.forEach(({ encoded: { term }, id }) => {
|
|
557
|
+
if (Option.isNone(id)) return;
|
|
558
|
+
MutableHashMap.set(result, term.key, id.value);
|
|
559
|
+
if (cacheable) {
|
|
560
|
+
if (MutableHashMap.size(idCache) >= CACHE_LIMIT) MutableHashMap.clear(idCache);
|
|
561
|
+
MutableHashMap.set(idCache, term.key, id.value);
|
|
562
|
+
}
|
|
563
|
+
});
|
|
564
|
+
}),
|
|
565
|
+
{ concurrency: 1, discard: true },
|
|
566
|
+
);
|
|
567
|
+
return result;
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
// --- decoding -------------------------------------------------------------
|
|
571
|
+
|
|
572
|
+
/**
|
|
573
|
+
* Records the term with id `id` whose `kind, value, datatype, lang, dir`
|
|
574
|
+
* columns start at `row[at]` (`kind` is SQL `NULL` for an id with no term
|
|
575
|
+
* row).
|
|
576
|
+
*/
|
|
577
|
+
const addRow = (state: DecodeState, id: number, row: ReadonlyArray<unknown>, at: number) => {
|
|
578
|
+
if (isResolved(state, id)) return;
|
|
579
|
+
const cached = MutableHashMap.get(termCache, id);
|
|
580
|
+
if (Option.isSome(cached)) {
|
|
581
|
+
MutableHashMap.set(state.known, id, cached.value);
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
const kind = row[at];
|
|
585
|
+
if (Predicate.isNullish(kind)) return;
|
|
586
|
+
const t = Enc.decode(
|
|
587
|
+
num(kind),
|
|
588
|
+
str(row[at + 1]),
|
|
589
|
+
str(row[at + 2]),
|
|
590
|
+
str(row[at + 3]),
|
|
591
|
+
str(row[at + 4]),
|
|
592
|
+
);
|
|
593
|
+
if (Enc.isComponentIds(t)) MutableHashMap.set(state.triples, id, t);
|
|
594
|
+
else MutableHashMap.set(state.known, id, t);
|
|
595
|
+
};
|
|
596
|
+
|
|
597
|
+
/** Reads the dictionary rows of `ids` (one chunk) into a decode state. */
|
|
598
|
+
const fetchTerms = (state: DecodeState, ids: ReadonlyArray<number>) =>
|
|
599
|
+
Effect.map(
|
|
600
|
+
run(
|
|
601
|
+
`SELECT id, kind, value, datatype, lang, dir FROM ${T} WHERE id IN (${ids.join(', ')})`,
|
|
602
|
+
),
|
|
603
|
+
(rows) =>
|
|
604
|
+
rows.forEach((r) => {
|
|
605
|
+
addRow(state, num(r[0]), r, 1);
|
|
606
|
+
}),
|
|
607
|
+
);
|
|
608
|
+
|
|
609
|
+
/** Fetches the components of the triple terms of a decode state, until none is missing. */
|
|
610
|
+
const complete = (
|
|
611
|
+
state: DecodeState,
|
|
612
|
+
): Effect.Effect<void, Store.StoreError | SqlError.SqlError> =>
|
|
613
|
+
Effect.suspend(() => {
|
|
614
|
+
const missing = MutableHashSet.empty<number>();
|
|
615
|
+
MutableHashMap.forEach(state.triples, (comps) =>
|
|
616
|
+
comps.forEach((c) => {
|
|
617
|
+
if (!isResolved(state, c)) MutableHashSet.add(missing, c);
|
|
618
|
+
}),
|
|
619
|
+
);
|
|
620
|
+
// The cached terms need no query.
|
|
621
|
+
const unknown = Arr.filter(Arr.fromIterable(missing), (c) =>
|
|
622
|
+
Option.match(MutableHashMap.get(termCache, c), {
|
|
623
|
+
onNone: () => true,
|
|
624
|
+
onSome: (cached) => {
|
|
625
|
+
MutableHashMap.set(state.known, c, cached);
|
|
626
|
+
return false;
|
|
627
|
+
},
|
|
628
|
+
}),
|
|
629
|
+
);
|
|
630
|
+
if (Arr.isReadonlyArrayEmpty(unknown)) return Effect.void;
|
|
631
|
+
return Effect.forEach(
|
|
632
|
+
chunks(unknown, 500),
|
|
633
|
+
(chunk) =>
|
|
634
|
+
Effect.flatMap(fetchTerms(state, chunk), () =>
|
|
635
|
+
Option.match(
|
|
636
|
+
Arr.findFirst(chunk, (c) => !isResolved(state, c)),
|
|
637
|
+
{
|
|
638
|
+
onNone: () => Effect.void,
|
|
639
|
+
onSome: (c) =>
|
|
640
|
+
Effect.fail(new Store.StoreError({ message: `Unknown term id ${c}` })),
|
|
641
|
+
},
|
|
642
|
+
),
|
|
643
|
+
),
|
|
644
|
+
{ concurrency: 1, discard: true },
|
|
645
|
+
).pipe(Effect.flatMap(() => complete(state)));
|
|
646
|
+
});
|
|
647
|
+
|
|
648
|
+
const remember = (state: DecodeState) =>
|
|
649
|
+
Effect.map(inTransaction, (inTx) => {
|
|
650
|
+
if (inTx) return;
|
|
651
|
+
if (MutableHashMap.size(termCache) + MutableHashMap.size(state.known) > CACHE_LIMIT) {
|
|
652
|
+
MutableHashMap.clear(termCache);
|
|
653
|
+
}
|
|
654
|
+
MutableHashMap.forEach(state.known, (t, id) => {
|
|
655
|
+
MutableHashMap.set(termCache, id, t);
|
|
656
|
+
});
|
|
657
|
+
});
|
|
658
|
+
|
|
659
|
+
// --- quads ------------------------------------------------------------------
|
|
660
|
+
|
|
661
|
+
const patternConditions = (pattern: Store.QuadPattern) =>
|
|
662
|
+
Effect.gen(function* () {
|
|
663
|
+
const positions = [
|
|
664
|
+
['s', pattern.subject],
|
|
665
|
+
['p', pattern.predicate],
|
|
666
|
+
['o', pattern.object],
|
|
667
|
+
['g', pattern.graph],
|
|
668
|
+
] as const;
|
|
669
|
+
const present = Arr.filterMap(positions, ([column, t]) =>
|
|
670
|
+
t === undefined ? Result.failVoid : Result.succeed({ column, t }),
|
|
671
|
+
);
|
|
672
|
+
const ids = yield* resolveTerms(
|
|
673
|
+
Arr.filterMap(present, ({ t }) =>
|
|
674
|
+
Term.isDefaultGraph(t) ? Result.failVoid : Result.succeed(t),
|
|
675
|
+
),
|
|
676
|
+
false,
|
|
677
|
+
);
|
|
678
|
+
// A term that is not in the dictionary matches nothing.
|
|
679
|
+
return Option.all(
|
|
680
|
+
present.map(({ column, t }) =>
|
|
681
|
+
Option.map(idIn(ids, t), (id): readonly [string, number] => [column, id]),
|
|
682
|
+
),
|
|
683
|
+
);
|
|
684
|
+
});
|
|
685
|
+
|
|
686
|
+
const decodeQuads = (rows: ReadonlyArray<ReadonlyArray<unknown>>) =>
|
|
687
|
+
Effect.gen(function* () {
|
|
688
|
+
const state = newState();
|
|
689
|
+
rows.forEach((r) => {
|
|
690
|
+
addRow(state, num(r[0]), r, 4);
|
|
691
|
+
addRow(state, num(r[1]), r, 9);
|
|
692
|
+
addRow(state, num(r[2]), r, 14);
|
|
693
|
+
const g = num(r[3]);
|
|
694
|
+
if (g !== 0) addRow(state, g, r, 19);
|
|
695
|
+
});
|
|
696
|
+
yield* complete(state);
|
|
697
|
+
yield* remember(state);
|
|
698
|
+
// The store only inserts quads, so each column decodes to its position's kind and a
|
|
699
|
+
// non-zero graph to an IRI or blank node.
|
|
700
|
+
return rows.map((r) => {
|
|
701
|
+
const g = num(r[3]);
|
|
702
|
+
return new Term.Quad(
|
|
703
|
+
termAs(state, num(r[0]), isSubject, 'subject'),
|
|
704
|
+
termAs(state, num(r[1]), Term.isNamedNode, 'predicate'),
|
|
705
|
+
termOf(state, num(r[2])),
|
|
706
|
+
g === 0 ? Term.defaultGraph : termAs(state, g, isGraphName, 'graph name'),
|
|
707
|
+
);
|
|
708
|
+
});
|
|
709
|
+
});
|
|
710
|
+
|
|
711
|
+
const match = (pattern: Store.QuadPattern): Stream.Stream<Term.Quad, Store.StoreError> =>
|
|
712
|
+
Stream.unwrap(
|
|
713
|
+
Effect.gen(function* () {
|
|
714
|
+
const conds = yield* patternConditions(pattern);
|
|
715
|
+
if (Option.isNone(conds)) return Stream.empty;
|
|
716
|
+
const bound = MutableHashSet.fromIterable(conds.value.map(([c]) => c));
|
|
717
|
+
const order = indexFor(bound);
|
|
718
|
+
const where = conds.value.map(([c, id]) => `${c} = ${id}`);
|
|
719
|
+
const attrs = ['s', 'p', 'o', 'g']
|
|
720
|
+
.map((c) => `m${c}.kind, m${c}.value, m${c}.datatype, m${c}.lang, m${c}.dir`)
|
|
721
|
+
.join(', ');
|
|
722
|
+
const joins = ['s', 'p', 'o', 'g']
|
|
723
|
+
.map((c) => ` LEFT JOIN ${T} m${c} ON m${c}.id = q.${c}`)
|
|
724
|
+
.join('');
|
|
725
|
+
const page = (after: Option.Option<ReadonlyArray<number>>) => {
|
|
726
|
+
const w = Option.match(after, {
|
|
727
|
+
onNone: () => where,
|
|
728
|
+
onSome: (cursor) => [...where, `(${order.join(', ')}) > (${cursor.join(', ')})`],
|
|
729
|
+
});
|
|
730
|
+
return `SELECT q.s, q.p, q.o, q.g, ${attrs} FROM (SELECT s, p, o, g FROM ${Qt}${Arr.isReadonlyArrayNonEmpty(w) ? ` WHERE ${w.join(' AND ')}` : ''} ORDER BY ${order.join(', ')} LIMIT ${pageSize}) q${joins}`;
|
|
731
|
+
};
|
|
732
|
+
// The first page has no cursor.
|
|
733
|
+
return Stream.paginate(Option.none<ReadonlyArray<number>>(), (after) =>
|
|
734
|
+
Effect.gen(function* () {
|
|
735
|
+
const rows = yield* run(page(after));
|
|
736
|
+
const quads = yield* decodeQuads(rows);
|
|
737
|
+
const next =
|
|
738
|
+
rows.length < pageSize
|
|
739
|
+
? Option.none()
|
|
740
|
+
: Option.map(Arr.last(rows), (last) =>
|
|
741
|
+
Option.some(order.map((c) => num(last[['s', 'p', 'o', 'g'].indexOf(c)]))),
|
|
742
|
+
);
|
|
743
|
+
return [quads, next] as const;
|
|
744
|
+
}),
|
|
745
|
+
);
|
|
746
|
+
}),
|
|
747
|
+
).pipe(Stream.mapError(storeError('match failed')));
|
|
748
|
+
|
|
749
|
+
const countWhere = (pattern: Store.QuadPattern, limit: Option.Option<number>) =>
|
|
750
|
+
Effect.gen(function* () {
|
|
751
|
+
const conds = yield* patternConditions(pattern);
|
|
752
|
+
if (Option.isNone(conds)) return 0;
|
|
753
|
+
const where = conds.value.map(([c, id]) => `${c} = ${id}`);
|
|
754
|
+
const filter = Arr.isReadonlyArrayNonEmpty(where) ? ` WHERE ${where.join(' AND ')}` : '';
|
|
755
|
+
const rows = yield* run(
|
|
756
|
+
Option.match(limit, {
|
|
757
|
+
onNone: () => `SELECT COUNT(*) FROM ${Qt}${filter}`,
|
|
758
|
+
onSome: (n) => `SELECT COUNT(*) FROM (SELECT 1 FROM ${Qt}${filter} LIMIT ${n}) x`,
|
|
759
|
+
}),
|
|
760
|
+
);
|
|
761
|
+
return num(rows[0]?.[0] ?? 0);
|
|
762
|
+
}).pipe(Effect.mapError(storeError('count failed')));
|
|
763
|
+
|
|
764
|
+
const quadIds = (quads: Iterable<Term.Quad>, create: boolean) =>
|
|
765
|
+
Effect.gen(function* () {
|
|
766
|
+
const list = Arr.fromIterable(quads);
|
|
767
|
+
const terms: Array<Term.GroundTerm> = [];
|
|
768
|
+
list.forEach((q) => {
|
|
769
|
+
terms.push(q.subject, q.predicate, q.object);
|
|
770
|
+
if (!Term.isDefaultGraph(q.graph)) terms.push(q.graph);
|
|
771
|
+
});
|
|
772
|
+
const ids = yield* resolveTerms(terms, create);
|
|
773
|
+
return Arr.filterMap(list, (q) => quadRow(ids, q));
|
|
774
|
+
});
|
|
775
|
+
|
|
776
|
+
const tuples = (rows: ReadonlyArray<readonly [number, number, number, number]>) => {
|
|
777
|
+
const params: Array<number> = [];
|
|
778
|
+
const text = rows
|
|
779
|
+
.map((r) => {
|
|
780
|
+
const base = params.length;
|
|
781
|
+
params.push(...r);
|
|
782
|
+
return `(${r.map((_, i) => dialect.castId(ph(base + i + 1))).join(', ')})`;
|
|
783
|
+
})
|
|
784
|
+
.join(', ');
|
|
785
|
+
return { text, params };
|
|
786
|
+
};
|
|
787
|
+
|
|
788
|
+
/** Runs one statement per `batchSize` quad-id rows, `statement` building it from the tuples. */
|
|
789
|
+
const execBatches = (
|
|
790
|
+
rows: ReadonlyArray<readonly [number, number, number, number]>,
|
|
791
|
+
statement: (tuplesText: string) => string,
|
|
792
|
+
) =>
|
|
793
|
+
Effect.forEach(
|
|
794
|
+
chunks(rows, batchSize),
|
|
795
|
+
(chunk) => {
|
|
796
|
+
const { text, params } = tuples(chunk);
|
|
797
|
+
return exec(statement(text), params);
|
|
798
|
+
},
|
|
799
|
+
{ concurrency: 1, discard: true },
|
|
800
|
+
);
|
|
801
|
+
|
|
802
|
+
const insert = (quads: Iterable<Term.Quad>) =>
|
|
803
|
+
sql
|
|
804
|
+
.withTransaction(
|
|
805
|
+
Effect.gen(function* () {
|
|
806
|
+
const list = Array.from(quads);
|
|
807
|
+
yield* Effect.forEach(
|
|
808
|
+
chunks(list, batchSize * 4),
|
|
809
|
+
(batch) =>
|
|
810
|
+
Effect.flatMap(quadIds(batch, true), (rows) =>
|
|
811
|
+
execBatches(
|
|
812
|
+
rows,
|
|
813
|
+
(text) =>
|
|
814
|
+
`INSERT INTO ${Qt} (s, p, o, g) VALUES ${text} ON CONFLICT DO NOTHING`,
|
|
815
|
+
),
|
|
816
|
+
),
|
|
817
|
+
{ concurrency: 1, discard: true },
|
|
818
|
+
);
|
|
819
|
+
}),
|
|
820
|
+
)
|
|
821
|
+
.pipe(Effect.mapError(storeError('insert failed')));
|
|
822
|
+
|
|
823
|
+
const del = (quads: Iterable<Term.Quad>) =>
|
|
824
|
+
sql
|
|
825
|
+
.withTransaction(
|
|
826
|
+
Effect.gen(function* () {
|
|
827
|
+
const rows = yield* quadIds(quads, false);
|
|
828
|
+
yield* execBatches(
|
|
829
|
+
rows,
|
|
830
|
+
(text) => `DELETE FROM ${Qt} WHERE (s, p, o, g) IN (VALUES ${text})`,
|
|
831
|
+
);
|
|
832
|
+
}),
|
|
833
|
+
)
|
|
834
|
+
.pipe(Effect.mapError(storeError('delete failed')));
|
|
835
|
+
|
|
836
|
+
const decodeIds = (ids: ReadonlyArray<number>) =>
|
|
837
|
+
Effect.gen(function* () {
|
|
838
|
+
const state = newState();
|
|
839
|
+
yield* Effect.forEach(chunks(ids, 500), (chunk) => fetchTerms(state, chunk), {
|
|
840
|
+
concurrency: 1,
|
|
841
|
+
discard: true,
|
|
842
|
+
});
|
|
843
|
+
yield* complete(state);
|
|
844
|
+
yield* remember(state);
|
|
845
|
+
// The ids come from the graph table and the quads' graph column, so they decode to IRIs
|
|
846
|
+
// or blank nodes.
|
|
847
|
+
return ids.map((id) => termAs(state, id, isGraphName, 'graph name'));
|
|
848
|
+
});
|
|
849
|
+
|
|
850
|
+
const graphs: Stream.Stream<Term.NamedNode | Term.BlankNode, Store.StoreError> = Stream.unwrap(
|
|
851
|
+
Effect.gen(function* () {
|
|
852
|
+
const rows = yield* run(
|
|
853
|
+
`SELECT id FROM ${Gt} UNION SELECT DISTINCT g FROM ${Qt} WHERE g <> 0`,
|
|
854
|
+
);
|
|
855
|
+
return Stream.fromArray(yield* decodeIds(rows.map((r) => num(r[0]))));
|
|
856
|
+
}),
|
|
857
|
+
).pipe(Stream.mapError(storeError('graphs failed')));
|
|
858
|
+
|
|
859
|
+
const graphIdOf = (graph: Term.NamedNode | Term.BlankNode, create: boolean) =>
|
|
860
|
+
Effect.map(resolveTerms([graph], create), (ids) => MutableHashMap.get(ids, graph.key));
|
|
861
|
+
|
|
862
|
+
const hasGraph = (graph: Term.NamedNode | Term.BlankNode) =>
|
|
863
|
+
Effect.gen(function* () {
|
|
864
|
+
const found = yield* graphIdOf(graph, false);
|
|
865
|
+
if (Option.isNone(found)) return false;
|
|
866
|
+
const id = found.value;
|
|
867
|
+
const rows = yield* run(
|
|
868
|
+
`SELECT 1 WHERE EXISTS (SELECT 1 FROM ${Gt} WHERE id = ${id}) OR EXISTS (SELECT 1 FROM ${Qt} WHERE g = ${id})`,
|
|
869
|
+
);
|
|
870
|
+
return Arr.isReadonlyArrayNonEmpty(rows);
|
|
871
|
+
}).pipe(Effect.mapError(storeError('hasGraph failed')));
|
|
872
|
+
|
|
873
|
+
const createGraph = (graph: Term.NamedNode | Term.BlankNode) =>
|
|
874
|
+
sql
|
|
875
|
+
.withTransaction(
|
|
876
|
+
Effect.gen(function* () {
|
|
877
|
+
const id = yield* graphIdOf(graph, true);
|
|
878
|
+
if (Option.isNone(id)) return;
|
|
879
|
+
yield* exec(`INSERT INTO ${Gt} (id) VALUES (${id.value}) ON CONFLICT DO NOTHING`);
|
|
880
|
+
}),
|
|
881
|
+
)
|
|
882
|
+
.pipe(Effect.mapError(storeError('createGraph failed')));
|
|
883
|
+
|
|
884
|
+
const dropGraph = (graph: Term.NamedNode | Term.BlankNode) =>
|
|
885
|
+
sql
|
|
886
|
+
.withTransaction(
|
|
887
|
+
Effect.gen(function* () {
|
|
888
|
+
const id = yield* graphIdOf(graph, false);
|
|
889
|
+
if (Option.isNone(id)) return;
|
|
890
|
+
yield* exec(`DELETE FROM ${Qt} WHERE g = ${id.value}`);
|
|
891
|
+
yield* exec(`DELETE FROM ${Gt} WHERE id = ${id.value}`);
|
|
892
|
+
}),
|
|
893
|
+
)
|
|
894
|
+
.pipe(Effect.mapError(storeError('dropGraph failed')));
|
|
895
|
+
|
|
896
|
+
const clear = (graph: Term.Graph) =>
|
|
897
|
+
Effect.gen(function* () {
|
|
898
|
+
const id = Term.isDefaultGraph(graph) ? Option.some(0) : yield* graphIdOf(graph, false);
|
|
899
|
+
if (Option.isNone(id)) return;
|
|
900
|
+
yield* exec(`DELETE FROM ${Qt} WHERE g = ${id.value}`);
|
|
901
|
+
}).pipe(Effect.mapError(storeError('clear failed')));
|
|
902
|
+
|
|
903
|
+
const transaction = <A, E, R>(
|
|
904
|
+
effect: Effect.Effect<A, E, R>,
|
|
905
|
+
): Effect.Effect<A, E | Store.StoreError, R> =>
|
|
906
|
+
sql.withTransaction(effect).pipe(
|
|
907
|
+
Effect.mapError((e) =>
|
|
908
|
+
// SAFETY: `withTransaction` adds only `SqlError` to `E`, and that case was handled.
|
|
909
|
+
SqlError.isSqlError(e) ? storeError('transaction failed')(e) : e,
|
|
910
|
+
),
|
|
911
|
+
);
|
|
912
|
+
|
|
913
|
+
// --- SPARQL to SQL ------------------------------------------------------------
|
|
914
|
+
|
|
915
|
+
const storeClasses = Effect.map(
|
|
916
|
+
run(`SELECT cls FROM ${tables.classes}`),
|
|
917
|
+
(rows) => new Set(rows.map((r) => num(r[0]))),
|
|
918
|
+
);
|
|
919
|
+
|
|
920
|
+
const translationContext = (
|
|
921
|
+
context?: Partial<Pick<Store.EvaluationContext, 'dataset' | 'activeGraph'>>,
|
|
922
|
+
): Translation.TranslationContext => ({
|
|
923
|
+
dialect,
|
|
924
|
+
tables,
|
|
925
|
+
dataset: context?.dataset ?? DEFAULT_DATASET,
|
|
926
|
+
activeGraph: context?.activeGraph ?? { _tag: 'DefaultGraph' },
|
|
927
|
+
});
|
|
928
|
+
|
|
929
|
+
const compile: SqlStoreShape['compile'] = (op, context) =>
|
|
930
|
+
Effect.gen(function* () {
|
|
931
|
+
const ctx = translationContext(context);
|
|
932
|
+
const ids = yield* resolveTerms(Translation.constants(op, ctx), false);
|
|
933
|
+
return Translation.compile(op, ctx, resolveIn(ids));
|
|
934
|
+
}).pipe(Effect.mapError(storeError('compile failed')));
|
|
935
|
+
|
|
936
|
+
const decodeSolutions = (
|
|
937
|
+
compiled: Translation.CompiledQuery,
|
|
938
|
+
rows: ReadonlyArray<ReadonlyArray<unknown>>,
|
|
939
|
+
) =>
|
|
940
|
+
Effect.gen(function* () {
|
|
941
|
+
const layout = columnLayout(compiled.columns);
|
|
942
|
+
const terms = layout.filter(({ column }) => column.type === 'id');
|
|
943
|
+
const state = newState();
|
|
944
|
+
compiled.locals.forEach((t, id) => {
|
|
945
|
+
MutableHashMap.set(state.known, id, t);
|
|
946
|
+
});
|
|
947
|
+
rows.forEach((r) =>
|
|
948
|
+
terms.forEach(({ at }) => {
|
|
949
|
+
// An unbound variable is SQL `NULL`.
|
|
950
|
+
const v = r[at];
|
|
951
|
+
if (Predicate.isNullish(v)) return;
|
|
952
|
+
const id = num(v);
|
|
953
|
+
if (id > 0) addRow(state, id, r, at + 1);
|
|
954
|
+
}),
|
|
955
|
+
);
|
|
956
|
+
yield* complete(state);
|
|
957
|
+
compiled.locals.forEach((_, id) => {
|
|
958
|
+
MutableHashMap.remove(state.known, id);
|
|
959
|
+
});
|
|
960
|
+
yield* remember(state);
|
|
961
|
+
compiled.locals.forEach((t, id) => {
|
|
962
|
+
MutableHashMap.set(state.known, id, t);
|
|
963
|
+
});
|
|
964
|
+
return rows.map((r) =>
|
|
965
|
+
B.fromEntries(
|
|
966
|
+
Arr.filterMap(layout, ({ column, at }) => {
|
|
967
|
+
const v = r[at];
|
|
968
|
+
if (Predicate.isNullish(v)) return Result.failVoid;
|
|
969
|
+
const term =
|
|
970
|
+
column.type === 'int' ? new Term.Literal(str(v), INTEGER) : termOf(state, num(v));
|
|
971
|
+
return Result.succeed([column.variable, term] as const);
|
|
972
|
+
}),
|
|
973
|
+
),
|
|
974
|
+
);
|
|
975
|
+
});
|
|
976
|
+
|
|
977
|
+
const declined = new WeakSet<Algebra.Operation>();
|
|
978
|
+
|
|
979
|
+
const capability: Store.QueryCapability = {
|
|
980
|
+
evaluate: (op, context) => {
|
|
981
|
+
if (options.translate === false) return Option.none();
|
|
982
|
+
if (declined.has(op)) {
|
|
983
|
+
declined.delete(op);
|
|
984
|
+
return Option.none();
|
|
985
|
+
}
|
|
986
|
+
const ctx = translationContext(context);
|
|
987
|
+
const check = Translation.compile(op, ctx, () => undefined);
|
|
988
|
+
if (Result.isFailure(check)) {
|
|
989
|
+
onQuery?.({ _tag: 'Declined', operation: op, reason: check.failure });
|
|
990
|
+
return Option.none();
|
|
991
|
+
}
|
|
992
|
+
const stream: Stream.Stream<B.Bindings, Store.StoreError> = Stream.unwrap(
|
|
993
|
+
Effect.gen(function* () {
|
|
994
|
+
const ids = yield* resolveTerms(Translation.constants(op, ctx), false);
|
|
995
|
+
const compiled = Translation.compile(op, ctx, resolveIn(ids));
|
|
996
|
+
if (Result.isFailure(compiled)) {
|
|
997
|
+
return yield* new Store.StoreError({ message: compiled.failure });
|
|
998
|
+
}
|
|
999
|
+
const q = compiled.success;
|
|
1000
|
+
if (
|
|
1001
|
+
Arr.isReadonlyArrayNonEmpty(q.risks) &&
|
|
1002
|
+
Translation.isRisky(q, yield* storeClasses)
|
|
1003
|
+
) {
|
|
1004
|
+
onQuery?.({
|
|
1005
|
+
_tag: 'Declined',
|
|
1006
|
+
operation: op,
|
|
1007
|
+
reason: 'The data contains values SQL cannot compare exactly',
|
|
1008
|
+
});
|
|
1009
|
+
declined.add(op);
|
|
1010
|
+
return Stream.mapError(context.evaluate(op), storeError('evaluation failed'));
|
|
1011
|
+
}
|
|
1012
|
+
const rows = yield* run(q.sql, q.params).pipe(
|
|
1013
|
+
Effect.withSpan('SqlStore.query', { attributes: { 'db.query.text': q.sql } }),
|
|
1014
|
+
);
|
|
1015
|
+
onQuery?.({
|
|
1016
|
+
_tag: 'Executed',
|
|
1017
|
+
operation: op,
|
|
1018
|
+
sql: q.sql,
|
|
1019
|
+
params: q.params,
|
|
1020
|
+
rows: rows.length,
|
|
1021
|
+
});
|
|
1022
|
+
return Stream.fromArray(yield* decodeSolutions(q, rows));
|
|
1023
|
+
}).pipe(Effect.mapError(storeError('SQL query failed'))),
|
|
1024
|
+
);
|
|
1025
|
+
return Option.some(stream);
|
|
1026
|
+
},
|
|
1027
|
+
};
|
|
1028
|
+
|
|
1029
|
+
const termCount = Effect.map(run(`SELECT COUNT(*) FROM ${T}`), (rows) =>
|
|
1030
|
+
num(rows[0]?.[0] ?? 0),
|
|
1031
|
+
).pipe(Effect.mapError(storeError('termCount failed')));
|
|
1032
|
+
|
|
1033
|
+
const store: SqlStoreShape = {
|
|
1034
|
+
dialect,
|
|
1035
|
+
tables,
|
|
1036
|
+
capability,
|
|
1037
|
+
compile,
|
|
1038
|
+
termCount,
|
|
1039
|
+
match,
|
|
1040
|
+
estimate: (pattern) => countWhere(pattern, Option.some(10_000)),
|
|
1041
|
+
count: (pattern) => countWhere(pattern, Option.none()),
|
|
1042
|
+
graphs,
|
|
1043
|
+
hasGraph,
|
|
1044
|
+
insert,
|
|
1045
|
+
delete: del,
|
|
1046
|
+
createGraph,
|
|
1047
|
+
dropGraph,
|
|
1048
|
+
clear,
|
|
1049
|
+
transaction,
|
|
1050
|
+
query: capability,
|
|
1051
|
+
};
|
|
1052
|
+
return store;
|
|
1053
|
+
});
|
|
1054
|
+
|
|
1055
|
+
/** The `resolve` of `Translation.compile` over resolved term ids. */
|
|
1056
|
+
const resolveIn = (ids: Ids) => (t: Term.GroundTerm) =>
|
|
1057
|
+
Option.getOrUndefined(MutableHashMap.get(ids, t.key));
|
|
1058
|
+
|
|
1059
|
+
const INTEGER = Term.namedNode('http://www.w3.org/2001/XMLSchema#integer');
|
|
1060
|
+
|
|
1061
|
+
// -----------------------------------------------------------------------------
|
|
1062
|
+
// Layers
|
|
1063
|
+
// -----------------------------------------------------------------------------
|
|
1064
|
+
|
|
1065
|
+
/**
|
|
1066
|
+
* A layer providing the SQL store as both `SqlStore` and the engine's
|
|
1067
|
+
* `QuadStore` (whose `query` is the SPARQL-to-SQL `QueryCapability`), over
|
|
1068
|
+
* the `SqlClient` service.
|
|
1069
|
+
*
|
|
1070
|
+
* @since 0.1.0
|
|
1071
|
+
* @category layers
|
|
1072
|
+
*/
|
|
1073
|
+
export const layer = (
|
|
1074
|
+
options: SqlStoreOptions = {},
|
|
1075
|
+
): Layer.Layer<SqlStore | Store.QuadStore, Store.StoreError, SqlClient.SqlClient> =>
|
|
1076
|
+
Layer.effectContext(
|
|
1077
|
+
Effect.map(make(options), (store) =>
|
|
1078
|
+
Context.make(SqlStore, store).pipe(Context.add(Store.QuadStore, store)),
|
|
1079
|
+
),
|
|
1080
|
+
);
|