From 7f3e45ea7c3bacebc57d1a15b48ce2400095e1bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20H=C3=B6ij?= Date: Sun, 6 Apr 2025 21:53:36 +0200 Subject: [PATCH] Use licensed tailwindui template --- generate_markdown.js | 90 + next.config.js => next.config.mjs | 9 +- package-lock.json | 5469 +++++++--- package.json | 44 +- postcss.config.js | 3 +- prettier.config.js | 7 + schema/all_documents.json | 2897 ++++++ schema/javascript.json | 9032 +++++++++++++++++ schema/python.json | 1 + .../access-control-with-javascript/page.md | 1157 +++ .../acid-transactions-explanation/page.md | 56 + src/app/docs/add-a-document/page.md | 43 + .../page.md | 26 + src/app/docs/add-a-schema/page.md | 37 + .../add-documents-with-python-client/page.md | 41 + src/app/docs/add-documents-with-woql/page.md | 31 + .../advanced-filtering-with-graphql/page.md | 273 + src/app/docs/array/page.md | 172 + src/app/docs/back-links-in-graphql/page.md | 62 + .../page.md | 99 + src/app/docs/branch-a-project/page.md | 107 + src/app/docs/branch/page.md | 55 + src/app/docs/change-request-workflows/page.md | 116 + src/app/docs/choice-document/page.md | 211 + src/app/docs/choice-subdocuments/page.md | 362 + .../docs/clone-a-database-with-python/page.md | 40 + .../clone-a-demo-terminuscms-project/page.md | 29 + src/app/docs/clone-a-project/page.md | 30 + src/app/docs/clone/page.md | 28 + .../page.md | 14 + .../collaboration-with-python-client/page.md | 14 + .../page.md | 14 + .../page.md | 36 + src/app/docs/connect-to-a-database/page.md | 23 + .../docs/connect-with-apollo-client/page.md | 142 + .../docs/connect-with-python-client/page.md | 60 + .../page.md | 54 + .../connecting-to-graphql-reference/page.md | 85 + .../content-curation-terminuscms-tour/page.md | 114 + src/app/docs/create-a-database/page.md | 37 + .../create-a-project-with-terminuscms/page.md | 30 + .../create-a-team-with-terminuscms/page.md | 39 + .../page.md | 30 + src/app/docs/curate-and-import-data/page.md | 14 + src/app/docs/datalog-explanation/page.md | 64 + src/app/docs/delete-a-document/page.md | 22 + .../page.md | 18 + .../docs/delete-documents-with-woql/page.md | 32 + .../docs/diff-and-patch-operations/page.md | 97 + src/app/docs/document-insertion/page.md | 446 + .../docs/document-ui-sdk-data-types/page.md | 381 + src/app/docs/document-ui-sdk/page.md | 300 + src/app/docs/document-ui-template/page.md | 34 + src/app/docs/documentclassessummary/page.md | 91 + src/app/docs/documents-explanation/page.md | 315 + src/app/docs/documentsgraphqltable/page.md | 127 + src/app/docs/edit-a-document/page.md | 30 + src/app/docs/edit-document-component/page.md | 131 + .../edit-documents-with-python-client/page.md | 24 + src/app/docs/edit-documents-with-woql/page.md | 29 + src/app/docs/filter-with-graphql/page.md | 84 + src/app/docs/filter-with-woql/page.md | 115 + .../get-documents-with-python-client/page.md | 61 + src/app/docs/get-documents/page.md | 66 + .../docs/get-started-with-terminusdb/page.md | 80 + src/app/docs/get-started/page.md | 37 + .../get-your-api-key-from-terminuscms/page.md | 51 + src/app/docs/glossary/page.md | 182 + .../page.md | 57 + src/app/docs/graphql-basics/page.md | 171 + .../page.md | 60 + src/app/docs/graphql-query-reference/page.md | 436 + src/app/docs/graphs-explanation/page.md | 95 + src/app/docs/group-query-results/page.md | 94 + .../docs/how-to-connect-terminuscms/page.md | 27 + .../docs/how-to-query-with-graphql/page.md | 12 + src/app/docs/how-to-query-with-woql/page.md | 12 + src/app/docs/how-to-query/page.md | 12 + src/app/docs/immutability-explanation/page.md | 44 + .../import-data-with-python-client/page.md | 26 + src/app/docs/index-your-data/page.md | 19 + src/app/docs/install-on-kubernetes/page.md | 119 + .../page.md | 156 + .../page.md | 134 + .../docs/install-terminusdb-js-client/page.md | 40 + .../docs/install-the-python-client/page.md | 25 + .../invite-users-using-terminuscms/page.md | 60 + src/app/docs/javascript/page.tsx | 87 + src/app/docs/js-access-control/page.md | 1096 ++ src/app/docs/json-diff-and-patch/page.md | 476 + src/app/docs/limit-results-in-graphql/page.md | 71 + src/app/docs/list-documents-component/page.md | 170 + src/app/docs/list/page.md | 172 + .../manage-projects-with-terminuscms/page.md | 14 + .../page.md | 111 + src/app/docs/mandatory/page.md | 155 + .../docs/maths-based-queries-in-woql/page.md | 41 + src/app/docs/model-schema/page.md | 14 + src/app/docs/newdocumentcomponent/page.md | 123 + src/app/docs/offset-to-provide-paging/page.md | 105 + src/app/docs/oneof/page.md | 142 + src/app/docs/openai-handlebars-config/page.md | 79 + src/app/docs/openapi/SwaggerDark.tsx | 11 + src/app/docs/openapi/SwaggerLight.tsx | 10 + src/app/docs/openapi/page.tsx | 26 + src/app/docs/openapi/swaggerdark.css | 849 ++ src/app/docs/optional/page.md | 182 + src/app/docs/order-by-in-graphql/page.md | 97 + src/app/docs/order-by-with-woql/page.md | 63 + src/app/docs/orderby/page.md | 105 + src/app/docs/page.md | 39 + src/app/docs/path-queries-in-graphql/page.md | 51 + src/app/docs/path-queries-in-woql/page.md | 37 + .../docs/path-query-reference-guide/page.md | 286 + src/app/docs/product-tour/page.md | 37 + .../docs/projects-terminuscms-tour/page.md | 161 + .../page.md | 319 + src/app/docs/python/page.tsx | 87 + .../query-arrays-and-sets-in-woql/page.md | 70 + src/app/docs/query-documents/page.md | 30 + src/app/docs/read-documents-with-woql/page.md | 25 + src/app/docs/render-as/page.md | 79 + src/app/docs/reset-a-project/page.md | 23 + .../reset-to-a-commit-with-python/page.md | 54 + src/app/docs/reset/page.md | 38 + src/app/docs/run-woql-query/page.md | 27 + .../schema-migration-reference-guide/page.md | 373 + src/app/docs/schema-queries-with-woql/page.md | 56 + src/app/docs/schema-reference-guide/page.md | 1648 +++ src/app/docs/set-up-vectorlink/page.md | 30 + src/app/docs/set/page.md | 180 + .../docs/squash-a-project-with-python/page.md | 25 + src/app/docs/squash-projects/page.md | 50 + src/app/docs/squash/page.md | 38 + src/app/docs/sysjson/page.md | 104 + .../page.md | 38 + src/app/docs/tdb-react-table/page.md | 377 + .../terminuscms-dashboard-reference/page.md | 102 + src/app/docs/terminuscms-data-types/page.md | 300 + src/app/docs/terminusdb-cli-commands/page.md | 1020 ++ src/app/docs/terminusdb-explanation/page.md | 105 + .../docs/terminusdb-install-options/page.md | 12 + .../time-travel-to-previous-commits/page.md | 91 + src/app/docs/time-travel-with-python/page.md | 56 + src/app/docs/time-travel/page.md | 39 + src/app/docs/ui-components/page.md | 14 + src/app/docs/ui-sdk-geojson/page.md | 511 + .../page.md | 215 + src/app/docs/use-the-clients/page.md | 14 + .../use-the-collaboration-features/page.md | 14 + .../docs/use-the-javascript-client/page.md | 14 + src/app/docs/use-the-json-editor/page.md | 39 + src/app/docs/use-the-model-builder-ui/page.md | 94 + src/app/docs/use-the-python-client/page.md | 12 + src/app/docs/use-vectorlink/page.md | 13 + src/app/docs/usetdbdocuments/page.md | 71 + src/app/docs/usetdbgraphqlquery/page.md | 115 + src/app/docs/viewdocumentcomponent/page.md | 142 + src/app/docs/what-is-schema-weakening/page.md | 48 + src/app/docs/woql-basics/page.md | 111 + .../docs/woql-class-reference-guide/page.md | 2692 +++++ src/app/docs/woql-explanation/page.md | 215 + .../woql-query-with-python-client/page.md | 30 + src/app/favicon.ico | Bin 0 -> 15406 bytes src/app/layout.tsx | 61 + src/app/not-found.tsx | 25 + src/app/page.md | 28 + src/app/providers.tsx | 11 + src/components/Button.tsx | 30 + src/components/Callout.tsx | 53 + src/components/DocsHeader.tsx | 31 + src/components/DocsLayout.tsx | 32 + src/components/Fence.tsx | 37 + src/components/Hero.tsx | 175 + src/components/HeroBackground.tsx | 188 + src/components/Icon.tsx | 96 + src/components/Layout.tsx | 90 + src/components/Logo.tsx | 51 + src/components/MobileNavigation.tsx | 103 + src/components/Navigation.tsx | 200 + src/components/PrevNextLinks.tsx | 70 + src/components/Prose.tsx | 33 + src/components/QuickLinks.tsx | 41 + src/components/Search.tsx | 464 + src/components/TableOfContents.tsx | 119 + src/components/ThemeSelector.tsx | 125 + src/components/_onThisPage.tsx | 6 +- src/components/icons/InstallationIcon.tsx | 47 + src/components/icons/LightbulbIcon.tsx | 52 + src/components/icons/PluginsIcon.tsx | 69 + src/components/icons/PresetsIcon.tsx | 49 + src/components/icons/ThemingIcon.tsx | 65 + src/components/icons/WarningIcon.tsx | 61 + src/components/seo.tsx | 1 + src/fonts/lexend.txt | 93 + src/fonts/lexend.woff2 | Bin 0 -> 71760 bytes src/images/TerminusDB-Logo.svg | 83 + src/images/blur-cyan.png | Bin 0 -> 218615 bytes src/images/blur-indigo.png | Bin 0 -> 224214 bytes src/lib/navigation.ts | 994 ++ src/lib/sections.ts | 97 + src/markdoc/nodes.js | 63 + src/markdoc/search.mjs | 145 + src/markdoc/tags.js | 47 + src/pages/404.tsx | 22 - src/pages/_app.tsx | 67 - src/pages/_document.tsx | 45 - src/pages/docs/[name].tsx | 121 - src/pages/docs/index.tsx | 52 - src/pages/docs/javascript.tsx | 133 - src/pages/docs/openapi.tsx | 29 - src/pages/docs/python.tsx | 141 - src/pages/index.tsx | 52 - src/styles/globals.css | 17 +- src/styles/prism.css | 47 + src/styles/tailwind-terminusdb.css | 2156 ++++ src/styles/tailwind.css | 2194 +--- tailwind.config.js | 4 + tsconfig.json | 11 +- types.d.ts | 11 + 220 files changed, 45200 insertions(+), 4056 deletions(-) create mode 100644 generate_markdown.js rename next.config.js => next.config.mjs (59%) create mode 100644 prettier.config.js create mode 100644 schema/javascript.json create mode 100644 schema/python.json create mode 100644 src/app/docs/access-control-with-javascript/page.md create mode 100644 src/app/docs/acid-transactions-explanation/page.md create mode 100644 src/app/docs/add-a-document/page.md create mode 100644 src/app/docs/add-a-schema-with-the-python-client/page.md create mode 100644 src/app/docs/add-a-schema/page.md create mode 100644 src/app/docs/add-documents-with-python-client/page.md create mode 100644 src/app/docs/add-documents-with-woql/page.md create mode 100644 src/app/docs/advanced-filtering-with-graphql/page.md create mode 100644 src/app/docs/array/page.md create mode 100644 src/app/docs/back-links-in-graphql/page.md create mode 100644 src/app/docs/branch-a-project-with-the-python-client/page.md create mode 100644 src/app/docs/branch-a-project/page.md create mode 100644 src/app/docs/branch/page.md create mode 100644 src/app/docs/change-request-workflows/page.md create mode 100644 src/app/docs/choice-document/page.md create mode 100644 src/app/docs/choice-subdocuments/page.md create mode 100644 src/app/docs/clone-a-database-with-python/page.md create mode 100644 src/app/docs/clone-a-demo-terminuscms-project/page.md create mode 100644 src/app/docs/clone-a-project/page.md create mode 100644 src/app/docs/clone/page.md create mode 100644 src/app/docs/collaboration-with-javascript-client/page.md create mode 100644 src/app/docs/collaboration-with-python-client/page.md create mode 100644 src/app/docs/collaboration-with-terminuscms-dashboard/page.md create mode 100644 src/app/docs/connect-to-a-database-with-python-client/page.md create mode 100644 src/app/docs/connect-to-a-database/page.md create mode 100644 src/app/docs/connect-with-apollo-client/page.md create mode 100644 src/app/docs/connect-with-python-client/page.md create mode 100644 src/app/docs/connect-with-the-javascript-client/page.md create mode 100644 src/app/docs/connecting-to-graphql-reference/page.md create mode 100644 src/app/docs/content-curation-terminuscms-tour/page.md create mode 100644 src/app/docs/create-a-database/page.md create mode 100644 src/app/docs/create-a-project-with-terminuscms/page.md create mode 100644 src/app/docs/create-a-team-with-terminuscms/page.md create mode 100644 src/app/docs/create-database-with-python-client/page.md create mode 100644 src/app/docs/curate-and-import-data/page.md create mode 100644 src/app/docs/datalog-explanation/page.md create mode 100644 src/app/docs/delete-a-document/page.md create mode 100644 src/app/docs/delete-documents-with-python-client/page.md create mode 100644 src/app/docs/delete-documents-with-woql/page.md create mode 100644 src/app/docs/diff-and-patch-operations/page.md create mode 100644 src/app/docs/document-insertion/page.md create mode 100644 src/app/docs/document-ui-sdk-data-types/page.md create mode 100644 src/app/docs/document-ui-sdk/page.md create mode 100644 src/app/docs/document-ui-template/page.md create mode 100644 src/app/docs/documentclassessummary/page.md create mode 100644 src/app/docs/documents-explanation/page.md create mode 100644 src/app/docs/documentsgraphqltable/page.md create mode 100644 src/app/docs/edit-a-document/page.md create mode 100644 src/app/docs/edit-document-component/page.md create mode 100644 src/app/docs/edit-documents-with-python-client/page.md create mode 100644 src/app/docs/edit-documents-with-woql/page.md create mode 100644 src/app/docs/filter-with-graphql/page.md create mode 100644 src/app/docs/filter-with-woql/page.md create mode 100644 src/app/docs/get-documents-with-python-client/page.md create mode 100644 src/app/docs/get-documents/page.md create mode 100644 src/app/docs/get-started-with-terminusdb/page.md create mode 100644 src/app/docs/get-started/page.md create mode 100644 src/app/docs/get-your-api-key-from-terminuscms/page.md create mode 100644 src/app/docs/glossary/page.md create mode 100644 src/app/docs/graphql-and-woql-query-terminuscms-tour/page.md create mode 100644 src/app/docs/graphql-basics/page.md create mode 100644 src/app/docs/graphql-naming-conventions-reference/page.md create mode 100644 src/app/docs/graphql-query-reference/page.md create mode 100644 src/app/docs/graphs-explanation/page.md create mode 100644 src/app/docs/group-query-results/page.md create mode 100644 src/app/docs/how-to-connect-terminuscms/page.md create mode 100644 src/app/docs/how-to-query-with-graphql/page.md create mode 100644 src/app/docs/how-to-query-with-woql/page.md create mode 100644 src/app/docs/how-to-query/page.md create mode 100644 src/app/docs/immutability-explanation/page.md create mode 100644 src/app/docs/import-data-with-python-client/page.md create mode 100644 src/app/docs/index-your-data/page.md create mode 100644 src/app/docs/install-on-kubernetes/page.md create mode 100644 src/app/docs/install-terminusdb-as-a-docker-container/page.md create mode 100644 src/app/docs/install-terminusdb-from-source-code/page.md create mode 100644 src/app/docs/install-terminusdb-js-client/page.md create mode 100644 src/app/docs/install-the-python-client/page.md create mode 100644 src/app/docs/invite-users-using-terminuscms/page.md create mode 100644 src/app/docs/javascript/page.tsx create mode 100644 src/app/docs/js-access-control/page.md create mode 100644 src/app/docs/json-diff-and-patch/page.md create mode 100644 src/app/docs/limit-results-in-graphql/page.md create mode 100644 src/app/docs/list-documents-component/page.md create mode 100644 src/app/docs/list/page.md create mode 100644 src/app/docs/manage-projects-with-terminuscms/page.md create mode 100644 src/app/docs/manage-teams-users-terminuscms-tour/page.md create mode 100644 src/app/docs/mandatory/page.md create mode 100644 src/app/docs/maths-based-queries-in-woql/page.md create mode 100644 src/app/docs/model-schema/page.md create mode 100644 src/app/docs/newdocumentcomponent/page.md create mode 100644 src/app/docs/offset-to-provide-paging/page.md create mode 100644 src/app/docs/oneof/page.md create mode 100644 src/app/docs/openai-handlebars-config/page.md create mode 100644 src/app/docs/openapi/SwaggerDark.tsx create mode 100644 src/app/docs/openapi/SwaggerLight.tsx create mode 100644 src/app/docs/openapi/page.tsx create mode 100644 src/app/docs/openapi/swaggerdark.css create mode 100644 src/app/docs/optional/page.md create mode 100644 src/app/docs/order-by-in-graphql/page.md create mode 100644 src/app/docs/order-by-with-woql/page.md create mode 100644 src/app/docs/orderby/page.md create mode 100644 src/app/docs/page.md create mode 100644 src/app/docs/path-queries-in-graphql/page.md create mode 100644 src/app/docs/path-queries-in-woql/page.md create mode 100644 src/app/docs/path-query-reference-guide/page.md create mode 100644 src/app/docs/product-tour/page.md create mode 100644 src/app/docs/projects-terminuscms-tour/page.md create mode 100644 src/app/docs/python-woql-customer-data-processing-example/page.md create mode 100644 src/app/docs/python/page.tsx create mode 100644 src/app/docs/query-arrays-and-sets-in-woql/page.md create mode 100644 src/app/docs/query-documents/page.md create mode 100644 src/app/docs/read-documents-with-woql/page.md create mode 100644 src/app/docs/render-as/page.md create mode 100644 src/app/docs/reset-a-project/page.md create mode 100644 src/app/docs/reset-to-a-commit-with-python/page.md create mode 100644 src/app/docs/reset/page.md create mode 100644 src/app/docs/run-woql-query/page.md create mode 100644 src/app/docs/schema-migration-reference-guide/page.md create mode 100644 src/app/docs/schema-queries-with-woql/page.md create mode 100644 src/app/docs/schema-reference-guide/page.md create mode 100644 src/app/docs/set-up-vectorlink/page.md create mode 100644 src/app/docs/set/page.md create mode 100644 src/app/docs/squash-a-project-with-python/page.md create mode 100644 src/app/docs/squash-projects/page.md create mode 100644 src/app/docs/squash/page.md create mode 100644 src/app/docs/sysjson/page.md create mode 100644 src/app/docs/system-graph-graphql-interface-reference/page.md create mode 100644 src/app/docs/tdb-react-table/page.md create mode 100644 src/app/docs/terminuscms-dashboard-reference/page.md create mode 100644 src/app/docs/terminuscms-data-types/page.md create mode 100644 src/app/docs/terminusdb-cli-commands/page.md create mode 100644 src/app/docs/terminusdb-explanation/page.md create mode 100644 src/app/docs/terminusdb-install-options/page.md create mode 100644 src/app/docs/time-travel-to-previous-commits/page.md create mode 100644 src/app/docs/time-travel-with-python/page.md create mode 100644 src/app/docs/time-travel/page.md create mode 100644 src/app/docs/ui-components/page.md create mode 100644 src/app/docs/ui-sdk-geojson/page.md create mode 100644 src/app/docs/use-the-admin-ui-curate-and-import-data/page.md create mode 100644 src/app/docs/use-the-clients/page.md create mode 100644 src/app/docs/use-the-collaboration-features/page.md create mode 100644 src/app/docs/use-the-javascript-client/page.md create mode 100644 src/app/docs/use-the-json-editor/page.md create mode 100644 src/app/docs/use-the-model-builder-ui/page.md create mode 100644 src/app/docs/use-the-python-client/page.md create mode 100644 src/app/docs/use-vectorlink/page.md create mode 100644 src/app/docs/usetdbdocuments/page.md create mode 100644 src/app/docs/usetdbgraphqlquery/page.md create mode 100644 src/app/docs/viewdocumentcomponent/page.md create mode 100644 src/app/docs/what-is-schema-weakening/page.md create mode 100644 src/app/docs/woql-basics/page.md create mode 100644 src/app/docs/woql-class-reference-guide/page.md create mode 100644 src/app/docs/woql-explanation/page.md create mode 100644 src/app/docs/woql-query-with-python-client/page.md create mode 100644 src/app/favicon.ico create mode 100644 src/app/layout.tsx create mode 100644 src/app/not-found.tsx create mode 100644 src/app/page.md create mode 100644 src/app/providers.tsx create mode 100644 src/components/Button.tsx create mode 100644 src/components/Callout.tsx create mode 100644 src/components/DocsHeader.tsx create mode 100644 src/components/DocsLayout.tsx create mode 100644 src/components/Fence.tsx create mode 100644 src/components/Hero.tsx create mode 100644 src/components/HeroBackground.tsx create mode 100644 src/components/Icon.tsx create mode 100644 src/components/Layout.tsx create mode 100644 src/components/Logo.tsx create mode 100644 src/components/MobileNavigation.tsx create mode 100644 src/components/Navigation.tsx create mode 100644 src/components/PrevNextLinks.tsx create mode 100644 src/components/Prose.tsx create mode 100644 src/components/QuickLinks.tsx create mode 100644 src/components/Search.tsx create mode 100644 src/components/TableOfContents.tsx create mode 100644 src/components/ThemeSelector.tsx create mode 100644 src/components/icons/InstallationIcon.tsx create mode 100644 src/components/icons/LightbulbIcon.tsx create mode 100644 src/components/icons/PluginsIcon.tsx create mode 100644 src/components/icons/PresetsIcon.tsx create mode 100644 src/components/icons/ThemingIcon.tsx create mode 100644 src/components/icons/WarningIcon.tsx create mode 100644 src/fonts/lexend.txt create mode 100644 src/fonts/lexend.woff2 create mode 100644 src/images/TerminusDB-Logo.svg create mode 100644 src/images/blur-cyan.png create mode 100644 src/images/blur-indigo.png create mode 100644 src/lib/navigation.ts create mode 100644 src/lib/sections.ts create mode 100644 src/markdoc/nodes.js create mode 100644 src/markdoc/search.mjs create mode 100644 src/markdoc/tags.js delete mode 100644 src/pages/404.tsx delete mode 100644 src/pages/_app.tsx delete mode 100644 src/pages/_document.tsx delete mode 100644 src/pages/docs/[name].tsx delete mode 100644 src/pages/docs/index.tsx delete mode 100644 src/pages/docs/javascript.tsx delete mode 100644 src/pages/docs/openapi.tsx delete mode 100644 src/pages/docs/python.tsx delete mode 100644 src/pages/index.tsx create mode 100644 src/styles/prism.css create mode 100644 src/styles/tailwind-terminusdb.css create mode 100644 types.d.ts diff --git a/generate_markdown.js b/generate_markdown.js new file mode 100644 index 0000000..e166e40 --- /dev/null +++ b/generate_markdown.js @@ -0,0 +1,90 @@ +const fs = require('fs'); +const path = require('path'); +const yaml = require('js-yaml'); + +// Load the JSON data +const allDocuments = require('./schema/all_documents.json'); + +// Function to create directory if it doesn't exist +function ensureDirectoryExists(dirPath) { + if (!fs.existsSync(dirPath)) { + fs.mkdirSync(dirPath, { recursive: true }); + } +} + +// Function to generate markdown content from a page object +function generateMarkdown(page) { + if (!page) return null; + + // Extract title from title/value + const title = page.title && page.title.value ? page.title.value : 'Untitled'; + + // Extract slug + const slug = page.slug || ''; + + // Extract SEO metadata (removing @type) + const seo = page.seo_metadata ? { ...page.seo_metadata } : {}; + delete seo['@type']; + + // Extract media array with titles + const media = page.media ? page.media.map(item => { + const mediaObj = { ...item }; + if (mediaObj.title && mediaObj.title.value) { + mediaObj.title = mediaObj.title.value; + } + delete mediaObj['@type']; + return mediaObj; + }) : []; + + // Extract body content + const bodyContent = page.body && page.body.value ? page.body.value : ''; + + // Create frontmatter object + const frontmatter = { + title, + slug, + seo, + media + }; + + // Convert to YAML and create markdown content + const yamlContent = yaml.dump(frontmatter); + const markdownContent = `---\n${yamlContent}---\n\n${bodyContent}`; + + return markdownContent; +} + +// Function to process all documents and generate files +function processAllDocuments(documents) { + documents.forEach(doc => { + if (doc['@type'] === 'Page' && doc.slug) { + const slug = doc.slug; + + // Special case for index page + if (slug === 'index') { + const dirPath = path.join(__dirname, 'src', 'app', 'docs'); + ensureDirectoryExists(dirPath); + + const markdownContent = generateMarkdown(doc); + if (markdownContent) { + fs.writeFileSync(path.join(dirPath, 'page.md'), markdownContent); + console.log(`Created: docs/page.md (index)`); + } + } else { + const dirPath = path.join(__dirname, 'src', 'app', 'docs', slug); + ensureDirectoryExists(dirPath); + + const markdownContent = generateMarkdown(doc); + if (markdownContent) { + fs.writeFileSync(path.join(dirPath, 'page.md'), markdownContent); + console.log(`Created: docs/${slug}/page.md`); + } + } + } + }); +} + +// Main execution +console.log('Starting markdown generation...'); +processAllDocuments(allDocuments); +console.log('Markdown generation complete!'); diff --git a/next.config.js b/next.config.mjs similarity index 59% rename from next.config.js rename to next.config.mjs index 4754024..4bfb28b 100644 --- a/next.config.js +++ b/next.config.mjs @@ -1,3 +1,7 @@ +import withMarkdoc from '@markdoc/next.js' + +import withSearch from './src/markdoc/search.mjs' + /** @type {import('next').NextConfig} */ const nextConfig = { basePath: process.env.BASE_PATH || "", @@ -12,6 +16,9 @@ const nextConfig = { 'swagger-client', 'react-syntax-highlighter', ], + pageExtensions: ['js', 'jsx', 'md', 'ts', 'tsx'], } -module.exports = nextConfig +export default withSearch( + withMarkdoc({ schemaPath: './src/markdoc' })(nextConfig), +) diff --git a/package-lock.json b/package-lock.json index 906c4ab..20ff3fb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,39 +8,282 @@ "name": "terminusdb-docs-static", "version": "0.1.0", "dependencies": { - "@tailwindcss/typography": "^0.5.9", + "@algolia/autocomplete-core": "^1.9.2", + "@headlessui/react": "^2.1.0", + "@markdoc/markdoc": "^0.4.0", + "@markdoc/next.js": "^0.3.4", + "@sindresorhus/slugify": "^2.1.0", + "@tailwindcss/postcss": "^4.1.2", + "@tailwindcss/typography": "^0.5.7", "@terminusdb/terminusdb-client": "^10.0.28", - "@types/node": "18.15.11", - "@types/react": "18.0.37", - "@types/react-dom": "18.0.11", + "@types/node": "^20.10.8", + "@types/react": "^18.2.47", + "@types/react-dom": "^18.2.18", + "@types/react-highlight-words": "^0.16.4", "axios": "^1.8.4", "cheerio": "^1.0.0", + "clsx": "^2.1.0", "dompurify": "^3.0.2", "eslint": "8.38.0", "eslint-config-next": "13.3.0", + "fast-glob": "^3.2.12", + "flexsearch": "^0.7.31", "flowbite": "^1.6.5", "fs-extra": "^11.3.0", - "next": "13.3.0", + "js-yaml": "^4.1.0", + "next": "^14.0.4", + "next-themes": "^0.2.1", + "prism-react-renderer": "^2.0.6", "prismjs": "^1.29.0", "probe-image-size": "^7.2.3", "puppeteer": "^24.4.0", - "react": "18.2.0", - "react-dom": "18.2.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-highlight-words": "^0.20.0", "showdown": "^2.1.0", + "simple-functional-loader": "^1.2.1", "swagger-ui-react": "^4.19.0", + "tailwindcss": "^4.1.2", "turndown": "^7.2.0", - "typescript": "5.0.4" + "typescript": "^5.3.3" }, "devDependencies": { "@types/fs-extra": "^11.0.4", "@types/prismjs": "^1.26.0", "autoprefixer": "^10.4.14", "dotenv": "^16.1.4", + "eslint": "^8.56.0", + "eslint-config-next": "^14.0.4", "next-sitemap": "^4.1.3", "postcss": "^8.4.24", - "prettier": "^2.8.8", - "prettier-plugin-tailwindcss": "^0.3.0", - "tailwindcss": "^3.3.2" + "prettier": "^3.3.2", + "prettier-plugin-tailwindcss": "^0.6.11", + "sharp": "0.33.1" + } + }, + "node_modules/@algolia/autocomplete-core": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.18.1.tgz", + "integrity": "sha512-+lOAwRkvxTt24AXNu3pT0EfCEh1ZOQkKlrgFa0Ji2jxSbY2WW3gb1k39JBPyXcCLlivdxYPXREdg8ImAF2Nw9Q==", + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-plugin-algolia-insights": "1.18.1", + "@algolia/autocomplete-shared": "1.18.1" + } + }, + "node_modules/@algolia/autocomplete-plugin-algolia-insights": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.18.1.tgz", + "integrity": "sha512-zrl5trCnSHXkBRZwo2VPw4fN5zT3DowgFR6O2Qh0gTni8HB+aQltJYVwBrFeTvZHHFKNY9Cua4Y1KNsYiJ9Rdw==", + "license": "MIT", + "dependencies": { + "@algolia/autocomplete-shared": "1.18.1" + }, + "peerDependencies": { + "search-insights": ">= 1 < 3" + } + }, + "node_modules/@algolia/autocomplete-shared": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.18.1.tgz", + "integrity": "sha512-vMKFYX5+SX+kIaJSMXOtj6zcMBhAWNyQJkfMrsuK38iJRTwemR23nzUE8qd3rHfWh6Iqgj89vDkf/CuOXDYllA==", + "license": "MIT", + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@algolia/client-abtesting": { + "version": "5.23.2", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.23.2.tgz", + "integrity": "sha512-EudQGeYEzviwqPH8WoqP5VTQssE/PW6sEdL0zzOyKt2bWnWoUp5Rnm67sCbxYDR44JpUchbkul0PfWrSYsBPjQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@algolia/client-common": "5.23.2", + "@algolia/requester-browser-xhr": "5.23.2", + "@algolia/requester-fetch": "5.23.2", + "@algolia/requester-node-http": "5.23.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-analytics": { + "version": "5.23.2", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.23.2.tgz", + "integrity": "sha512-zmJrkZqWFu+ft+VRcttZZJhw5ElkhBtOArRzQOu9sRnrSSodBOdPRhAfvu8tG93Hv67wh5qQaTBwLxM58AxuMg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@algolia/client-common": "5.23.2", + "@algolia/requester-browser-xhr": "5.23.2", + "@algolia/requester-fetch": "5.23.2", + "@algolia/requester-node-http": "5.23.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-common": { + "version": "5.23.2", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.23.2.tgz", + "integrity": "sha512-xaE6o4BMdqYBe0iB7JjX6G9/Qeqx6TSs9T4d6VJ0JHPsEyklSwIbKRiomPeYD7vzt2P4t45Io6QBhifOUP+0qg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-insights": { + "version": "5.23.2", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.23.2.tgz", + "integrity": "sha512-F85hpMszbr5ZGt8gFdl7WOugELRF4z3R1nD9n3t7PZ/2alV7IR75UQY8/jMQDwij/lrnVaKbLeIvKKy6K7ncZw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@algolia/client-common": "5.23.2", + "@algolia/requester-browser-xhr": "5.23.2", + "@algolia/requester-fetch": "5.23.2", + "@algolia/requester-node-http": "5.23.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-personalization": { + "version": "5.23.2", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.23.2.tgz", + "integrity": "sha512-TuGaGKiQvQqFNR4c3Vdl+JBe6dkEPmRzVyIdWLrurOPEmFmVCKRxtSnLr0TVFl6de/JfDAXuchvtvLHFxv9P2A==", + "license": "MIT", + "peer": true, + "dependencies": { + "@algolia/client-common": "5.23.2", + "@algolia/requester-browser-xhr": "5.23.2", + "@algolia/requester-fetch": "5.23.2", + "@algolia/requester-node-http": "5.23.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-query-suggestions": { + "version": "5.23.2", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.23.2.tgz", + "integrity": "sha512-fg2tZf7Sf51Icjfrea0dnfbfwlJ7kXMcRsWSJN3DZhEi/Y4mMmK9L0Cq8sby6HDzxy5T8xEWNWC3TMx5FvrJ6w==", + "license": "MIT", + "peer": true, + "dependencies": { + "@algolia/client-common": "5.23.2", + "@algolia/requester-browser-xhr": "5.23.2", + "@algolia/requester-fetch": "5.23.2", + "@algolia/requester-node-http": "5.23.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-search": { + "version": "5.23.2", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.23.2.tgz", + "integrity": "sha512-XiTjt0qgsJk9OqvDpMwTgUaPAYNSQcMILRfSYiorgiyc71yYM7Lq1vRSVxhB0m51mrViWj4rIR6kSiJRXebqvQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@algolia/client-common": "5.23.2", + "@algolia/requester-browser-xhr": "5.23.2", + "@algolia/requester-fetch": "5.23.2", + "@algolia/requester-node-http": "5.23.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/ingestion": { + "version": "1.23.2", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.23.2.tgz", + "integrity": "sha512-7ClIghvUFZTomBipD8Kor9Z5llcAM3lHUBG3VFOvUsOxOJcaMMONlBXyoFDfI1na+u14lVaGehY2oIEfY1eB0w==", + "license": "MIT", + "peer": true, + "dependencies": { + "@algolia/client-common": "5.23.2", + "@algolia/requester-browser-xhr": "5.23.2", + "@algolia/requester-fetch": "5.23.2", + "@algolia/requester-node-http": "5.23.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/monitoring": { + "version": "1.23.2", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.23.2.tgz", + "integrity": "sha512-kF7KKd0iIIlaD70flFS+8+DNxRvIzrG9A22iWG5LDX225Kl6pITroq+qIUweqqyyoqJBYuIXKZGDGtnahEwQxw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@algolia/client-common": "5.23.2", + "@algolia/requester-browser-xhr": "5.23.2", + "@algolia/requester-fetch": "5.23.2", + "@algolia/requester-node-http": "5.23.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/recommend": { + "version": "5.23.2", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.23.2.tgz", + "integrity": "sha512-nAgS2O5ww8J4fgW6GAiybAdr0uH7MV74srPdx51cPJRpQBEge4WnYBaOWx1/a53qI0xwNtQudnEyBGUzsSYaAw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@algolia/client-common": "5.23.2", + "@algolia/requester-browser-xhr": "5.23.2", + "@algolia/requester-fetch": "5.23.2", + "@algolia/requester-node-http": "5.23.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-browser-xhr": { + "version": "5.23.2", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.23.2.tgz", + "integrity": "sha512-yw6IzgQcwr4cZuoQCEoQui9G0rhVRGCyhPhW+gmrXe6oVr4qB50FV6mWGLA170+iqGVjPn/DVuOhExjBzcViTQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@algolia/client-common": "5.23.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-fetch": { + "version": "5.23.2", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.23.2.tgz", + "integrity": "sha512-8rmSybTwIqmGx3P0qkOEUkkyeIewglaKq6yUnxnVkBJbd4USfIZsw9cME1YUEHeZI7aOhTQg9QteUHSKXclF5A==", + "license": "MIT", + "peer": true, + "dependencies": { + "@algolia/client-common": "5.23.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-node-http": { + "version": "5.23.2", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.23.2.tgz", + "integrity": "sha512-IHpUiW3d3oVE5tCYqQN7X71/EbXI7f8WxU85eWW1UYEWEknqW3csdGctyIW7+qMHFfxeDymI1Wln/gGHHIXLIw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@algolia/client-common": "5.23.2" + }, + "engines": { + "node": ">= 14.0.0" } }, "node_modules/@alloc/quick-lru": { @@ -658,10 +901,22 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@emnapi/runtime": { + "version": "0.44.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-0.44.0.tgz", + "integrity": "sha512-ZX/etZEZw8DR7zAB1eVQT40lNo0jeqpb6dCgOvctB6FIQ5PoXfMuNY8+ayQfu8tNQbAB8gQWSSJupR8NxeiZXw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, "dependencies": { "eslint-visitor-keys": "^3.3.0" }, @@ -673,21 +928,25 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", - "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/eslintrc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", - "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "license": "MIT", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.5.2", + "espree": "^9.6.0", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -703,20 +962,97 @@ } }, "node_modules/@eslint/js": { - "version": "8.38.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.38.0.tgz", - "integrity": "sha512-IoD2MfUnOV58ghIHCiil01PcohxjbYR/qCxsoC+xNgUwh1EY8jOOrYmu3d3a71+tJJ23uscEV4X2HJWMsPJu4g==", + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "dev": true, + "license": "MIT", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.6.9", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.9.tgz", + "integrity": "sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.9" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.13", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.13.tgz", + "integrity": "sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.9" + } + }, + "node_modules/@floating-ui/react": { + "version": "0.26.28", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.28.tgz", + "integrity": "sha512-yORQuuAtVpiRjpMhdc0wJj06b9JFjrYF4qp96j++v2NBpbi6SEGF7donUJ3TMieerQ6qVkAv1tgr7L4r5roTqw==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.1.2", + "@floating-ui/utils": "^0.2.8", + "tabbable": "^6.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.2.tgz", + "integrity": "sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.9.tgz", + "integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==", + "license": "MIT" + }, + "node_modules/@headlessui/react": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-2.2.1.tgz", + "integrity": "sha512-daiUqVLae8CKVjEVT19P/izW0aGK0GNhMSAeMlrDebKmoVZHcRRwbxzgtnEadUVDXyBsWo9/UH4KHeniO+0tMg==", + "license": "MIT", + "dependencies": { + "@floating-ui/react": "^0.26.16", + "@react-aria/focus": "^3.17.1", + "@react-aria/interactions": "^3.21.3", + "@tanstack/react-virtual": "^3.11.1" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": "^18 || ^19 || ^19.0.0-rc", + "react-dom": "^18 || ^19 || ^19.0.0-rc" + } + }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", - "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "license": "Apache-2.0", "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", "minimatch": "^3.0.5" }, "engines": { @@ -727,6 +1063,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, "engines": { "node": ">=12.22" }, @@ -736,85 +1073,653 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true, + "license": "BSD-3-Clause" }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.1.tgz", + "integrity": "sha512-esr2BZ1x0bo+wl7Gx2hjssYhjrhUsD88VQulI0FrG8/otRQUOxLWHMBd1Y1qo2Gfg2KUvXNpT0ASnV9BzJCexw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" + "glibc": ">=2.26", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" }, - "engines": { - "node": ">=8" + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.0.0" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "node_modules/@img/sharp-darwin-x64": { + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.1.tgz", + "integrity": "sha512-YrnuB3bXuWdG+hJlXtq7C73lF8ampkhU3tMxg5Hh+E7ikxbUVOU9nlNtVTloDXz6pRHt2y2oKJq7DY/yt+UXYw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "glibc": ">=2.26", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.0.0" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dependencies": { - "p-locate": "^4.1.0" - }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.0.tgz", + "integrity": "sha512-VzYd6OwnUR81sInf3alj1wiokY50DjsHz5bvfnsFpxs5tqQxESoHtJO6xyksDs3RIkyhMWq2FufXo6GNSU9BMw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=8" + "macos": ">=11", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dependencies": { - "p-try": "^2.0.0" - }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.0.tgz", + "integrity": "sha512-dD9OznTlHD6aovRswaPNEy8dKtSAmNo4++tO7uuR4o5VxbVAOoEQ1uSmN4iFAdQneTHws1lkTZeiXPrcCkh6IA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=6" + "macos": ">=10.13", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/libvips" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.0.tgz", + "integrity": "sha512-VwgD2eEikDJUk09Mn9Dzi1OW2OJFRQK+XlBTkUNmAWPrtj8Ly0yq05DFgu1VCMx2/DqCGQVi5A1dM9hTmxf3uw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.28", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.0.tgz", + "integrity": "sha512-xTYThiqEZEZc0PRU90yVtM3KE7lw1bKdnDQ9kCTHWbqWyHOe4NpPOtMGy27YnN51q0J5dqRrvicfPbALIOeAZA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.26", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.0.tgz", + "integrity": "sha512-o9E46WWBC6JsBlwU4QyU9578G77HBDT1NInd+aERfxeOPbk0qBZHgoDsQmA2v9TbqJRWzoBPx1aLOhprBMgPjw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.28", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.0.tgz", + "integrity": "sha512-naldaJy4hSVhWBgEjfdBY85CAa4UO+W1nx6a1sWStHZ7EUfNiuBTTN2KUYT5dH1+p/xij1t2QSXfCiFJoC5S/Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.26", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.0.tgz", + "integrity": "sha512-OdorplCyvmSAPsoJLldtLh3nLxRrkAAAOHsGWGDYfN0kh730gifK+UZb3dWORRa6EusNqCTjfXV4GxvgJ/nPDQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "musl": ">=1.2.2", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.0.tgz", + "integrity": "sha512-FW8iK6rJrg+X2jKD0Ajhjv6y74lToIBEvkZhl42nZt563FfxkCYacrXZtd+q/sRQDypQLzY5WdLkVTbJoPyqNg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "musl": ">=1.2.2", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.1.tgz", + "integrity": "sha512-Ii4X1vnzzI4j0+cucsrYA5ctrzU9ciXERfJR633S2r39CiD8npqH2GMj63uFZRCFt3E687IenAdbwIpQOJ5BNA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.28", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.0.0" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.1.tgz", + "integrity": "sha512-59B5GRO2d5N3tIfeGHAbJps7cLpuWEQv/8ySd9109ohQ3kzyCACENkFVAnGPX00HwPTQcaBNF7HQYEfZyZUFfw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.26", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.0.0" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.1.tgz", + "integrity": "sha512-tRGrb2pHnFUXpOAj84orYNxHADBDIr0J7rrjwQrTNMQMWA4zy3StKmMvwsI7u3dEZcgwuMMooIIGWEWOjnmG8A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.28", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.0.0" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.1.tgz", + "integrity": "sha512-4y8osC0cAc1TRpy02yn5omBeloZZwS62fPZ0WUAYQiLhSFSpWJfY/gMrzKzLcHB9ulUV6ExFiu2elMaixKDbeg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.26", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.0.0" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.1.tgz", + "integrity": "sha512-D3lV6clkqIKUizNS8K6pkuCKNGmWoKlBGh5p0sLO2jQERzbakhu4bVX1Gz+RS4vTZBprKlWaf+/Rdp3ni2jLfA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "musl": ">=1.2.2", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.0.0" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.1.tgz", + "integrity": "sha512-LOGKNu5w8uu1evVqUAUKTix2sQu1XDRIYbsi5Q0c/SrXhvJ4QyOx+GaajxmOg5PZSsSnCYPSmhjHHsRBx06/wQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "musl": ">=1.2.2", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.0.0" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.1.tgz", + "integrity": "sha512-vWI/sA+0p+92DLkpAMb5T6I8dg4z2vzCUnp8yvxHlwBpzN8CIcO3xlSXrLltSvK6iMsVMNswAv+ub77rsf25lA==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^0.44.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.1.tgz", + "integrity": "sha512-/xhYkylsKL05R+NXGJc9xr2Tuw6WIVl2lubFJaFYfW4/MQ4J+dgjIo/T4qjNRizrqs/szF/lC9a5+updmY9jaQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.1.tgz", + "integrity": "sha512-XaM69X0n6kTEsp9tVYYLhXdg7Qj32vYJlAKRutxUsm1UlgQNx6BOhHwZPwukCGXBU2+tH87ip2eV1I/E8MQnZg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dependencies": { "p-limit": "^2.2.0" @@ -1151,6 +2056,44 @@ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" }, + "node_modules/@markdoc/markdoc": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@markdoc/markdoc/-/markdoc-0.4.0.tgz", + "integrity": "sha512-fSh4P3Y4E7oaKYc2oNzSIJVPDto7SMzAuQN1Iyx53UxzleA6QzRdNWRxmiPqtVDaDi5dELd2yICoG91csrGrAw==", + "license": "MIT", + "engines": { + "node": ">=14.7.0" + }, + "optionalDependencies": { + "@types/markdown-it": "12.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "react": "*" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + } + } + }, + "node_modules/@markdoc/next.js": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/@markdoc/next.js/-/next.js-0.3.7.tgz", + "integrity": "sha512-lp/J0Lfx8YPWes82HOMSDvXBfIkJxPKfEwgzGTwfFBJUGBNM1TBvchaaAzDP2X+HRORP4jNcGbJrZoXSdon0BQ==", + "license": "MIT", + "dependencies": { + "js-yaml": "^4.1.0" + }, + "peerDependencies": { + "@markdoc/markdoc": "*", + "next": "*", + "react": "*" + } + }, "node_modules/@mixmark-io/domino": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@mixmark-io/domino/-/domino-2.2.0.tgz", @@ -1158,27 +2101,78 @@ "license": "BSD-2-Clause" }, "node_modules/@next/env": { - "version": "13.4.6", - "resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.6.tgz", - "integrity": "sha512-nqUxEtvDqFhmV1/awSg0K2XHNwkftNaiUqCYO9e6+MYmqNObpKVl7OgMkGaQ2SZnFx5YqF0t60ZJTlyJIDAijg==", - "dev": true, - "peer": true + "version": "14.2.26", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.26.tgz", + "integrity": "sha512-vO//GJ/YBco+H7xdQhzJxF7ub3SUwft76jwaeOyVVQFHCi5DCnkP16WHB+JBylo4vOKPoZBlR94Z8xBxNBdNJA==", + "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-13.3.0.tgz", - "integrity": "sha512-wuGN5qSEjSgcq9fVkH0Y/qIPFjnZtW3ZPwfjJOn7l/rrf6y8J24h/lo61kwqunTyzZJm/ETGfGVU9PUs8cnzEA==", + "version": "14.2.26", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-14.2.26.tgz", + "integrity": "sha512-SPEj1O5DAVTPaWD9XPupelfT2APNIgcDYD2OzEm328BEmHaglhmYNUvxhzfJYDr12AgAfW4V3UHSV93qaeELJA==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob": "10.3.10" + } + }, + "node_modules/@next/eslint-plugin-next/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@next/eslint-plugin-next/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@next/eslint-plugin-next/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", "dependencies": { - "glob": "7.1.7" + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/@next/swc-darwin-arm64": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.3.0.tgz", - "integrity": "sha512-DmIQCNq6JtccLPPBzf0dgh2vzMWt5wjxbP71pCi5EWpWYE3MsP6FcRXi4MlAmFNDQOfcFXR2r7kBeG1LpZUh1w==", + "version": "14.2.26", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.26.tgz", + "integrity": "sha512-zDJY8gsKEseGAxG+C2hTMT0w9Nk9N1Sk1qV7vXYz9MEiyRoF5ogQX2+vplyUMIfygnjn9/A04I6yrUTRTuRiyQ==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "darwin" @@ -1188,12 +2182,13 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.3.0.tgz", - "integrity": "sha512-oQoqFa88OGgwnYlnAGHVct618FRI/749se0N3S8t9Bzdv5CRbscnO0RcX901+YnNK4Q6yeiizfgO3b7kogtsZg==", + "version": "14.2.26", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.26.tgz", + "integrity": "sha512-U0adH5ryLfmTDkahLwG9sUQG2L0a9rYux8crQeC92rPhi3jGQEY47nByQHrVrt3prZigadwj/2HZ1LUUimuSbg==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "darwin" @@ -1203,12 +2198,13 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.3.0.tgz", - "integrity": "sha512-Wzz2p/WqAJUqTVoLo6H18WMeAXo3i+9DkPDae4oQG8LMloJ3if4NEZTnOnTUlro6cq+S/W4pTGa97nWTrOjbGw==", + "version": "14.2.26", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.26.tgz", + "integrity": "sha512-SINMl1I7UhfHGM7SoRiw0AbwnLEMUnJ/3XXVmhyptzriHbWvPPbbm0OEVG24uUKhuS1t0nvN/DBvm5kz6ZIqpg==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -1218,12 +2214,13 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.3.0.tgz", - "integrity": "sha512-xPVrIQOQo9WXJYgmoTlMnAD/HlR/1e1ZIWGbwIzEirXBVBqMARUulBEIKdC19zuvoJ477qZJgBDCKtKEykCpyQ==", + "version": "14.2.26", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.26.tgz", + "integrity": "sha512-s6JaezoyJK2DxrwHWxLWtJKlqKqTdi/zaYigDXUJ/gmx/72CrzdVZfMvUc6VqnZ7YEvRijvYo+0o4Z9DencduA==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -1233,12 +2230,13 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.3.0.tgz", - "integrity": "sha512-jOFlpGuPD7W2tuXVJP4wt9a3cpNxWAPcloq5EfMJRiXsBBOjLVFZA7boXYxEBzSVgUiVVr1V9T0HFM7pULJ1qA==", + "version": "14.2.26", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.26.tgz", + "integrity": "sha512-FEXeUQi8/pLr/XI0hKbe0tgbLmHFRhgXOUiPScz2hk0hSmbGiU8aUqVslj/6C6KA38RzXnWoJXo4FMo6aBxjzg==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -1248,12 +2246,13 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.3.0.tgz", - "integrity": "sha512-2OwKlzaBgmuet9XYHc3KwsEilzb04F540rlRXkAcjMHL7eCxB7uZIGtsVvKOnQLvC/elrUegwSw1+5f7WmfyOw==", + "version": "14.2.26", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.26.tgz", + "integrity": "sha512-BUsomaO4d2DuXhXhgQCVt2jjX4B4/Thts8nDoIruEJkhE5ifeQFtvW5c9JkdOtYvE5p2G0hcwQ0UbRaQmQwaVg==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -1263,12 +2262,13 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.3.0.tgz", - "integrity": "sha512-OeHiA6YEvndxT46g+rzFK/MQTfftKxJmzslERMu9LDdC6Kez0bdrgEYed5eXFK2Z1viKZJCGRlhd06rBusyztA==", + "version": "14.2.26", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.26.tgz", + "integrity": "sha512-5auwsMVzT7wbB2CZXQxDctpWbdEnEW/e66DyXO1DcgHxIyhP06awu+rHKshZE+lPLIGiwtjo7bsyeuubewwxMw==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -1278,12 +2278,13 @@ } }, "node_modules/@next/swc-win32-ia32-msvc": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.3.0.tgz", - "integrity": "sha512-4aB7K9mcVK1lYEzpOpqWrXHEZympU3oK65fnNcY1Qc4HLJFLJj8AViuqQd4jjjPNuV4sl8jAwTz3gN5VNGWB7w==", + "version": "14.2.26", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.26.tgz", + "integrity": "sha512-GQWg/Vbz9zUGi9X80lOeGsz1rMH/MtFO/XqigDznhhhTfDlDoynCM6982mPCbSlxJ/aveZcKtTlwfAjwhyxDpg==", "cpu": [ "ia32" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -1293,12 +2294,13 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.3.0.tgz", - "integrity": "sha512-Reer6rkLLcoOvB0dd66+Y7WrWVFH7sEEkF/4bJCIfsSKnTStTYaHtwIJAwbqnt9I392Tqvku0KkoqZOryWV9LQ==", + "version": "14.2.26", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.26.tgz", + "integrity": "sha512-2rdB3T1/Gp7bv1eQTTm9d1Y1sv9UuJ2LAwOE0Pe2prHKe32UNscj7YS13fRB37d0GAiGNR+Y7ZcW8YjDI8Ns0w==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -1339,10 +2341,22 @@ "node": ">= 8" } }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@pkgr/utils": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.1.tgz", "integrity": "sha512-JOqwkgFEyi+OROIyq7l4Jy28h/WwhDnG/cPkXG2Z1iFbubB6jsHW1NDvmyOzTBxHr3yg68YGirmh1JUgMqa+9w==", + "dev": true, "dependencies": { "cross-spawn": "^7.0.3", "fast-glob": "^3.2.12", @@ -1362,6 +2376,7 @@ "version": "9.1.0", "resolved": "https://registry.npmjs.org/open/-/open-9.1.0.tgz", "integrity": "sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==", + "dev": true, "dependencies": { "default-browser": "^4.0.0", "define-lazy-prop": "^3.0.0", @@ -1384,61 +2399,222 @@ "url": "https://opencollective.com/popperjs" } }, - "node_modules/@puppeteer/browsers": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.8.0.tgz", - "integrity": "sha512-yTwt2KWRmCQAfhvbCRjebaSX8pV1//I0Y3g+A7f/eS7gf0l4eRJoUCvcYdVtboeU4CTOZQuqYbZNS8aBYb8ROQ==", - "license": "Apache-2.0", + "node_modules/@puppeteer/browsers": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.8.0.tgz", + "integrity": "sha512-yTwt2KWRmCQAfhvbCRjebaSX8pV1//I0Y3g+A7f/eS7gf0l4eRJoUCvcYdVtboeU4CTOZQuqYbZNS8aBYb8ROQ==", + "license": "Apache-2.0", + "dependencies": { + "debug": "^4.4.0", + "extract-zip": "^2.0.1", + "progress": "^2.0.3", + "proxy-agent": "^6.5.0", + "semver": "^7.7.1", + "tar-fs": "^3.0.8", + "yargs": "^17.7.2" + }, + "bin": { + "browsers": "lib/cjs/main-cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@puppeteer/browsers/node_modules/tar-fs": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.8.tgz", + "integrity": "sha512-ZoROL70jptorGAlgAYiLoBLItEKw/fUxg9BSYK/dF/GAGYFJOJJJMvjPAKDJraCXFwadD456FCuvLWgfhMsPwg==", + "license": "MIT", + "dependencies": { + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + }, + "optionalDependencies": { + "bare-fs": "^4.0.1", + "bare-path": "^3.0.0" + } + }, + "node_modules/@puppeteer/browsers/node_modules/tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "license": "MIT", + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/@react-aria/focus": { + "version": "3.20.1", + "resolved": "https://registry.npmjs.org/@react-aria/focus/-/focus-3.20.1.tgz", + "integrity": "sha512-lgYs+sQ1TtBrAXnAdRBQrBo0/7o5H6IrfDxec1j+VRpcXL0xyk0xPq+m3lZp8typzIghqDgpnKkJ5Jf4OrzPIw==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/interactions": "^3.24.1", + "@react-aria/utils": "^3.28.1", + "@react-types/shared": "^3.28.0", + "@swc/helpers": "^0.5.0", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/interactions": { + "version": "3.24.1", + "resolved": "https://registry.npmjs.org/@react-aria/interactions/-/interactions-3.24.1.tgz", + "integrity": "sha512-OWEcIC6UQfWq4Td5Ptuh4PZQ4LHLJr/JL2jGYvuNL6EgL3bWvzPrRYIF/R64YbfVxIC7FeZpPSkS07sZ93/NoA==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/ssr": "^3.9.7", + "@react-aria/utils": "^3.28.1", + "@react-stately/flags": "^3.1.0", + "@react-types/shared": "^3.28.0", + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/ssr": { + "version": "3.9.7", + "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.7.tgz", + "integrity": "sha512-GQygZaGlmYjmYM+tiNBA5C6acmiDWF52Nqd40bBp0Znk4M4hP+LTmI0lpI1BuKMw45T8RIhrAsICIfKwZvi2Gg==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + }, + "engines": { + "node": ">= 12" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-aria/utils": { + "version": "3.28.1", + "resolved": "https://registry.npmjs.org/@react-aria/utils/-/utils-3.28.1.tgz", + "integrity": "sha512-mnHFF4YOVu9BRFQ1SZSKfPhg3z+lBRYoW5mLcYTQihbKhz48+I1sqRkP7ahMITr8ANH3nb34YaMME4XWmK2Mgg==", + "license": "Apache-2.0", + "dependencies": { + "@react-aria/ssr": "^3.9.7", + "@react-stately/flags": "^3.1.0", + "@react-stately/utils": "^3.10.5", + "@react-types/shared": "^3.28.0", + "@swc/helpers": "^0.5.0", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1", + "react-dom": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-stately/flags": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@react-stately/flags/-/flags-3.1.0.tgz", + "integrity": "sha512-KSHOCxTFpBtxhIRcKwsD1YDTaNxFtCYuAUb0KEihc16QwqZViq4hasgPBs2gYm7fHRbw7WYzWKf6ZSo/+YsFlg==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + } + }, + "node_modules/@react-stately/utils": { + "version": "3.10.5", + "resolved": "https://registry.npmjs.org/@react-stately/utils/-/utils-3.10.5.tgz", + "integrity": "sha512-iMQSGcpaecghDIh3mZEpZfoFH3ExBwTtuBEcvZ2XnGzCgQjeYXcMdIUwAfVQLXFTdHUHGF6Gu6/dFrYsCzySBQ==", + "license": "Apache-2.0", + "dependencies": { + "@swc/helpers": "^0.5.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@react-types/shared": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/@react-types/shared/-/shared-3.28.0.tgz", + "integrity": "sha512-9oMEYIDc3sk0G5rysnYvdNrkSg7B04yTKl50HHSZVbokeHpnU0yRmsDaWb9B/5RprcKj8XszEk5guBO8Sa/Q+Q==", + "license": "Apache-2.0", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" + } + }, + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rushstack/eslint-patch": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.11.0.tgz", + "integrity": "sha512-zxnHvoMQVqewTJr/W4pKjF0bMGiKJv1WX7bSrkl46Hg0QjESbzBROWK0Wg4RphzSOS5Jiy7eFimmM3UgMrMZbQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sinclair/typebox": { + "version": "0.25.24", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", + "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==" + }, + "node_modules/@sindresorhus/slugify": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@sindresorhus/slugify/-/slugify-2.2.1.tgz", + "integrity": "sha512-MkngSCRZ8JdSOCHRaYd+D01XhvU3Hjy6MGl06zhOk614hp9EOAp5gIkBeQg7wtmxpitU6eAL4kdiRMcJa2dlrw==", + "license": "MIT", "dependencies": { - "debug": "^4.4.0", - "extract-zip": "^2.0.1", - "progress": "^2.0.3", - "proxy-agent": "^6.5.0", - "semver": "^7.7.1", - "tar-fs": "^3.0.8", - "yargs": "^17.7.2" - }, - "bin": { - "browsers": "lib/cjs/main-cli.js" + "@sindresorhus/transliterate": "^1.0.0", + "escape-string-regexp": "^5.0.0" }, "engines": { - "node": ">=18" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@puppeteer/browsers/node_modules/tar-fs": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.8.tgz", - "integrity": "sha512-ZoROL70jptorGAlgAYiLoBLItEKw/fUxg9BSYK/dF/GAGYFJOJJJMvjPAKDJraCXFwadD456FCuvLWgfhMsPwg==", + "node_modules/@sindresorhus/slugify/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", "license": "MIT", - "dependencies": { - "pump": "^3.0.0", - "tar-stream": "^3.1.5" + "engines": { + "node": ">=12" }, - "optionalDependencies": { - "bare-fs": "^4.0.1", - "bare-path": "^3.0.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@puppeteer/browsers/node_modules/tar-stream": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", - "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "node_modules/@sindresorhus/transliterate": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/transliterate/-/transliterate-1.6.0.tgz", + "integrity": "sha512-doH1gimEu3A46VX6aVxpHTeHrytJAG6HgdxntYnCFiIFHEM/ZGpG8KiZGBChchjQmG0XFIBL552kBTjVcMZXwQ==", "license": "MIT", "dependencies": { - "b4a": "^1.6.4", - "fast-fifo": "^1.2.0", - "streamx": "^2.15.0" + "escape-string-regexp": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@rushstack/eslint-patch": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.3.2.tgz", - "integrity": "sha512-V+MvGwaHH03hYhY+k6Ef/xKd6RYlc4q8WBx+2ANmipHJcKuktNcI/NgEsJgdSUF6Lw32njT6OnrRsKYCdgHjYw==" - }, - "node_modules/@sinclair/typebox": { - "version": "0.25.24", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", - "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==" + "node_modules/@sindresorhus/transliterate/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/@sinonjs/commons": { "version": "3.0.0", @@ -1807,12 +2983,270 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "license": "Apache-2.0" + }, "node_modules/@swc/helpers": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.14.tgz", - "integrity": "sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==", + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "license": "Apache-2.0", "dependencies": { - "tslib": "^2.4.0" + "tslib": "^2.8.0" + } + }, + "node_modules/@tailwindcss/node": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.3.tgz", + "integrity": "sha512-H/6r6IPFJkCfBJZ2dKZiPJ7Ueb2wbL592+9bQEl2r73qbX6yGnmQVIfiUvDRB2YI0a3PWDrzUwkvQx1XW1bNkA==", + "license": "MIT", + "dependencies": { + "enhanced-resolve": "^5.18.1", + "jiti": "^2.4.2", + "lightningcss": "1.29.2", + "tailwindcss": "4.1.3" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.3.tgz", + "integrity": "sha512-t16lpHCU7LBxDe/8dCj9ntyNpXaSTAgxWm1u2XQP5NiIu4KGSyrDJJRlK9hJ4U9yJxx0UKCVI67MJWFNll5mOQ==", + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.1.3", + "@tailwindcss/oxide-darwin-arm64": "4.1.3", + "@tailwindcss/oxide-darwin-x64": "4.1.3", + "@tailwindcss/oxide-freebsd-x64": "4.1.3", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.3", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.3", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.3", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.3", + "@tailwindcss/oxide-linux-x64-musl": "4.1.3", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.3", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.3" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.3.tgz", + "integrity": "sha512-cxklKjtNLwFl3mDYw4XpEfBY+G8ssSg9ADL4Wm6//5woi3XGqlxFsnV5Zb6v07dxw1NvEX2uoqsxO/zWQsgR+g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.3.tgz", + "integrity": "sha512-mqkf2tLR5VCrjBvuRDwzKNShRu99gCAVMkVsaEOFvv6cCjlEKXRecPu9DEnxp6STk5z+Vlbh1M5zY3nQCXMXhw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.3.tgz", + "integrity": "sha512-7sGraGaWzXvCLyxrc7d+CCpUN3fYnkkcso3rCzwUmo/LteAl2ZGCDlGvDD8Y/1D3ngxT8KgDj1DSwOnNewKhmg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.3.tgz", + "integrity": "sha512-E2+PbcbzIReaAYZe997wb9rId246yDkCwAakllAWSGqe6VTg9hHle67hfH6ExjpV2LSK/siRzBUs5wVff3RW9w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.3.tgz", + "integrity": "sha512-GvfbJ8wjSSjbLFFE3UYz4Eh8i4L6GiEYqCtA8j2Zd2oXriPuom/Ah/64pg/szWycQpzRnbDiJozoxFU2oJZyfg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.3.tgz", + "integrity": "sha512-35UkuCWQTeG9BHcBQXndDOrpsnt3Pj9NVIB4CgNiKmpG8GnCNXeMczkUpOoqcOhO6Cc/mM2W7kaQ/MTEENDDXg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.3.tgz", + "integrity": "sha512-dm18aQiML5QCj9DQo7wMbt1Z2tl3Giht54uVR87a84X8qRtuXxUqnKQkRDK5B4bCOmcZ580lF9YcoMkbDYTXHQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.3.tgz", + "integrity": "sha512-LMdTmGe/NPtGOaOfV2HuO7w07jI3cflPrVq5CXl+2O93DCewADK0uW1ORNAcfu2YxDUS035eY2W38TxrsqngxA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.3.tgz", + "integrity": "sha512-aalNWwIi54bbFEizwl1/XpmdDrOaCjRFQRgtbv9slWjmNPuJJTIKPHf5/XXDARc9CneW9FkSTqTbyvNecYAEGw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.3.tgz", + "integrity": "sha512-PEj7XR4OGTGoboTIAdXicKuWl4EQIjKHKuR+bFy9oYN7CFZo0eu74+70O4XuERX4yjqVZGAkCdglBODlgqcCXg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.3.tgz", + "integrity": "sha512-T8gfxECWDBENotpw3HR9SmNiHC9AOJdxs+woasRZ8Q/J4VHN0OMs7F+4yVNZ9EVN26Wv6mZbK0jv7eHYuLJLwA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/postcss": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.3.tgz", + "integrity": "sha512-6s5nJODm98F++QT49qn8xJKHQRamhYHfMi3X7/ltxiSQ9dyRsaFSfFkfaMsanWzf+TMYQtbk8mt5f6cCVXJwfg==", + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "@tailwindcss/node": "4.1.3", + "@tailwindcss/oxide": "4.1.3", + "postcss": "^8.4.41", + "tailwindcss": "4.1.3" + } + }, + "node_modules/@tailwindcss/postcss/node_modules/postcss": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", + "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.8", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" } }, "node_modules/@tailwindcss/typography": { @@ -1826,7 +3260,34 @@ "postcss-selector-parser": "6.0.10" }, "peerDependencies": { - "tailwindcss": ">=3.0.0 || insiders" + "tailwindcss": ">=3.0.0 || insiders" + } + }, + "node_modules/@tanstack/react-virtual": { + "version": "3.13.6", + "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.13.6.tgz", + "integrity": "sha512-WT7nWs8ximoQ0CDx/ngoFP7HbQF9Q2wQe4nh2NB+u2486eX3nZRE40P9g6ccCVq7ZfTSH5gFOuCoVH5DLNS/aA==", + "license": "MIT", + "dependencies": { + "@tanstack/virtual-core": "3.13.6" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@tanstack/virtual-core": { + "version": "3.13.6", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.13.6.tgz", + "integrity": "sha512-cnQUeWnhNP8tJ4WsGcYiX24Gjkc9ALstLbHcBj1t3E7EimN6n6kHH+DPV4PpDnuw00NApQp+ViojMj1GRdwYQg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" } }, "node_modules/@terminusdb/terminusdb-client": { @@ -1976,7 +3437,9 @@ "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true, + "license": "MIT" }, "node_modules/@types/jsonfile": { "version": "6.1.4", @@ -1988,10 +3451,39 @@ "@types/node": "*" } }, + "node_modules/@types/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", + "license": "MIT", + "optional": true + }, + "node_modules/@types/markdown-it": { + "version": "12.2.3", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz", + "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "@types/linkify-it": "*", + "@types/mdurl": "*" + } + }, + "node_modules/@types/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", + "license": "MIT", + "optional": true + }, "node_modules/@types/node": { - "version": "18.15.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz", - "integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==" + "version": "20.17.30", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.30.tgz", + "integrity": "sha512-7zf4YyHA+jvBNfVrk2Gtvs6x7E8V+YDW05bNfG2XkWDJfYRXrTiP/DsB2zSYTaHX0bGIujTBQdMVAhb+j7mwpg==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.19.2" + } }, "node_modules/@types/prettier": { "version": "2.7.3", @@ -2001,8 +3493,7 @@ "node_modules/@types/prismjs": { "version": "1.26.0", "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.0.tgz", - "integrity": "sha512-ZTaqn/qSqUuAq1YwvOFQfVW1AR/oQJlLSZVustdjwI+GZ8kr0MSHBj0tsXPW1EqHubx50gtBEjbPGsdZwQwCjQ==", - "dev": true + "integrity": "sha512-ZTaqn/qSqUuAq1YwvOFQfVW1AR/oQJlLSZVustdjwI+GZ8kr0MSHBj0tsXPW1EqHubx50gtBEjbPGsdZwQwCjQ==" }, "node_modules/@types/prop-types": { "version": "15.7.5", @@ -2018,28 +3509,33 @@ } }, "node_modules/@types/react": { - "version": "18.0.37", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.37.tgz", - "integrity": "sha512-4yaZZtkRN3ZIQD3KSEwkfcik8s0SWV+82dlJot1AbGYHCzJkWP3ENBY6wYeDRmKZ6HkrgoGAmR2HqdwYGp6OEw==", + "version": "18.3.20", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.20.tgz", + "integrity": "sha512-IPaCZN7PShZK/3t6Q87pfTkRm6oLTd4vztyoj+cbHUF1g3FfVb2tFIL79uCRKEfv16AhqDMBywP2VW3KIZUvcg==", + "license": "MIT", "dependencies": { "@types/prop-types": "*", - "@types/scheduler": "*", "csstype": "^3.0.2" } }, "node_modules/@types/react-dom": { - "version": "18.0.11", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.11.tgz", - "integrity": "sha512-O38bPbI2CWtgw/OoQoY+BRelw7uysmXbWvw3nLWO21H1HSh+GOlqPuXshJfjmpNlKiiSDG9cc1JZAaMmVdcTlw==", + "version": "18.3.6", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.6.tgz", + "integrity": "sha512-nf22//wEbKXusP6E9pfOCDwFdHAX4u172eaJI4YkDRQEZiorm6KfYnSC2SWLDMVWUOWPERmJnN0ujeAfTBLvrw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "^18.0.0" + } + }, + "node_modules/@types/react-highlight-words": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@types/react-highlight-words/-/react-highlight-words-0.16.7.tgz", + "integrity": "sha512-+upXTIaRd3rGvh1aDQSs9z5X+sV3UM6Jrmjk03GN2GXl4v/+iOJKQj2LZHo6Vp2IoTvMdtxgME26feqo12xXLg==", + "license": "MIT", "dependencies": { "@types/react": "*" } }, - "node_modules/@types/scheduler": { - "version": "0.16.3", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", - "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==" - }, "node_modules/@types/stack-utils": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", @@ -2078,54 +3574,111 @@ "@types/node": "*" } }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.29.0.tgz", + "integrity": "sha512-PAIpk/U7NIS6H7TEtN45SPGLQaHNgB7wSjsQV/8+KYokAb2T/gloOA/Bee2yd4/yKVhPKe5LlaUGhAZk5zmSaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.29.0", + "@typescript-eslint/type-utils": "8.29.0", + "@typescript-eslint/utils": "8.29.0", + "@typescript-eslint/visitor-keys": "8.29.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.0.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, "node_modules/@typescript-eslint/parser": { - "version": "5.59.11", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.11.tgz", - "integrity": "sha512-s9ZF3M+Nym6CAZEkJJeO2TFHHDsKAM3ecNkLuH4i4s8/RCPnF5JRip2GyviYkeEAcwGMJxkqG9h2dAsnA1nZpA==", + "version": "8.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.29.0.tgz", + "integrity": "sha512-8C0+jlNJOwQso2GapCVWWfW/rzaq7Lbme+vGUFKE31djwNncIpgXD7Cd4weEsDdkoZDjH0lwwr3QDQFuyrMg9g==", + "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "5.59.11", - "@typescript-eslint/types": "5.59.11", - "@typescript-eslint/typescript-estree": "5.59.11", + "@typescript-eslint/scope-manager": "8.29.0", + "@typescript-eslint/types": "8.29.0", + "@typescript-eslint/typescript-estree": "8.29.0", + "@typescript-eslint/visitor-keys": "8.29.0", "debug": "^4.3.4" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.59.11", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.11.tgz", - "integrity": "sha512-dHFOsxoLFtrIcSj5h0QoBT/89hxQONwmn3FOQ0GOQcLOOXm+MIrS8zEAhs4tWl5MraxCY3ZJpaXQQdFMc2Tu+Q==", + "version": "8.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.29.0.tgz", + "integrity": "sha512-aO1PVsq7Gm+tcghabUpzEnVSFMCU4/nYIgC2GOatJcllvWfnhrgW0ZEbnTxm36QsikmCN1K/6ZgM7fok2I7xNw==", + "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "5.59.11", - "@typescript-eslint/visitor-keys": "5.59.11" + "@typescript-eslint/types": "8.29.0", + "@typescript-eslint/visitor-keys": "8.29.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.29.0.tgz", + "integrity": "sha512-ahaWQ42JAOx+NKEf5++WC/ua17q5l+j1GFrbbpVKzFL/tKVc0aYY8rVSYUpUvt2hUP1YBr7mwXzx+E/DfUWI9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "8.29.0", + "@typescript-eslint/utils": "8.29.0", + "debug": "^4.3.4", + "ts-api-utils": "^2.0.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/types": { - "version": "5.59.11", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.11.tgz", - "integrity": "sha512-epoN6R6tkvBYSc+cllrz+c2sOFWkbisJZWkOE+y3xHtvYaOE6Wk6B8e114McRJwFRjGvYdJwLXQH5c9osME/AA==", + "version": "8.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.29.0.tgz", + "integrity": "sha512-wcJL/+cOXV+RE3gjCyl/V2G877+2faqvlgtso/ZRbTCnZazh0gXhe+7gbAnfubzN2bNsBtZjDvlh7ero8uIbzg==", + "dev": true, + "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -2133,47 +3686,120 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.59.11", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.11.tgz", - "integrity": "sha512-YupOpot5hJO0maupJXixi6l5ETdrITxeo5eBOeuV7RSKgYdU3G5cxO49/9WRnJq9EMrB7AuTSLH/bqOsXi7wPA==", + "version": "8.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.29.0.tgz", + "integrity": "sha512-yOfen3jE9ISZR/hHpU/bmNvTtBW1NjRbkSFdZOksL1N+ybPEE7UVGMwqvS6CP022Rp00Sb0tdiIkhSCe6NI8ow==", + "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "5.59.11", - "@typescript-eslint/visitor-keys": "5.59.11", + "@typescript-eslint/types": "8.29.0", + "@typescript-eslint/visitor-keys": "8.29.0", "debug": "^4.3.4", - "globby": "^11.1.0", + "fast-glob": "^3.3.2", "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.29.0.tgz", + "integrity": "sha512-gX/A0Mz9Bskm8avSWFcK0gP7cZpbY4AIo6B0hWYFCaIsz750oaiWR4Jr2CI+PQhfW1CpcQr9OlfPS+kMFegjXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.29.0", + "@typescript-eslint/types": "8.29.0", + "@typescript-eslint/typescript-estree": "8.29.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.59.11", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.11.tgz", - "integrity": "sha512-KGYniTGG3AMTuKF9QBD7EIrvufkB6O6uX3knP73xbKLMpH+QRPcgnCxjWXSHjMRuOxFLovljqQgQpR0c7GvjoA==", + "version": "8.29.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.29.0.tgz", + "integrity": "sha512-Sne/pVz8ryR03NFK21VpN88dZ2FdQXOlq3VIklbrTYEt8yXtRFr9tvUhqvCeKjqYk5FSim37sHbooT6vzBTZcg==", + "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "5.59.11", - "eslint-visitor-keys": "^3.3.0" + "@typescript-eslint/types": "8.29.0", + "eslint-visitor-keys": "^4.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "dev": true, + "license": "ISC" + }, "node_modules/@yarnpkg/lockfile": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", @@ -2194,6 +3820,8 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } @@ -2219,6 +3847,8 @@ "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -2230,6 +3860,31 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/algoliasearch": { + "version": "5.23.2", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.23.2.tgz", + "integrity": "sha512-IhKP22Czzg8Y9HaF6aIb5aAHK2HBj4VAzLLnKEPUnxqDwxpryH9sXbm0NkeY7Cby9GlF81wF+AG/VulKDFBphg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@algolia/client-abtesting": "5.23.2", + "@algolia/client-analytics": "5.23.2", + "@algolia/client-common": "5.23.2", + "@algolia/client-insights": "5.23.2", + "@algolia/client-personalization": "5.23.2", + "@algolia/client-query-suggestions": "5.23.2", + "@algolia/client-search": "5.23.2", + "@algolia/ingestion": "1.23.2", + "@algolia/monitoring": "1.23.2", + "@algolia/recommend": "5.23.2", + "@algolia/requester-browser-xhr": "5.23.2", + "@algolia/requester-fetch": "5.23.2", + "@algolia/requester-node-http": "5.23.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -2277,11 +3932,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" - }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", @@ -2310,11 +3960,6 @@ "readable-stream": "^2.0.6" } }, - "node_modules/arg": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" - }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -2324,31 +3969,40 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.2.1.tgz", "integrity": "sha512-7uFg4b+lETFgdaJyETnILsXgnnzVnkHcgRbwbPwevm5x/LmUlt3MjczMRe1zg824iBgXZNRPTBftNYyRSKLp2g==", + "dev": true, "dependencies": { "dequal": "^2.0.3" } }, "node_modules/array-buffer-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", - "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "is-array-buffer": "^3.0.1" + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/array-includes": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", - "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", + "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "get-intrinsic": "^1.1.3", + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", "is-string": "^1.0.7" }, "engines": { @@ -2358,23 +4012,60 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", + "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-shim-unscopables": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/array.prototype.flat": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", - "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", + "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0" + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -2384,14 +4075,16 @@ } }, "node_modules/array.prototype.flatmap": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", - "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", + "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0" + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -2401,15 +4094,42 @@ } }, "node_modules/array.prototype.tosorted": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz", - "integrity": "sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", + "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "es-shim-unscopables": "^1.0.0", - "get-intrinsic": "^1.1.3" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/ast-types": { @@ -2427,7 +4147,18 @@ "node_modules/ast-types-flow": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", - "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==" + "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==", + "dev": true + }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } }, "node_modules/asynckit": { "version": "0.4.0", @@ -2485,9 +4216,14 @@ } }, "node_modules/available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, "engines": { "node": ">= 0.4" }, @@ -2499,6 +4235,7 @@ "version": "4.7.2", "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.2.tgz", "integrity": "sha512-zIURGIS1E1Q4pcrMjp+nnEh+16G56eG/MUllJH8yEvw7asDo7Ac9uhC9KIH5jzpITueEZolfYglnCGIuSBz39g==", + "dev": true, "engines": { "node": ">=4" } @@ -2518,6 +4255,7 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", "integrity": "sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==", + "dev": true, "dependencies": { "dequal": "^2.0.3" } @@ -2723,16 +4461,18 @@ "version": "1.6.51", "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", + "dev": true, "engines": { "node": ">=0.6" } }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "license": "MIT", "engines": { - "node": ">=8" + "node": "*" } }, "node_modules/bl": { @@ -2770,6 +4510,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==", + "dev": true, "dependencies": { "big-integer": "^1.6.44" }, @@ -2787,11 +4528,12 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -2878,6 +4620,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz", "integrity": "sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==", + "dev": true, "dependencies": { "run-applescript": "^5.0.0" }, @@ -2885,27 +4628,63 @@ "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/busboy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", - "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", "dependencies": { - "streamsearch": "^1.1.0" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" }, "engines": { - "node": ">=10.16.0" + "node": ">= 0.4" } }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2927,14 +4706,6 @@ "node": ">=6" } }, - "node_modules/camelcase-css": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "engines": { - "node": ">= 6" - } - }, "node_modules/caniuse-lite": { "version": "1.0.30001707", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001707.tgz", @@ -3047,43 +4818,6 @@ "url": "https://github.com/sponsors/fb55" } }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/chownr": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", @@ -3171,6 +4905,15 @@ "node": ">=8" } }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -3194,6 +4937,20 @@ "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==" }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -3210,6 +4967,17 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -3326,9 +5094,10 @@ } }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -3390,7 +5159,8 @@ "node_modules/damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", - "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==" + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true }, "node_modules/data-uri-to-buffer": { "version": "6.0.2", @@ -3401,6 +5171,60 @@ "node": ">= 14" } }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/debug": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", @@ -3446,7 +5270,9 @@ "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" }, "node_modules/deepmerge": { "version": "4.3.1", @@ -3460,6 +5286,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-4.0.0.tgz", "integrity": "sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==", + "dev": true, "dependencies": { "bundle-name": "^3.0.0", "default-browser-id": "^3.0.0", @@ -3477,6 +5304,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz", "integrity": "sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==", + "dev": true, "dependencies": { "bplist-parser": "^0.2.0", "untildify": "^4.0.0" @@ -3492,6 +5320,7 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-7.1.1.tgz", "integrity": "sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q==", + "dev": true, "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.1", @@ -3514,6 +5343,7 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", + "dev": true, "engines": { "node": ">=14.18.0" } @@ -3522,6 +5352,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, @@ -3533,6 +5364,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, "engines": { "node": ">=12" }, @@ -3544,6 +5376,7 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "dev": true, "dependencies": { "path-key": "^4.0.0" }, @@ -3558,6 +5391,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, "dependencies": { "mimic-fn": "^4.0.0" }, @@ -3572,6 +5406,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, "engines": { "node": ">=12" }, @@ -3583,6 +5418,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, "engines": { "node": ">=12" }, @@ -3590,10 +5426,29 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/define-lazy-prop": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, "engines": { "node": ">=12" }, @@ -3602,10 +5457,13 @@ } }, "node_modules/define-properties": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", - "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", "dependencies": { + "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" }, @@ -3648,6 +5506,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, "engines": { "node": ">=6" } @@ -3678,11 +5537,6 @@ "integrity": "sha512-yRtvFD8Oyk7C9Os3GmnFZLu53yAfsnyw1s+mLmHHUK0GQEc9zthHWvS1r67Zqzm5t7v56PILHIVZ7kmFMaL2yQ==", "license": "BSD-3-Clause" }, - "node_modules/didyoumean": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" - }, "node_modules/diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", @@ -3703,6 +5557,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, "dependencies": { "path-type": "^4.0.0" }, @@ -3710,15 +5565,11 @@ "node": ">=8" } }, - "node_modules/dlv": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" - }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, "dependencies": { "esutils": "^2.0.2" }, @@ -3806,6 +5657,27 @@ "node": ">=4" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, "node_modules/electron-to-chromium": { "version": "1.4.432", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.432.tgz", @@ -3825,7 +5697,17 @@ "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "license": "MIT", + "engines": { + "node": ">= 4" + } }, "node_modules/encoding-sniffer": { "version": "0.2.0", @@ -3861,9 +5743,10 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", - "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", + "version": "5.18.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz", + "integrity": "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==", + "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -3902,44 +5785,63 @@ } }, "node_modules/es-abstract": { - "version": "1.21.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz", - "integrity": "sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==", - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.2.0", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", + "version": "1.23.9", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.9.tgz", + "integrity": "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.0", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.10", - "is-weakref": "^1.0.2", - "object-inspect": "^1.12.3", + "is-data-view": "^1.0.2", + "is-regex": "^1.2.1", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.0", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.3", "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.4.3", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.7", - "string.prototype.trimend": "^1.0.6", - "string.prototype.trimstart": "^1.0.6", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.9" + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.3", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.18" }, "engines": { "node": ">= 0.4" @@ -3948,35 +5850,103 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.1.tgz", + "integrity": "sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.3", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.6", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "iterator.prototype": "^1.1.4", + "safe-array-concat": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-set-tostringtag": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", - "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", "dependencies": { - "get-intrinsic": "^1.1.3", - "has": "^1.0.3", - "has-tostringtag": "^1.0.0" + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" } }, "node_modules/es-shim-unscopables": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", - "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", + "dev": true, + "license": "MIT", "dependencies": { - "has": "^1.0.3" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" } }, "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "dev": true, + "license": "MIT", "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" }, "engines": { "node": ">= 0.4" @@ -3997,6 +5967,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, "engines": { "node": ">=10" }, @@ -4026,26 +5997,30 @@ } }, "node_modules/eslint": { - "version": "8.38.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.38.0.tgz", - "integrity": "sha512-pIdsD2jwlUGf/U38Jv97t8lq6HpaU/G9NKbYmpWpZGw3LdTNhZLbJePqxOXGB5+JEKfOPU/XLxYxFh03nr1KTg==", + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.2", - "@eslint/js": "8.38.0", - "@humanwhocodes/config-array": "^0.11.8", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-visitor-keys": "^3.4.0", - "espree": "^9.5.1", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -4053,22 +6028,19 @@ "find-up": "^5.0.0", "glob-parent": "^6.0.2", "globals": "^13.19.0", - "grapheme-splitter": "^1.0.4", + "graphemer": "^1.4.0", "ignore": "^5.2.0", - "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", + "optionator": "^0.9.3", "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" }, "bin": { @@ -4082,19 +6054,22 @@ } }, "node_modules/eslint-config-next": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-13.3.0.tgz", - "integrity": "sha512-6YEwmFBX0VjBd3ODGW9df0Is0FLaRFdMN8eAahQG9CN6LjQ28J8AFr19ngxqMSg7Qv6Uca/3VeeBosJh1bzu0w==", + "version": "14.2.26", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-14.2.26.tgz", + "integrity": "sha512-KZNh1xvWG1ZDFD2f2WkvvnMpp7Sjsl6xJXCsvfEe8GH1FLXn6GtXo7lY9S8xDcn6oBWmKA0hSrlrp1DNQ9QDnQ==", + "dev": true, + "license": "MIT", "dependencies": { - "@next/eslint-plugin-next": "13.3.0", - "@rushstack/eslint-patch": "^1.1.3", - "@typescript-eslint/parser": "^5.42.0", + "@next/eslint-plugin-next": "14.2.26", + "@rushstack/eslint-patch": "^1.3.3", + "@typescript-eslint/eslint-plugin": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0", + "@typescript-eslint/parser": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0", "eslint-import-resolver-node": "^0.3.6", "eslint-import-resolver-typescript": "^3.5.2", - "eslint-plugin-import": "^2.26.0", - "eslint-plugin-jsx-a11y": "^6.5.1", - "eslint-plugin-react": "^7.31.7", - "eslint-plugin-react-hooks": "^4.5.0" + "eslint-plugin-import": "^2.28.1", + "eslint-plugin-jsx-a11y": "^6.7.1", + "eslint-plugin-react": "^7.33.2", + "eslint-plugin-react-hooks": "^4.5.0 || 5.0.0-canary-7118f5dd7-20230705" }, "peerDependencies": { "eslint": "^7.23.0 || ^8.0.0", @@ -4107,27 +6082,52 @@ } }, "node_modules/eslint-import-resolver-node": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", - "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "license": "MIT", "dependencies": { "debug": "^3.2.7", - "is-core-module": "^2.11.0", - "resolve": "^1.22.1" + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" } }, "node_modules/eslint-import-resolver-node/node_modules/debug": { "version": "3.2.7", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, "dependencies": { "ms": "^2.1.1" } }, + "node_modules/eslint-import-resolver-node/node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/eslint-import-resolver-typescript": { "version": "3.5.5", "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.5.5.tgz", "integrity": "sha512-TdJqPHs2lW5J9Zpe17DZNQuDnox4xo2o+0tE7Pggain9Rbc19ik8kFtXdxZ250FVx2kF4vlt2RSf4qlUpG7bhw==", + "dev": true, "dependencies": { "debug": "^4.3.4", "enhanced-resolve": "^5.12.0", @@ -4153,6 +6153,7 @@ "version": "13.1.4", "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.4.tgz", "integrity": "sha512-iui/IiiW+QrJ1X1hKH5qwlMQyv34wJAYwH1vrf8b9kBA4sNiif3gKsMHa+BrdnOpEudWjpotfa7LrTzB1ERS/g==", + "dev": true, "dependencies": { "dir-glob": "^3.0.1", "fast-glob": "^3.2.11", @@ -4171,6 +6172,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true, "engines": { "node": ">=12" }, @@ -4179,9 +6181,11 @@ } }, "node_modules/eslint-module-utils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", - "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz", + "integrity": "sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==", + "dev": true, + "license": "MIT", "dependencies": { "debug": "^3.2.7" }, @@ -4198,42 +6202,50 @@ "version": "3.2.7", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, "dependencies": { "ms": "^2.1.1" } }, "node_modules/eslint-plugin-import": { - "version": "2.27.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz", - "integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==", + "version": "2.31.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz", + "integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==", + "dev": true, + "license": "MIT", "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flat": "^1.3.1", - "array.prototype.flatmap": "^1.3.1", + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.8", + "array.prototype.findlastindex": "^1.2.5", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", "debug": "^3.2.7", "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.7", - "eslint-module-utils": "^2.7.4", - "has": "^1.0.3", - "is-core-module": "^2.11.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.12.0", + "hasown": "^2.0.2", + "is-core-module": "^2.15.1", "is-glob": "^4.0.3", "minimatch": "^3.1.2", - "object.values": "^1.1.6", - "resolve": "^1.22.1", - "semver": "^6.3.0", - "tsconfig-paths": "^3.14.1" + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.0", + "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.8", + "tsconfig-paths": "^3.15.0" }, "engines": { "node": ">=4" }, "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" } }, "node_modules/eslint-plugin-import/node_modules/debug": { "version": "3.2.7", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, "dependencies": { "ms": "^2.1.1" } @@ -4242,6 +6254,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, "dependencies": { "esutils": "^2.0.2" }, @@ -4250,9 +6263,11 @@ } }, "node_modules/eslint-plugin-import/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } @@ -4261,6 +6276,7 @@ "version": "6.7.1", "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.7.1.tgz", "integrity": "sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==", + "dev": true, "dependencies": { "@babel/runtime": "^7.20.7", "aria-query": "^5.1.3", @@ -4290,42 +6306,49 @@ "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, "bin": { "semver": "bin/semver.js" } }, "node_modules/eslint-plugin-react": { - "version": "7.32.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz", - "integrity": "sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==", + "version": "7.37.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", + "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", + "dev": true, + "license": "MIT", "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flatmap": "^1.3.1", - "array.prototype.tosorted": "^1.1.1", + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.3", + "array.prototype.tosorted": "^1.1.4", "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.2.1", "estraverse": "^5.3.0", + "hasown": "^2.0.2", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", - "object.entries": "^1.1.6", - "object.fromentries": "^2.0.6", - "object.hasown": "^1.1.2", - "object.values": "^1.1.6", + "object.entries": "^1.1.9", + "object.fromentries": "^2.0.8", + "object.values": "^1.2.1", "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.4", - "semver": "^6.3.0", - "string.prototype.matchall": "^4.0.8" + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.12", + "string.prototype.repeat": "^1.0.0" }, "engines": { "node": ">=4" }, "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, "node_modules/eslint-plugin-react-hooks": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", + "dev": true, "engines": { "node": ">=10" }, @@ -4337,6 +6360,8 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, @@ -4345,11 +6370,13 @@ } }, "node_modules/eslint-plugin-react/node_modules/resolve": { - "version": "2.0.0-next.4", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", - "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "dev": true, + "license": "MIT", "dependencies": { - "is-core-module": "^2.9.0", + "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -4361,17 +6388,21 @@ } }, "node_modules/eslint-plugin-react/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/eslint-scope": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", - "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -4384,9 +6415,11 @@ } }, "node_modules/eslint-visitor-keys": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", - "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -4395,11 +6428,13 @@ } }, "node_modules/espree": { - "version": "9.5.2", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", - "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.8.0", + "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^3.4.1" }, @@ -4426,6 +6461,7 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, "dependencies": { "estraverse": "^5.1.0" }, @@ -4437,6 +6473,8 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -4552,7 +6590,9 @@ "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" }, "node_modules/fast-fifo": { "version": "1.3.2", @@ -4561,15 +6601,16 @@ "license": "MIT" }, "node_modules/fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "micromatch": "^4.0.8" }, "engines": { "node": ">=8.6.0" @@ -4599,7 +6640,9 @@ "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" }, "node_modules/fastq": { "version": "1.15.0", @@ -4642,6 +6685,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, "dependencies": { "flat-cache": "^3.0.4" }, @@ -4650,9 +6694,10 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -4664,6 +6709,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -4687,6 +6733,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, "dependencies": { "flatted": "^3.1.0", "rimraf": "^3.0.2" @@ -4698,7 +6745,14 @@ "node_modules/flatted": { "version": "3.2.7", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==" + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "node_modules/flexsearch": { + "version": "0.7.43", + "resolved": "https://registry.npmjs.org/flexsearch/-/flexsearch-0.7.43.tgz", + "integrity": "sha512-c5o/+Um8aqCSOXGcZoqZOm+NqtVwNsvVpWv6lfmSclU954O3wvQKxxK8zj74fPaSJbXpSLTs4PRhh+wnoCXnKg==", + "license": "Apache-2.0" }, "node_modules/flowbite": { "version": "1.6.6", @@ -4730,11 +6784,49 @@ } }, "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", "dependencies": { - "is-callable": "^1.1.3" + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/form-data": { @@ -4827,19 +6919,27 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/function.prototype.name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" }, "engines": { "node": ">= 0.4" @@ -4852,6 +6952,8 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -4910,14 +7012,24 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4931,6 +7043,19 @@ "node": ">=8.0.0" } }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/get-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", @@ -4943,12 +7068,15 @@ } }, "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" }, "engines": { "node": ">= 0.4" @@ -4961,6 +7089,7 @@ "version": "4.6.0", "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.6.0.tgz", "integrity": "sha512-lgbo68hHTQnFddybKbbs/RDRJnJT5YyGy2kQzVwbq+g67X73i+5MVTval34QxGkOe9X5Ujf1UYpCaphLyltjEg==", + "dev": true, "dependencies": { "resolve-pkg-maps": "^1.0.0" }, @@ -5011,6 +7140,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, "dependencies": { "is-glob": "^4.0.3" }, @@ -5019,9 +7149,11 @@ } }, "node_modules/globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", "dependencies": { "type-fest": "^0.20.2" }, @@ -5033,11 +7165,14 @@ } }, "node_modules/globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", "dependencies": { - "define-properties": "^1.1.3" + "define-properties": "^1.2.1", + "gopd": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -5046,31 +7181,13 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dependencies": { - "get-intrinsic": "^1.1.3" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5081,15 +7198,18 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==" + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" }, "node_modules/has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, "dependencies": { "function-bind": "^1.1.1" }, @@ -5098,9 +7218,14 @@ } }, "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -5114,20 +7239,27 @@ } }, "node_modules/has-property-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", "dependencies": { - "get-intrinsic": "^1.1.1" + "es-define-property": "^1.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, "engines": { "node": ">= 0.4" }, @@ -5136,9 +7268,10 @@ } }, "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -5147,11 +7280,13 @@ } }, "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", "dependencies": { - "has-symbols": "^1.0.2" + "has-symbols": "^1.0.3" }, "engines": { "node": ">= 0.4" @@ -5166,6 +7301,18 @@ "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", "optional": true }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/hast-util-parse-selector": { "version": "2.2.5", "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz", @@ -5191,6 +7338,12 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/highlight-words-core": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/highlight-words-core/-/highlight-words-core-1.2.3.tgz", + "integrity": "sha512-m1O9HW3/GNHxzSIXWw1wCNXXsgLlxrP0OI6+ycGUhiUHkikqW3OrwVHz+lxeNBe5yqLESdIcj8PowHQ2zLvUvQ==", + "license": "MIT" + }, "node_modules/highlight.js": { "version": "10.7.3", "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", @@ -5301,9 +7454,11 @@ ] }, "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } @@ -5378,13 +7533,15 @@ "optional": true }, "node_modules/internal-slot": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", - "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, + "license": "MIT", "dependencies": { - "get-intrinsic": "^1.2.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -5440,13 +7597,18 @@ } }, "node_modules/is-array-buffer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", - "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "is-typed-array": "^1.1.10" + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5457,35 +7619,51 @@ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, + "license": "MIT", "dependencies": { - "has-bigints": "^1.0.1" + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "dev": true, + "license": "MIT", "dependencies": { - "binary-extensions": "^2.0.0" + "has-bigints": "^1.0.2" }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -5498,6 +7676,8 @@ "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -5522,22 +7702,47 @@ "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" }, "node_modules/is-core-module": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", - "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "dev": true, + "license": "MIT", "dependencies": { - "has": "^1.0.3" + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "dev": true, + "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -5577,6 +7782,22 @@ "node": ">=0.10.0" } }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-fullwidth-code-point": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", @@ -5594,7 +7815,26 @@ "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", "engines": { - "node": ">=6" + "node": ">=6" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", + "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-proto": "^1.0.0", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-glob": { @@ -5621,6 +7861,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, "dependencies": { "is-docker": "^3.0.0" }, @@ -5638,6 +7879,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, "bin": { "is-docker": "cli.js" }, @@ -5648,10 +7890,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -5663,16 +7907,20 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", "engines": { "node": ">=0.12.0" } }, "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "dev": true, + "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -5685,6 +7933,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, "engines": { "node": ">=8" } @@ -5698,13 +7947,30 @@ } }, "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -5713,11 +7979,16 @@ } }, "node_modules/is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2" + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5735,11 +8006,14 @@ } }, "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "dev": true, + "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -5749,11 +8023,15 @@ } }, "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, + "license": "MIT", "dependencies": { - "has-symbols": "^1.0.2" + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -5763,15 +8041,13 @@ } }, "node_modules/is-typed-array": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", - "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dev": true, + "license": "MIT", "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" + "which-typed-array": "^1.1.16" }, "engines": { "node": ">= 0.4" @@ -5780,12 +8056,47 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2" + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5882,6 +8193,43 @@ "node": ">=8" } }, + "node_modules/iterator.prototype": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", + "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "get-proto": "^1.0.0", + "has-symbols": "^1.1.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/jest": { "version": "29.5.0", "resolved": "https://registry.npmjs.org/jest/-/jest-29.5.0.tgz", @@ -6413,11 +8761,12 @@ } }, "node_modules/jiti": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz", - "integrity": "sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", + "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", + "license": "MIT", "bin": { - "jiti": "bin/jiti.js" + "jiti": "lib/jiti-cli.mjs" } }, "node_modules/js-file-download": { @@ -6425,15 +8774,6 @@ "resolved": "https://registry.npmjs.org/js-file-download/-/js-file-download-0.4.12.tgz", "integrity": "sha512-rML+NkoD08p5Dllpjo0ffy4jRHeY6Zsapvr/W86N7E0yuzAO6qa5X9+xog6zQNlH102J7IXljNY2FtS6Lj3ucg==" }, - "node_modules/js-sdsl": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.1.tgz", - "integrity": "sha512-6Gsx8R0RucyePbWqPssR8DyfuXmLBooYN5cZFZKjHGnQuaf7pEzhtpceagJxVu4LqhYY5EYA7nko3FmeHZ1KbA==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -6443,6 +8783,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -6475,12 +8816,15 @@ "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==" + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true }, "node_modules/json5": { "version": "2.2.3", @@ -6508,6 +8852,7 @@ "version": "3.3.3", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==", + "dev": true, "dependencies": { "array-includes": "^3.1.5", "object.assign": "^4.1.3" @@ -6532,45 +8877,278 @@ "node": ">=6" } }, - "node_modules/language-subtag-registry": { - "version": "0.3.22", - "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", - "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==" - }, - "node_modules/language-tags": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", - "integrity": "sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==", - "dependencies": { - "language-subtag-registry": "~0.3.2" + "node_modules/language-subtag-registry": { + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", + "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==", + "dev": true + }, + "node_modules/language-tags": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", + "integrity": "sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==", + "dev": true, + "dependencies": { + "language-subtag-registry": "~0.3.2" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lightningcss": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.29.2.tgz", + "integrity": "sha512-6b6gd/RUXKaw5keVdSEtqFVdzWnU5jMxTUjA2bVcMNPLwSQ08Sv/UodBVtETLCn7k4S1Ibxwh7k68IwLZPgKaA==", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-darwin-arm64": "1.29.2", + "lightningcss-darwin-x64": "1.29.2", + "lightningcss-freebsd-x64": "1.29.2", + "lightningcss-linux-arm-gnueabihf": "1.29.2", + "lightningcss-linux-arm64-gnu": "1.29.2", + "lightningcss-linux-arm64-musl": "1.29.2", + "lightningcss-linux-x64-gnu": "1.29.2", + "lightningcss-linux-x64-musl": "1.29.2", + "lightningcss-win32-arm64-msvc": "1.29.2", + "lightningcss-win32-x64-msvc": "1.29.2" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.29.2.tgz", + "integrity": "sha512-cK/eMabSViKn/PG8U/a7aCorpeKLMlK0bQeNHmdb7qUnBkNPnL+oV5DjJUo0kqWsJUapZsM4jCfYItbqBDvlcA==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.29.2.tgz", + "integrity": "sha512-j5qYxamyQw4kDXX5hnnCKMf3mLlHvG44f24Qyi2965/Ycz829MYqjrVg2H8BidybHBp9kom4D7DR5VqCKDXS0w==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.29.2.tgz", + "integrity": "sha512-wDk7M2tM78Ii8ek9YjnY8MjV5f5JN2qNVO+/0BAGZRvXKtQrBC4/cn4ssQIpKIPP44YXw6gFdpUF+Ps+RGsCwg==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.29.2.tgz", + "integrity": "sha512-IRUrOrAF2Z+KExdExe3Rz7NSTuuJ2HvCGlMKoquK5pjvo2JY4Rybr+NrKnq0U0hZnx5AnGsuFHjGnNT14w26sg==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.29.2.tgz", + "integrity": "sha512-KKCpOlmhdjvUTX/mBuaKemp0oeDIBBLFiU5Fnqxh1/DZ4JPZi4evEH7TKoSBFOSOV3J7iEmmBaw/8dpiUvRKlQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.29.2.tgz", + "integrity": "sha512-Q64eM1bPlOOUgxFmoPUefqzY1yV3ctFPE6d/Vt7WzLW4rKTv7MyYNky+FWxRpLkNASTnKQUaiMJ87zNODIrrKQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.29.2.tgz", + "integrity": "sha512-0v6idDCPG6epLXtBH/RPkHvYx74CVziHo6TMYga8O2EiQApnUPZsbR9nFNrg2cgBzk1AYqEd95TlrsL7nYABQg==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.29.2.tgz", + "integrity": "sha512-rMpz2yawkgGT8RULc5S4WiZopVMOFWjiItBT7aSfDX4NQav6M44rhn5hjtkKzB+wMTRlLLqxkeYEtQ3dd9696w==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.29.2.tgz", + "integrity": "sha512-nL7zRW6evGQqYVu/bKGK+zShyz8OVzsCotFgc7judbt6wnB2KbiKKJwBE4SGoDBQ1O94RjW4asrCjQL4i8Fhbw==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=6" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.29.2.tgz", + "integrity": "sha512-EdIUW3B2vLuHmv7urfzMI/h2fmlnOQBk1xlsDxkN1tCWKjNFjfLhGxYk8C8mzpSfr+A6jFFIi8fU6LbQGsRWjA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">= 0.8.0" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/lilconfig": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", - "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "node_modules/lightningcss/node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "license": "Apache-2.0", "engines": { - "node": ">=10" + "node": ">=8" } }, "node_modules/lines-and-columns": { @@ -6578,10 +9156,25 @@ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, + "node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "license": "MIT", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, "dependencies": { "p-locate": "^5.0.0" }, @@ -6684,6 +9277,21 @@ "tmpl": "1.0.5" } }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/memoize-one": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-4.0.3.tgz", + "integrity": "sha512-QmpUu4KqDmX0plH4u+tf0riMc1KHE1+lw95cMrLlXQAFOx/xnBtwhZ52XJxd9X2O6kwKBqX32kmhbhlobD0cuw==", + "license": "MIT" + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -6698,11 +9306,12 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -6786,6 +9395,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/mitt": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", @@ -6804,16 +9423,6 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, - "node_modules/mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dependencies": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, "node_modules/nan": { "version": "2.17.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", @@ -6821,15 +9430,16 @@ "optional": true }, "node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "funding": [ { "type": "github", "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -6882,38 +9492,39 @@ } }, "node_modules/next": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/next/-/next-13.3.0.tgz", - "integrity": "sha512-OVTw8MpIPa12+DCUkPqRGPS3thlJPcwae2ZL4xti3iBff27goH024xy4q2lhlsdoYiKOi8Kz6uJoLW/GXwgfOA==", + "version": "14.2.26", + "resolved": "https://registry.npmjs.org/next/-/next-14.2.26.tgz", + "integrity": "sha512-b81XSLihMwCfwiUVRRja3LphLo4uBBMZEzBBWMaISbKTwOmq3wPknIETy/8000tr7Gq4WmbuFYPS7jOYIf+ZJw==", + "license": "MIT", "dependencies": { - "@next/env": "13.3.0", - "@swc/helpers": "0.4.14", + "@next/env": "14.2.26", + "@swc/helpers": "0.5.5", "busboy": "1.6.0", - "caniuse-lite": "^1.0.30001406", - "postcss": "8.4.14", + "caniuse-lite": "^1.0.30001579", + "graceful-fs": "^4.2.11", + "postcss": "8.4.31", "styled-jsx": "5.1.1" }, "bin": { "next": "dist/bin/next" }, "engines": { - "node": ">=14.6.0" + "node": ">=18.17.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "13.3.0", - "@next/swc-darwin-x64": "13.3.0", - "@next/swc-linux-arm64-gnu": "13.3.0", - "@next/swc-linux-arm64-musl": "13.3.0", - "@next/swc-linux-x64-gnu": "13.3.0", - "@next/swc-linux-x64-musl": "13.3.0", - "@next/swc-win32-arm64-msvc": "13.3.0", - "@next/swc-win32-ia32-msvc": "13.3.0", - "@next/swc-win32-x64-msvc": "13.3.0" + "@next/swc-darwin-arm64": "14.2.26", + "@next/swc-darwin-x64": "14.2.26", + "@next/swc-linux-arm64-gnu": "14.2.26", + "@next/swc-linux-arm64-musl": "14.2.26", + "@next/swc-linux-x64-gnu": "14.2.26", + "@next/swc-linux-x64-musl": "14.2.26", + "@next/swc-win32-arm64-msvc": "14.2.26", + "@next/swc-win32-ia32-msvc": "14.2.26", + "@next/swc-win32-x64-msvc": "14.2.26" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", - "fibers": ">= 3.1.0", - "node-sass": "^6.0.0 || ^7.0.0", + "@playwright/test": "^1.41.2", "react": "^18.2.0", "react-dom": "^18.2.0", "sass": "^1.3.0" @@ -6922,10 +9533,7 @@ "@opentelemetry/api": { "optional": true }, - "fibers": { - "optional": true - }, - "node-sass": { + "@playwright/test": { "optional": true }, "sass": { @@ -6960,32 +9568,25 @@ "next": "*" } }, - "node_modules/next/node_modules/@next/env": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/@next/env/-/env-13.3.0.tgz", - "integrity": "sha512-AjppRV4uG3No7L1plinoTQETH+j2F10TEnrMfzbTUYwze5sBUPveeeBAPZPm8OkJZ1epq9OyYKhZrvbD6/9HCQ==" + "node_modules/next-themes": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.2.1.tgz", + "integrity": "sha512-B+AKNfYNIzh0vqQQKqQItTS8evEouKD7H5Hj3kmuPERwddR2TxvDSFZuTj6T7Jfn1oyeUyJMydPl1Bkxkh0W7A==", + "license": "MIT", + "peerDependencies": { + "next": "*", + "react": "*", + "react-dom": "*" + } }, - "node_modules/next/node_modules/postcss": { - "version": "8.4.14", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", - "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - } - ], + "node_modules/next/node_modules/@swc/helpers": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.5.tgz", + "integrity": "sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==", + "license": "Apache-2.0", "dependencies": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" + "@swc/counter": "^0.1.3", + "tslib": "^2.4.0" } }, "node_modules/nice-try": { @@ -7135,18 +9736,14 @@ "node": ">=0.10.0" } }, - "node_modules/object-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "engines": { - "node": ">= 6" - } - }, "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -7155,18 +9752,23 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, "engines": { "node": ">= 0.4" } }, "node_modules/object.assign": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", "object-keys": "^1.1.1" }, "engines": { @@ -7177,26 +9779,32 @@ } }, "node_modules/object.entries": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.6.tgz", - "integrity": "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==", + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz", + "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==", + "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.1" }, "engines": { "node": ">= 0.4" } }, "node_modules/object.fromentries": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz", - "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -7205,26 +9813,32 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/object.hasown": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.2.tgz", - "integrity": "sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==", + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "license": "MIT", "dependencies": { - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">= 0.4" } }, "node_modules/object.values": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", - "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", + "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -7271,16 +9885,18 @@ } }, "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "word-wrap": "^1.2.5" }, "engines": { "node": ">= 0.8.0" @@ -7294,6 +9910,24 @@ "node": ">=0.10.0" } }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -7312,6 +9946,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, "dependencies": { "p-limit": "^3.0.2" }, @@ -7601,10 +10236,35 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, "engines": { "node": ">=8" } @@ -7624,9 +10284,10 @@ "license": "MIT" }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", @@ -7639,14 +10300,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/pirates": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", @@ -7714,10 +10367,20 @@ "node": ">=8" } }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/postcss": { - "version": "8.4.24", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz", - "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==", + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", "funding": [ { "type": "opencollective", @@ -7732,6 +10395,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", @@ -7741,106 +10405,6 @@ "node": "^10 || ^12 || >=14" } }, - "node_modules/postcss-import": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", - "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", - "dependencies": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "postcss": "^8.0.0" - } - }, - "node_modules/postcss-js": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", - "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", - "dependencies": { - "camelcase-css": "^2.0.1" - }, - "engines": { - "node": "^12 || ^14 || >= 16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.4.21" - } - }, - "node_modules/postcss-load-config": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz", - "integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==", - "dependencies": { - "lilconfig": "^2.0.5", - "yaml": "^2.1.1" - }, - "engines": { - "node": ">= 14" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": ">=8.0.9", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "postcss": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "node_modules/postcss-load-config/node_modules/yaml": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz", - "integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==", - "engines": { - "node": ">= 14" - } - }, - "node_modules/postcss-nested": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", - "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", - "dependencies": { - "postcss-selector-parser": "^6.0.11" - }, - "engines": { - "node": ">=12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.2.14" - } - }, - "node_modules/postcss-nested/node_modules/postcss-selector-parser": { - "version": "6.0.13", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", - "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/postcss-selector-parser": { "version": "6.0.10", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", @@ -7856,7 +10420,8 @@ "node_modules/postcss-value-parser": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true }, "node_modules/prebuild-install": { "version": "6.1.4", @@ -7889,50 +10454,55 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8.0" } }, "node_modules/prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", + "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", "dev": true, + "license": "MIT", "bin": { - "prettier": "bin-prettier.js" + "prettier": "bin/prettier.cjs" }, "engines": { - "node": ">=10.13.0" + "node": ">=14" }, "funding": { "url": "https://github.com/prettier/prettier?sponsor=1" } }, "node_modules/prettier-plugin-tailwindcss": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.3.0.tgz", - "integrity": "sha512-009/Xqdy7UmkcTBpwlq7jsViDqXAYSOMLDrHAdTMlVZOrKfM2o9Ci7EMWTMZ7SkKBFTG04UM9F9iM2+4i6boDA==", + "version": "0.6.11", + "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.6.11.tgz", + "integrity": "sha512-YxaYSIvZPAqhrrEpRtonnrXdghZg1irNg4qrjboCXrpybLWVs55cW2N3juhspVJiO0JBvYJT8SYsJpc8OQSnsA==", "dev": true, + "license": "MIT", "engines": { - "node": ">=12.17.0" + "node": ">=14.21.3" }, "peerDependencies": { "@ianvs/prettier-plugin-sort-imports": "*", "@prettier/plugin-pug": "*", "@shopify/prettier-plugin-liquid": "*", - "@shufo/prettier-plugin-blade": "*", "@trivago/prettier-plugin-sort-imports": "*", - "prettier": ">=2.2.0", + "@zackad/prettier-plugin-twig": "*", + "prettier": "^3.0", "prettier-plugin-astro": "*", "prettier-plugin-css-order": "*", "prettier-plugin-import-sort": "*", "prettier-plugin-jsdoc": "*", "prettier-plugin-marko": "*", + "prettier-plugin-multiline-arrays": "*", "prettier-plugin-organize-attributes": "*", "prettier-plugin-organize-imports": "*", + "prettier-plugin-sort-imports": "*", "prettier-plugin-style-order": "*", - "prettier-plugin-svelte": "*", - "prettier-plugin-twig-melody": "*" + "prettier-plugin-svelte": "*" }, "peerDependenciesMeta": { "@ianvs/prettier-plugin-sort-imports": { @@ -7944,10 +10514,10 @@ "@shopify/prettier-plugin-liquid": { "optional": true }, - "@shufo/prettier-plugin-blade": { + "@trivago/prettier-plugin-sort-imports": { "optional": true }, - "@trivago/prettier-plugin-sort-imports": { + "@zackad/prettier-plugin-twig": { "optional": true }, "prettier-plugin-astro": { @@ -7965,19 +10535,22 @@ "prettier-plugin-marko": { "optional": true }, + "prettier-plugin-multiline-arrays": { + "optional": true + }, "prettier-plugin-organize-attributes": { "optional": true }, "prettier-plugin-organize-imports": { "optional": true }, - "prettier-plugin-style-order": { + "prettier-plugin-sort-imports": { "optional": true }, - "prettier-plugin-svelte": { + "prettier-plugin-style-order": { "optional": true }, - "prettier-plugin-twig-melody": { + "prettier-plugin-svelte": { "optional": true } } @@ -8006,6 +10579,19 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/prism-react-renderer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-2.4.1.tgz", + "integrity": "sha512-ey8Ls/+Di31eqzUxC46h8MksNuGx/n0AAC8uKpwFau4RPDYLuE3EXTp8N8G2vX2N7UC/+IXeNUnlWBGGcAG+Ig==", + "license": "MIT", + "dependencies": { + "@types/prismjs": "^1.26.0", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "react": ">=16.0.0" + } + }, "node_modules/prismjs": { "version": "1.29.0", "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", @@ -8129,9 +10715,11 @@ } }, "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -8342,6 +10930,20 @@ "react": "^18.2.0" } }, + "node_modules/react-highlight-words": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/react-highlight-words/-/react-highlight-words-0.20.0.tgz", + "integrity": "sha512-asCxy+jCehDVhusNmCBoxDf2mm1AJ//D+EzDx1m5K7EqsMBIHdZ5G4LdwbSEXqZq1Ros0G0UySWmAtntSph7XA==", + "license": "MIT", + "dependencies": { + "highlight-words-core": "^1.2.0", + "memoize-one": "^4.0.0", + "prop-types": "^15.5.8" + }, + "peerDependencies": { + "react": "^0.14.0 || ^15.0.0 || ^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0" + } + }, "node_modules/react-immutable-proptypes": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/react-immutable-proptypes/-/react-immutable-proptypes-2.2.0.tgz", @@ -8433,14 +11035,6 @@ "react": ">= 0.14.0" } }, - "node_modules/read-cache": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", - "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", - "dependencies": { - "pify": "^2.3.0" - } - }, "node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", @@ -8462,17 +11056,6 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "optional": true }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, "node_modules/redux": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", @@ -8489,6 +11072,29 @@ "immutable": "^3.8.1 || ^4.0.0-rc.1" } }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/refractor": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/refractor/-/refractor-3.6.0.tgz", @@ -8517,13 +11123,18 @@ "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" }, "node_modules/regexp.prototype.flags": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", - "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "functions-have-names": "^1.2.3" + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -8628,6 +11239,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, "funding": { "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } @@ -8661,6 +11273,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, "dependencies": { "glob": "^7.1.3" }, @@ -8675,6 +11288,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", "integrity": "sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==", + "dev": true, "dependencies": { "execa": "^5.0.0" }, @@ -8707,6 +11321,33 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/safe-array-concat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-array-concat/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -8726,14 +11367,43 @@ } ] }, - "node_modules/safe-regex-test": { + "node_modules/safe-push-apply": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", - "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-push-apply/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-regex": "^1.1.4" + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -8757,6 +11427,13 @@ "loose-envify": "^1.1.0" } }, + "node_modules/search-insights": { + "version": "2.17.3", + "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.17.3.tgz", + "integrity": "sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==", + "license": "MIT", + "peer": true + }, "node_modules/semver": { "version": "7.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", @@ -8789,6 +11466,55 @@ "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", "optional": true }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/sha.js": { "version": "2.4.11", "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", @@ -8801,6 +11527,57 @@ "sha.js": "bin.js" } }, + "node_modules/sharp": { + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.1.tgz", + "integrity": "sha512-iAYUnOdTqqZDb3QjMneBKINTllCJDZ3em6WaWy7NPECM4aHncvqHRm0v0bN9nqJxMiwamv5KIdauJ6lUzKDpTQ==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.2", + "semver": "^7.5.4" + }, + "engines": { + "libvips": ">=8.15.0", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.33.1", + "@img/sharp-darwin-x64": "0.33.1", + "@img/sharp-libvips-darwin-arm64": "1.0.0", + "@img/sharp-libvips-darwin-x64": "1.0.0", + "@img/sharp-libvips-linux-arm": "1.0.0", + "@img/sharp-libvips-linux-arm64": "1.0.0", + "@img/sharp-libvips-linux-s390x": "1.0.0", + "@img/sharp-libvips-linux-x64": "1.0.0", + "@img/sharp-libvips-linuxmusl-arm64": "1.0.0", + "@img/sharp-libvips-linuxmusl-x64": "1.0.0", + "@img/sharp-linux-arm": "0.33.1", + "@img/sharp-linux-arm64": "0.33.1", + "@img/sharp-linux-s390x": "0.33.1", + "@img/sharp-linux-x64": "0.33.1", + "@img/sharp-linuxmusl-arm64": "0.33.1", + "@img/sharp-linuxmusl-x64": "0.33.1", + "@img/sharp-wasm32": "0.33.1", + "@img/sharp-win32-ia32": "0.33.1", + "@img/sharp-win32-x64": "0.33.1" + } + }, + "node_modules/sharp/node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -8845,13 +11622,72 @@ } }, "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -8882,6 +11718,15 @@ ], "optional": true }, + "node_modules/simple-functional-loader": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/simple-functional-loader/-/simple-functional-loader-1.2.1.tgz", + "integrity": "sha512-GPDrxrQkE7ijm35QlfPFVp5hBHR6ZcaUq42TEDgf1U5iTL3IDLFvKAbHE/ODqpdfJJ7Xn4cr/slBn12jjNPkaQ==", + "license": "MIT", + "dependencies": { + "loader-utils": "^2.0.0" + } + }, "node_modules/simple-get": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", @@ -8893,6 +11738,23 @@ "simple-concat": "^1.0.0" } }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "dev": true, + "license": "MIT" + }, "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -8953,9 +11815,10 @@ } }, "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -9090,6 +11953,39 @@ "node": ">=0.10.0" } }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/string-width/node_modules/ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", @@ -9112,31 +12008,58 @@ } }, "node_modules/string.prototype.matchall": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz", - "integrity": "sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "get-intrinsic": "^1.1.3", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.3", - "regexp.prototype.flags": "^1.4.3", - "side-channel": "^1.0.4" + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", + "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "regexp.prototype.flags": "^1.5.3", + "set-function-name": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, "node_modules/string.prototype.trim": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", - "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", + "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -9146,26 +12069,37 @@ } }, "node_modules/string.prototype.trimend": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", - "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", + "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/string.prototype.trimstart": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", - "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -9182,6 +12116,20 @@ "node": ">=8" } }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-bom": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", @@ -9231,54 +12179,6 @@ } } }, - "node_modules/sucrase": { - "version": "3.32.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz", - "integrity": "sha512-ydQOU34rpSyj2TGyz4D2p8rbktIOZ8QY9s+DGLvFU1i5pWJE8vkpruCjGCMHsdXwnD7JDcS+noSwM/a7zyNFDQ==", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "glob": "7.1.6", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "ts-interface-checker": "^0.1.9" - }, - "bin": { - "sucrase": "bin/sucrase", - "sucrase-node": "bin/sucrase-node" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/sucrase/node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "engines": { - "node": ">= 6" - } - }, - "node_modules/sucrase/node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -9379,6 +12279,7 @@ "version": "0.8.5", "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz", "integrity": "sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==", + "dev": true, "dependencies": { "@pkgr/utils": "^2.3.1", "tslib": "^2.5.0" @@ -9390,54 +12291,17 @@ "url": "https://opencollective.com/unts" } }, - "node_modules/tailwindcss": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.2.tgz", - "integrity": "sha512-9jPkMiIBXvPc2KywkraqsUfbfj+dHDb+JPWtSJa9MLFdrPyazI7q6WX2sUrm7R9eVR7qqv3Pas7EvQFzxKnI6w==", - "dependencies": { - "@alloc/quick-lru": "^5.2.0", - "arg": "^5.0.2", - "chokidar": "^3.5.3", - "didyoumean": "^1.2.2", - "dlv": "^1.1.3", - "fast-glob": "^3.2.12", - "glob-parent": "^6.0.2", - "is-glob": "^4.0.3", - "jiti": "^1.18.2", - "lilconfig": "^2.1.0", - "micromatch": "^4.0.5", - "normalize-path": "^3.0.0", - "object-hash": "^3.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.4.23", - "postcss-import": "^15.1.0", - "postcss-js": "^4.0.1", - "postcss-load-config": "^4.0.1", - "postcss-nested": "^6.0.1", - "postcss-selector-parser": "^6.0.11", - "postcss-value-parser": "^4.2.0", - "resolve": "^1.22.2", - "sucrase": "^3.32.0" - }, - "bin": { - "tailwind": "lib/cli.js", - "tailwindcss": "lib/cli.js" - }, - "engines": { - "node": ">=14.0.0" - } + "node_modules/tabbable": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", + "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==", + "license": "MIT" }, - "node_modules/tailwindcss/node_modules/postcss-selector-parser": { - "version": "6.0.13", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", - "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } + "node_modules/tailwindcss": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.3.tgz", + "integrity": "sha512-2Q+rw9vy1WFXu5cIxlvsabCwhU2qUwodGq03ODhLJ0jW4ek5BUtoCsnLB0qG+m8AHgEsSJcJGDSDe06FXlP74g==", + "license": "MIT" }, "node_modules/tapable": { "version": "2.2.1", @@ -9514,31 +12378,14 @@ "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" - }, - "node_modules/thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dependencies": { - "any-promise": "^1.0.0" - } - }, - "node_modules/thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, - "engines": { - "node": ">=0.8" - } + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true }, "node_modules/titleize": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz", "integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==", + "dev": true, "engines": { "node": ">=12" }, @@ -9574,6 +12421,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -9630,10 +12478,18 @@ "nan": "^2.14.0" } }, - "node_modules/ts-interface-checker": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" + "node_modules/ts-api-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } }, "node_modules/ts-node": { "version": "10.9.1", @@ -9688,9 +12544,11 @@ "integrity": "sha512-nsZd8ZeNUzukXPlJmTBwUAuABDe/9qtVDelJeT/qW0ow3ZS3BsQJtNkan1802aM9Uf68/Y8ljw86Hu0h5IUW3w==" }, "node_modules/tsconfig-paths": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", - "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "license": "MIT", "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.2", @@ -9702,6 +12560,8 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "license": "MIT", "dependencies": { "minimist": "^1.2.0" }, @@ -9713,33 +12573,17 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/tslib": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz", - "integrity": "sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==" - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, - "node_modules/tsutils/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" }, "node_modules/tunnel-agent": { "version": "0.6.0", @@ -9766,6 +12610,8 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" }, @@ -9792,14 +12638,79 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/typed-array-length": { + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", - "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", + "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", + "call-bind": "^1.0.7", "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -9820,26 +12731,32 @@ } }, "node_modules/typescript": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", - "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=12.20" + "node": ">=14.17" } }, "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", + "call-bound": "^1.0.3", "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -9859,6 +12776,12 @@ "node": ">=18.17" } }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "license": "MIT" + }, "node_modules/universalify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", @@ -9876,6 +12799,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "dev": true, "engines": { "node": ">=8" } @@ -9913,6 +12837,8 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } @@ -10060,31 +12986,93 @@ } }, "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/which-collection": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "license": "MIT", "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/which-typed-array": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", - "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "dev": true, + "license": "MIT", "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.10" + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -10103,9 +13091,11 @@ } }, "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -10126,6 +13116,57 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/wrap-ansi/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", diff --git a/package.json b/package.json index 499ad46..5712efb 100644 --- a/package.json +++ b/package.json @@ -19,38 +19,58 @@ "perf_hooks": false }, "dependencies": { - "@tailwindcss/typography": "^0.5.9", + "@algolia/autocomplete-core": "^1.9.2", + "@headlessui/react": "^2.1.0", + "@markdoc/markdoc": "^0.4.0", + "@markdoc/next.js": "^0.3.4", + "@sindresorhus/slugify": "^2.1.0", + "@tailwindcss/postcss": "^4.1.2", + "@tailwindcss/typography": "^0.5.7", "@terminusdb/terminusdb-client": "^10.0.28", - "@types/node": "18.15.11", - "@types/react": "18.0.37", - "@types/react-dom": "18.0.11", + "@types/node": "^20.10.8", + "@types/react": "^18.2.47", + "@types/react-dom": "^18.2.18", + "@types/react-highlight-words": "^0.16.4", + "@types/swagger-ui-react": "^5.18.0", "axios": "^1.8.4", "cheerio": "^1.0.0", + "clsx": "^2.1.0", "dompurify": "^3.0.2", "eslint": "8.38.0", "eslint-config-next": "13.3.0", + "fast-glob": "^3.2.12", + "flexsearch": "^0.7.31", "flowbite": "^1.6.5", "fs-extra": "^11.3.0", - "next": "13.3.0", + "js-yaml": "^4.1.0", + "next": "^14.0.4", + "next-themes": "^0.2.1", + "prism-react-renderer": "^2.0.6", "prismjs": "^1.29.0", "probe-image-size": "^7.2.3", "puppeteer": "^24.4.0", - "react": "18.2.0", - "react-dom": "18.2.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-highlight-words": "^0.20.0", "showdown": "^2.1.0", - "swagger-ui-react": "^4.19.0", + "simple-functional-loader": "^1.2.1", + "swagger-ui-react": "^5.20.6", + "tailwindcss": "^4.1.2", "turndown": "^7.2.0", - "typescript": "5.0.4" + "typescript": "^5.3.3", + "usehooks-ts": "^3.1.1" }, "devDependencies": { "@types/fs-extra": "^11.0.4", "@types/prismjs": "^1.26.0", "autoprefixer": "^10.4.14", "dotenv": "^16.1.4", + "eslint": "^8.56.0", + "eslint-config-next": "^14.0.4", "next-sitemap": "^4.1.3", "postcss": "^8.4.24", - "prettier": "^2.8.8", - "prettier-plugin-tailwindcss": "^0.3.0", - "tailwindcss": "^3.3.2" + "prettier": "^3.3.2", + "prettier-plugin-tailwindcss": "^0.6.11", + "sharp": "0.33.1" } } diff --git a/postcss.config.js b/postcss.config.js index 33ad091..52b9b4b 100644 --- a/postcss.config.js +++ b/postcss.config.js @@ -1,6 +1,5 @@ module.exports = { plugins: { - tailwindcss: {}, - autoprefixer: {}, + '@tailwindcss/postcss': {}, }, } diff --git a/prettier.config.js b/prettier.config.js new file mode 100644 index 0000000..910f5a8 --- /dev/null +++ b/prettier.config.js @@ -0,0 +1,7 @@ +/** @type {import('prettier').Options} */ +module.exports = { + singleQuote: true, + semi: false, + plugins: ['prettier-plugin-tailwindcss'], + tailwindStylesheet: './src/styles/tailwind.css', +} diff --git a/schema/all_documents.json b/schema/all_documents.json index d66a135..e657f10 100644 --- a/schema/all_documents.json +++ b/schema/all_documents.json @@ -762,5 +762,2902 @@ "description": "A guide to show how to connect to TerminusDB and TerminusCMS using the JavaScript Client", "og_image": "https://github.com/terminusdb/terminusdb-web-assets/blob/master/docs/js-client-use-connect-with-js-client.png?raw=true" } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Create a Database" + }, + "slug": "create-a-database", + "body": { + "@type": "Body", + "value": "To create a database with an already [connected client](/docs/connect-with-the-javascript-client/), you can write:\n\n```javascript\nconst createNewDB = async () => {\n try {\n​\n await client.createDatabase('ExampleDatabase', {\n label: \"ExampleDatabase\",\n comment: \"Created new ExampleDatabase\",\n schema: true\n });\n​\n console.log(\"Database created Successfully!\")\n​\n } catch (err) {\n console.error(err)\n }\n};\n​\n```\n\nAfter the database is created the client will be connected to it.\n\n> Try out the [Getting Started with the TerminusDB JavaScript Client](https://github.com/terminusdb/terminusdb-tutorials/blob/main/getting_started/javascript-client/lesson_1.md) five-part tutorial to get to grips with it." + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Create a Database using the JavaScript Client", + "description": "A guide to show how to create a database using the TerminusDB JavaScript Client.", + "og_image": "https://github.com/terminusdb/terminusdb-web-assets/blob/master/docs/js-client-use-create-a-db.png?raw=true" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Connect to a Database" + }, + "slug": "connect-to-a-database", + "body": { + "@type": "Body", + "value": "Assuming you have [connected with the JavaScript Client](/docs/connect-with-the-javascript-client/), connecting to a database is the same for TerminusDB and TerminusCMS -\n\nThe example code below registers your database in woqlClient parameters and then all your calls will be made to this db -\n\n```\nclient.db('ExampleDatabase')\nclient.getSchema().then(result=>{\n console.log(result)\n})\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Connect to a Database using the JavaScript Client", + "description": "A guide to show how to connect to an existing database using the TerminusDB JavaScript Client.", + "og_image": "https://github.com/terminusdb/terminusdb-web-assets/blob/master/docs/js-client-use-connect.png?raw=true" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Add a Schema" + }, + "slug": "add-a-schema", + "body": { + "@type": "Body", + "value": "After you have imported the terminusdb\\_client, [created a client](/docs/connect-with-the-javascript-client/), and [connected to a database](/docs/connect-to-a-database/) you can create a schema.\n\n## Create a schema\n\nYou can create a JSON schema, in this example, we'll create a schema with one object called Player with two properties name and position with the name forming the lexical key:\n\n```javascript\nconst schema = { \"@type\" : \"Class\",\n \"@id\" : \"Player\",\n \"@key\" : { \"@type\": \"Lexical\", \"@fields\": [\"name\"] },\n name : \"xsd:string\",\n position: \"xsd:string\" };\n```\n\n## Add the schema\n\nAdd the schema object with:\n\n```javascript\nconst addSchema = async () => {\n const result = await client.addDocument(schema, { graph_type: \"schema\" });\n console.log(\"the schema has been created\", result)\n}\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Add a Schema using the JavaScript Client", + "description": "A guide to show how to add a schema to TerminusDB and TerminusCMS using the TerminusDB JavaScript Client.", + "og_image": "https://github.com/terminusdb/terminusdb-web-assets/blob/master/docs/js-client-use-add-a-schema.png?raw=true" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Add Documents" + }, + "slug": "add-a-document", + "body": { + "@type": "Body", + "value": "After you have imported the terminusdb\\_client, [created a client](/docs/connect-with-the-javascript-client/), [connected to a database](/docs/connect-to-a-database/), and [added a schema](/docs/add-a-schema/), you can then use this client to insert a document that conforms to the schema.\n\n## Insert documents\n\nAdd documents to the schema using addDocument:\n\n```javascript\nconst objects = [\n {\n \"@type\" : \"Player\",\n name : \"George\",\n position: \"Center Back\",\n },\n {\n \"@type\" : \"Player\",\n name : \"Doug\",\n position: \"Full Back\",\n },\n { \n \"@type\" : \"Player\", \n name : \"Karen\", \n position: \"Center Forward\" \n }\n];\n\nconst addDocs = async () => {\n const result = await client.addDocument(objects);\n console.log(\"the documents have been added\", result)\n}\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Add Documents using the JavaScript Client", + "description": "A guide to show how to add documents to TerminusDB and TerminusCMS using the JavaScript Client.", + "og_image": "https://github.com/terminusdb/terminusdb-web-assets/blob/master/docs/js-client-use-add-documents.png?raw=true" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Edit a Document with the JavaScript Client" + }, + "slug": "edit-a-document", + "body": { + "@type": "Body", + "value": "To update documents in your database, you first need to [get the document](/docs/get-documents/) you want to change. You then need to make your changes and update it. This example shows how -\n\n```javascript\nconst docs = {\n '@id' : 'Player/George',\n '@type' : 'Player',\n name : 'George',\n position: 'Center Back' \n }\n\ndocs.position = \"Full Back\"\n\nconst updateDocs = async () => {\n const result = await client.updateDocument(docs);\n console.log(\"updated document\", result)\n}\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Edit a Document using the JavaScript Client", + "description": "A guide to show how to update a document in TerminusDB and TerminusCMS using the JavaScript Client.", + "og_image": "https://github.com/terminusdb/terminusdb-web-assets/blob/master/docs/js-client-use-edit-a-document.png?raw=true" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Delete a Document" + }, + "slug": "delete-a-document", + "body": { + "@type": "Body", + "value": "In order to delete a document you need to know the document id.\n\n```javascript\nconst deleteDoc = async () => {\n const docId = \"Player/George\"\n await client.deleteDoc({id:docId});\n console.log(`the ${docId} has been deleted`)\n}\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Delete a Document using the JavaScript Client", + "description": "A guide to show how to delete a document in TerminusDB and TerminusCMS using the JavaScript Client.", + "og_image": "https://github.com/terminusdb/terminusdb-web-assets/blob/master/docs/js-client-use-delete-a-document.png?raw=true" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Get Documents" + }, + "slug": "get-documents", + "body": { + "@type": "Body", + "value": "## Get a single document\n\nTo get a single document to make changes or simply to view it, use the following code -\n\n```javascript\nconst getDoc = async () => {\n const doc = await client.getDocument({id:\"Player/Doug\"});\n console.log(\"Player/Doug\", doc)\n}\n```\n\n```\n {\n '@id' : 'Player/Doug',\n '@type' : 'Player',\n name : 'Doug',\n position: 'Full Back'\n }\n```\n\n## Get a list of all documents\n\nGet a list of all documents in the database using getDocument as\\_list. The results are shown further below.\n\n```javascript\nconst getDocs = async () => {\n const documents = await client.getDocument({ as_list: \"true\" });\n console.log(\"All Documents\", documents)\n}\n```\n\n```\n[\n {\n '@id' : 'Player/Doug',\n '@type' : 'Player',\n name : 'Doug',\n position: 'Full Back'\n },\n {\n '@id' : 'Player/George',\n '@type' : 'Player',\n name : 'George',\n position: 'Center Back'\n },\n {\n '@id' : 'Player/Karen',\n '@type' : 'Player',\n name : 'Karen',\n position: 'Center Forward'\n }\n]\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Get Documents using the JavaScript Client", + "description": "A guide to show how to get documents to TerminusDB and TerminusCMS using the JavaScript Client", + "og_image": "https://github.com/terminusdb/terminusdb-web-assets/blob/master/docs/js-client-use-get-documents.png?raw=true" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Query Documents" + }, + "slug": "query-documents", + "body": { + "@type": "Body", + "value": "Get a list of documents matching a query. For more advanced queries, take a look at the GraphQL and WOQL how-to guides.\n\n```javascript\nconst queryDocuments = async () => {\n\n const queryTemplate = { \"position\": \"Full Back\" }\n\n const result = await client.getDocument({\"@type\":\"Player\",\"as_list\":true,\"query\":queryTemplate});\n console.log(\"Query Documents\",result)\n}\n```\n\n```\n[{\"@type\" : \"Player\",\n \"name\" : \"Doug\",\n \"position\" : \"Full Back\"}]\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Query Documents using the JavaScript Client", + "description": "A guide to show how to perform basic document queries using the JavaScript Client.", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Run a WOQL Query" + }, + "slug": "run-woql-query", + "body": { + "@type": "Body", + "value": "Assuming you have [connected with the JavaScript Client](/docs/connect-with-the-javascript-client/), have a database, added a schema and some data, you now would like to query the database.\n\nThe example code below shows a simple query that returns all of the database's triples\n\n```javascript\n const runQuery = async () => {\n const WOQL = Terminusdb.WOQL\n const v = WOQL.Vars(\"subject\",\"predicate\",\"object\")\n const query = Terminusdb.WOQL.triple(v.subject,v.predicate,v.object)\n const result = await client.query(query)\n\n console.log(\"my query result\", JSON.stringyfy(result,null,4))\n } \n```\n\nFor more information and examples about querying with WOQL please see the \\[/woql-basics)" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Run a WOQL Query using the JavaScript Client", + "description": "A quick example to show you how to run a query using WOQL.", + "og_image": "https://github.com/terminusdb/terminusdb-web-assets/blob/master/docs/js-client-use-woql-query.png?raw=true" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "How to Use the Python Client" + }, + "slug": "use-the-python-client", + "body": { + "@type": "Body", + "value": "[Install Python Client](/docs/install-the-python-client/)[Connect with Python Client](/docs/connect-with-python-client/)[Create DB with Python](/docs/create-database-with-python-client/)[Connect to DB with Python](/docs/connect-to-a-database-with-python-client/)[Add Docs with Python](/docs/add-documents-with-python-client/)[Add Schema with Python](/docs/add-a-schema-with-the-python-client/)[Edit Docs with Python](/docs/edit-documents-with-python-client/)[Get Docs with Python](/docs/get-documents-with-python-client/)[Delete Docs with Python](/docs/delete-documents-with-python-client/)[Import Data with Python](/docs/import-data-with-python-client/)[WOQL Query with Python](/docs/woql-query-with-python-client/)" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "How to Use the Python Client", + "description": "Bite sized how to guides to help you get started with the Python Client", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Install the TerminusCMS & DB Python Client" + }, + "slug": "install-the-python-client", + "body": { + "@type": "Body", + "value": "It is recommended that you install the TerminusDB Python client (which works with [Python >= 3.7](https://www.python.org/downloads)) in a [separate Python environment](https://docs.python.org/3/tutorial/venv.html). For example, if we use `venv` which comes with standard installation of Python 3.\n\nFirst we create a new environment:\n\n```\n$ python3 -m venv ~/.virtualenvs/terminusdb\n$ source ~/.virtualenvs/terminusdb/bin/activate\n```\n\nThen we can install using pip:\n\n```\n$ python3 -m pip install terminusdb-client\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Install the TerminusCMS & DB Python Client", + "description": "A guide showing how to install the TerminusCMS/DB Python Client.", + "og_image": "https://assets.terminusdb.com/docs/python-client-use-install-python-client.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "How to Connect with the Python Client" + }, + "slug": "connect-with-python-client", + "body": { + "@type": "Body", + "value": "First, you should install the Python client. For installation instructions, see [the Python install instructions](/docs/install-the-python-client/).\n\n## Connecting with the Python Client\n\nDepending on whether you are connecting to an instance you have set up yourself, or whether you are using TerminusCMS in the cloud, there are two different methods of connection.\n\nIn both cases, you should load TerminusDB in your script with the following:\n\n```python\nfrom terminusdb_client import Client\n```\n\n### TerminusCMS\n\nThe TerminusCMS endpoint has the form `https://cloud.terminusdb.com/TEAM/` where `TEAM` is the name of the team you are using in TerminusCMS for the data products you want to access.\n\nIn order to connect to this team, you will need to [get your API key](/docs/how-to-connect-terminuscms/) after selecting the team you want to use.\n\nYou should put your access token in your environment, using the environment variable `TERMINUSDB_ACCESS_TOKEN`. This ensures that scripts do not leak the access token when checked into source control.\n\n```\nexport TERMINUSDB_ACCESS_TOKEN=\"...\"\n```\n\nAt this point, you can connect with the API key using the code:\n\n```\nteam=\"MyTeam\"\nclient.connect(team=team, use_token=True)\n```\n\n### Connecting to a TerminusDB installation\n\nWhether you are connecting to a local docker, a local server, or on a server that you've set up somewhere, you can use the following to log in to TerminusDB.\n\n```\nteam=\"MyTeam\",\nclient = Client(\"http://localhost:6363/\")\nclient.connect(team=team, password=\"MyPassword\")\n```\n\nIf you are using TerminusDB locally, and you have not set up a specific team, or changed the password differently from the default, you can simply connect with:\n\n```\nteam=\"admin\",\nclient = Client(\"http://localhost:6363/\")\nclient.connect(team=team)\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "How to Connect with the Python Client", + "description": "A guide to show how to connect with the Python Client for TerminusDB and TerminusCMS.", + "og_image": "https://assets.terminusdb.com/docs/python-client-use-connect.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Create a Database with the Python Client" + }, + "slug": "create-database-with-python-client", + "body": { + "@type": "Body", + "value": "To create a database with an already [connected client](/docs/connect-with-python-client/), you can write:\n\n```\ndbid=\"MyDatabase\"\nlabel=\"My Database\",\ndescription=\"This is a database which is mine\"\nprefixes = {'@base' : 'iri:///mydatabase/',\n '@schema' : 'iri:///mydatabase#'}\nteam=\"MyTeam\"\nclient.create_database(\n dbid,\n team,\n label=label,\n description=description,\n prefixes=prefixes)\n```\n\nThis creates a new database called `\"MyDatabase\"` using the descriptive label `\"My Database\"`. It starts the database with special `@base` and `@schema` prefixes, all in the team named `\"MyTeam\"`" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Create a Database with the Python Client", + "description": "A guide showing how to create a TerminusDB or TerminusCMS database using the Python Client.", + "og_image": "https://assets.terminusdb.com/docs/python-client-use-create-a-db.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Connect to a Database using the Python Client" + }, + "slug": "connect-to-a-database-with-python-client", + "body": { + "@type": "Body", + "value": "## TerminusCMS\n\nIf you have created a Team in TerminusCMS, and put an [API key](/docs/how-to-connect-terminuscms/) in your environment you can connect to an existing database in the following way:\n\n```\nteam = \"MyTeam\",\nclient.connect(db=\"nuclear\", team=team, use_token=True)\n```\n\n## TerminusDB\n\nYou can connect to a database with basic authorization just by using the `connect` member function.\n\n```\nteam = \"MyTeam\",\nclient.connect(db=\"nuclear\")\n```\n\nIf you want to connect as a specific user and with a specific password, you can pass them here:\n\n```\nteam = \"MyTeam\",\nclient.connect(db=\"nuclear\", team=team, key=\"your_password\")\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Connect to a Database using the Python Client", + "description": "A guide to show how to connect to a TerminusCMS project using the Python client.", + "og_image": "https://assets.terminusdb.com/docs/python-client-use-connect-database.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Add Documents with the Python Client" + }, + "slug": "add-documents-with-python-client", + "body": { + "@type": "Body", + "value": "After you have imported the `terminusdb_client`, and [created a client](/docs/connect-with-python-client/), [connected to a database](/docs/connect-with-python-client/), and [added a schema](/docs/add-a-schema-with-the-python-client/), you can then use this client to insert a document that conforms to the schema.\n\n## Insert a document\n\nTo insert a document, you should use `insert_document`:\n\n```\ndocument = { '@type' : 'Person', 'name' : \"Jim\" }\nresults = client.insert_document(document)\n```\n\n## Insert multiple documents\n\nTo insert multiple documents you can also invoke `insert_document`:\n\n```\ndocuments = [{ '@type' : 'Person', 'name' : \"Jim\" },\n { '@type' : 'Person', 'name' : \"Jill\" }]\nresults = client.insert_document(document)\n```\n\n## Insert schema document(s)\n\nAdditionally, you can update the schema itself by adding schema documents:\n\n```\nschema = { '@type' : 'Class', '@id' : 'Person', 'name' : 'xsd:string'}\nresults = client.insert_document(schema,graph_type=\"schema\")\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "How To Add Documents with the Python Client", + "description": "A guide to show how to add documents to your TerminusCMS projects using the Python Client.", + "og_image": "https://assets.terminusdb.com/docs/python-client-use-add-documents.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Add a schema to TerminusCMS with the Python Client" + }, + "slug": "add-a-schema-with-the-python-client", + "body": { + "@type": "Body", + "value": "After you have imported the `terminusdb_client`, and [created a client](/docs/create-database-with-python-client/), and [connected to a database](/docs/connect-to-a-database-with-python-client/) you can create a schema.\n\n## Insert schema document(s)\n\nYou can update the schema by adding well-formed JSON schema documents:\n\n```\nschema = [{ '@type' : 'Class', '@id' : 'Country'},\n { '@type' : 'Class', '@id' : 'Person',\n 'name' : 'xsd:string',\n 'nationality' : 'Country'\n }]\nresults = client.insert_document(schema,graph_type=\"schema\")\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Add a schema to TerminusCMS with the Python Client", + "description": "A guide to show how to add a schema to TerminusCMS projects with the Python Client.", + "og_image": "https://assets.terminusdb.com/docs/python-client-use-add-a-schema.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Edit a Document with the Python Client" + }, + "slug": "edit-documents-with-python-client", + "body": { + "@type": "Body", + "value": "To update a document in your database, you first need to [get the document](/docs/get-documents-with-python-client/) you want to change. You then need to make your changes and update them. This example shows how -\n\n```\ndoc = {\n '@id' : 'Player/George',\n '@type' : 'Player',\n 'name' : 'George',\n 'position': 'Center Back'\n }\ndoc[\"position\"] = \"Full Back\"\nclient.update_document(doc)\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Edit a Document with the Python Client", + "description": "A guide to show how to update a document in TerminusDB and TerminusCMS using the Python Client", + "og_image": "https://assets.terminusdb.com/docs/python-client-use-edit-a-document.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Get Documents with the Python Client" + }, + "slug": "get-documents-with-python-client", + "body": { + "@type": "Body", + "value": "This guide assumes that you are already connected to the database using the Python client.\n\n## Get a single document\n\nTo get a single document to make changes or simply to view it, use the following code:\n\n```\ndocument = client.get_document(\"Player/Doug\")\n```\n\n```\n {\n '@id' : 'Player/Doug',\n '@type' : 'Player',\n name : 'Doug',\n position: 'Full Back'\n }\n```\n\n## Get a list of all documents\n\nTo get a list of all documents in the database, you can use the `get_all_documents` function.\n\n```\ndocuments = client.get_all_documents()\n```\n\n```\n[\n {\n '@id' : 'Player/Doug',\n '@type' : 'Player',\n name : 'Doug',\n position: 'Full Back'\n },\n {\n '@id' : 'Player/George',\n '@type' : 'Player',\n name : 'George',\n position: 'Center Back'\n },\n {\n '@id' : 'Player/Karen',\n '@type' : 'Player',\n name : 'Karen',\n position: 'Center Forward'\n }\n]\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Get Documents with the Python Client", + "description": "A guide to show how-to get documents from TerminusDB and TerminusCMS using the Python Client", + "og_image": "https://assets.terminusdb.com/docs/python-client-use-get-documents.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Delete a Document with the Python Client" + }, + "slug": "delete-documents-with-python-client", + "body": { + "@type": "Body", + "value": "In order to delete a document you need to know the document id.\n\n```\ndoc_id = \"Player/George\"\nclient.delete_document(doc_id)\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "How to delete a document using the Python client", + "description": "A guide to show how to delete a document from TerminusCMS using the Python Client", + "og_image": "https://assets.terminusdb.com/docs/python-client-use-delete-a-document.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Import Data with the Python Client" + }, + "slug": "import-data-with-python-client", + "body": { + "@type": "Body", + "value": "This how-to assumes that you are already connected to a database and have a schema that matches the CSV you want to import.\n\n## Importing a CSV file\n\nYou can import CSV files easily by importing them into dictionaries using Python's built-in libraries. Those dictionary objects can be inserted into the database using the `insert_document` function.\n\n```python\nimport csv\nobjects = []\nwith open('test.csv', 'r') as f:\n csv_reader = csv.DictReader(f)\n objects = list(csv_reader)\nclient.insert_document(objects)\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Import Data with the Python Client", + "description": "A guide to show how to import CSV data into TerminusCMS & DB using the Python Client", + "og_image": "https://assets.terminusdb.com/docs/python-client-use-import-data.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Run a WOQL Query with the Python Client" + }, + "slug": "woql-query-with-python-client", + "body": { + "@type": "Body", + "value": "Assuming you have [installed the client](/docs/install-the-python-client/), [connected to a database](/docs/connect-to-a-database-with-python-client/), and [connected with a client](/docs/connect-with-python-client/), you can then query with WOQL.\n\n## WOQLQuery\n\nWriting WOQL queries in Python is fairly simple. We have a WOQLQuery class that can be used to construct WOQL Queries.\n\nA simple example, in which we get all the names of the people in the database:\n\n```python\nfrom terminusdb_client import WOQLQuery, WOQLClient\nquery = WOQLQuery().woql_and(\n WOQLQuery().triple('v:PersonId', 'rdf:type', '@schema:Person'),\n WOQLQuery().trople('v:PersonId', '@schema:name', 'v:Name')\n)\nresult = client.query(query)\n```\n\nFor more information about WOQL query, read our [WOQL query how-to guides](/docs/woql-basics/)." + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Run a WOQL Query with the Python Client", + "description": "This how-to guide provides an example of the WOQL query language using the Python client", + "og_image": "https://assets.terminusdb.com/docs/python-client-use-woql-query.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "How to Use the Collaboration Features" + }, + "slug": "use-the-collaboration-features", + "body": { + "@type": "Body", + "value": "[Collaboration with JS](/docs/collaboration-with-javascript-client/)[Collaboration with Python](/docs/collaboration-with-python-client/)[Collaboration Dashboard](/docs/collaboration-with-terminuscms-dashboard/)" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "How to Use the Collaboration Features", + "description": "How to guides for using TerminusCMS & TerminusDB's collaboration features using the clients and dashboard.", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Collaboration Features with the JavaScript Client" + }, + "slug": "collaboration-with-javascript-client", + "body": { + "@type": "Body", + "value": "[Clone with JS](/docs/clone-a-project/)[Branch with JS](/docs/branch-a-project/)[Reset with JS](/docs/reset-a-project/)[Squash with JS](/docs/squash-projects/)[Time Travel with JS](/docs/time-travel-to-previous-commits/)[Diff & Patch with JS](/docs/diff-and-patch-operations/)" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Collaboration Features with the JavaScript Client", + "description": "How to guides to help you use TerminusCMS and TerminusDB's collaboration features using the JavaScript Client", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Cloning a Database" + }, + "slug": "clone-a-project", + "body": { + "@type": "Body", + "value": "## Clone a database from terminusdb.com to your local machine\n\nAssuming you have [connected with the JavaScript Client](/docs/connect-with-the-javascript-client/) you can clone your database.\n\nCloning a database pulls down a full copy of all data at that point in time, including all document and schema versions.\n\nIf the database that you are cloning is not public, you need to provide an APIKey to the client setting the remoteAuth For more info visit the ['How to get your API key'](/docs/how-to-connect-terminuscms/) page.\n\n```python\nconst cloneLocally = async () => {\n client.remoteAuth( {\"type\":\"apikey\" , \"key\":myApiKey})\n const cloneDetails = {remote_url: \"http://cloud.terminusdb.com/MyTeam/MyTeam/mydb\", \n label \"Cloned DB\",\n comment: \"Cloned from mydb\"}\n await client.clonedb(cloneDetails, \"new_mydb\")\n\n console.log(\"the database has been cloned\")\n}\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Cloning a Database", + "description": "A guide to show how to clone a database with the JS WOQLClient.", + "og_image": "https://github.com/terminusdb/terminusdb-web-assets/blob/master/docs/js-client-collaboration-clone.png?raw=true" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Branch a Project using the TerminusDB JS Client" + }, + "slug": "branch-a-project", + "body": { + "@type": "Body", + "value": "Assuming you have [connected with the JavaScript Client](/docs/connect-with-the-javascript-client/) and [created a database](/docs/create-a-database/) you can then create a branch of your project.\n\nCreating a branch is the same for TerminusDB and TerminusCMS. By default, in TerminusDB or TerminusCMS you are working in the main branch.\n\n## Create a new branch from main branch\n\nUse this code to create a new branch starting from the main branch head.\n\n```javascript\nconst createBranch = async () => {\n await client.branch(\"mybranch\");\n client.checkout(\"mybranch\")\n} \n```\n\n## Create a new branch from mybranch branch\n\nNow you are in the branch called `mybranch`.\n\nYou can create a new branch starting from the `mybranch` head\n\n```javascript\nconst createBranchFromMyBranch = async () => {\n await client.branch(\"branch_from_mybranch\",\"mybranch\");\n client.checkout(\"branch_from_mybranch\")\n} \n```\n\n## Get a branch list\n\nGet all of the database's branches in a list using a \\[WOQL\\]() library method\n\n```javascript\nconst getBranchList = async () => {\n const branchList = await TerminusClient.WOQL.lib().branches()\n console.log(\"ExampleDatabase branch list\", JSON.stringify(branchList.bindings,null,4))\n\n} \n```\n\nResponse example\n\n```\n[\n {\n \"Branch\":\"terminusdb://ref/data/Branch/main\",\n \"Head\":\"terminusdb://ref/data/InitialCommit/ohj33rrh5kmnmr9cq6vzfajfxog0629\",\n \"Name\":{\n \"@type\":\"xsd:string\",\n \"@value\":\"main\"\n },\n \"Timestamp\":{\n \"@type\":\"xsd:decimal\",\n \"@value\":1678385706.694406\n },\n \"commit_identifier\":{\n \"@type\":\"xsd:string\",\n \"@value\":\"ohj33rrh5kmnmr9cq6vzfajfxog0629\"\n }\n },\n {\n \"Branch\":\"terminusdb://ref/data/Branch/mybranch\",\n \"Head\":\"terminusdb://ref/data/ValidCommit/prh0yvftqmsrgctn8gqvdxv7gc4i8p8\",\n \"Name\":{\n \"@type\":\"xsd:string\",\n \"@value\":\"mybranch\"\n },\n \"Timestamp\":{\n \"@type\":\"xsd:decimal\",\n \"@value\":1678385762.7790234\n },\n \"commit_identifier\":{\n \"@type\":\"xsd:string\",\n \"@value\":\"prh0yvftqmsrgctn8gqvdxv7gc4i8p8\"\n }\n },\n {\n \"Branch\":\"terminusdb://ref/data/Branch/branch_from_mybranch\",\n \"Head\":\"terminusdb://ref/data/ValidCommit/prh0yvftqmsrgctn8gqvdxv7gc4i8p8\",\n \"Name\":{\n \"@type\":\"xsd:string\",\n \"@value\":\"branch_from_mybranch\"\n },\n \"Timestamp\":{\n \"@type\":\"xsd:decimal\",\n \"@value\":1678385762.7790234\n },\n \"commit_identifier\":{\n \"@type\":\"xsd:string\",\n \"@value\":\"prh0yvftqmsrgctn8gqvdxv7gc4i8p8\"\n }\n }\n ]\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Branch a Project using the JavaScript Client", + "description": "A guide to show how to create a new branch in TerminusDB and TerminusCMS using the JavaScript Client.", + "og_image": "https://github.com/terminusdb/terminusdb-web-assets/blob/master/docs/JS-client-collaboration-branch.png?raw=true" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Reset the Branch Head to a Specific Commit" + }, + "slug": "reset-a-project", + "body": { + "@type": "Body", + "value": "Assuming you have created a database, and made a few commits, you [can time travel](/docs/time-travel-to-previous-commits/) to inspect them.\n\nYou may want to reset the branch to a specific commit. You will need your branch name and commit ID which can be obtained by time travelling.\n\nThe below code will rest your branch to a specific commit ID -\n\n```javascript\nconst resetBranch = async () => {\n await client.resetBracnh(mybranchName, mycommitid)\n console.log(\"Succesfully reset branch HEAD to mycommitid\")\n}\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Reset the Branch Head to a Specific Commit", + "description": "A guide to using the JS WOQLClient to reset a branch.", + "og_image": "https://github.com/terminusdb/terminusdb-web-assets/blob/master/docs/js-client-collaboration-reset.png?raw=true" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Squashing Commits with the TerminusDB JS Client" + }, + "slug": "squash-projects", + "body": { + "@type": "Body", + "value": "Squashing allows you to combine multiple commits in your branch's history into a single commit.\n\n```javascript\nconst squashBranch = async () => {\n const branchName = \"mybranch\" \n const commitMessage = \"merge all the commits\"\n await client.squashBranch(branchName,commitMessage);\n // get mybranch commits list \n const commits = await TerminusClient.WOQL.lib().commits(\"mybranch\");\n console.log(\"Show my commit after squash\", JSON.stringify(commits.bindings,null,4))\n}\n```\n\na response example\n\n```\n[\n {\n \"Author\":{\n \"@type\":\"xsd:string\",\n \"@value\":\"myuser@terminusdb.com\"\n },\n \"Commit ID\":{\n \"@type\":\"xsd:string\",\n \"@value\":\"vn7l94v4broiaz28346mdhwtgxvvy6p\"\n },\n \"Message\":{\n \"@type\":\"xsd:string\",\n \"@value\":\"merge all the commits\"\n },\n \"Parent ID\":null,\n \"Time\":{\n \"@type\":\"xsd:decimal\",\n \"@value\":1678402502.1979887\n }\n }\n ]\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "How to Squash Commits", + "description": "A guide to show how to use the JS Client to squash commits in your branch's history.", + "og_image": "https://assets.terminusdb.com/docs/js-client-collaboration-squash.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Time Travel through your Database History" + }, + "slug": "time-travel-to-previous-commits", + "body": { + "@type": "Body", + "value": "Assuming you have [connected with the JavaScript Client](/docs/connect-with-the-javascript-client/), created a database, and made a few commits, you can time travel to inspect them to see what they looked like.\n\n## Get the branch commits list\n\nYou can use the JS WOQL Client Library method to get a list of branch commits. This example uses pagination to get the last 10 commits starting from the branch head -\n\n```javascript\nconst getCommits= async () => {\n const commits = await TerminusClient.WOQL.lib().commits(\"mybranch\", 10 ,0);\n console.log(\"Show the last 10 commits\", JSON.stringify(commits.bindings,null,4))\n}\n```\n\n## Get the branch commits list starting with a specific timestamp\n\nYou can also get a list of commits from a specific timestamp. The timestamp can be obtained from the log -\n\n```javascript\nconst getCommitsByTime= async () => {\n const commits = await TerminusClient.WOQL.lib().commits(\"mybranch\", 10 ,0, 1678385999.7790234);\n console.log(\"Show the last 10 commits before the timestamp\", JSON.stringify(commits.bindings,null,4))\n}\n```\n\na response example\n\n```python\n[\n {\n \"Author\":{\n \"@type\":\"xsd:string\",\n \"@value\":\"myuser@terminusdb.com\"\n },\n \"Commit ID\":{\n \"@type\":\"xsd:string\",\n \"@value\":\"prh0yvftqmsrgctn8gqvdxv7gc4i8p8\"\n },\n \"Message\":{\n \"@type\":\"xsd:string\",\n \"@value\":\"Update from model builder\"\n },\n \"Parent ID\":\"terminusdb://ref/data/ValidCommit/onckvm1q9u98j5momtsfxia3optjkdi\",\n \"Time\":{\n \"@type\":\"xsd:decimal\",\n \"@value\":1678385762.7790234\n }\n },\n {\n \"Author\":{\n \"@type\":\"xsd:string\",\n \"@value\":\"myuser@terminusdb.com\"\n },\n \"Commit ID\":{\n \"@type\":\"xsd:string\",\n \"@value\":\"onckvm1q9u98j5momtsfxia3optjkdi\"\n },\n \"Message\":{\n \"@type\":\"xsd:string\",\n \"@value\":\"Update from model builder\"\n },\n \"Parent ID\":null,\n \"Time\":{\n \"@type\":\"xsd:decimal\",\n \"@value\":1678385749.9860663\n }\n }\n ]\n```\n\n## Time travel and point the client to a specific commit\n\nTo travel back in time to a particular commit, you need to specify the commit ID in the JS woqlClient parameters. To obtain the commit ID, refer to the code snippet above. All your calls after will be made for this commit.\n\n```javascript\nconst getDocumentsAtCommit= async () => {\n client.ref(\"onckvm1q9u98j5momtsfxia3optjkdi\")\n const docs = await client.getDocument({graph_type:\"schema\"})\n}\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Time Travel to a Specific Commit in your Database", + "description": "A guide showing how to time travel to a specific commit in TerminusCMS and TerminusDB", + "og_image": "https://assets.terminusdb.com/docs/js-client-collaboration-time-travel.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Diff and Path with JavaScript" + }, + "slug": "diff-and-patch-operations", + "body": { + "@type": "Body", + "value": "## Diff an object\n\nReturn the diff from two objects\n\n```javascript\nconst diffObjects = async () => {\n const before = { \"@id\" : \"Person/Jane\", \"@type\" : \"Person\", \"name\" : \"Jane\"}\n const after = { \"@id\" : \"Person/Jane\", \"@type\" : \"Person\", \"name\" : \"Janine\"}\n const options = {keep:{ \"@id\" : true, \"name\" : true }}\n\n //in the options you can list the properties that you would like to see in the diff result.\n const diffResult = await client.getJSONDiff = function (before, after, options) {\n\n console.log(\"the diff result \", JSON.stringify(diffResult,null,4))\n}\n```\n\nHere is an example of a diff result between two objects\n\n```\n{\n \"name\":{\n \"@op\":\"ValueSwap\",\n \"@before\":\"Jane\",\n \"@after\":\"Janine\"\n },\n \"@id\":\"Person/Jane\"\n}\n```\n\n## Get the patch of differences between branches or commits.\n\n```javascript\nconst diffDocsVersion = async () => {\n const beforeVersion = \"a73ssscfx0kke7z76083cgswszdxy6l\"\n const afterVersion = \"73rqpooz65kbsheuno5dsayh71x7wf4\"\n const options = {keep:{ \"@id\" : true, \"name\" : true }}\n\n const diffResult = await client.getVersionDiff = function (beforeVersion, afterVersion, null, options) {\n\n console.log(\"the diff result \", JSON.stringify(diffResult,null,4))\n}\n```\n\nHere is the example result\n\n```\n[\n {\n \"@id\":\"Person/Jane\",\n \"@type\":\"Person\",\n \"name\" : \"Jane\"\n \"age\":{\n \"@after\":23,\n \"@before\":22,\n \"@op\":\"SwapValue\"\n }\n },\n {\n \"@id\":\"Person/Tom\",\n \"@type\":\"Person\",\n \"name\" : \"Tom\"\n \"age\":{\n \"@after\":10,\n \"@before\":null,\n \"@op\":\"SwapValue\"\n }\n }\n]\n```\n\n## Get the patch of difference between a document and an object.\n\n```javascript\nconst diffDocToObject = async () => {\n const jsonObject = { \"@id\" : \"Person/Jane\", \"@type\" : \"Person\", \"name\" : \"Jannet\"}\n const options = {keep:{ \"@id\" : true, \"name\" : true }}\n\n //in the options you can list the properties that you would like to see in the diff result.\n const diffResult = await client.getVersionObjectDiff = function (\"main\", jsonObject, \"Person/Jane\", options) {\n\n console.log(\"the diff result \", JSON.stringify(diffResult,null,4))\n}\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Diff an Object or a Database Branch with the JS Client", + "description": "A guide to show how to use the JS Client to diff an object or a database branch.", + "og_image": "https://github.com/terminusdb/terminusdb-web-assets/blob/master/docs/js-client-collaboration-diff-patch.png?raw=true" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Collaboration Features with the Python Client" + }, + "slug": "collaboration-with-python-client", + "body": { + "@type": "Body", + "value": "[Branch with Python](/docs/branch-a-project-with-the-python-client/)[Clone with Python](/docs/clone-a-database-with-python/)[Reset with Python](/docs/reset-to-a-commit-with-python/)[Squash with Python](/docs/squash-a-project-with-python/)[Time Travel with Python](/docs/time-travel-with-python/)" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Collaboration Features with the Python Client", + "description": "How to guides to help you get to grips with TerminusCMS and TerminusDB's collaboration features using the Python Client.", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Branch a Project Using the Python Client" + }, + "slug": "branch-a-project-with-the-python-client", + "body": { + "@type": "Body", + "value": "Assuming you have [connected with the Python Client](/docs/connect-with-python-client/) and [created a database](/docs/create-database-with-python-client/) you can then create a branch of your project.\n\nCreating a branch is the same for TerminusDB and TerminusCMS. By default, in TerminusDB or TerminusCMS you are working in the main branch.\n\n## Create a new branch from main branch\n\nUse this code to create a new branch starting from the main branch head.\n\n```\nclient.create_branch(\"mybranch\")\nclient.branch(\"mybranch\")\n```\n\nIf you add documents to the `mybranch`, they won't end up in the `main` branch unless you merge them.\n\n## Create a new branch from mybranch branch\n\nNow you are in the branch called `mybranch`.\n\nYou can create a new branch starting from the `mybranch` head. Since we are checked out on the \"mybranch\" already, we can just create a new branch from there. It will have `mybranch` as its parent.\n\n```\nclient.create_branch(\"branch_from_mybranch\")\nclient.branch(\"branch_from_mybranch\")\n```\n\n## Get a branch list\n\nGet all of the data product's branches in a list using a method\n\n```\nbranches = client.get_all_branches()\nprint(branches)\n```\n\nResponse example\n\n```\n[\n {\n \"Branch\":\"terminusdb://ref/data/Branch/main\",\n \"Head\":\"terminusdb://ref/data/InitialCommit/ohj33rrh5kmnmr9cq6vzfajfxog0629\",\n \"Name\":{\n \"@type\":\"xsd:string\",\n \"@value\":\"main\"\n },\n \"Timestamp\":{\n \"@type\":\"xsd:decimal\",\n \"@value\":1678385706.694406\n },\n \"commit_identifier\":{\n \"@type\":\"xsd:string\",\n \"@value\":\"ohj33rrh5kmnmr9cq6vzfajfxog0629\"\n }\n },\n {\n \"Branch\":\"terminusdb://ref/data/Branch/mybranch\",\n \"Head\":\"terminusdb://ref/data/ValidCommit/prh0yvftqmsrgctn8gqvdxv7gc4i8p8\",\n \"Name\":{\n \"@type\":\"xsd:string\",\n \"@value\":\"mybranch\"\n },\n \"Timestamp\":{\n \"@type\":\"xsd:decimal\",\n \"@value\":1678385762.7790234\n },\n \"commit_identifier\":{\n \"@type\":\"xsd:string\",\n \"@value\":\"prh0yvftqmsrgctn8gqvdxv7gc4i8p8\"\n }\n },\n {\n \"Branch\":\"terminusdb://ref/data/Branch/branch_from_mybranch\",\n \"Head\":\"terminusdb://ref/data/ValidCommit/prh0yvftqmsrgctn8gqvdxv7gc4i8p8\",\n \"Name\":{\n \"@type\":\"xsd:string\",\n \"@value\":\"branch_from_mybranch\"\n },\n \"Timestamp\":{\n \"@type\":\"xsd:decimal\",\n \"@value\":1678385762.7790234\n },\n \"commit_identifier\":{\n \"@type\":\"xsd:string\",\n \"@value\":\"prh0yvftqmsrgctn8gqvdxv7gc4i8p8\"\n }\n }\n ]\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Branch a Project Using the Python Client", + "description": "A guide to show how to branch a TerminusCMS project using the Python Client.", + "og_image": "https://assets.terminusdb.com/docs/python-client-collaboration-branch.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Cloning a Database with the Python Client" + }, + "slug": "clone-a-database-with-python", + "body": { + "@type": "Body", + "value": "> Before starting, you should create an account on TerminusCMS and get an API Token. You can read about this [here](/docs/how-to-connect-terminuscms/).\n\nThis how-to will show how to clone a public database from TerminusCMS into your own TerminusCMS team.\n\n## Running the Python client with the API Token\n\nBe sure to construct the Python client object first, and set the appropriate authentication token.\n\n```python\nfrom terminusdb_client import Client\nclient = Client('https://cloud.terminusdb.com/MyTeam')\nclient.connect(team='MyTeam', api_token='YOUR_API_TOKEN_HERE')\n```\n\n## Cloning the database\n\nCheck the TerminusCMS dashboard for a database that you want to clone. In this how-to, we will be using the Lego database as an example.\n\n```\nclone_url = 'https://cloud.terminusdb.com/MyTeam/Terminusdb_demo/lego'\nclient.clonedb(clone_url, 'my_lego', remote_auth={'type': 'token': 'key': 'YOUR_API_TOKEN_HERE'})\n```\n\nYou now have the my\\_lego database cloned in your TerminusCMS team.\n\nTo verify whether the database has been successfully cloned, you can run:\n\n```\nclient.get_database('my_lego')\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Cloning a Database with the Python Client", + "description": "A guide to show how to clone a database using the Python Client.", + "og_image": "https://assets.terminusdb.com/docs/python-client-collaboration-clone.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Reset to a Particular Commit with the Python Client" + }, + "slug": "reset-to-a-commit-with-python", + "body": { + "@type": "Body", + "value": "Assuming you have [connected with the Python Client](/docs/connect-with-python-client/), created a database, and made a few commits, you can reset the HEAD of a database to a particular commit. Just like you would do in `git` with `git reset`.\n\n## Get the commits list\n\nYou can use the Python Client Library method to get a list of branch commits. This example uses pagination to get the last commits starting from the branch head -\n\n```python\n//For TerminusCMS\nfrom terminusdb_client import Client\nclient = Client('https://cloud.terminusdb.com/MyTeam')\nclient.connect(team='MyTeam' db='your_db', api_token='YOUR_API_TOKEN_HERE')\ncommits = client.logs(count=10)\nprint(commits)\n// For TerminusDB\nfrom terminusdb_client import Client\nclient = Client('http://localhost:6363')\nclient.connect(key='root', user='root', team='root' db='your_db')\ncommits = client.logs(count=10)\nprint(commits)\n```\n\nA response example will be a list of objects like this:\n\n```\n{\n\"@id\":\"InitialCommit/hpl18q42dbnab4vzq8me4bg1xn8p2a0\",\n\"@type\":\"InitialCommit\",\n\"author\":\"system\",\n\"identifier\":\"hpl18q42dbnab4vzq8me4bg1xn8p2a0\",\n\"message\":\"create initial schema\",\n\"schema\":\"layer_data:Layer_4234adfe377fa9563a17ad764ac37f5dcb14de13668ea725ef0748248229a91b\",\n\"timestamp\":1660919664.9129035\n}\n```\n\n## Reset to a specific commit\n\nTo reset the HEAD of your database to a particular commit, you need to get the identifier of a particular commit. To obtain the identifier, refer to the code snippet above.\n\n```\nclient.reset(\"hpl18q42dbnab4vzq8me4bg1xn8p2a0\")\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Reset to a Particular Commit with the Python Client", + "description": "A guide to show how to reset your TerminusDB project, or project branch, to a specific commit using Python.", + "og_image": "https://assets.terminusdb.com/docs/python-client-collaboration-reset.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Squashing Commits with the TerminusDB Python Client" + }, + "slug": "squash-a-project-with-python", + "body": { + "@type": "Body", + "value": "Squashing allows you to combine multiple commits in your branch's history into a single commit. This how-to assumes that you [connected to a database already](/docs/connect-to-a-database-with-python-client/).\n\n```\n client.branch = \"mybranch\"\n commitMessage = \"merge all the commits\"\n result = client.squash(commitMessage);\n}\n```\n\nThe result will contain the new commit id. You can use it to reset the HEAD to the new squashed commit.\n\n```\nclient.reset(result)\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Squashing Commits with the Python Client", + "description": "A guide to show how to squash commits into one big commit using the TerminusDB & TerminusCMS Python Client.", + "og_image": "https://assets.terminusdb.com/docs/python-client-collaboration-squash.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Time Travel Through your Database History" + }, + "slug": "time-travel-with-python", + "body": { + "@type": "Body", + "value": "Assuming you have [connected with the Python Client](/docs/connect-with-python-client/), created a database, and made a few commits, you can time travel to inspect them to see what they looked like.\n\n## Get the commits list\n\nYou can use the Python WOQL Client Library method to get a list of branch commits. This example uses pagination to get the last 10 commits starting from the branch head -\n\n```python\n// For TerminusCMS\nfrom terminusdb_client import Client\nclient = Client('https://cloud.terminusdb.com/MyTeam')\nclient.connect(team='MyTeam' db='your_db', api_token='YOUR_API_TOKEN_HERE')\ncommits = client.logs(count=10)\nprint(commits)\n// For TerminusDB\nfrom terminusdb_client import Client\nclient = Client('http://localhost:6363')\nclient.connect(key='root', user='root', team='root' db='your_db')\ncommits = client.logs(count=10)\nprint(commits)\n```\n\nA response example will be a list of objects like this:\n\n```\n {\n \"@id\":\"InitialCommit/hpl18q42dbnab4vzq8me4bg1xn8p2a0\",\n \"@type\":\"InitialCommit\",\n \"author\":\"system\",\n \"identifier\":\"hpl18q42dbnab4vzq8me4bg1xn8p2a0\",\n \"message\":\"create initial schema\",\n \"schema\":\"layer_data:Layer_4234adfe377fa9563a17ad764ac37f5dcb14de13668ea725ef0748248229a91b\",\n \"timestamp\":1660919664.9129035\n }\n```\n\n## Time travel and point the client to a specific commit\n\nTo travel back in time to a particular commit, you need to specify the commit ID in the ref property. To obtain the commit ID, refer to the code snippet above. All your calls after will be made for this commit.\n\n```\nclient.ref = \"hpl18q42dbnab4vzq8me4bg1xn8p2a0\")\ndocs = client.get_all_documents()\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Time Travel Through your Database History", + "description": "A guide to show to time travel through your TerminusDB and TerminusCMS projects using the Python Client.", + "og_image": "https://assets.terminusdb.com/docs/python-client-collaboration-time-travel.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Collaboration Features with the TerminusCMS Dashboard" + }, + "slug": "collaboration-with-terminuscms-dashboard", + "body": { + "@type": "Body", + "value": "[Branch with Dashboard](/docs/branch/)[Clone with Dashboard](/docs/clone/)[Reset with Dashboard](/docs/reset/)[Squash with Dashboard](/docs/squash/)[Time Travel with Dashboard](/docs/time-travel/)" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Collaboration Features with the TerminusCMS Dashboard", + "description": "How to guides for leveraging collaboration features using TerminusCMS dashboard. ", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Branch a Project with the TerminusCMS Dashboard" + }, + "slug": "branch", + "body": { + "@type": "Body", + "value": "The TerminusCMS dashboard enables you to branch projects. To do this, choose the team and project you want to branch. You will be directed to the project home page. This is where you can branch it.\n\nScroll down to see the manage `branch` section.\n\n![Branch the project](https://assets.terminusdb.com/docs/branch-project.png)\n\nEach project can have one or more branches, the default is called main. Each branch contains a snapshot of the data as it was at the time of branching. This is useful for experimenting or providing data to other teams when you want to keep them away from main.\n\n## Create a new branch\n\nClick the `new branch` button.\n\n![Create a new project branch in TerminusCMS](https://assets.terminusdb.com/docs/branch-new.png)\n\nGive the branch and ID.\n\nYou then have two choices:\n\n1. Branch from the current head to include all of the data\n2. Create an empty branch\n\nClick `new branch` to create it.\n\nYou will then be switched to that branch.\n\n## Swap between branches\n\nFrom the manage branch section use the ellipsis symbol next to the branches to switch between branches and main.\n\n![Branch Options](https://assets.terminusdb.com/docs/branch-options.png)" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Branch a Project using the TerminusCMS Dashboard", + "description": "A guide to show how to branch projects using the TerminusCMS dashboard.", + "og_image": "https://assets.terminusdb.com/docs/branch-project.png" + }, + "media": [ + { + "@type": "Media", + "alt": "Branch the project", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "Branch the project" + }, + "value": "https://assets.terminusdb.com/docs/branch-project.png" + }, + { + "@type": "Media", + "alt": "Create a new project branch in TerminusCMS", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "Create a new project branch in TerminusCMS" + }, + "value": "https://assets.terminusdb.com/docs/branch-new.png" + }, + { + "@type": "Media", + "alt": "Branch Options", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "Branch Options" + }, + "value": "https://assets.terminusdb.com/docs/branch-options.png" + } + ] + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Clone a Project" + }, + "slug": "clone", + "body": { + "@type": "Body", + "value": "From the project home page, on the right you will see the `Clone Project` section.\n\n![Clone a project from the project home page](https://assets.terminusdb.com/docs/project-admin.png)\n\nYou can clone the project with -\n\n* The same name to another team - choose this from the dropdown menu\n* A different name to another team\n* A different name to the same team\n\nPress the `Clone` button.\n\nYou will be directed to the cloned project. If you clone to a different team, you will also move teams." + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Clone a Project using the TerminusCMS Dashboard", + "description": "A guide to show how to clone a project using the TerminusCMS dashboard.", + "og_image": "https://assets.terminusdb.com/docs/project-admin.png" + }, + "media": [ + { + "@type": "Media", + "alt": "Clone a project from the project home page", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "Clone a project from the project home page" + }, + "value": "https://assets.terminusdb.com/docs/project-admin.png" + } + ] + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Reset a Project with the TerminusCMS Dashboard" + }, + "slug": "reset", + "body": { + "@type": "Body", + "value": "To reset a branch of a database, or indeed main, navigate to the project home page, the first icon on the left that looks like a database.\n\nScroll down to the `Manage Branches` section and selected `Branches`.\n\nNext to the branch you want to reset, select the ellipses symbol to see the branch options.\n\n![Branch options with the ability to squash the branch of the database](https://assets.terminusdb.com/docs/branch-options.png)\n\nChoose the `Reset` button.\n\nChoose the commit you would like to reset to and copy the commit ID by selecting the clipboard icon. _You can inspect commits using the [time travel feature](/docs/time-travel/)._\n\nPaste the commit ID and press the `Reset Branch` button.\n\n![A squashed branch combines all commits into one big one](https://assets.terminusdb.com/docs/reset-a-branch.png)" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Reset a Project with the TerminusCMS Dashboard", + "description": "A guide to show how to reset to a particular commit of a branch or main using the TerminusCMS dashboard.", + "og_image": "https://github.com/terminusdb/terminusdb-web-assets/blob/master/docs/reset-a-branch.png?raw=true" + }, + "media": [ + { + "@type": "Media", + "alt": "Branch options with the ability to squash the branch of the database", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "Branch options with the ability to squash the branch of the database" + }, + "value": "https://assets.terminusdb.com/docs/branch-options.png" + }, + { + "@type": "Media", + "alt": "A squashed branch combines all commits into one big one", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "A squashed branch combines all commits into one big one" + }, + "value": "https://assets.terminusdb.com/docs/reset-a-branch.png" + } + ] + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Squash Commits with the TerminusCMS Dashboard" + }, + "slug": "squash", + "body": { + "@type": "Body", + "value": "To squash a branch of a database, or indeed main, navigate to the project home page, the first icon on the left that looks like a database.\n\nScroll down to the `Manage Branches` section and selected `Branches`.\n\nNext to the branch you want to squash, select the ellipses symbol to see the branch options.\n\n![Branch options with the ability to squash the branch of the database](https://assets.terminusdb.com/docs/branch-options.png)\n\nChoose the `Squash` button.\n\nGive the operation a description and press the `Squash Branch` button.\n\n![A squashed branch combines all commits into one big one](https://assets.terminusdb.com/docs/squashed-branch.png)\n\n> Be wary as squashing a project will result in the commit history being lost" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Squash Commits with the TerminusCMS Dashboard", + "description": "A guide to show how to squash the commits of a branch or main into one large commit using the TerminusCMS dashboard.", + "og_image": "https://github.com/terminusdb/terminusdb-web-assets/blob/master/docs/squashed-branch.png?raw=true" + }, + "media": [ + { + "@type": "Media", + "alt": "Branch options with the ability to squash the branch of the database", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "Branch options with the ability to squash the branch of the database" + }, + "value": "https://assets.terminusdb.com/docs/branch-options.png" + }, + { + "@type": "Media", + "alt": "A squashed branch combines all commits into one big one", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "A squashed branch combines all commits into one big one" + }, + "value": "https://assets.terminusdb.com/docs/squashed-branch.png" + } + ] + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Time Travel using the TerminusCMS Dashboard" + }, + "slug": "time-travel", + "body": { + "@type": "Body", + "value": "It is possible in the TerminusCMS dashboard to time travel to any previous commit to examine the data and schema. This is particularly useful if you want to see what something looked like at a particular date, or if something has broken and you want to see when the last stable state was so you can revert back to it.\n\nTime travel is each to do. From any screen when viewing a project (apart from the project home page), you will see a `stopwatch symbol` in the top bar.\n\nSelect this and a panel will appear from the right.\n\n![Time travel to any previous commit using the TerminusCMS dashboard](https://assets.terminusdb.com/docs/time-travel.png)\n\nEach commit in the list features the comments from the merged change request.\n\nTravel back in time by selecting the button next to the commit you want to go back to.\n\n![See what data used to look like in a previou commit](https://assets.terminusdb.com/docs/travel-back-in-time.png)\n\nThe dashboard informs you that you are not on the latest version.\n\nYou can then go an inspect the data in your project and the schema to see what's changed." + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Time Travel using the TerminusCMS Dashboard", + "description": "A guide to show how to time travel to any previous commit using the TerminusCMS dashboard.", + "og_image": "https://assets.terminusdb.com/docs/time-travel.png" + }, + "media": [ + { + "@type": "Media", + "alt": "Time travel to any previous commit using the TerminusCMS dashboard", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "Time travel to any previous commit using the TerminusCMS dashboard" + }, + "value": "https://assets.terminusdb.com/docs/time-travel.png" + }, + { + "@type": "Media", + "alt": "See what data used to look like in a previou commit", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "See what data used to look like in a previou commit" + }, + "value": "https://assets.terminusdb.com/docs/travel-back-in-time.png" + } + ] + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "How to Use VectorLink" + }, + "slug": "use-vectorlink", + "body": { + "@type": "Body", + "value": "[Add OpenAI Key](/docs/set-up-vectorlink/)[Configure Vector Embeddings](/docs/openai-handlebars-config/)[Index Your Data](/docs/index-your-data/)" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "How to use VectorLink", + "description": "A series of how-to guides to get you started with VectorLink, the semantic indexer", + "og_image": "https://assets.terminusdb.com/docs/vectorlink-semantic-cms.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Set up VectorLink" + }, + "slug": "set-up-vectorlink", + "body": { + "@type": "Body", + "value": "VectorLink is a semantic indexer for TerminusCMS. It is a vector database that uses OpenAI, vector embeddings and GraphQL to provide AI-assisted semantic search, similar search, clustering and entity resolution.\n\nTo use VectorLink you need an OpenAI API key. The OpenAI key applies to the team and all data products within that team.\n\n## Set OpenAI API Key\n\nTo set your OpenAI Key -\n\n1. Log in to the user interface dashboard - dashboard.terminusdb.com\n2. Select a Team\n3. Select your Profile by clicking on ▼ at the top-right corner of the screen.\n4. Paste your OpenAI API key and press save.\n5. Check that the checkbox is ticked to ensure the automatic document indexing will run after every change request approval process\n\n![Add your OpenAI key in the relevant section within your profile](https://assets.terminusdb.com/docs/vectorlink-openai-key.png)" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Set up VectorLink", + "description": "Steps to set up VectorLink to work with OpenAI", + "og_image": "https://assets.terminusdb.com/docs/vectorlink-semantic-cms.png" + }, + "media": [ + { + "@type": "Media", + "alt": "Add your OpenAI key in the relevant section within your profile", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "Add your OpenAI key in the relevant section within your profile" + }, + "value": "https://assets.terminusdb.com/docs/vectorlink-openai-key.png" + } + ] + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "OpenAI and Handlebars Configuration" + }, + "slug": "openai-handlebars-config", + "body": { + "@type": "Body", + "value": "To use VectorLink’s semantic search you first need to configure the Handlebars semantic templates to generate the vector embeddings in a word-based query format for OpenAI.\n\n![High quality text embeddings for OpenAI using GraphQL query with Handlebars templates](https://assets.terminusdb.com/docs/vectorlink-text-embeddings.png)\n\n## Quick Guide\n\nYou need to create a Handlebars embedding for each document class that you want to index.\n\nAssuming you have logged into TerminusCMS, selected a team and data product, do the following -\n\n1. Choose the OpenAI icon from the menu on the left\n2. Using the dropdown menu, select the document class you want to generate an embedding for.\n3. Check the GraphQL query - ensure that all properties that you want to include in your embedding are there.\n4. Write your Handlebars template and press preview.\n5. Check the preview pane to ensure the embedding is as it should be.\n6. When done, press save.\n7. Repeat the process for all the document classes you want indexing.\n\n## Choose your Document Class\n\nFrom the dropdown menu, choose the document class you want to index.\n\nThis generates the GraphQL query to include in the template. Check that all of the document properties you want to index are there. In some cases, it is more useful to choose a property label rather than an ID.\n\n## Write Handlebars Semantic Templates\n\n> If you clone the Star Wars data product from TerminusCMS, this comes with a working Handlebars template for you to copy.\n\nThis is currently a manual process. The templates are written in an easy-to-understand way.\n\nUsing the Star Wars data product example - that you can clone from the dashboard, this example shows the structure of a semantic template for the People class in Star Wars -\n\n```\n{\n \"embedding\": {\n \"query\": \"query($id: ID){ People(id : $id) { birth_year, created, desc, edited, eye_color, gender, hair_colors, height, homeworld { label }, label, mass, skin_colors, species { label }, url } }\",\n \"template\": \"The person's name is {{label}}.{{#if desc}} They are described with the following synopsis: {{#each desc}} *{{this}} {{/each}}.{{/if}}{{#if gender}} Their gender is {{gender}}.{{/if}}{{#if hair_colors}} They have the following hair colours: {{hair_colors}}.{{/if}}{{#if mass}} They have a mass of {{mass}}.{{/if}}{{#if skin_colors}} Their skin colours are {{skin_colors}}.{{/if}}{{#if species}} Their species is {{species.label}}.{{/if}}{{#if homeworld}} Their homeworld is {{homeworld.label}}.{{/if}}\"\n }\n}\n```\n\nThe query parameters use the document properties. This information is used in the template. Additional information is then added to give each property some context.\n\nNotice that a link document property can reference the linked document and its properties, for example -\n\n```\n{{homeworld.label}}\n```\n\nMore information about Handlebars can be found here - [Handlebars documentation](https://handlebarsjs.com/guide/).\n\n## Preview & Save Config\n\nPreview your template by pressing the Preview button on the right.\n\nAdjust your template if it needs it.\n\nPress save. The template will be saved for that document class.\n\nRepeat these steps for each class you want to be indexed." + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "How to configure high-quality text embeddings for OpenAI", + "description": "OpenAI and Handlebars Configuration", + "og_image": "https://assets.terminusdb.com/docs/vectorlink-semantic-cms.png" + }, + "media": [ + { + "@type": "Media", + "alt": "High quality text embeddings for OpenAI using GraphQL query with Handlebars templates", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "High quality text embeddings for OpenAI using GraphQL query with Handlebars templates" + }, + "value": "https://assets.terminusdb.com/docs/vectorlink-text-embeddings.png" + } + ] + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Index Your Data" + }, + "slug": "index-your-data", + "body": { + "@type": "Body", + "value": "Once you have configured OpenAI, you can index your data. Indexing happens on a commit level so to start indexing you need a new commit.\n\nTo do this, create and approve a change request. The indexing process will begin.\n\nYou can see the commit index history by clicking on the cog symbol on the left. Here you can also restart indexing processes.\n\nOnce you have indexed your data, you can ask the semantic index server questions about your data and content.\n\nTo sumbit prompts about your data, select the magnifying glass icon from the left and fill in the form with your prompts." + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Index Your Data with VectorLink", + "description": "How to index your content and data with VectorLink", + "og_image": "https://assets.terminusdb.com/docs/vectorlink-semantic-cms.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "How to Model Schema" + }, + "slug": "model-schema", + "body": { + "@type": "Body", + "value": "[Model Schema UI](/docs/use-the-model-builder-ui/)[JSON Editor](/docs/use-the-json-editor/)" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "How to Model Schema", + "description": "Bit sized how to guides to help you model and build schema for TerminusDB and TerminusCMS projects.", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Use the Model Builder UI" + }, + "slug": "use-the-model-builder-ui", + "body": { + "@type": "Body", + "value": "## Make a New Data Product\n\nFirst, log in to TerminusCMS, choose (or create) a team, and then click on `New Data Product`.\n\n![Create a new data product using the TerminusDB/TerminusCMS dashboard](https://assets.terminusdb.com/docs/new-data-product.png)\n\n## Create a Class\n\nNow click on the pink bubbles on the left panel. This takes you to the schema builder page.\n\nHover over the gray schema bubble in the center of the graph view.\n\n![JSON schema editor in the TerminusCMS dashboard](https://assets.terminusdb.com/docs/schema-ui-no-docs.png)\n\nThis will give you a `+` icon. This will allow you to add either a document class or an enum. Choose _document_.\n\nThe document will appear as an orange Square and on the right-hand side you will have a panel for editing the schema. You can choose a name for your new document class under the field `Unique ID*`.\n\nOnce you have chosen an id, you can (optionally) choose the _printed_ name of the document under `Label`.\n\n## Add Properties\n\n![Add document properties using the schema builder UI](https://assets.terminusdb.com/docs/schema-ui-doc-properties.png)\n\nNow you can switch the properties tab, and click on `Add Property`. This will give you a choice of several different property types. You can choose `String` for instance for various string properties.\n\nAgain you will have to give it a unique id, and by default the property will be _optional_, but you can change this to _mandatory_, _list_ or _set_.\n\nWhen you are done, click the Disk icon above (meaning save).\n\n## Add Link Property\n\n![Add link properties to a document using the schema builder UI](https://assets.terminusdb.com/docs/schema-ui-doc-link-properties.png)\n\nYou can also add a link property by choosing `Link Property` under the `AddProperty` selector once you have saved at least one document class.\n\nYou must again specify an ID, and link to an already created document class.\n\n## Add Enum\n\n![Create an enum for your schema using the schema builder UI](https://assets.terminusdb.com/docs/schema-ui-doc-enum.png)\n\nYou can add an enum by clicking the `+` on the gray schema bubble and selecting `Add Enum`.\n\nAfter you have chosen a name for your enum, click on the `Values` tab on the right, and begin entering valid values for this enum.\n\n## Add an Enum Property\n\n![Add an enum property to a document using the schema builder UI](https://assets.terminusdb.com/docs/schema-ui-doc-add-enum-property.png)\n\nNow it is possible to link to this enum from any document class. You can do this by selecting `Enum Property` under the `AddProperty` selector." + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Use the Model Builder UI to Build Schema", + "description": "The model builder UI allows you to construct classes of objects and define what data they have, and what links (or relationships) they have between them.", + "og_image": "https://assets.terminusdb.com/docs/schema-ui-doc-properties.png" + }, + "media": [ + { + "@type": "Media", + "alt": "Create a new data product using the TerminusDB/TerminusCMS dashboard", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "Create a new data product using the TerminusDB/TerminusCMS dashboard" + }, + "value": "https://assets.terminusdb.com/docs/new-data-product.png" + }, + { + "@type": "Media", + "alt": "JSON schema editor in the TerminusCMS dashboard", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "JSON schema editor in the TerminusCMS dashboard" + }, + "value": "https://assets.terminusdb.com/docs/schema-ui-no-docs.png" + }, + { + "@type": "Media", + "alt": "Add document properties using the schema builder UI", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "Add document properties using the schema builder UI" + }, + "value": "https://assets.terminusdb.com/docs/schema-ui-doc-properties.png" + }, + { + "@type": "Media", + "alt": "Add link properties to a document using the schema builder UI", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "Add link properties to a document using the schema builder UI" + }, + "value": "https://assets.terminusdb.com/docs/schema-ui-doc-link-properties.png" + }, + { + "@type": "Media", + "alt": "Create an enum for your schema using the schema builder UI", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "Create an enum for your schema using the schema builder UI" + }, + "value": "https://assets.terminusdb.com/docs/schema-ui-doc-enum.png" + }, + { + "@type": "Media", + "alt": "Add an enum property to a document using the schema builder UI", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "Add an enum property to a document using the schema builder UI" + }, + "value": "https://assets.terminusdb.com/docs/schema-ui-doc-add-enum-property.png" + } + ] + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Use the JSON View for building a Schema" + }, + "slug": "use-the-json-editor", + "body": { + "@type": "Body", + "value": "## Make a New Data Product\n\nFirst, log in to TerminusCMS, choose (or create) a team, and then click on \"New Data Product\".\n\n![Create a new product with the TerminusCMS or TerminusDB dashboard](https://assets.terminusdb.com/docs/new-data-product.png)\n\n## Create a schema as JSON\n\nNow click on the pink bubbles on the left panel. This takes you to the schema builder page. Select JSON view from the tab and you'll see your entire schema as JSON.\n\n![TerminusCMS schema editor JSON view](https://assets.terminusdb.com/docs/schema-as-code.png)\n\nIf you click on the Edit button in the upper right-hand corner, you'll be able to directly edit the schema.\n\nIf you have no data in your database, it should be possible to freely edit the schema. However, if you have data, then you may not be able to make arbitrary edits. The schema editor will warn you upon submission if some restrictions are violated.\n\nEssentially it should _always_ be possible to [weaken](/docs/what-is-schema-weakening/) the schema safely through the interface. However, other changes will require [schema migration](/docs/schema-migration-reference-guide/)." + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Use the JSON editor to build schema", + "description": "Use the JSON editor to build your TerminusCMS schema. Define documents, properties, links, and enums. ", + "og_image": "https://assets.terminusdb.com/docs/schema-as-code.png" + }, + "media": [ + { + "@type": "Media", + "alt": "Create a new product with the TerminusCMS or TerminusDB dashboard", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "Create a new product with the TerminusCMS or TerminusDB dashboard" + }, + "value": "https://assets.terminusdb.com/docs/new-data-product.png" + }, + { + "@type": "Media", + "alt": "TerminusCMS schema editor JSON view", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "TerminusCMS schema editor JSON view" + }, + "value": "https://assets.terminusdb.com/docs/schema-as-code.png" + } + ] + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "How to Manage Projects with TerminusCMS" + }, + "slug": "manage-projects-with-terminuscms", + "body": { + "@type": "Body", + "value": "[Create Teams with UI](/docs/create-a-team-with-terminuscms/)[Create Projects with UI](/docs/create-a-project-with-terminuscms/)[Invite Users with UI](/docs/invite-users-using-terminuscms/)[Get API Key](/docs/get-your-api-key-from-terminuscms/)" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "How to Manage Projects with TerminusCMS", + "description": "Bit sized how to guides to get to know the TerminusCMS dashboard to manage your projects", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Create a Team with the TerminusCMS Dashboard" + }, + "slug": "create-a-team-with-terminuscms", + "body": { + "@type": "Body", + "value": "Follow these instruction to create a new team in the TerminusCMS dashboard -\n\n> Note, if it is your first time logging in you will see the pricing page. Select Community Package to proceed and follow these instructions.\\*\n\n1. In team selection screen, choose the team that was automatically generated upon your sign up (or any other).\n2. In the resulting screen, choose profile by selecting the arrow next to your profile avitar/initials.\n\n![select profile from the top menu](https://assets.terminusdb.com/docs/manage-your-projects-create-a-new-team.png)\n\n3. Under your profile details, click the 'Create a New Team' button.\n\n![Name your team and press create new team button](https://assets.terminusdb.com/docs/manage-your-projects-create-a-new-team-2.png)\n\n4. Name your team and press the 'Create a New Team' button.\n\nYou are now ready to [add projects](/docs/create-a-project-with-terminuscms/) to your team and [invite collaborators](/docs/invite-users-using-terminuscms/)." + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Create teams using TerminusCMS", + "description": "A how-to guide for creating teams using the TerminusCMS dashboard.", + "og_image": "https://assets.terminusdb.com/docs/manage-your-projects-create-a-new-team-2.pn" + }, + "media": [ + { + "@type": "Media", + "alt": "select profile from the top menu", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "select profile from the top menu" + }, + "value": "https://assets.terminusdb.com/docs/manage-your-projects-create-a-new-team.png" + }, + { + "@type": "Media", + "alt": "Name your team and press create new team button", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "Name your team and press create new team button" + }, + "value": "https://assets.terminusdb.com/docs/manage-your-projects-create-a-new-team-2.png" + } + ] + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Create a Project/Data Project in TerminusCMS" + }, + "slug": "create-a-project-with-terminuscms", + "body": { + "@type": "Body", + "value": "Follow this instructions to create a project/data product in TerminusCMS -\n\n1. Login to the dashboard at [dashboard.terminusdb.com](https://dashboard.terminusdb.com).\n2. Select the team that you want the project to live.\n3. Choose 'New Data Product' from the top menu.\n4. Provide your project ID - this can only contain alphanumeric characters and underscores.\n5. Name your project.\n6. Provide a description for your project. This is useful if you are collaborating to provide context to other users.\n7. Select 'Create New Data Product' button.\n\n![how to create a project in the TerminusCMS dashboard](https://assets.terminusdb.com/docs/new-data-product.png)\n\nYour project is created and you can now start working with it. To access it at any time, select the project from the list of projects on left of the dashboard." + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "How to create a project with TerminusCMS", + "description": "A how-to guide showing you how to create a new project using the TerminusCMS dashboard", + "og_image": "https://assets.terminusdb.com/docs/new-data-product.png" + }, + "media": [ + { + "@type": "Media", + "alt": "how to create a project in the TerminusCMS dashboard", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "how to create a project in the TerminusCMS dashboard" + }, + "value": "https://assets.terminusdb.com/docs/new-data-product.png" + } + ] + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Invite Users to Your Team" + }, + "slug": "invite-users-using-terminuscms", + "body": { + "@type": "Body", + "value": "To invite team members and manage the team, do the following:\n\n1. Click the arrow next to your profile icon in the top right corner.\n2. Select 'Team Members'.\n3. In the following screen, select 'Invite a Member'.\n![add a new user to your team](https://assets.terminusdb.com/docs/manage-your-projects-add-a-new-user.png)5. In the pop-up window, enter the user’s email address and select one of the following access permissions - \\_this will be applied to team-level permissions so will apply to all data products within your team. If you want to only give read-write access to a specific data product, it makes sense to give the user low-level permissions and assign higher permissions for that data product only - we will explain this next\n\n* Admin - can add and remove users and permissions and has total access to data products.\n* Collaborator - Able to access data products.\n* Data Updater - Read and write access to data products.\n* Data Reader - Read-only access to data products.\n* Info Reader - Schema-level access but not data-level access.\n\n7. The user will be sent an email with a link they need to click (if they don’t receive it, tell them to check their spam folder).\n8. When the user has accepted the invitation, their details will display within the Team Members section.\n\n### **Editing & Removing Users**\n\nTo edit the role given to a user:\n\n1. Navigate to the Team Members section from the profile dropdown.\n2. Find the user to change from the list and click on the second icon.\n3. From the pop-up window, select the new role to give them.\n\nTo delete a user from a team, do the same as above, but select the third icon in red.\n\n> Hover over the icons for information about what they do.\n\n### **Granular Permissions**\n\nGrant different permissions for different data products/projects. To do this do the following:\n\n1. Navigate to the Team Members section from the profile dropdown.\n2. Find the user to add specific data product permissions for and click on the first icon.\n3. The resulting table below will list all of the data products in the team.\n4. Choose the data product to change the user’s role for by clicking on the edit permissions icon.\n5. Choose from the list of permissions\n\n> Users can only have permissions higher than the team permissions, so if someone needs read/write permissions for only one data product, ensure that the team permissions are set at a lower level.\n\n## Manage Access Control with the JS Client\n\n[JS Client Access Control Reference Guide](/docs/js-client-access-control-reference/)" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "How to invite team members to TerminusCMS", + "description": "A how-to guide for inviting collaborators to your team using the TerminusCMS dashboard.", + "og_image": "https://assets.terminusdb.com/docs/manage-your-projects-add-a-new-user.png" + }, + "media": [ + { + "@type": "Media", + "alt": "add a new user to your team", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "add a new user to your team" + }, + "value": "https://assets.terminusdb.com/docs/manage-your-projects-add-a-new-user.png" + } + ] + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Get your API key from TerminusCMS" + }, + "slug": "get-your-api-key-from-terminuscms", + "body": { + "@type": "Body", + "value": "### Generate your API key\n\nTo use the Python or JavaScropt client with TerminusCMS, an API key is required. The API key is obtained in the TerminusCMS dashboard by using the steps below.\n\n**1\\. Log in**\n\nLog in to the user interface dashboard [dashboard.terminusdb.com](https://dashboard.terminusdb.com)\n\n**2\\. Select a Team**\n\nThe teams are listed in the centre of the screen after logging in (and selecting a plan if you have not already done so). This will be the team in which the API key will be generated.\n\n**3\\. Select your profile**\n\nSelect your `Profile` by clicking on ▼ at the top-right corner of the screen.\n\n**4\\. Generate a Personal Access Token**\n\nEnter a description in `Add a Token Description` then click `Generate New Token`. Copy the token generated.\n\n**5\\. Copy the required code snippet**\n\nSelect the `Python` or `JavaScript` tab then copy the code snippet.\n\n### Set up your environment\n\nAssign your token to the environment variable `TERMINUSDB_ACCESS_TOKEN` in your code snippet. The example below is in `bash`.\n\n#### Code: API key environment configuration\n\n```\nexport TERMINUSDB_ACCESS_TOKEN=\"my API key here\"\n```\n\nYou are now ready to start with a client -\n\n[Connect to JavaScript Client](/docs/connect-with-the-javascript-client/)\n\n[Connect to Python Client](/docs/connect-with-python-client/)" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "How to get your API key using TerminusCMS", + "description": "A how-to guide showing how to get your API key to set up and configure your environment to use with a client.", + "og_image": "https://assets.terminusdb.com/docs/get-your-api-key.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "How to Query TerminusCMS and TerminusDB" + }, + "slug": "how-to-query", + "body": { + "@type": "Body", + "value": "[GraphQL Query](/docs/how-to-query-with-graphql/)[WOQL Query](/docs/how-to-query-with-woql/)" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "How to Query TerminusCMS and TerminusDB", + "description": "Guides showing how to query using GraphQL and WOQL", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "How to Query with GraphQL" + }, + "slug": "how-to-query-with-graphql", + "body": { + "@type": "Body", + "value": "[GraphQL Basics](/docs/graphql-basics/)[GraphQL Filter](/docs/filter-with-graphql/)[GraphQL Advanced Filter](/docs/advanced-filtering-with-graphql/)[GraphQL Limit](/docs/limit-results-in-graphql/)[GraphQL Order By](/docs/order-by-in-graphql/)[GraphQL Offset](/docs/offset-to-provide-paging/)[GraphQL Path Queries](/docs/path-queries-in-graphql/)[GraphQL Back Links](/docs/back-links-in-graphql/)" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "How to Query with GraphQL", + "description": "Bit sized how to guides for querying TerminusCMS and TerminusDB with GraphQL", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Query with GraphQL" + }, + "slug": "graphql-basics", + "body": { + "@type": "Body", + "value": "> To use this HowTo, first [clone the Star Wars demo](/docs/clone-a-demo-terminuscms-project/) into your team on TerminusCMS. You will then have full access to the data needed for this tutorial.\n\n![Clone a demo project from the dashboard](https://assets.terminusdb.com/docs/how-to-clone-a-demo.png)\n\nOnce you have cloned the database, go to the GraphQL icon (triangle in hexagon) on the left hand side and select the filing cabinet icon.\n\n![GraphQL query playground](https://assets.terminusdb.com/docs/how-to-query-graphql.png)\n\nNow you have two panels, one on the left for query, and one on the right for results.\n\n## Entering a query\n\nFirst type `query{` into the query panel. It should look like this:\n\n```\nquery{\n █\n}\n```\n\nIf at the cursor point you type: `Ctrl-c` you'll get a list of options you can choose from. These options are legal GraphQL syntax according to your provided schema. Let's search for people from the Star Wars universe.\n\n```\nquery{\n People{\n label\n }\n}\n```\n\nThe `label` property in this schema, supplies the name of the person we are interested in. Of course this query might give us a bit too much, so let us also limit it.\n\n```\nquery{\n People(limit: 5){\n label\n }\n}\n```\n\nThis should result in:\n\n```\n{\n \"data\": {\n \"People\": [\n {\n \"label\": \"Luke Skywalker\"\n },\n {\n \"label\": \"Obi-Wan Kenobi\"\n },\n {\n \"label\": \"Anakin Skywalker\"\n },\n {\n \"label\": \"Wilhuff Tarkin\"\n },\n {\n \"label\": \"Chewbacca\"\n }\n ]\n }\n}\n```\n\nTo get more fields in our query, we can just add words, using `Ctrl-c` if we are stuck for names of fields.\n\n```\nquery{\n People(limit: 5){\n label\n }\n}\n```\n\nWhen following links to other objects, we have to embed a query inside our query. So, for instance, if we want to know the homeworld that each of these people come from we can write:\n\n```\nquery{\n People(limit: 2){\n label\n homeworld{\n label\n }\n }\n}\n```\n\nThis will get us:\n\n```\n{\n \"data\": {\n \"People\": [\n {\n \"label\": \"Luke Skywalker\",\n \"homeworld\": {\n \"label\": \"Tatooine\"\n }\n },\n {\n \"label\": \"Obi-Wan Kenobi\",\n \"homeworld\": {\n \"label\": \"Stewjon\"\n }\n }\n ]\n }\n}\n```\n\n## Paging\n\nIf we want to page the results, we can also add an offset to our query, and we'll get _the next_ results.\n\n```\nquery{\n People(limit: 2, offset:2){\n label\n homeworld{\n label\n }\n }\n}\n```\n\nAnd now we get two more:\n\n```\n{\n \"data\": {\n \"People\": [\n {\n \"label\": \"Anakin Skywalker\",\n \"homeworld\": {\n \"label\": \"Tatooine\"\n }\n },\n {\n \"label\": \"Wilhuff Tarkin\",\n \"homeworld\": {\n \"label\": \"Eriadu\"\n }\n }\n ]\n }\n}\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Learn the GraphQL Basics for TerminusCMS", + "description": "Learn to query TerminusDB and TerminusCMS using GraphQL and a Star Wars data project that you can clone from the dashboard.", + "og_image": "https://assets.terminusdb.com/docs/graphqll-basics.png" + }, + "media": [ + { + "@type": "Media", + "alt": "Clone a demo project from the dashboard", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "Clone a demo project from the dashboard" + }, + "value": "https://assets.terminusdb.com/docs/how-to-clone-a-demo.png" + }, + { + "@type": "Media", + "alt": "GraphQL query playground", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "GraphQL query playground" + }, + "value": "https://assets.terminusdb.com/docs/how-to-query-graphql.png" + } + ] + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Filter with GraphQL" + }, + "slug": "filter-with-graphql", + "body": { + "@type": "Body", + "value": "> To use this HowTo, first [clone the Star Wars demo](/docs/clone-a-demo-terminuscms-project/) into your team on TerminusCMS. You will then have full access to the data needed for this tutorial.\n\n## Using a Filter\n\nOnce you have Star Wars, you can enter into the data product and you can type the following in the [GraphQL query panel](/docs/graphql-basics/):\n\nLet's choose `homeworld`\n\n```\nquery{\n People(filter: { label : { █ }}){\n\n }\n}\n```\n\nType `Ctrl-c` and you'll be given some filters which can be used to constrain the label field.\n\nLet's choose a regex which demonstrates the fondness the creators of Star Wars had for the 'oo' sound.\n\n```\nquery{\n People(filter:{ label : {regex: \".*oo.*\"}}){\n label\n homeworld{\n label\n }\n }\n}\n```\n\nThis results in:\n\n```\n{\n \"data\": {\n \"People\": [\n {\n \"label\": \"Roos Tarpals\",\n \"homeworld\": {\n \"label\": \"Naboo\"\n }\n },\n {\n \"label\": \"Yarael Poof\",\n \"homeworld\": {\n \"label\": \"Quermia\"\n }\n },\n {\n \"label\": \"Plo Koon\",\n \"homeworld\": {\n \"label\": \"Dorin\"\n }\n },\n {\n \"label\": \"Dooku\",\n \"homeworld\": {\n \"label\": \"Serenno\"\n }\n },\n {\n \"label\": \"Sly Moore\",\n \"homeworld\": {\n \"label\": \"Umbara\"\n }\n }\n ]\n }\n}\n```\n\nFor more sophisticated filtering, see [Advanced filtering](/docs/advanced-filtering-with-graphql/)." + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Filter", + "description": "Filter with GraphQL", + "og_image": "https://github.com/terminusdb/terminusdb-web-assets/blob/master/docs/graphql-filter.png?raw=true" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Advanced Filtering with GraphQL" + }, + "slug": "advanced-filtering-with-graphql", + "body": { + "@type": "Body", + "value": "> To use this HowTo, first [clone the Star Wars demo](/docs/clone-a-demo-terminuscms-project/) into your team on TerminusCMS. You will then have full access to the data needed for this tutorial.\n\nTerminusDB exposes a _filter_ object, which can be used to select specific documents. See here for basic [Filtering](/docs/filter-with-graphql/)\n\nNow we can filter the homeworld of the people we are interested in. We will use a `regex` because Tatooine is hard to spell.\n\n```\nquery{\n People(filter: { homeworld: { label: { regex : \"Tat.*\" }}}){\n label\n homeworld{\n label\n }\n }\n}\n```\n\nYou can also find out what fields are available with the same `Ctrl-c` trick. Now, fire off the query above, and you'll see something like:\n\n```\n{\n \"data\": {\n \"People\": [\n {\n \"label\": \"Luke Skywalker\",\n \"homeworld\": {\n \"label\": \"Tatooine\"\n }\n },\n {\n \"label\": \"Anakin Skywalker\",\n \"homeworld\": {\n \"label\": \"Tatooine\"\n }\n },\n {\n \"label\": \"C-3PO\",\n \"homeworld\": {\n \"label\": \"Tatooine\"\n }\n },\n {\n \"label\": \"Darth Vader\",\n \"homeworld\": {\n \"label\": \"Tatooine\"\n }\n },\n {\n \"label\": \"Shmi Skywalker\",\n \"homeworld\": {\n \"label\": \"Tatooine\"\n }\n },\n {\n \"label\": \"Owen Lars\",\n \"homeworld\": {\n \"label\": \"Tatooine\"\n }\n },\n {\n \"label\": \"Cliegg Lars\",\n \"homeworld\": {\n \"label\": \"Tatooine\"\n }\n },\n {\n \"label\": \"Beru Whitesun lars\",\n \"homeworld\": {\n \"label\": \"Tatooine\"\n }\n },\n {\n \"label\": \"R5-D4\",\n \"homeworld\": {\n \"label\": \"Tatooine\"\n }\n },\n {\n \"label\": \"Biggs Darklighter\",\n \"homeworld\": {\n \"label\": \"Tatooine\"\n }\n }\n ]\n }\n}\n```\n\n## Adding conjunctions\n\nWe can also add other elements to the filter, by using the `_and` keyword. This requires that both filters are true.\n\n```\nquery{\n People(filter:{ _and : [ {homeworld : {label : {eq : \"Coruscant\"}}},\n {species : {label : { eq: \"Human\"}}},\n ]}){\n label\n species{\n label\n }\n homeworld{\n label\n }\n }\n}\n```\n\nWhich yields:\n\n```\n{\n \"data\": {\n \"People\": [\n {\n \"label\": \"Finis Valorum\",\n \"species\": {\n \"label\": \"Human\"\n },\n \"homeworld\": {\n \"label\": \"Coruscant\"\n }\n },\n {\n \"label\": \"Jocasta Nu\",\n \"species\": {\n \"label\": \"Human\"\n },\n \"homeworld\": {\n \"label\": \"Coruscant\"\n }\n }\n ]\n }\n}\n```\n\n## `_not` and `_or`\n\nYou can also use `_not` and `_or` keywords to create even more complex filters. To find all species, excluding droids with a lifespan greater than 500 who don't have a typical sort of skin colour, you can write the following:\n\n```\n{\n Species(\n filter: {_and : [\n {_not :{label:{eq:\"Droid\"}}},\n {_or :[\n {average_lifespan:{gt : \"500\"}},\n {_not:\n {skin_colors:\n {anyOfTerms: [\"blue\", \"black\", \"white\", \"green\", \"grey\"\n \"brown\", \"red\", \"gray\"]}}}]\n }]}\n ) {\n label\n }\n}\n```\n\nAnd yields:\n\n```\n{\n \"data\": {\n \"Species\": [\n {\n \"label\": \"Yoda's species\"\n },\n {\n \"label\": \"Pau'an\"\n },\n {\n \"label\": \"Hutt\"\n },\n {\n \"label\": \"Sullustan\"\n },\n {\n \"label\": \"Cerean\"\n },\n {\n \"label\": \"Iktotchi\"\n },\n {\n \"label\": \"Tholothian\"\n }\n ]\n }\n}\n```\n\n## A Bit of GraphQL theory\n\nThe filter is defined as part of the query for objects. If we look at the `People` query in the Star Wars demo we see the following:\n\n```\ntype Query {\n People(\n id: ID\n ids: [ID!]\n\n \"\"\"skip N elements\"\"\"\n offset: Int\n\n \"\"\"limit results to N elements\"\"\"\n limit: Int\n filter: People_Filter\n\n \"\"\"order by the given fields\"\"\"\n orderBy: People_Ordering\n ): [People!]!\n}\n```\n\nThis query exposes a `filter` argument, with the type of `People_Filter`.\n\nA `People_Filter` in turn looks like:\n\n```\ninput People_Filter {\n birth_year: StringFilter\n created: DateTimeFilter\n desc: CollectionStringFilter\n edited: DateTimeFilter\n eye_color: StringFilter\n film: Film_Collection_Filter\n gender: StringFilter\n hair_colors: StringFilter\n height: StringFilter\n homeworld: Planet_Filter\n label: StringFilter\n mass: StringFilter\n skin_colors: StringFilter\n species: Species_Filter\n starship: Starship_Collection_Filter\n url: StringFilter\n vehicle: Vehicle_Collection_Filter\n _and: [People_Filter!]\n _or: [People_Filter!]\n _not: People_Filter\n}\n```\n\nIn this way we can recursively qualify all of the objects to which a `People` might point to, terminating at leaves that use the various concrete type filters.\n\nFor instance, the `StringFilter` looks like:\n\n```\ninput StringFilter {\n eq: String\n ne: String\n lt: String\n le: String\n gt: String\n ge: String\n regex: String\n startsWith: String\n allOfTerms: [String!]\n anyOfTerms: [String!]\n}\n```\n\nWe can specify any of these operands to narrow down our search. For more information on the operations against concrete datatypes, see the [GraphQL Reference](/docs/graphql-query-reference/) section." + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Advanced Filtering", + "description": "Advanced Filtering with GraphQL", + "og_image": "https://assets.terminusdb.com/docs/graphql-advanced-filter.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Limit Results with GraphQL" + }, + "slug": "limit-results-in-graphql", + "body": { + "@type": "Body", + "value": "> To use this HowTo, first [clone the Star Wars demo](/docs/clone-a-demo-terminuscms-project/) into your team on TerminusCMS. You will then have full access to the data needed for this tutorial.\n\n![Clone the Star Wars demo from the TerminusCMS dashboard](https://assets.terminusdb.com/docs/how-to-clone-a-demo.png)\n\nOnce you have cloned the database, go to the GraphQL icon (triangle in hexagon) on the left hand side and select the filing cabinet icon.\n\n![GraphQL query playground in TerminusCMS](https://assets.terminusdb.com/docs/how-to-query-graphql.png)\n\nThere are two panels, one on the left for query, and one on the right for results.\n\n## Adding a limit\n\nThe `limit` keyword is an argument which can be passed to a query to restrict the number of results to precisely the number supplied by the argument.\n\nFor instance we can get exactly 5 people from the Star Wars universe by specifying the query here:\n\n```\nquery{\n People(limit: 5){\n label\n }\n}\n```\n\nThis will result in\n\n```\n{\n \"data\": {\n \"People\": [\n {\n \"label\": \"Luke Skywalker\"\n },\n {\n \"label\": \"Obi-Wan Kenobi\"\n },\n {\n \"label\": \"Anakin Skywalker\"\n },\n {\n \"label\": \"Wilhuff Tarkin\"\n },\n {\n \"label\": \"Chewbacca\"\n }\n ]\n }\n}\n```\n\nIf you want to page, to get the next results, you can use an [offset](/docs/offset-to-provide-paging/)" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Limit Results with GraphQL in TerminusCMS", + "description": "How to use limit to limit query results with GraphQL", + "og_image": "https://assets.terminusdb.com/docs/graphql-limit.png" + }, + "media": [ + { + "@type": "Media", + "alt": "Clone the Star Wars demo from the TerminusCMS dashboard", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "Clone the Star Wars demo from the TerminusCMS dashboard" + }, + "value": "https://assets.terminusdb.com/docs/how-to-clone-a-demo.png" + }, + { + "@type": "Media", + "alt": "GraphQL query playground in TerminusCMS", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "GraphQL query playground in TerminusCMS" + }, + "value": "https://assets.terminusdb.com/docs/how-to-query-graphql.png" + } + ] + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Order By in GraphQL" + }, + "slug": "order-by-in-graphql", + "body": { + "@type": "Body", + "value": "> To use this HowTo, first [clone the Star Wars demo](/docs/clone-a-demo-terminuscms-project/) into your team on TerminusCMS. You will then have full access to the data needed for this tutorial.\n\n## Ordering results of a GraphQL query\n\nBy default, results in GraphQL will choose an implementation specific order which may not even be stable between invocations. If you need results in a _specific order_ then you need to supply an `orderBy` argument.\n\nWe can search for the names of people in reverse alphabetical order such that we only recover the first 5 results in the following way:\n\n```\nquery{\n People(limit:5, orderBy:{label:DESC}){\n label\n }\n}\n```\n\nThis will give us the following people:\n\n```\n{\n \"data\": {\n \"People\": [\n {\n \"label\": \"Zam Wesell\"\n },\n {\n \"label\": \"Yoda\"\n },\n {\n \"label\": \"Yarael Poof\"\n },\n {\n \"label\": \"Wilhuff Tarkin\"\n },\n {\n \"label\": \"Wicket Systri Warrick\"\n }\n ]\n }\n}\n```\n\nOrder by can also take more than one argument, allowing us to order on more than one value using the remaining arguments when there is a tie in the preceding (lexicographic ordering).\n\nWe can see this by searching for species, and which language they speak and their name. Since many will share the same language, we can see the ordering of the fields independently.\n\n```\nquery{\n Species(offset:8, limit:5, orderBy:{language:ASC, label:ASC}){\n label\n language\n }\n}\n```\n\nAnd here we have a number of Galactic Basic speakers who nevertheless are ordered by species name.\n\n```\n{\n \"data\": {\n \"Species\": [\n {\n \"label\": \"Ewok\",\n \"language\": \"Ewokese\"\n },\n {\n \"label\": \"Human\",\n \"language\": \"Galactic Basic\"\n },\n {\n \"label\": \"Rodian\",\n \"language\": \"Galactic Basic\"\n },\n {\n \"label\": \"Yoda's species\",\n \"language\": \"Galactic basic\"\n },\n {\n \"label\": \"Geonosian\",\n \"language\": \"Geonosian\"\n }\n ]\n }\n}\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Order By GraphQL Queries in TerminusCMS", + "description": "How to use the order by argument in GraphQL queries with TerminusCMS and TerminusDB", + "og_image": "https://assets.terminusdb.com/docs/graphql-order-by.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Offset to Provide Paging" + }, + "slug": "offset-to-provide-paging", + "body": { + "@type": "Body", + "value": "> To use this HowTo, first [clone the Star Wars demo](/docs/clone-a-demo-terminuscms-project/) into your team on TerminusCMS. You will then have full access to the data needed for this tutorial.\n\n![Clone the Star Wars demo from the TerminusCMS dashboard](https://assets.terminusdb.com/docs/how-to-clone-a-demo.png)\n\nOnce you have cloned the database, go to the GraphQL icon (triangle in hexagon) on the left hand side and select the filing cabinet icon.\n\n![GraphQL query playground in TerminusCMS](https://assets.terminusdb.com/docs/how-to-query-graphql.png)\n\nThere are two panels, one on the left for query, and one on the right for results.\n\n## Adding an offset\n\nThe `offset` keyword is most often used with the [limit](/docs/limit-results-in-graphql/) keyword which when used together enable paging of results.\n\nFor instance, we can get exactly 5 people from the star-wars universe by specifying the query here:\n\n```\nquery{\n People(limit: 5){\n label\n }\n}\n```\n\nThis will result in\n\n```\n{\n \"data\": {\n \"People\": [\n {\n \"label\": \"Luke Skywalker\"\n },\n {\n \"label\": \"Obi-Wan Kenobi\"\n },\n {\n \"label\": \"Anakin Skywalker\"\n },\n {\n \"label\": \"Wilhuff Tarkin\"\n },\n {\n \"label\": \"Chewbacca\"\n }\n ]\n }\n}\n```\n\nIf we then want to get the _next_ page of data we can write:\n\n```\nquery{\n People(limit: 5, offset: 5){\n label\n }\n}\n```\n\nThis will result in:\n\n```\n{\n \"data\": {\n \"People\": [\n {\n \"label\": \"Han Solo\"\n },\n {\n \"label\": \"Greedo\"\n },\n {\n \"label\": \"Jabba Desilijic Tiure\"\n },\n {\n \"label\": \"Wedge Antilles\"\n },\n {\n \"label\": \"Jek Tono Porkins\"\n }\n ]\n }\n}\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "GraphQL Offset to Provide Pagination", + "description": "A guide showing how to use offset in GraphQL to provide pagination", + "og_image": "https://assets.terminusdb.com/docs/graphql-offset.png" + }, + "media": [ + { + "@type": "Media", + "alt": "Clone the Star Wars demo from the TerminusCMS dashboard", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "Clone the Star Wars demo from the TerminusCMS dashboard" + }, + "value": "https://assets.terminusdb.com/docs/how-to-clone-a-demo.png" + }, + { + "@type": "Media", + "alt": "GraphQL query playground in TerminusCMS", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "GraphQL query playground in TerminusCMS" + }, + "value": "https://assets.terminusdb.com/docs/how-to-query-graphql.png" + } + ] + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Path Queries in GraphQL" + }, + "slug": "path-queries-in-graphql", + "body": { + "@type": "Body", + "value": "> To use this HowTo, first [clone the Star Wars demo](/docs/clone-a-demo-terminuscms-project/) into your team on TerminusCMS. You will then have full access to the data needed for this tutorial.\n\n## Using a Path Query\n\nSometimes we want to search for links that are not immediate, but need to follow a chain of links to get the object of interest. TerminusCMS gives us [path queries](/docs/path-query-reference-guide/) which allow us to succinctly express this.\n\nWe can find a path in GraphQL by using the `_path_to_CLASS` query, where CLASS is the name of one of our classes. One path should be populated for each of the available classes.\n\nTo find everyone who was in a film with Chewbacca, we can write:\n\n```\nquery{\n People(filter:{label:{eq:\"Chewbacca\"}}){\n label\n _path_to_People(path:\"film, To use this HowTo, first [clone the Star Wars demo](/docs/clone-a-demo-terminuscms-project/) into your team on TerminusCMS. You will then have full access to the data needed for this tutorial.\n\n## Using a Back Link\n\nMany times when we are looking at an object, we are interested in which objects are pointing to it. In TerminusCMS each object gets a number of extended queries which allows one to discover any objects which point at that object.\n\nOnce you have cloned the Star Wars demo, go to the [GraphQL query panel](/docs/graphql-basics/) and type:\n\n```\nquery{\n People(limit:1) {\n █\n }\n}\n```\n\nWe would like to find the first person in the database, and then find out which starships they are the pilot of. A `Starship` has a `pilot` field, and the backlink is automatically constructed as the `pilot_of_Starship` by TerminusCMS.\n\n```\nquery{\n People(limit:1){\n label\n _pilot_of_Starship{\n label\n }\n }\n}\n```\n\nThis _back link_ will give us back the following:\n\n```\n{\n \"data\": {\n \"People\": [\n {\n \"label\": \"Luke Skywalker\",\n \"_pilot_of_Starship\": [\n {\n \"label\": \"X-wing\"\n },\n {\n \"label\": \"Imperial shuttle\"\n }\n ]\n }\n ]\n }\n}\n```\n\nBacklinking allows us to focus on modeling our data in a natural way, while still allowing us to follow the graph in either direction of a field or its opposite without bias." + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Back Links", + "description": "Back Links in GraphQL", + "og_image": "https://assets.terminusdb.com/docs/graphql-backlink.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "How to Query with WOQL" + }, + "slug": "how-to-query-with-woql", + "body": { + "@type": "Body", + "value": "[WOQL Basics](/docs/woql-basics/)[WOQL Add Docs](/docs/add-documents-with-woql/)[WOQL Edit Docs](/docs/edit-documents-with-woql/)[WOQL Delete Docs](/docs/delete-documents-with-woql/)[WOQL Read Docs](/docs/read-documents-with-woql/)[WOQL Filter](/docs/filter-with-woql/)[WOQL Order By](/docs/order-by-with-woql/)[WOQL Query Arrays](/docs/query-arrays-and-sets-in-woql/)[WOQL Group Results](/docs/group-query-results/)[WOQL Path Queries](/docs/path-queries-in-woql/)[WOQL Math Queries](/docs/maths-based-queries-in-woql/)[WOQL Schema Queries](/docs/schema-queries-with-woql/)" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "How to Query with WOQL", + "description": "Bite sized how to guides to query TerminusCMS and TerminusDB using WOQL", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "WOQL Basics" + }, + "slug": "woql-basics", + "body": { + "@type": "Body", + "value": "> To use this HowTo, first [clone the Star Wars demo](/docs/clone-a-demo-terminuscms-project/) into your team on TerminusCMS. You will then have full access to the data needed for this tutorial.\n\n## Writing a WOQL Query\n\n![WOQL query playground in the TerminusCMS dashboard](https://assets.terminusdb.com/docs/how-to-query-woql.png)\n\nFirst, go to the WOQL Query Panel in the UI. Now you can type a query using the syntax of the JS client in the panel.\n\nQueries are composed of variables, names, words and values.\n\nLets start with a simple query which just looks at one field.\n\nWe need to describe which variables we want to use, and we do that with `Vars`.\n\nNext we add the `limit` word, to limit to 10 entries.\n\nThen we complete the query with a `triple` word, using the `source` variable, the `label` field, and the `destination` variable.\n\n```javascript\nlet v = Vars(\"source\", \"destination\");\nlimit(10).triple(v.source, 'label', v.destination)\n```\n\nThe results will come back in a table below in the UI. In the client it will return as a list of JSON objects, having each of the variables described in `Vars` bound.\n\nThe `destination` variable is filled with elements of type _string_, because `label` always terminates in a string. However we can also add other fields to our object, to search for more information by chaining `triple` together.\n\n```javascript\nlet v = Vars(\"person\", \"eyes\", \"name\");\nlimit(5)\n .triple(v.person, 'label', v.name)\n .triple(v.person, 'eye_color', v.eyes)\n```\n\nThis query results in the following:\n\nName\n\nEyes\n\nPerson\n\nLuke Skywalker\n\nblue\n\nPeople/1\n\nObi-Wan Kenobi\n\nblue-gray\n\nPeople/10\n\nAnakin Skywalker\n\nblue\n\nPeople/11\n\nWilhuff Tarkin\n\nblue\n\nPeople/12\n\nChewbacca\n\nblue\n\nPeople/13\n\n## and\n\nThe `.` syntax is actually introducing an implicit `and` between `triple` words. We can rewrite our query above as:\n\n```javascript\nlet v = Vars(\"person\", \"eyes\", \"name\");\nlimit(5)\n .and(triple(v.person, 'label', v.name),\n triple(v.person, 'eye_color', v.eyes))\n```\n\n## select\n\nSince we probably do not really need the `person` variable, as it is an id, and we are just using it to make sure we are talking about the _same_ person in both triples, we can use `select` to remove it.\n\n```javascript\nlet v = Vars(\"person\", \"eyes\", \"name\");\nlimit(5)\n .select(v.name, v.eyes)\n .and(triple(v.person, 'label', v.name),\n triple(v.person, 'eye_color', v.eyes))\n```\n\nNow we get back the table with the `person` column removed." + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Learn the WOQL query basics for TerminusDB and TerminusCMS", + "description": "A guide to show the WOQL query basics in TerminusDB and TerminusCMS.", + "og_image": "https://assets.terminusdb.com/docs/woql-basics.png" + }, + "media": [ + { + "@type": "Media", + "alt": "WOQL query playground in the TerminusCMS dashboard", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "WOQL query playground in the TerminusCMS dashboard" + }, + "value": "https://assets.terminusdb.com/docs/how-to-query-woql.png" + } + ] + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Add a document in WOQL" + }, + "slug": "add-documents-with-woql", + "body": { + "@type": "Body", + "value": "> To use this HowTo, first [clone the Star Wars demo](/docs/clone-a-demo-terminuscms-project/) into your team on TerminusCMS. You will then have full access to the data needed for this tutorial.\n\n## Add a document in WOQL\n\nYou can add a document in WOQL using the `insert_document` keyword.\n\n```javascript\nlet v = Vars(\"id\");\ninsert_document(doc({'@type' : 'Planet', label: 'Planet-X'}), v.id)\n```\n\nWe can also add documents by using a variable. For instance, we can create a new planet for each individual in the star wars universe as follows:\n\n```javascript\nlet v = Vars(\"person\", \"name\");\nand(isa(v.person, \"People\"),\n triple(v.person,\"label\",v.name),\n insert_document(doc({'@type' : 'Planet', label: v.name})))\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "How to add documents using WOQL", + "description": "A how-to guide with an example showing how to add documents using a WOQL query.", + "og_image": "https://assets.terminusdb.com/docs/woql-add-documents.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Edit documents in WOQL" + }, + "slug": "edit-documents-with-woql", + "body": { + "@type": "Body", + "value": "> To use this HowTo, first [clone the Star Wars demo](/docs/clone-a-demo-terminuscms-project/) into your team on TerminusCMS. You will then have full access to the data needed for this tutorial.\n\nWe can get a document by Id, by using `read_document`. For instance, we can write:\n\n```javascript\nlet v = Vars(\"doc\", \"id\");\nand(isa(v.id, \"People\"),\n triple(v.id, \"label\", string(\"Bossk\")),\n read_document(v.id, v.doc))\n```\n\nWe can also add documents by using a variable. For instance, we can create a new planet for each individual in the star wars universe as follows:\n\n```javascript\nlet v = Vars(\"person\", \"name\");\nand(isa(v.person, \"People\"),\n triple(v.person,\"label\",v.name),\n insert_document(doc({'@type' : 'Planet', label: v.name})))\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Edit Documents using WOQL", + "description": "A guide with example showing how to edit documents using WOQL", + "og_image": "https://assets.terminusdb.com/docs/woql-edit-documents.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Delete a document in WOQL" + }, + "slug": "delete-documents-with-woql", + "body": { + "@type": "Body", + "value": "> To use this HowTo, first [clone the Star Wars demo](/docs/clone-a-demo-terminuscms-project/) into your team on TerminusCMS. You will then have access to the data needed for this tutorial.\n\nDeleting a document in WOQL is possible using the `delete_document` keyword.\n\nFirst, let's insert a document.\n\n```javascript\nlet v = Vars(\"id\");\ninsert_document(doc({'@type' : 'Planet', label: 'Planet-X'}), v.id)\n```\n\nSupposing we get back the following:\n\n```\n\"Planet/01dd97a75800f01f43ab7ab55b6dd08f198dd34d2bdbbeeb7bf4edee45111863\"\n```\n\nNow we can delete it with the following:\n\n```\ndelete_document(\"Planet/01dd97a75800f01f43ab7ab55b6dd08f198dd34d2bdbbeeb7bf4edee45111863\")\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "How to delete documents using WOQL", + "description": "A how-to guide showing how to construct a WOQL query to delete documents.", + "og_image": "https://assets.terminusdb.com/docs/woql-delete-documents.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Read documents with WOQL" + }, + "slug": "read-documents-with-woql", + "body": { + "@type": "Body", + "value": "> To use this HowTo, first [clone the Star Wars demo](/docs/clone-a-demo-terminuscms-project/) into your team on TerminusCMS. You will then have access to the data needed for this tutorial.\n\nYou can read a document after finding the document id as follows:\n\n```javascript\nlet v = Vars(\"doc\", \"id\");\nand(isa(v.id, \"People\"),\n triple(v.id, \"label\", string(\"Bossk\")),\n read_document(v.id, v.doc))\n```\n\nThis find a `People` document, makes sure it has the label `\"Boosk\"` and then reads the document into the variable `doc`." + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Read Documents in WOQL - TerminusDB\n", + "description": "A guide to show how to read documents with WOQL in your TerminusDB and TerminusCMS projects.", + "og_image": "https://assets.terminusdb.com/docs/woql-read-documents.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Writing a filter in WOQL" + }, + "slug": "filter-with-woql", + "body": { + "@type": "Body", + "value": "> To use this HowTo, first [clone the Star Wars demo](/docs/clone-a-demo-terminuscms-project/) into your team on TerminusCMS. You will then have access to the data needed for this tutorial.\n\nSince WOQL is a datalog, filters are just part of the query. You can express negative information, or constraints on the variables in order to get a restriction down to the things you want.\n\nFor instance, we can write the following query in the query panel for the Star Wars demo:\n\n```javascript\nlet v = Vars(\"person\",\"person_name\",\"vehicle\",\"vehicle_name\");\nlimit(10)\n.select(v.person_name, v.vehicle_name)\n .and(triple(v.vehicle, \"pilot\", v.person),\n triple(v.vehicle, \"label\", v.vehicle_name),\n triple(v.person, \"label\", v.person_name))\n```\n\nThis results in:\n\n```\n[ {\"person_name\": {\"@type\":\"xsd:string\", \"@value\":\"Chewbacca\"},\n \"vehicle_name\": {\"@type\":\"xsd:string\", \"@value\":\"Millennium Falcon\"}},\n {\"person_name\": {\"@type\":\"xsd:string\", \"@value\":\"Han Solo\"},\n \"vehicle_name\": {\"@type\":\"xsd:string\", \"@value\":\"Millennium Falcon\"}},\n {\"person_name\": {\"@type\":\"xsd:string\", \"@value\":\"Lando Calrissian\"},\n \"vehicle_name\": {\"@type\":\"xsd:string\", \"@value\":\"Millennium Falcon\"}},\n {\"person_name\": {\"@type\":\"xsd:string\", \"@value\":\"Nien Nunb\"},\n \"vehicle_name\": {\"@type\":\"xsd:string\", \"@value\":\"Millennium Falcon\"}},\n {\"person_name\": {\"@type\":\"xsd:string\", \"@value\":\"Luke Skywalker\"},\n \"vehicle_name\": {\"@type\":\"xsd:string\", \"@value\":\"X-wing\"}},\n {\"person_name\": {\"@type\":\"xsd:string\", \"@value\":\"Wedge Antilles\"},\n \"vehicle_name\": {\"@type\":\"xsd:string\", \"@value\":\"X-wing\"}},\n {\"person_name\": {\"@type\":\"xsd:string\", \"@value\":\"Jek Tono Porkins\"},\n \"vehicle_name\": {\"@type\":\"xsd:string\", \"@value\":\"X-wing\"}},\n {\"person_name\": {\"@type\":\"xsd:string\", \"@value\":\"Biggs Darklighter\"},\n \"vehicle_name\": {\"@type\":\"xsd:string\", \"@value\":\"X-wing\"}},\n {\"person_name\": {\"@type\":\"xsd:string\", \"@value\":\"Darth Vader\"},\n \"vehicle_name\": {\"@type\":\"xsd:string\", \"@value\":\"TIE Advanced x1\"}},\n {\"person_name\": {\"@type\":\"xsd:string\", \"@value\":\"Boba Fett\"},\n \"vehicle_name\": {\"@type\":\"xsd:string\", \"@value\":\"Slave 1\"}}\n]\n```\n\nWe can ask for a _specific_ example of a vehicle name by filtering on equality.\n\nFor instance:\n\n```javascript\nlet v = Vars(\"person\",\"person_name\",\"vehicle\",\"vehicle_name\");\nselect(v.person_name, v.vehicle_name)\n .and(triple(v.vehicle, \"pilot\", v.person),\n triple(v.vehicle, \"label\", v.vehicle_name),\n triple(v.person, \"label\", v.person_name),\n eq(v.vehicle_name, string(\"Millennium Falcon\")))\n```\n\nWhich results in:\n\n```\n[ {\"person_name\": {\"@type\":\"xsd:string\", \"@value\":\"Chewbacca\"},\n \"vehicle_name\": {\"@type\":\"xsd:string\", \"@value\":\"Millennium Falcon\"}},\n {\"person_name\": {\"@type\":\"xsd:string\", \"@value\":\"Han Solo\"},\n \"vehicle_name\": {\"@type\":\"xsd:string\", \"@value\":\"Millennium Falcon\"}},\n {\"person_name\": {\"@type\":\"xsd:string\", \"@value\":\"Lando Calrissian\"},\n \"vehicle_name\": {\"@type\":\"xsd:string\", \"@value\":\"Millennium Falcon\"}},\n {\"person_name\": {\"@type\":\"xsd:string\", \"@value\":\"Nien Nunb\"},\n \"vehicle_name\": {\"@type\":\"xsd:string\", \"@value\":\"Millennium Falcon\"}}\n]\n```\n\nWe can also write:\n\n```javascript\nlet v = Vars(\"person\",\"person_name\",\"vehicle\",\"vehicle_name\");\nselect(v.person_name, v.vehicle_name)\n .and(triple(v.vehicle, \"pilot\", v.person),\n triple(v.vehicle, \"label\", v.vehicle_name),\n triple(v.person, \"label\", v.person_name),\n not(eq(v.vehicle_name, string(\"Millennium Falcon\"))))\n```\n\nIn which we get the complement of the above.\n\nOr, we can use the regex operator to get a wider variety, for instance:\n\n```javascript\nlet v = Vars(\"person\",\"person_name\",\"vehicle\",\"vehicle_name\",\"pattern\");\nselect(v.person_name, v.vehicle_name)\n .and(triple(v.vehicle, \"pilot\", v.person),\n triple(v.vehicle, \"label\", v.vehicle_name),\n triple(v.person, \"label\", v.person_name),\n regex(\"W.*\", v.vehicle_name, [v.pattern]))\n```\n\nIn this case, we get the following back in JSON format:\n\n```\n[ {\"person_name\": {\"@type\":\"xsd:string\", \"@value\":\"Darth Vader\"},\n \"vehicle_name\": {\"@type\":\"xsd:string\", \"@value\":\"TIE Advanced x1\"}},\n {\"person_name\": {\"@type\":\"xsd:string\", \"@value\":\"Arvel Crynyd\"},\n \"vehicle_name\": {\"@type\":\"xsd:string\", \"@value\":\"A-wing\"}},\n {\"person_name\": {\"@type\":\"xsd:string\", \"@value\":\"Chewbacca\"},\n \"vehicle_name\": {\"@type\":\"xsd:string\", \"@value\":\"AT-ST\"}}\n]\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "How to filter with WOQL", + "description": "A guide showing how to filter with WOQL in your TerminusCMS and TerminusDB projects ", + "og_image": "https://assets.terminusdb.com/docs/woql-filter.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "How to Order Results in WOQL" + }, + "slug": "order-by-with-woql", + "body": { + "@type": "Body", + "value": "> To use this HowTo, first [clone the Star Wars demo](/docs/clone-a-demo-terminuscms-project/) into your team on TerminusCMS. You will then have access to the data needed for this tutorial.\n\n## Ordering results using `order_by`\n\nThe `order_by` keyword will allow you to sort results.\n\n```javascript\nlet v = Vars(\"person\", \"label\", \"eyes\", \"group\");\nlimit(2)\n.order_by([\"eyes\", \"desc\"])\n.select(v.eyes, v.group)\n.group_by(\n \"eyes\",\n [\"label\"],\n v.group,\n and(triple(v.person, \"rdf:type\", \"@schema:People\"),\n triple(v.person, \"label\", v.label),\n triple(v.person, \"eye_color\", v.eyes)))\n```\n\nThis returns the first two results of people, who have a given eye color, sorted by eye color, in reverse order.\n\nTo get the alternative order, you can write:\n\n```javascript\nlet v = Vars(\"person\", \"label\", \"eyes\", \"group\");\nlimit(2)\n.order_by([\"eyes\", \"asc\"])\n.select(v.eyes, v.group)\n.group_by(\n \"eyes\",\n [\"label\"],\n v.group,\n and(triple(v.person, \"rdf:type\", \"@schema:People\"),\n triple(v.person, \"label\", v.label),\n triple(v.person, \"eye_color\", v.eyes)))\n```\n\nOr simply:\n\n```javascript\nlet v = Vars(\"person\", \"label\", \"eyes\", \"group\");\nlimit(2)\n.order_by(\"eyes\")\n.select(v.eyes, v.group)\n.group_by(\n \"eyes\",\n [\"label\"],\n v.group,\n and(triple(v.person, \"rdf:type\", \"@schema:People\"),\n triple(v.person, \"label\", v.label),\n triple(v.person, \"eye_color\", v.eyes)))\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "How to Order Results in WOQL - TerminusDB", + "description": "A guide to show you how to order results using order_by in WOQL.", + "og_image": "https://assets.terminusdb.com/docs/woql-order-by.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Query Arrays and Sets with WOQL" + }, + "slug": "query-arrays-and-sets-in-woql", + "body": { + "@type": "Body", + "value": "In TerminusDB there are a number of collection types, including `List`, `Set`, and `Array`.\n\nWhile these all generate JSON lists through the document interface, they have different semantics due to their different realisation in the graph.\n\n## Sets\n\nSets are the simplest objects in TerminusDB. They are simply edges with the same name that leads to more than one object.\n\nFor instance, an example of the document:\n\n```\n{ \"@type\" : \"Class\",\n \"@id\" : \"Person\",\n \"name\" : \"xsd:string\",\n \"friends\" : { \"@type\" : \"Set\", \"@class\" : \"Person\" }\n}\n```\n\nTo search for the results of friends in WOQL, we can simply use `triple`.\n\n```javascript\nlet v = Vars(\"id\", \"friend\")\ntriple(v.id, \"friends\", v.friend)\n```\n\nIf you want to get back the values in a specific order, you can use an `order_by` clause.\n\n## Lists\n\nTo search a list of objects, you need to traverse the intermediate _cons cells_. The list is actually a graph structure shaped like:\n\n```\n∘ → ∘ rest→ ∘ rest→ ∘ rest→ rdf:nil\n ↓ first ↓ first ↓ first\n v0 v1 v2\n```\n\nThis can be traversed using a [path query](/docs/query-arrays-and-sets-in-woql/) as follows:\n\n```javascript\nlet v = Vars(\"queue\", \"person\")\npath(v.queue, \"contacts,rdf:rest*,rdf:first\", v.person)\n```\n\n## Arrays\n\nTo search an array, you can use select, and group by.\n\n```javascript\nlet v = Vars(\"queue\", \"arr\", \"person\", \"index\")\norder_by(v.index)\n .select(v.queue, v.person, v.index)\n .and(triple(v.queue, \"contacts\", v.arr),\n triple(v.arr, \"sys:index\", v.index),\n triple(v.arr, \"sys:value\", v.person))\n```\n\nThis will give you back the array value (a person) as well as the index in the array, in order." + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Query Arrays and Sets with WOQL - TerminusDB", + "description": "A guide to show how to query arrays and sets with WOQL in your TerminusDB and TerminusCMS projects.", + "og_image": "https://assets.terminusdb.com/docs/woql-query-arrays-sets.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "How to Group Results in WOQL" + }, + "slug": "group-query-results", + "body": { + "@type": "Body", + "value": "> To use this HowTo, first [clone the Star Wars demo](/docs/clone-a-demo-terminuscms-project/) into your team on TerminusCMS. You will then have full access to the data needed for this tutorial.\n\n## How to use Group By\n\nIf we need to group variables according to some criteria, we can create an aggregate of solutions using `group_by`.\n\nA group by is composed of a _focus_, a _template_, and a _group_ together with a query.\n\nWe will demonstrate this with the following query:\n\n```javascript\nlet v = Vars(\"person\", \"label\", \"eyes\", \"group\");\nlimit(1)\n.group_by(\n \"eyes\",\n [\"label\"],\n v.group,\n and(triple(v.person, \"rdf:type\", \"@schema:People\"),\n triple(v.person, \"label\", v.label),\n triple(v.person, \"eye_color\", v.eyes)))\n```\n\nThe first argument, here `\"eyes\"` refers to the eyes variable, and is the variable around which to form the group, the _focus_.\n\nThe second `[\"label\"]` is the _template_, which refers to the variable `\"label\"`. The template will be those things grouped under the first variable.\n\nThe third variable `v.group`, is the _group_ variable, which will include groups of templates for each set of solutions which shares a _focus_.\n\nThis raw query output will be:\n\n```\n{\n \"eyes\": {\n \"@type\": \"xsd:string\",\n \"@value\": \"black\"\n },\n \"group\": [\n [{\n \"@type\": \"xsd:string\",\n \"@value\": \"Greedo\"\n }],\n [{\n \"@type\": \"xsd:string\",\n \"@value\": \"Nien Nunb\"\n }],\n [{\n \"@type\": \"xsd:string\",\n \"@value\": \"Gasgano\"\n }],\n [{\n \"@type\": \"xsd:string\",\n \"@value\": \"Kit Fisto\"\n }],\n [{\n \"@type\": \"xsd:string\",\n \"@value\": \"Plo Koon\"\n }],\n [{\n \"@type\": \"xsd:string\",\n \"@value\": \"Lama Su\"\n }],\n [{\n \"@type\": \"xsd:string\",\n \"@value\": \"Taun We\"\n }],\n [{\n \"@type\": \"xsd:string\",\n \"@value\": \"Shaak Ti\"\n }],\n [{\n \"@type\": \"xsd:string\",\n \"@value\": \"Tion Medon\"\n }],\n [{\n \"@type\": \"xsd:string\",\n \"@value\": \"BB8\"\n }]\n ],\n \"label\": null,\n \"person\": null\n}\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "How to Group Results in WOQL", + "description": "A guide to show how to group results of data in your TerminusCMS and TerminusDB projects using WOQL.", + "og_image": "https://assets.terminusdb.com/docs/woql-group-query-results.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Path Queries in WOQL" + }, + "slug": "path-queries-in-woql", + "body": { + "@type": "Body", + "value": "> To use this HowTo, first [clone the Star Wars demo](/docs/clone-a-demo-terminuscms-project/) into your team on TerminusCMS. You will then have full access to the data needed for this tutorial.\n\n## How to use `path`\n\nTerminusCMS gives us [path queries](/docs/path-query-reference-guide/) which allow us to succinctly express chains of relationships.\n\nThe `path` keyword allows you to find a path through the graph traversing intermediate edges. An example would be finding a group of individuals who have at some point shared a vehicle as a pilot or piloted another vehicle that in turn was shared with someone. This is a _transitive_ relationship and will explore the entire graph.\n\nFor instance\n\n```javascript\nlet v = Vars(\"person1\", \"person2\");\npath(v.person1, \"()+\", v.person2)\n```\n\nThis `path` means we follow the `pilot` field _backwards_ (because of the `<` arrow), to the vehicle of which the person is a pilot and then follow it forwards `pilot>` any number of times _but at least once_ which is what the `+` means.\n\nThe path itself can also be returned by adding another field, as so:\n\n```javascript\nlet v = Vars(\"person1\", \"person2\", \"path\");\npath(v.person1, \"()+\", v.person2, v.path)\n```\n\nThis can be inspected to understand the manner in which we got from `person1` to `person2`." + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "How to do Path Queries in WOQL - TerminusDB", + "description": "A guide to show how to do path queries in WOQL for your TerminusCMS and TerminusDB projects.", + "og_image": "https://assets.terminusdb.com/docs/woql-path-query.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Mathematical Operations in WOQL" + }, + "slug": "maths-based-queries-in-woql", + "body": { + "@type": "Body", + "value": "WOQL has a number of mathematical operations that can be performed. These include, `plus`, `minus`, `divide`, `times`, `div` (for integer division), `exp` and `floor`.\n\nTo use these operations you need to `evaluate` an arithmetic expression, and then you will be able to bind the result to a variable.\n\nFor instance:\n\n```javascript\nlet v = Vars(\"result\");\nevaluate(times(2,3), v.result)\n```\n\nThis will store the value of 2 times 3 in the variable `result`. The bindings which result from this query are:\n\n```\n[ {\"result\": {\"@type\":\"xsd:decimal\", \"@value\":12}} ]\n```\n\nYou can also chain these together, to build up more complicated computations, or use the results obtained by queries to derive new values.\n\n```javascript\nlet v = Vars(\"result1\", \"result2\");\nand(evaluate(times(2,3), v.result1),\n evaluate(times(v.result1,3), v.result2))\n```\n\nWhich results in:\n\n```\n[ {\"result1\": {\"@type\":\"xsd:decimal\", \"@value\":6},\n \"result2\": {\"@type\":\"xsd:decimal\", \"@value\":18}} ]\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Mathematical Operations in WOQL - TerminusDB", + "description": "A guide to show how to how to perform mathematical operations using WOQL ", + "og_image": "https://assets.terminusdb.com/docs/woql-maths-query.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Schema Queries with WOQL" + }, + "slug": "schema-queries-with-woql", + "body": { + "@type": "Body", + "value": "> To use this HowTo, first [clone the Star Wars demo](/docs/clone-a-demo-terminuscms-project/) into your team on TerminusCMS. You will then have access to the data needed for this tutorial.\n\n## Finding elements from the schema.\n\nIn order to query the schema, you can use _graph_ arguments to WOQL. TerminusCMS stores each branch as a pair of graphs, an instance graph and a schema graph.\n\nWe can specify the graph by passing it as an argument to the `quad` word.\n\nTo find all classes in the schema we can write:\n\n```javascript\nlet v = Vars(\"cls\");\nquad(v.cls, \"rdf:type\", \"sys:Class\", \"schema\")\n```\n\nThis results in:\n\ncls\n\n@schema:Film\n\n@schema:People\n\n@schema:Planet\n\n@schema:Species\n\n@schema:Starship\n\n@schema:Vehicle\n\nThe `@schema` denotes the default schema prefix, and makes it clear that this identifier lives in the schema name space rather than the data name space.\n\nWe can also use the typical `triple` word if we use `from` to set our default graph to `schema` instead of `instance`.\n\n```javascript\nlet v = Vars(\"cls\");\nfrom(\"schema\")\n .triple(v.cls, \"rdf:type\", \"sys:Class\")\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Schema Queries with WOQL - TerminusDB", + "description": "A guide to show how to query schema with WOQL in your TerminusDB and TerminusCMS projects.", + "og_image": "https://assets.terminusdb.com/docs/woql-query-schema.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "How to Curate & Import Data" + }, + "slug": "curate-and-import-data", + "body": { + "@type": "Body", + "value": "[Curate with Dashboard](/docs/use-the-admin-ui-curate-and-import-data/)[Import with Python](/docs/import-data-with-python-client/)" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "How to Curate & Import Data", + "description": "How to guides for curating and importing data into TerminusCMS and TerminusDB", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Use the TerminusCMS Dashboard to Curate Data & Content" + }, + "slug": "use-the-admin-ui-curate-and-import-data", + "body": { + "@type": "Body", + "value": "The TerminusCMS dashboard features a data and content editing section called the Document Explorer. It is here where users can add, edit and delete content and data directly into the backend.\n\nIn this example, we've cloned the [Star Wars demo project](/docs/clone-a-demo-terminuscms-project/).\n\nFirst, select the Star Wars project (or an existing project of your own) and navigate to the document explorer section by selecting the third icon on the left, the document with a tick.\n\n![TerminusCMS document explorer to edit content via the UI](https://assets.terminusdb.com/docs/document-explorer-home.png)\n\nThe screen displays a list of documents that are included within the project's schema and the number of documents within the database. It also includes a list of the documents on the left with a `+` symbol to add a new one.\n\n## View and filter documents\n\nClick on film (from the left or on the main screen). This will produce a list of the Star Wars films.\n\nIf it is a long list, you can use the filter to narrow down the results. In this example, we have added a rule to filter the films using the director property of the document specifying it equals _George Lucas_.\n\n![Filtering documents based on its properties in the document explorer section of the TerminusCMS dashboard](https://assets.terminusdb.com/docs/document-explorer-filter-view.png)\n\nDepending on the property you filter by, you can use these filter parameters -\n\n* Equals\n* Does not equal\n* Starts with\n* Contains\n* Greater than\n* Greater than or equal to\n* Less than\n* Less than or equal to\n\nYou can also group filters to combine multiple properties.\n\nThere is also a GraphQL query tab that displays how the document can be queried and the structure of any filters applied.\n\nTo view a document, click on it from the table view. This will open up that document where you can edit it.\n\nEditing, adding, and deleting content and data will first create a change request.\n\n## Change Requests\n\nTo edit, add, or delete a document you must first create a change request. A change request creates a branch of the database at that moment and lets you make any changes to this branch, safely away from live data. This process happens automatically. When selecting to edit, add, or delete a document you will be prompted to open a change request.\n\nIn this example, we're going to add Even Piell, a character in The Phantom Menace, to the People documents. We choose either the plus next to `People` on the left, or select `Add new People` from the top right.\n\nYou will then be prompted with a popup.\n\n![create a new change request to make changes to content.](https://assets.terminusdb.com/docs/create-a-new-change-request.png)\n\nGive the change request and title and description. If you're working with others, provide a good title and description so they have some context if they review the request.\n\nSelect `Start a change request`. You'll then be in the change request branch to make changes.\n\nThe screen looks like this now. You will notice on the left, and in the top bar, there is a notice that informs you that you're in a change request with the title given. We have expanded the top bar using the dropdown arrow to show the options available. You can -\n\n* Exit the change request - Come back at a later date to pick up your changes.\n* Ready for review - This sends the change request for review to either be accepted and merged, or rejected and deleted. _Make sure you are finished with your changes before sending it for review_.\n\nFor this how-to guide's flow, we'll skip adding the document here and continue it in the next section. We will continue with the change request and hypothetically make some changes to show you how change requests work.\n\n### Change Request Home\n\nFor open change requests, ones sent for review, and approved or rejected change requests, you need to navigate to the change request section by clicking the last icon on the left, with the merge symbol.\n\n![Manage change requests in the TerminusCMS dashboard](https://assets.terminusdb.com/docs/change-request-screen-open.png)\n\nThere are four tabs on this screen:\n\n* **Open:** These are change requests that have been exited rather than submitted for review. You can click `keep editing` to carry on with your changes or `submit it for review`.\n* **Review:** Change requests submitted for review are added here.\n* **Merged:** Accepted and approved change requests go here. On this screen, you can see past change requests and view the details to see what changed.\n* **Rejected:** Change requests that have been rejected.\n\n### Reviewing Change Requests\n\nA user has added some documents and made some changes and submitted the change request for review.\n\n![Change requests ready for review are listed in chronological order](https://assets.terminusdb.com/docs/change-request-waiting-for-review.png)\n\nThe requests are listed in chronological order. To review the change request, select the `Review` button.\n\nThe review screen will tell you who has made the change request and allow you to add notes and accept or reject the change request.\n\n![accept or reject a change request and leave a comment to explain why.](https://assets.terminusdb.com/docs/change-request-review-comment.png)\n\nFurther below the comments section, there is a diff view to display all of the changes that have been made to make reviewing faster and easier.\n\n![change requests feature a diff viewer to make review processes quicker.](https://assets.terminusdb.com/docs/change-request-review-diff.png)\n\nTo accept or reject the change request. Press the corresponding button.\n\n### Conflict Checking\n\nIn some cases when a change request has been opened and worked on, other users may have merged change requests. This results in your change request becoming out-of-date as it was a snapshot of before the recently merged change requests took place.\n\nTerminusCMS checks the commit history when you begin to review a change request to ensure it includes the latest data. If it is out-of-date it flags a message and prompts you to update it to ensure no past changes are stomped.\n\n![A message to update the change request to the latest database.](https://assets.terminusdb.com/docs/change-request-out-of-date-message.png)\n\n## Adding, Editing, & Deleting Documents\n\nAdding, editing, and deleting documents is straightforward.\n\n### Adding a document\n\nNavigate to the Document Explorer by clicking on the document with a tick icon on the left.\n\n![Filtering documents based on its properties in the document explorer section of the TerminusCMS dashboard](https://assets.terminusdb.com/docs/document-explorer-filter-view.png)\n\nEither -\n\n1. Click the plus symbol next to the document you wish to add from the left, or\n2. Click into a document and on the top right, click the `Add New Document` button.\n\nCreate a new change request, see the section above for details.\n\nGo ahead and fill in the form. The fields of the form will provide detail about what format is required. Any field with an asterisk denotes that it is mandatory.\n\nSubmit your changes by pressing the `Submit` button.\n\n_You will need to submit and review the change request for the changes to be applied_.\n\n### Editing\n\nLet's assume you're in a change request.\n\nFind the document you want to edit and click on it.\n\n![Edit or delete a document from within TerminusCMS's Document Explorer](https://assets.terminusdb.com/docs/document-explorer-edit-or-delete.png)\n\nPress the `Edit` button.\n\nMake your changes.\n\nEnsure to press `Submit` to commit the changes to the change request.\n\n_You will need to submit and review the change request for the changes to be applied_.\n\n### Deleting\n\nFind the document you want to delete and click on it.\n\nSelect the `red bin icon`.\n\nConfirm you wish to delete the document.\n\n_You will need to submit and review the change request for the changes to be applied_." + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Curate Data with the TerminusCMS Dashboard", + "description": "A how-to guide describing how to use the TerminusCMS dashboard to add, edit, and delete content and data", + "og_image": "https://assets.terminusdb.com/docs/document-explorer-home.png" + }, + "media": [ + { + "@type": "Media", + "alt": "TerminusCMS document explorer to edit content via the UI", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "TerminusCMS document explorer to edit content via the UI" + }, + "value": "https://assets.terminusdb.com/docs/document-explorer-home.png" + }, + { + "@type": "Media", + "alt": "Filtering documents based on its properties in the document explorer section of the TerminusCMS dashboard", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "Filtering documents based on its properties in the document explorer section of the TerminusCMS dashboard" + }, + "value": "https://assets.terminusdb.com/docs/document-explorer-filter-view.png" + }, + { + "@type": "Media", + "alt": "create a new change request to make changes to content.", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "create a new change request to make changes to content." + }, + "value": "https://assets.terminusdb.com/docs/create-a-new-change-request.png" + }, + { + "@type": "Media", + "alt": "Manage change requests in the TerminusCMS dashboard", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "Manage change requests in the TerminusCMS dashboard" + }, + "value": "https://assets.terminusdb.com/docs/change-request-screen-open.png" + }, + { + "@type": "Media", + "alt": "Change requests ready for review are listed in chronological order", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "Change requests ready for review are listed in chronological order" + }, + "value": "https://assets.terminusdb.com/docs/change-request-waiting-for-review.png" + }, + { + "@type": "Media", + "alt": "accept or reject a change request and leave a comment to explain why.", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "accept or reject a change request and leave a comment to explain why." + }, + "value": "https://assets.terminusdb.com/docs/change-request-review-comment.png" + }, + { + "@type": "Media", + "alt": "change requests feature a diff viewer to make review processes quicker.", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "change requests feature a diff viewer to make review processes quicker." + }, + "value": "https://assets.terminusdb.com/docs/change-request-review-diff.png" + }, + { + "@type": "Media", + "alt": "A message to update the change request to the latest database.", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "A message to update the change request to the latest database." + }, + "value": "https://assets.terminusdb.com/docs/change-request-out-of-date-message.png" + }, + { + "@type": "Media", + "alt": "Filtering documents based on its properties in the document explorer section of the TerminusCMS dashboard", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "Filtering documents based on its properties in the document explorer section of the TerminusCMS dashboard" + }, + "value": "https://assets.terminusdb.com/docs/document-explorer-filter-view.png" + }, + { + "@type": "Media", + "alt": "Edit or delete a document from within TerminusCMS's Document Explorer", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "Edit or delete a document from within TerminusCMS's Document Explorer" + }, + "value": "https://assets.terminusdb.com/docs/document-explorer-edit-or-delete.png" + } + ] + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Schema Reference Guide" + }, + "slug": "schema-reference-guide", + "body": { + "@type": "Body", + "value": "The TerminusDB schema language enables documents and their relationships to be specified using simple JSON syntax. This syntax makes it as easy as possible to specify a JSON object to automatically convert to a graph. This approach enables data to be viewed as collections of documents or as knowledge graphs of interconnected objects.\n\n### Schema Objects\n\nA JSON object in TerminusDB schema is composed of **key-value** pairs.\n\n#### Key\n\nA key is one of two values, **keyword** or **property**, described in the table below. The full schema definition is a stream or list of these values or JSON objects.\n\n#### Table: Types of keys\n\nKey type\n\nExample\n\nDescription\n\n**keyword**\n\n`@id`\n\nStarts with `@`, has a value with a special meaning.\n\n**property**\n\n`name`\n\nDoes not start with `@`, has a value with a **range** type.\n\n### Class definition\n\nThe basic unit of specification is a **class**. A class definition is a schema object with the keyword `@type` with type value `Class`. The keyword `@id` specifies the name of the class. The example below define a class named `Person` with a property `name` of type `xsd:string`. Search XSD definitions for more information about types.\n\n#### Code: The basic unit of specification\n\n```\n{ \n \"@type\" : \"Class\",\n \"@id\" : \"Person\",\n \"name\" : \"xsd:string\" \n}\n```\n\n### Context object\n\nThe **context object** is a special schema object affecting the entire schema. The context object is specified by the special `@type` value `@context`. An example:\n\n#### Code: The context object\n\n```\n{ \"@type\" : \"@context\",\n \"@schema\" : \"http://terminusdb.com/schema/woql#\",\n \"@base\" : \"terminusdb://woql/data/\",\n \"xsd\" : \"http://www.w3.org/2001/XMLSchema#\",\n \"@documentation\" : \n {\n \"@title\" : \"WOQL schema\",\n \"@authors\" : [\"Gavin Mendel-Gleason\"],\n \"@description\" : \"The WOQL schema providing a complete specification of the WOQL syntax. \n This enables: \n * WOQL queries to be checked for syntactic correctness.\n * Storage and retrieval of queries. \n * Queries to be associated with data products.\n * Helps to prevent errors and detect conflicts in merge of queries.\", \n } \n}\n```\n\nThis example does the following:\n\n* Defines default prefixes in `@schema` and `@base` to use for the schema and data.\n* Defines the prefix `xsd` enabling vocabulary based on different URL prefixes.\n* For example, specify `xsd:string` to denote `http://www.w3.org/2001/XMLSchema#string`\n* Documents the schema in the `@documentation` value, providing:\n* `@title`\n* `@authors`\n* `@description`\n\n#### Context Prefixes\n\nAll properties in the context object that do not start with `@`, such as `xsd`, are URI definitions. They must be of the form shown below. Prefix and URI are defined by their respective regular expressions. That is, a prefix has an identifier starting with an alphabetic character followed by alphanumeric characters. The URI has a protocol followed by valid URI characters. Each prefix is paired with a URI.\n\n```\nPrefix := \":alpha::alphaNum:*\"\nURI := \":alpha:alphaNum:*://:uriChar:*\"\n\n{ ...\n Prefix : URI\n ... }\n```\n\n## Context keywords\n\nA list of keywords used in the context object.\n\n### @schema\n\nThe `@schema` keyword specifies the default URI expansion to use for all elements of the schema. In the example below, the class name `NamedQuery` expands to `http://terminusdb.com/schema/woql#NamedQuery`.\n\n#### Code: Context keyword @schema\n\n```\n{ \n \"@type\" : \"@context\",\n \"@schema\" : \"http://terminusdb.com/schema/woql#\",\n \"@base\" : \"terminusdb://woql/data/\" \n}\n{ \n \"@id\" : \"NamedQuery\",\n \"@type\" : \"Class\",\n \"@key\" :\n { \n \"@type\" : \"Lexical\",\n \"@fields\" : [ \"name\" ]\n },\n \"name\" : \"xsd:string\",\n \"query\" : \"Query\" \n}\n```\n\n### @base\n\n`@base` specifies the default URI expansion used for all elements of instance data. In the previous schema definition, and given the document in the instance graph example below, the id `NamedQuery_my_query` expands to `terminusdb://woql/data/NamedQuery_my_query`.\n\n#### Code: A document in the instance graph\n\n```\n{ \n \"@type\" : \"NamedQuery\",\n \"@id\" : \"NamedQuery_my_query\",\n \"name\" : \"my_query\",\n \"query\" : \n { \n \"@type\" : \"True\" \n }\n}\n```\n\n### @documentation\n\n`@documentation` specifies documentation global to the entire schema. See the `@documentation` section in the previous context object example. The `@documentation` tag can be a single value, or it can be a list with each element having an additional `@langugage` tag. The `@language` tag must have an IANA language code, and this will be used to select appropriate descriptions when internationalising the schema.\n\nThe documentation section contains the keywords:\n\n#### @title\n\nThe `@title` of the schema to display.\n\n#### @description\n\nA long-form `@description` of the purpose of the schema, the type of documents contained in the schema, and keywords useful for searching for the type of content that the schema encodes.\n\n#### @authors\n\nA list of strings of `@authors` involved in writing the schema.\n\n#### @metadata\n\nIf you would like to add arbitrary JSON structured metadata to a schema, you can place it in the `@metadata` field of the context object. This can be used to store data product-wide information in a structured format. For instance:\n\n```\n{ \"@type\" : \"@context\",\n \"@base\" : \"http://my_stuff/\",\n \"@schema\" : \"http://my_schema#\",\n \"@metadata\" : { \"configuration\" : { \"frob\" : 29 } }\n}\n```\n\n#### @language\n\nIf you use the `@language` code, specific documentation results can appear in different circumstances depending on the users language preferences.\n\nAn example of the `@language` tag for a context is as follows:\n\n```\n{ \"@base\": \"terminusdb:///data/\",\n \"@schema\": \"terminusdb:///schema#\",\n \"@type\": \"@context\",\n \"@documentation\" : [{\n \"@language\" : \"en\",\n \"@title\" : \"Example Schema\",\n \"@description\" : \"This is an example schema. We are using it to demonstrate the ability to display information in multiple languages about the same semantic content.\",\n \"@authors\" : [\"Gavin Mendel-Gleason\"]\n },\n { \"@language\" : \"ka\",\n \"@title\" : \"მაგალითი სქემა\",\n \"@description\" : \"ეს არის მაგალითის სქემა. ჩვენ ვიყენებთ მას, რათა ვაჩვენოთ ინფორმაციის მრავალ ენაზე ჩვენების შესაძლებლობა ერთი და იმავე სემანტიკური შინაარსის შესახებ.\",\n \"@authors\" : [\"გავინ მენდელ-გლისონი\"]\n }\n ],\n \"xsd\" : \"http://www.w3.org/2001/XMLSchema#\"\n}\n```\n\n## Document definition keywords\n\nA document definition includes several properties, and the keywords, prefixed `@`, describing class behavior.\n\n### @type\n\nThe `@type` of the object. At the schema level, this is one of: `Enum`, `Class`, `TaggedUnion` and `Unit`.\n\n### @metadata\n\nIf you would like to add arbitrary JSON structured metadata to a class, you can place it in the `@metadata` field of the class. This can be used to direct various approaches to display of the class, or associated information for backend or front-ends which may have different requirements. It is generally good practice to keep important metadata one level deeper in a JSON object so as to leave space for other kinds of metadata. For instance:\n\n```\n{ \"@type\" : \"Class\",\n \"@id\" : \"MyClass\",\n \"@metadata\" : { \"display_format\" : { \"colour\" : \"Blue\", \"size\" : [100,400]}},\n \"name\" : \"xsd:string\" }\n```\n\n#### Render as Markdown\n\nTo render properties as Markdown to enable users to curate data using a Markdown editor, specify `render_as` and the property in the `@metadata` field. The example below shows a document with the ID `People` with the `desc` string property set to render as Markdown:\n\n```\n{\n \"@id\": \"People\",\n \"@type\": \"Class\",\n \"@metadata\": {\n \"render_as\": {\n \"desc\": \"markdown\"\n }\n },\n \"desc\": {\n \"@class\": \"xsd:string\",\n \"@type\": \"Optional\"\n },\n },\n \"name\": {\n \"@class\": \"xsd:string\",\n \"@type\": \"Optional\"\n },\n \"gender\": {\n \"@class\": \"xsd:string\",\n \"@type\": \"Optional\"\n }\n```\n\n#### Order By\n\nYou can specify the order of properties within your schema so that it is displayed in the document explorer in an order specified by you. Using `order_by` in the `metadata` field in square brackets, list the property order you want, for example:\n\n```\n{\n \"@id\": \"People\",\n \"@type\": \"Class\",\n \"@metadata\": {\n \"order_by\": [\n \"name\",\n \"hair_color\",\n \"eye_color\",\n \"gender\",\n \"birth_year\"\n ],\n },\n...\n```\n\n### Class\n\n`Class` designates a standard class document. It contains the definition of several properties and keywords describing various class attributes. An example of a class, and an instance of the class:\n\n#### Code: An example of a class\n\n```\n{ \n \"@id\" : \"Dog\",\n \"@type\" : \"Class\",\n \"@base\" : \"Dog_\",\n \"@key\" : \n { \n \"@type\" : \"Lexical\",\n \"@fields\" : [ \"name\" ] \n },\n \"name\" : \"xsd:string\",\n \"hair_colour\" : \"Colour\" \n}\n```\n\n#### Code: An example of a class instance\n\n```\n{ \n \"@type\" : \"@context\",\n \"@base\" : \"http://i/\",\n \"@schema\" : \"http://s#\" \n}\n{ \n \"@type\" : \"Dog\",\n \"@id\" : \"Dog_Cerberus\",\n \"name\" : \"Cerberus\",\n \"hair_colour\" : \"Grey\" \n}\n```\n\n### Enum\n\nAn `Enum` is a non-standard class in which each instance is a simple URI with no additional structure. To be a member of the class, you must be one of the referent URIs. An `Enum` example with an extension `Blue` is s shown below. In the database, the actual URI for an Enum is expanded with the preceding type name, so the `Blue` extension becomes `http://s#PrimaryColour/Blue`\n\n#### Code: An example of an enum class\n\n```\n{ \n \"@type\" : \"Enum\",\n \"@id\" : \"PrimaryColour\",\n \"@value\" : \n [\n \"Red\", \n \"Blue\", \n \"Yellow\"\n ] \n}\n```\n\n```\n\"Blue\"\n```\n\n### TaggedUnion\n\nA `TaggedUnion` specifies mutually exclusive properties. This is useful when there is a disjoint choice between options.\n\nExamples below of a schema with a TaggedUnion and a concrete TaggedUnion class extension. In these examples, the `BinaryTree` class specifies a `TaggedUnion` enabling a choice between a `leaf` (with no value), or a `node` class with a value and branches.\n\n#### Code: An example schema with a TaggedUnion\n\n```\n{ \n \"@type\" : \"@context\",\n \"@base\" : \"http://i/\",\n \"@schema\" : \"http://s#\" \n}\n{ \n \"@id\" : \"BinaryTree\",\n \"@type\" : \"TaggedUnion\",\n \"@base\" : \"binary_tree_\",\n \"@key\" : \n { \n \"@type\" : \"ValueHash\" \n },\n \"leaf\" : \"sys:Unit\",\n \"node\" : \"Node\" \n}\n{ \n \"@id\" : \"Node\",\n \"@type\" : \"Class\",\n \"@key\" : \n { \n \"@type\" : \"ValueHash\" \n },\n \"value\" : \"xsd:integer\",\n \"left\" : \"BinaryTree\",\n \"right\" : \"BinaryTree\" \n}\n```\n\n#### Code: An example TaggedUnion class extension\n\n```\n{ \n \"@type\" : \"Node\",\n \"value\" : 0,\n \"left\" : \n {\n \"@type\" : \"BinaryTree\",\n \"leaf\" : []\n },\n \"right\": \n { \n \"@type\" : \"BinaryTree\",\n \"leaf\" : []\n }\n}\n```\n\n### @oneOf\n\nThe `TaggedUnion` is a special case and syntactic sugar for the more general case of collections of disjoint properties. These more complex cases can be represented by inheriting from a number of `TaggedUnion`s, but they may also be given explicitly using the `@oneOf` field, together with a Class.\n\nThe value of the `@oneOf` field is a set, so can be any number of documents all of which have mutually disjoint properties, but which can coexist. Examples with more than one disjoint property are given below.\n\n#### Code: An example schema with @oneOf\n\n```\n{\n \"@type\" : \"@context\",\n \"@base\" : \"http://i/\",\n \"@schema\" : \"http://s#\"\n}\n{\n \"@id\" : \"IntOrString\",\n \"@type\" : \"Class\",\n \"@oneOf\" :\n {\n \"integer\": \"xsd:integer\",\n \"string\" : \"xsd:string\"\n }\n}\n{\n \"@id\" : \"Friend\",\n \"@type\" : \"Class\",\n \"@key\" :\n {\n \"@type\" : \"Lexical\",\n \"@fields\": [\"name\"]\n },\n \"name\" : \"xsd:string\"\n}\n{\n \"@id\" : \"Toy\",\n \"@type\" : \"Class\",\n \"@key\" :\n {\n \"@type\" : \"Lexical\",\n \"@fields\": [\"name\"]\n },\n \"name\" : \"xsd:string\"\n}\n{\n \"@id\" : \"Pet\",\n \"@type\" : \"Class\",\n \"name\" : \"xsd:string\",\n \"@oneOf\" : [\n {\n \"cat\" : \"Toy\",\n \"dog\" : \"Friend\"\n },\n {\n \"employers\" : \"xsd:positiveInteger\",\n \"unemployed\": \"xsd:string\"\n },\n ]\n}\n```\n\n#### Code: Examples of `@oneOf` class extensions\n\n```\n{\n \"@type\" : \"IntOrString\",\n \"integer\" : 0\n}\n```\n\n```\n{\n \"@type\" : \"IntOrString\",\n \"string\" : \"zero\"\n}\n```\n\n```\n{\n \"@type\" : \"Pet\",\n \"cat\" : {\n \"@type\": \"Toy\",\n \"name\" : \"ball of string\"\n },\n \"employers\": 5\n}\n```\n\n```\n{\n \"@type\" : \"Pet\",\n \"dog\" : {\n \"@type\": \"Person\",\n \"name\" : \"Jim\"\n },\n \"unemployed\": \"A house pet.\"\n}\n```\n\n```\n{\n \"@type\" : \"Pet\",\n \"string\" : \"zero\"\n}\n```\n\nBut not:\n\n```\n{\n \"@type\" : \"IntOrString\",\n \"integer\" : 0,\n \"string\" : \"zero\"\n}\n```\n\n### Unit\n\nThe `Unit` type has a single extension `[]`. This is used when only the presence of the property is interesting, but it has no interesting value. See the `BinaryTree` in the [TaggedUnion class extension](#codeanexampletaggedunionclassextension) example above.\n\n### @id\n\nThe `@id` key of a class defines the class name and identifier. The name uniquely defines the class, enabling the class to be updated, retrieved, and deleted. In the example below, the class is named `NamedQuery`. It does not have a fully qualified URL or prefix, so it is implicitly based on the URI given for `@schema`.\n\n#### Code: The @id key of a class\n\n```\n{ \n \"@id\" : \"NamedQuery\",\n \"@type\" : \"Class\",\n \"@key\" : \n { \n \"@type\" : \"Lexical\",\n \"@fields\" : [ \"name\" ] \n },\n \"name\" : \"xsd:string\",\n \"query\" : \"Query\" \n}\n```\n\n### @key\n\n`@key` specifies the mechanism to define the `@id` of documents in the database, similar to a primary key in relational database terms. Valid key types are `Lexical`, `Hash`, `ValueHash`, `Random`.\n\nIf the key `@base` is specified in the class, then this is pre-pended to the key. If this is a fully qualified URI then it is complete, otherwise, it is combined with the value of `@base` from the context.\n\n#### Lexical\n\nA `Lexical` key specifies a URI name formed from a URI encoded combination of all `@fields` arguments provided, in the order provided. An example is shown below. With this key type (or key strategy) a URI is formed from the combination of `first_name` and `last_name`. If `@base` is specified in the class, this is prepended.\n\nGiven the [simple document definition](#codeasimpledocumentdefinition) below, this will either generate (if `@id` is not supplied) or check that the URI `http://example.com/people/Person_Hasdrupal_Barca` is the `@id` element.\n\n#### Code: An example Lexical key\n\n```\n{ \n \"@type\" : \"@context\",\n \"@schema\" : \"http://example.com/people#\",\n \"@base\" : \"http://example.com/people/\" \n}\n{ \n \"@id\" : \"Person\",\n \"@type\" : \"Class\",\n \"@base\" : \"Person_\",\n \"@key\" : \n {\n \"@type\" : \"Lexical\",\n \"@fields\" : \n [ \n \"first_name\", \n \"last_name\" \n ]\n },\n \"first_name\" : \"xsd:string\",\n \"last_name\" : \"xsd:string\",\n \"year_of_birth\" : \"xsd:gYear\"\n}\n```\n\n#### Code: A simple document definition\n\n```\n{ \n \"@type\" : \"Person\",\n \"first_name\" : \"Hasdrupal\",\n \"last_name\" : \"Barca\",\n \"year_of_birth\" : \"-245\" \n}\n```\n\n#### Hash\n\n`Hash` is generated in the same way as `Lexical` except that values are first hashed using the SHA-256 hash algorithm.\n\nUse this where there:\n\n* Are numerous items that form the key making the URI unwieldy.\n* Is no need for the URI to inform the user of the content of the object.\n* Is a requirement that data about the object is not be revealed by the key.\n\nDefine a `Hash` in the same way as the [Lexical key strategy](#codeanexamplelexicalkey) example in the previous section, replacing the `@key` `@type` value from `Lexical` to `Hash`.\n\nGiven the [simple document definition](#codeasimpledocumentdefinition) in the previous section, the `@id` `Person_5dd7004081e437b3e684075fa3132542f5cd06c1` is generated.\n\n#### ValueHash\n\nThe `ValueHash` key generates a key defined as the downward transitive closure of the directed acyclic graph from the root of the document. This means you can produce a key that is entirely based on the entire data object. Note `ValueHash`:\n\n* Takes no additional keywords.\n* Objects must be directed acyclic graphs, they **cannot be cyclic**.\n\nIn the example below, `ValueHash` is formed only from the value of `layer:identifier`.\n\n#### Code: An example ValueHash key\n\n```\n{ \n \"@id\" : \"layer:Layer\",\n \"@type\" : \"Class\",\n \"@documentation\" : \n {\n \"@comment\" : \"A layer object which has the identifier used in storage.\",\n \"@properties\" : \n { \n \"layer:identifier\" : \"The layer identifier.\" \n }\n },\n \"@base\" : \"layer_data:Layer_\",\n \"@key\" : \n { \n \"@type\" : \"ValueHash\" \n },\n \"layer:identifier\" : \"xsd:string\" \n}\n```\n\n#### Random\n\nUse `Random` as a convenient key type when an object has no important characteristics that inform a key or does not need to be constructed such that it is reproducible. In the example below, the `@key` `@type` is defined as `Random`, meaning each new database that is added is unique regardless of label.\n\n#### Code: An example of a Random key\n\n```\n{\n \"@id\" : \"UserDatabase\",\n \"@type\" : \"Class\",\n \"@documentation\" : \n {\n \"@comment\" : \"A normal user database.\",\n \"@properties\" : \n {\n \"label\" : \"The label name of the database.\",\n \"comment\" : \"A comment associated with the database.\",\n \"creation_date\" : \"The time of creation of the database.\",\n \"state\" : \"The system transaction state of the database.\" \n }\n },\n \"@inherits\" : \"Database\",\n \"@key\" : \n {\n \"@type\" : \"Random\" \n },\n \"label\" : \"xsd:string\",\n \"comment\" : \"xsd:string\",\n \"creation_date\" : \"xsd:dateTime\",\n \"state\" : \"DatabaseState\" \n}\n```\n\n### @documentation\n\nUse `@documentation` to add documentation to the class and the property fields or values of the class. The `@documentation` can either be an object, or a list of objects with specified languages (and at most one default unspecified). An example using multiple languages might be:\n\n```\n{ \"@id\" : \"Example\",\n \"@type\" : \"Class\",\n \"@documentation\" : [\n {\n \"@label\" : \"Example\",\n \"@comment\" : \"An example class\",\n \"@properties\" : { \"name\" : { \"@label\" : \"name\",\n \"@comment\" : \"The name of the example object\" },\n \"choice\" : { \"@label\" : \"choice\",\n \"@comment\" : \"A thing to choose\" }}\n },\n {\n \"@language\" : \"ka\",\n \"@label\" : \"მაგალითი\",\n \"@comment\" : \"მაგალითი კლასი\",\n \"@properties\" : { \"name\" : { \"@label\" : \"სახელი\",\n \"@comment\" : \"მაგალითის ობიექტის სახელი\" },\n \"choice\" : { \"@label\" : \"არჩევანი\",\n \"@comment\" : \"რაც უნდა აირჩიოთ\" }}\n }\n ],\n \"name\" : \"xsd:string\"\n}\n```\n\nThe keywords of the `@documentation` object are `@comment` and either `@properties` or `@values` for standard classes or `Enums` respectively. Each of the `@properties` or `@values` can likewise have either a simple label, or an object with `@label` and `@comment (as above)`.\n\nFor `Enum` we can write as follows:\n\n```\n{\n \"@id\": \"Pet\",\n \"@type\": \"Enum\",\n \"@documentation\" : {\n \"@comment\" : \"What kind of pet?\",\n \"@values\" : {\n \"dog\" : \"A doggie\",\n \"cat\" : \"A kitty\"\n }\n },\n \"@value\" : [\"dog\",\"cat\"]\n}\n```\n\nFor a standard `Class` with one default language, we can write as follows:\n\n```\n{\n \"@id\": \"Person\",\n \"@type\": \"Class\",\n \"@documentation\" : {\n \"@comment\" : \"Information about people\",\n \"@values\" : {\n \"name\" : \"The persons name\",\n \"friends\" : \"The kinds of company someone keeps\"\n }\n },\n \"name\" : \"xsd:string\",\n \"friends\" : {\n \"@type\" : \"Set\",\n \"@class\" : \"Person\"\n }\n}\n```\n\n#### @comment\n\nThe `@comment` is the class description.\n\n#### @properties\n\nThe `@properties` keyword is a JSON object with pairs of the form:\n\n```\n{\n \"property_1\" : \"description_1\",\n\n ...\n\n \"property_n\" : \"description_n\"\n}\n```\n\nor with properties pointing to JSON objects, as:\n\n```\n{\n \"property_1\" : { \"@label\" : \"description_1\", \"@comment\" : \"comment_1\" },\n\n ...\n\n \"property_n\" : { \"@label\" : \"description_2\", \"@comment\" : \"comment_2\" }\n}\n```\n\n### @base\n\n`@base` specifies a prefix to prepare to the `@key`. This prefix is absolute if `@base` is a fully qualified URI, otherwise, it will, in turn, be prefixed by the system-wide `@base` definition. In the example below, the `@base` for the class is fully qualified after the `layer_data` prefix is expanded. This means the layer URIs have the form `terminusdb://layer/data/Layer_` followed by a random string.\n\n#### Code: An example of the @base keyword\n\n```\n{ \n \"@type\" : \"@context\",\n \"@documentation\" :\n {\n \"@title\" : \"The Ref schema\",\n \"@description\" : \"This is the Ref schema. It gives a specification for storage of references, branches and commits in our commit graph.\",\n \"@authors\" :\n [\n \"Gavin Mendel-Gleason\",\n \"Matthijs van Otterdijk\"\n ]\n },\n \"@base\" : \"terminusdb://ref/data/\",\n \"@schema\" : \"http://terminusdb.com/schema/ref#\",\n \"layer\" : \"http://terminusdb.com/schema/layer#\",\n \"layer_data\" : \"terminusdb://layer/data/\",\n \"xsd\" : \"http://www.w3.org/2001/XMLSchema#\"\n}\n{\n \"@id\" : \"layer:Layer\",\n \"@type\" : \"Class\",\n \"@documentation\" :\n {\n \"@comment\" : \"A layer object which has the identifier used in storage.\",\n \"@properties\" :\n {\n \"layer:identifier\" : \"The layer identifier.\"\n }\n },\n \"@base\" : \"layer_data:Layer_\",\n \"@key\" :\n {\n \"@type\" : \"ValueHash\"\n },\n \"layer:identifier\" : \"xsd:string\"\n}\n```\n\n### @subdocument\n\nThe `@subdocument` key is present with the value `[]` or it is not present.\n\nA class designated as a sub-document is considered to be completely owned by its containing document. It is not possible to directly update or delete a subdocument, but it must be done through the containing document. Currently, subdocuments **must have a key** that is `Random` or `ValueHash` (this restriction may be relaxed in the future.)\n\nSee below for examples of a subdocument declaration in a schema, and a corresponding subdocument.\n\n#### Code: An example subdocument declaration\n\n```\n{ \n \"@type\" : \"@context\",\n \"@base\" : \"terminusdb://i/\",\n \"@schema\" : \"terminusdb://s#\" \n}\n{ \n \"@type\" : \"Class\",\n \"@id\" : \"Person\",\n \"age\" : \"xsd:integer\",\n \"name\" : \"xsd:string\",\n \"address\" : \"Address\" \n}\n{ \n \"@type\" : \"Class\",\n \"@id\" : \"Address\",\n \"@key\" : \n {\n \"@type\" : \"Random\"\n },\n \"@subdocument\" : [],\n \"country\" : \"xsd:string\",\n \"postal_code\" : \"xsd:string\",\n \"street\" : \"xsd:string\"\n}\n```\n\n#### Code: An example subdocument\n\n```\n{ \n \"@type\" : \"Person\",\n \"@id\" : \"doug\",\n \"name\" : \"Doug A. Trench\",\n \"address\" : \n { \n \"@type\" : \"Address\",\n \"country\" : \"Neverlandistan\",\n \"postal_code\" : \"3\",\n \"street\" : \"Cool Harbour lane\"\n }\n}\n```\n\n### @abstract\n\nThe `@abstract` key is present with the value `[]` or it is not present.\n\nAn abstract class has no concrete referents. It provides a common superclass and potentially several properties shared by all of its descendants. Create useful concrete members using the `@inherits` keyword.\n\nAn example of the abstract keyword in a schema, and a concrete instance of the `Person` class, but not of the `NamedEntity` class:\n\n#### Code: An example of the abstract keyword\n\n```\n{ \n \"@type\" : \"@context\",\n \"@base\" : \"terminusdb://i/\",\n \"@schema\" : \"terminusdb://s#\" \n}\n{ \n \"@type\" : \"Class\",\n \"@abstract\" : [],\n \"@id\" : \"NamedEntity\",\n \"name\" : \"xsd:string\" \n}\n{ \n \"@type\" : \"Person\",\n \"@id\" : \"Person\",\n \"@inherits\" : [\"NamedEntity\"] \n}\n```\n\n```\n{ \n \"@type\" : \"Person\",\n \"@id\" : \"doug\",\n \"name\" : \"Doug A. Trench\" \n}\n```\n\n### @inherits\n\n`@inherits` enables classes to inherit properties (and the `@subdocument` designation) from parent classes. It does **not** inherit key strategies.\n\nThis inheritance tree is also available as a `subsumption` relation in the WOQL query language and provides semantics for **frames** in the **schema API**.\n\nThe range of `@inherits` can be a class or a list of classes. For example:\n\n```\n{ \n ...,\n\n \"@inherits\" : \"MyClass\",\n\n ... \n}\n```\n\nOr\n\n```\n{ \n ...,\n\n \"@inherits\" : \n [\n \"MyFirstClass\", \"MySecondClass\"\n ]\n\n ... \n}\n```\n\n#### Multiple inheritance\n\nMultiple inheritance is allowed as long as all inherited properties of the same name have the same range class. If range classes conflict, the schema check fails.\n\nAn example of inheritance of properties and an object meeting this specification:\n\n#### Code: An example of inheritance\n\n```\n{ \n \"@type\" : \"@context\",\n \"@base\" : \"http://i/\",\n \"@schema\" : \"http://s/\" \n}\n{ \n \"@id\" : \"RightHanded\",\n \"@type\" : \"Class\",\n \"right_hand\" : \"xsd:string\" \n}\n{ \n \"@id\" : \"LeftHanded\",\n \"@type\" : \"Class\",\n \"left_hand\" : \"xsd:string\" \n}\n{ \n \"@id\" : \"TwoHanded\",\n \"@type\" : \"Class\",\n \"@inherits\" : \n [ \n \"RightHanded\", \"LeftHanded\"\n ] \n}\n```\n\n```\n{ \n \"@type\" : \"TwoHanded\",\n \"@id\" : \"a two-hander\",\n \"left_hand\" : \"Pretty sinister\",\n \"right_hand\" : \"But this one is dexterous\" \n}\n```\n\n## @unfoldable\n\nThe `@unfoldable` key is present with the value `[]` or it is not present.\n\nIn the document API, when retrieving documents, the default behavior is for any linked document to be returned as an IRI, while subdocuments are fully unfolded and returned as a nested document. With the `@unfoldable` option set, linked documents will behave just like subdocuments, and will also be unfolded on retrieval.\n\nThe `@unfoldable` option can only be set on a class which does not directly or indirectly link to itself. This prevents a self-referencing document from being unfolded infinitely.\n\nThe purpose of `@unfoldable` is to be able to treat linked (top-level) documents as subdocuments in representation. Subdocuments can only be linked by one document, its owner, whereas normal documents can be linked by any number of other documents. If the desired result is to have a document linked by several other documents, but still have it fully unfolded on retrieval like a subdocument, use this option.\n\n### Code: An example unfoldable\n\n```\n{\n \"@type\" : \"@context\",\n \"@base\" : \"terminusdb://i/\",\n \"@schema\" : \"terminusdb://s#\"\n}\n{\n \"@type\" : \"Class\",\n \"@id\" : \"Person\",\n \"name\" : \"xsd:string\",\n \"address\" : \"Address\"\n}\n{\n \"@type\" : \"Class\",\n \"@id\" : \"Address\",\n \"@unfoldable\" : [],\n \"country\" : \"xsd:string\",\n \"postal_code\" : \"xsd:string\",\n \"street\" : \"xsd:string\"\n}\n```\n\n#### Code: an example set of documents\n\n```\n{\n \"@type\" : \"Address\",\n \"@id\" : \"Address/1\",\n \"country\" : \"Neverlandistan\",\n \"postal_code\" : \"3\",\n \"street\" : \"Cool Harbour lane\"\n}\n\n{\n \"@type\" : \"Person\",\n \"@id\" : \"Person/doug\",\n \"name\" : \"Doug A. Trench\",\n \"address\" : \"Address/1\"\n}\n\n{\n \"@type\" : \"Person\",\n \"@id\" : \"Person/phil\",\n \"name\" : \"Phil A. Trench\",\n \"address\" : \"Address/1\"\n}\n```\n\nThe above example shows both Doug and Phil using the same address document. On retrieval of all Persons, the document API returns these documents:\n\n```\n{\n \"@type\" : \"Person\",\n \"@id\" : \"Person/doug\",\n \"name\" : \"Doug A. Trench\",\n \"address\" : { \"@type\" : \"Address\",\n \"@id\" : \"Address/1\",\n \"country\" : \"Neverlandistan\",\n \"postal_code\" : \"3\",\n \"street\" : \"Cool Hasrbour lane\" }\n}\n{\n \"@type\" : \"Person\",\n \"@id\" : \"Person/phil\",\n \"name\" : \"Phil A. Trench\",\n \"address\" : { \"@type\" : \"Address\",\n \"@id\" : \"Address/1\",\n \"country\" : \"Neverlandistan\",\n \"postal_code\" : \"3\",\n \"street\" : \"Cool Hasrbour lane\" }\n}\n```\n\nThe address is fully unfolded in both documents despite not being a subdocument.\n\n## Class properties\n\nAll non-keywords are treated as properties of the class, with the form:\n\n```\n : \n```\n\nOr\n\n```\n : { \"@type\" : , \"@class\" : }\n```\n\n#### Range classes\n\nA range class is a concrete base type defined as any of the xsd types (see XSD), or a class defined in the current schema, including the current class.\n\nIn the example range class below, `first_name` and `last_name` are strings, `year_of_birth` is a year, and `friend` is any number of `Person` objects, in no particular order and without duplication. Also, see below [an example of a concrete set of documents](#codeanexampleofaconcretesetofdocuments) with this form.\n\n#### Code: An example range class\n\n```\n{ \n \"@type\" : \"@context\",\n \"@schema\" : \"http://example.com/people#\",\n \"@base\" : \"http://example.com/people/\" \n}\n{ \n \"@id\" : \"Person\",\n \"@type\" : \"Class\",\n \"@base\" : \"Person/\",\n \"@key\" : \n { \n \"@type\" : \"Lexical\",\n \"@fields\" : \n [ \n \"first_name\", \"last_name\" \n ]\n },\n \"first_name\" : \"xsd:string\",\n \"last_name\" : \"xsd:string\",\n \"knows\" : \n { \n \"@type\" : \"Set\", \n \"@class\" : \"Person\"\n },\n \"year_of_birth\" : \"xsd:gYear\" \n}\n```\n\n#### Code: An example of a concrete set of documents\n\n```\n{ \n \"@type\" : \"Person\",\n \"@id\" : \"Person/Hasdrubal_Barca\",\n \"first_name\" : \"Hasdrubal\",\n \"last_name\" : \"Barca\",\n \"knows\" : \n [\n \"Person/Imilce_Barca\",\n \"Person/Hannibal_Barca\"\n ],\n \"year_of_birth\" : \"-245\"\n}\n{ \n \"@type\" : \"Person\",\n \"@id\" : \"Person/Imilce_Barca\",\n \"first_name\" : \"Imilce\",\n \"last_name\" : \"Barca\",\n \"knows\" : \n [\n \"Person/Hasdrupal_Barca\",\n \"Person/Hannibal_Barca\"\n ],\n \"year_of_birth\" : \"-255\" \n}\n{ \n \"@type\" : \"Person\",\n \"@id\" : \"Person/Hannibal_Barca\",\n \"first_name\" : \"Hannibal\",\n \"last_name\" : \"Barca\",\n \"knows\" : \n [\n \"Person/Imilce_Barca\",\"Person/Hannibal_Barca\"\n ],\n \"year_of_birth\" : \"-247\" \n}\n```\n\n#### JSON Type\n\nTwo special JSON types exist in TerminusDB. One is for use as a subdocument, and is called `\"sys:JSON\"` and the type `\"sys:JSONDocument\"` which is used for type level. Both allow un-constrained and untypechecked documents which can be stored or retrieved as apparently unmodified JSON, but which are still indexed and searchable using WOQL.\n\nIds for subdocuments of type `\"sys:JSON\"` are formed from a hash of the content, meaning that subdocuments are shared if their content is the same.\n\nHowever, those of type `\"sys:JSONDocument\"` are assigned a random id, such that they can be retrieved, modified etc. Alternatively they can be assigned an id by passing in an id of the form `{ \"@id\" : \"JSONDocument/my_id_here\", ...}` making sure to use the prefix `\"JSONDocument\"` so as not to ensure we do not have any id conflicts with other document types.\n\n#### Code: An example of `\"sys:JSON\"`\n\n```\n{\n \"@type\" : \"@context\",\n \"@schema\" : \"http://example.com/people#\",\n \"@base\" : \"http://example.com/people/\"\n}\n{\n \"@type\" : \"Class\",\n \"@id\" : \"Person\",\n \"name\" : \"xsd:string\",\n \"metadata\" : \"sys:JSON\"\n}\n```\n\nWe can now have a well typed `\"Person\"` which contains a metadata field of type `\"sys:JSON\"` which is unconstrained JSON as follows:\n\n```\n{\n \"@type\" : \"Person\",\n \"name\" : \"John\",\n \"metadata\" : { \"theme\" : \"Dark\", \"last_visit\" : \"10-01-02\" }\n}\n```\n\n#### Code: An example of `\"sys:JSONDocument\"`\n\nUsing the `{ \"json\" : true }` option to the insert API, or using the TerminusDB CLI with the `-j` or `--json=true` flag we can insert an arbitrary JSON document.\n\nUsing the CLI we can write:\n\n```\necho '{ \"size\" : 12.0, \"name\" : \"Bob\" }' | terminusdb doc insert admin/example -j\nDocument inserted [\"terminusdb:///json/JSONDocument/9cb4de0ff0b46b6035149a6b763e087d6c59cba2b417de3eedfd26063bee6bdf\"]\n```\n\n## Type families\n\nUse type families to construct optionality or collections of values. Type families are `List`, `Set`, `Array`, and `Optional`.\n\n### Optional\n\nUse `Optional` as a type family where a property is not required.\n\n#### Code: An example of type family Optional\n\n```\n{ \n \"@type\" : \"@context\",\n \"@schema\" : \"http://example.com/people#\",\n \"@base\" : \"http://example.com/people/\" }\n\n{ \n \"@type\" : \"Class\",\n \"@id\" : \"CodeBlock\",\n \"code\" : \"xsd:string\",\n \"comment\" : \n { \n \"@type\" : \"Optional\",\n \"@class\" : \"xsd:string\" \n }\n}\n```\n\nSupply an optional `comment` field in `CodeBlock`. Both of the following documents are valid:\n\n```\n{ \n \"@type\" : \"CodeBlock\",\n \"@id\" : \"my_code_block\",\n \"code\" : \"print('hello world')\",\n \"comment\" : \"This is a silly bit of code\" \n}\n```\n\nOR\n\n```\n{ \n \"@type\" : \"CodeBlock\",\n \"@id\" : \"my_code_block\",\n \"code\" : \"print('hello world')\" \n}\n```\n\n### List\n\nUse `List` to specify an ordered collection, with multiplicity, of values of a class or datatype.\n\n#### Code: An example of type family List\n\n```\n{ \n \"@type\" : \"@context\",\n \"@base\" : \"http://i/\",\n \"@schema\" : \"http://s/\" \n}\n{ \n \"@id\" : \"TaskList\",\n \"@type\" : \"Class\",\n \"tasks\" : \n { \n \"@type\" : \"List\",\n \"@class\" : \"Task\"\n } \n}\n{\n \"@id\" : \"Task\",\n \"@type\" : \"Class\",\n \"@key\" : \"ValueHash\",\n \"name\" : \"xsd:string\" \n}\n```\n\nAn example of an object `Task` contained in a `List` of elements known as a `TaskList`. This list is retrieved in the same order that it is inserted. It is also capable of storing duplicates.\n\n```\n{ \n \"@id\" : \"my_task_list\",\n \"@type\" : \"TaskList\",\n \"tasks\" : \n [\n { \n \"@type\" : \"Task\", \n \"name\" : \"Laundry\" \n },\n { \n \"@type\" : \"Task\", \n \"name\" : \"Take_Garage_Out\" \n }\n ]\n}\n```\n\n### Set\n\nUse `Set` to specify an unordered set of values of a class or datatype.\n\n#### Code: An example of type family Set\n\n```\n{ \n \"@type\" : \"@context\",\n \"@base\" : \"http://i/\",\n \"@schema\" : \"http://s/\" \n}\n{ \n \"@id\" : \"Person\",\n \"@type\" : \"Class\",\n \"name\" : \"xsd:string\",\n \"friends\" : \n { \n \"@type\" : \"Set\",\n \"@class\" : \"Person\" \n }\n}\n```\n\nAn example of an object `Person` that can have 0 to any number of friends. This list has no order and is retrieved from the database in a potentially different order. Inserted duplicates do not create additional linkages and only a single of the multiple supplied results are returned.\n\n```\n{ \n \"@id\" : \"Me\",\n \"@type\" : \"Person\",\n \"friends\" : \n [\n { \n \"@type\" : \"Person\",\n \"@id\" : \"you\",\n \"name\" : \"You\" \n },\n { \n \"@type\" : \"Person\",\n \"@id\" : \"someone_else\",\n \"name\" : \"Someone Else\"\n }\n ]\n}\n```\n\n### Foreign Types\n\nUse `Foreign` to specify types that are to be references to external data products. Foreign types are types that are opaque in the current data product. This allows us to give them identifiers although we don't actually store the objects locally. Foreign types have _no_ referential integrity checking, and as they refer to opaque identifiers, the schema is checked by the data product in which they are referred.\n\nA foreign type must be declared explicitly by giving the name of the type to be treated as foreign using the `Foreign` designation in the schema.\n\n#### Code: An example of adding a foreign Person type\n\nFor instance, to add a foreign type of type Person, we can write:\n\n```\n{ \"@type\" : \"Foreign\",\n \"@id\" : \"Person\"}\n```\n\nThe actual definition of person might be given in its home data product as:\n\n```\n{ \"@type\" : \"Person\",\n \"@key\" : { \"@type\" : \"Lexical\",\n \"@fields\" : [ \"name \" ] },\n \"name\" : \"xsd:string\" }\n```\n\n#### Code: An example creating and referring to a foreign type\n\nFrom the command line we can see how an HR data product might interact with an Events data product.\n\nCreate the HR data product:\n\n```\nterminusdb db create admin/hr\n```\n\nAdd the HR schema:\n\n```\necho '{ \"@type\" : \"Class\", \"@id\" : \"Person\", \"@key\" : { \"@type\" : \"Lexical\", \"@fields\" : [\"name\"]}, \"name\" : \"xsd:string\" }' | terminusdb doc insert admin/hr --graph_type=schema\n```\n\nCreate the Events data product:\n\n```\nterminusdb db create admin/events\n```\n\nAdd events, and a foreign type designation:\n\n```\necho '{ \"@type\" : \"Foreign\", \"@id\" : \"Person\"}{ \"@type\" : \"Class\", \"@id\" : \"Event\", \"date\" : \"xsd:date\", \"person\" : \"Person\" }' | terminusdb doc insert admin/events --graph_type=schema\n```\n\nAdd a person to HR:\n\n```\necho '{ \"@type\" : \"Person\", \"name\" : \"Gavin\" }' | terminusdb doc insert admin/hr\n```\n\nAdd an event referring to the person:\n\n```\necho '{ \"@type\" : \"Event\", \"date\" : \"2022-10-05\", \"person\" : \"terminusdb:///data/Person/Gavin\"}' | terminusdb doc insert admin/events\n```\n\nRecover the event:\n\n```\nterminusdb doc get admin/events --id='Event/9b3c5b174cb1f157dcdcedb692ed57f82ba31193fb81652dc602915732ae94e1'\n```\n\n### Cardinality\n\nUse `Cardinality` to specify an unordered set of values of a class or datatype in which the property has a limited number of elements as specified by the cardinality constraint properties.\n\nThe relevant properties are:\n\n#### `@cardinality`\n\nWhen specified, the number of elements for the given property must be _exactly_ the cardinality specified. This is equivalent to specifying both `@min_cardinality` and `@max_cardinality` as the same cardinality.\n\n#### Code: An example of type family Cardinality with `@cardinality`\n\n```\n{\n \"@type\" : \"@context\",\n \"@base\" : \"http://i/\",\n \"@schema\" : \"http://s/\"\n}\n{\n \"@id\" : \"Person\",\n \"@type\" : \"Class\",\n \"name\" : \"xsd:string\",\n \"friends\" :\n {\n \"@type\" : \"Cardinality\",\n \"@class\" : \"Person\"\n \"@cardinality\" : 3\n }\n}\n```\n\nAn example of an object `Person` that can have exactly three friends. As with `Set` This list has no order and is retrieved from the database in a potentially different order.\n\n```\n{\n \"@id\" : \"Person/Me\",\n \"@type\" : \"Person\",\n \"friends\" :\n [\n {\n \"@type\" : \"Person\",\n \"@id\" : \"Person/you\",\n \"name\" : \"You\"\n },\n {\n \"@type\" : \"Person\",\n \"@id\" : \"Person/someone_else\",\n \"name\" : \"Someone Else\"\n },\n {\n \"@type\" : \"Person\",\n \"@id\" : \"Person/Another\",\n \"name\" : \"Another\"\n }\n ]\n}\n```\n\n#### `@min_cardinality`\n\nWhen specified, the number of elements for the given property must be _at least_ the cardinality specified.\n\n```\n{\n \"@type\" : \"@context\",\n \"@base\" : \"http://i/\",\n \"@schema\" : \"http://s/\"\n}\n{\n \"@id\" : \"Person\",\n \"@type\" : \"Class\",\n \"name\" : \"xsd:string\",\n \"friends\" :\n {\n \"@type\" : \"Set\",\n \"@class\" : \"Person\"\n \"@min_cardinality\" : 1\n }\n}\n```\n\n#### `@max_cardinality`\n\nWhen specified, the number of elements for the given property must be _no more than_ the cardinality specified.\n\n```\n{\n \"@type\" : \"@context\",\n \"@base\" : \"http://i/\",\n \"@schema\" : \"http://s/\"\n}\n{\n \"@id\" : \"Person\",\n \"@type\" : \"Class\",\n \"name\" : \"xsd:string\",\n \"friends\" :\n {\n \"@type\" : \"Set\",\n \"@class\" : \"Person\"\n \"@min_cardinality\" : 1\n }\n}\n```\n\nWhen set to 1, this is functionally equivalent to the `Optional` constraint.\n\n### Array\n\nUse `Array` to specify an ordered collection, with multiplicity, of values of a class or datatype in which you may want random access to the data and which may be multi-dimensional. `Array` is implemented with intermediate indexed objects, with a `sys:value` and indexes placed at `sys:index`, `sys:index2`, … `sys:indexN` for each of the array indices of the multi-dimensional array. However when extracted as JSON they will appear merely as lists (possibly of lists), with possible null values representing gaps in the array.\n\n#### Code: An example of type family Array\n\n```\n{ \n \"@type\" : \"@context\",\n \"@base\" : \"http://i/\",\n \"@schema\" : \"http://s/\" \n}\n{ \n \"@id\" : \"GeoPolygon\",\n \"@type\" : \"Class\",\n \"name\" : \"xsd:string\",\n \"coordinates\" : \n { \n \"@type\" : \"Array\",\n \"@dimensions\" : 2,\n \"@class\" : \"xsd:decimal\" \n }\n}\n```\n\nAn example of a polygon object `GeoPolygon` points to a 2D array of coordinates which specify a polygon encompassing the Phoneix Park.\n\n```\n{\n \"@id\" : \"PhoenixPark\",\n \"@type\" : \"GeoPolygon\",\n \"name\" : \"The Pheonix Park\",\n \"coordinates\" :\n [\n [\n -6.3491535,\n 53.3700669\n ],\n [\n -6.3364506,\n 53.3717056\n ],\n [\n -6.349411,\n 53.3699645\n ]\n ]\n}\n```\n\n## Inference\n\nTerminusDB is equipped with a type inference engine that allows types to be inferred under certain conditions.\n\nThe algorithm attempts to find a _unique_ type that can successfully be ascribed to a document. In the event that no type is found, you will get an error that no type applies. If _several_ types might apply, you will see the list of candidate types in the error. If TerminusX is able to find the unique type which applies, it will ascribe the type automatically.\n\nType ascription is perhaps most useful in cases in which abstract types are used as ranges of a property, but in which there are only _sibling_ concrete types that might apply. In this case, it is easy to ensure a unique typing for the range class and improves the flexibility of the interface.\n\nIt should also be considered that the type being ascribed is based on the schema _as it is_ when the document is inserted. For this reason, in some cases it may be better to tag the document explicitly with the `@type` keyword.\n\n#### Code: An example of type inference\n\nGiven the following schema:\n\n```\n{\n \"@type\" : \"@context\",\n \"@base\" : \"http://i/\",\n \"@schema\" : \"http://s/\"\n}\n{\n \"@id\" : \"Person\",\n \"@type\" : \"Class\",\n \"name\" : \"xsd:string\",\n \"friends\" :\n {\n \"@type\" : \"Set\",\n \"@class\" : \"Person\"\n }\n}\n```\n\nWe can insert the following document through the document interface:\n\n```\n{ \"name\" : \"Gavin\",\n \"friends\" : [ { \"name\" : \"Tim\"}, { \"name\" : \"Julie\" }] }\n```\n\nThis document will be ascribed type `\"Person\"` and the two documents linked will likewise be typed as `\"Person\"`\n\n#### Code: An example of unambiguous inference\n\nIn the case of certain well-defined JSON documents schemata however, such as GeoJSON, there is never a possibility of ambiguity and so the type-inferencing helps to make it much more convenient.\n\n```\n{\n \"@type\" : \"@context\",\n \"@base\" : \"http://i/\",\n \"@schema\" : \"http://s/\"\n}\n{\n \"@type\" : \"Class\",\n \"@id\" : \"Geometry\",\n \"@abstract\" : []\n}\n{\n \"@type\" : \"Enum\",\n \"@id\" : \"Point_Type\",\n \"@value\" : [ \"Point\" ]\n}\n{\n \"@type\" : \"Class\",\n \"@id\" : \"Point\",\n \"@inherits\" : \"Geometry\",\n \"type\" : \"Point_Type\",\n \"coordinates\" : {\n \"@type\" : \"Array\",\n \"@dimensions\" : 1,\n \"@class\" : \"xsd:decimal\"\n }\n}\n```\n\nThis schema provides the `\"Point\"` type with a singleton enum tag. This singleton enum tag will help to uniquely assign the type.\n\nWe can then insert a point document which might be written as:\n\n```\n{\n \"type\" : \"Point\",\n \"coordinates\" : [33.2,24.0]\n}\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "TerminusCMS Schema Reference Guide", + "description": "A reference guide for the TerminusCMS and TerminusDB schema", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "@terminusdb/terminusdb-client" + }, + "slug": "javascript", + "body": { + "@type": "Body", + "value": "### AccessControl\n\n#### accessRequestsList(orgName)\n\n\\-- TerminusX API -- Get all the access request list for a specify organization\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\norgName\n\nstring\n\nThe organization name.\n\n##### Examples\n\n```\naccessControl.accessRequestsList().then(result=>{\n console.log(result)\n})\n```\n\n#### createOrganization(orgName)\n\n\\-- TerminusDB API --- This end point works in basic authentication, admin user Create an organization\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\norgName\n\nstring\n\nThe organization name to create\n\n##### Examples\n\n```\naccessControl.createOrganization(\"my_org_name\").then(result=>{\n console.log(result)\n})\n```\n\n#### createOrganizationRemote(orgName)\n\n\\-- TerminusX API --- IMPORTANT This does not work with the API-TOKEN. Create an organization\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\norgName\n\nstring\n\nThe organization name to create\n\n##### Examples\n\n```\naccessControl.createOrganization(\"my_org_name\").then(result=>{\n console.log(result)\n})\n```\n\n#### createRole(name, actions)\n\n\\--TerminusDB API --- basic authentication, admin user. Create a new role in the system database.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nname\n\nstring\n\nThe role name.\n\nactions\n\ntypedef.RolesActions\n\nA list of actions\n\n##### Examples\n\n```\naccessControl.createRole(\"Reader\",[ACTIONS.INSTANCE_READ_ACCESS]).then(result=>{\n console.log(result)\n})\n```\n\n#### createUser(name, password)\n\n\\-- TerminusdDB API --- basic Authentication, admin user. Add the user into the system database\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nname\n\nstring\n\nthe user name\n\npassword\n\nstring\n\nyou need the password for basic authentication\n\n##### Examples\n\n```\naccessControl.deleteUser(userId).then(result=>{\n console.log(result)\n})\n```\n\n#### createUserRole(userId, scope, role, orgName)\n\n\\-- TerminusX API -- Create a user's a role for a resource (organization/database)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nuserId\n\nstring\n\nThe user's id.\n\nscope\n\nstring\n\nThe resource name/id.\n\nrole\n\nstring\n\nThe user role to be assigned.\n\norgName\n\nstring\n\nThe organization name.\n\n##### Examples\n\n```javascript\nconst dbId = \"UserDatabase/acfcc2db02b83792sssb15239ccdf586fc5b176846ffe4878b1aea6a36c8f\"\naccessControl.assignUserRole('User/auth0%7C61790e11a3966d006906596a',dbId,\n\"Role/collaborator\").then(result=>{\n console.log(result)\n\n})\n```\n\n#### customHeaders(customHeaders)\n\nadd extra headers to your request\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ncustomHeaders\n\nobject\n\n#### deleteAccessRequest(orgName)\n\n\\-- TerminusX API -- Delete an access request to join your team, only an admin user can delete it\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\norgName\n\nstring\n\nThe organization name.\n\n##### Examples\n\n```\naccessControl.deleteAccessRequest(\"djjdshhsuuwewueueuiHYHYYW.......\").then(result=>{\n console.log(result)\n})\n```\n\n#### deleteOrgInvite(inviteId, orgName)\n\n\\-- TerminusX API --- Delete an invitation\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ninviteId\n\nstring\n\nThe invite id to delete.\n\norgName\n\nstring\n\nThe organization name.\n\n##### Examples\n\n```javascript\nconst fullInviteId=\"Organization/my_team_name/invitations/Invitation/7ad0c9eb82b6175bcda9\nc0dfc2ac51161ef5ba7cb0988d992c4bce82b3fa5d25\"\naccessControl.deleteOrgInvite(fullInviteId).then(result=>{\n console.log(result)\n})\n```\n\n#### deleteOrganization(orgName)\n\n\\-- TerminusDB API --- Delete an Organization\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\norgName\n\nstring\n\nThe organization name to delete\n\n##### Examples\n\n```\naccessControl.deleteOrganization(\"my_org_name\").then(result=>{\n console.log(result)\n})\n```\n\n#### deleteRole(name)\n\n\\-- TerminusdDB API --- basic Authentication, admin user. Delete role in the system database, (this api is enabled only in the local installation)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nname\n\nstring\n\nThe role name.\n\n##### Examples\n\n```\naccessControl.deleteRole(\"Reader\").then(result=>{\n console.log(result)\n})\n```\n\n#### deleteUser(userId)\n\n\\-- TerminusdDB API --- basic Authentication, admin user. Remove the user from the system database.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nuserId\n\nstring\n\nthe document user id\n\n##### Examples\n\n```\naccessControl.deleteUser(userId).then(result=>{\n console.log(result)\n})\n```\n\n#### getAPIUrl(cloudAPIUrl)\n\nGet a API url from cloudAPIUrl\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ncloudAPIUrl\n\nstring\n\nThe base url for cloud\n\n#### getAccessRoles()\n\n\\--TerminusX and TerminusDB API --- Get all the system database roles types.\n\n#### getAllOrganizations()\n\n\\-- TerminusDB API --- This end point works in basic authentication, admin user Get list of organizations\n\n#### getAllUsers()\n\n\\-- TerminusdDB API --- basic Authentication, admin user. Return the list of all the users (this api is enabled only in the local installation)\n\n##### Examples\n\n```\naccessControl.getAllUsers().then(result=>{\n console.log(result)\n})\n```\n\n#### getDatabaseRolesOfUser(userId, orgName)\n\n\\-- TerminusX API -- Get the user's role for every databases under the organization\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nuserId\n\nstring\n\nThe user's id.\n\norgName\n\nstring\n\nThe organization name.\n\n##### Examples\n\n```\naccessControl.getDatabaseRolesOfUser('User/auth0%7C61790e366377Yu6596a').then(result=>{\n console.log(result)\n})\n\n//this is a capabilities list of databases and roles\n//[ {capability: \"Capability/b395e8523d509dec6b33aefc9baed3b2e2bfadbd4c79d4ff9b20dce2b14e2edc\"\n//if there is an id we have a user specific capabality for this database\n // name: {@type: \"xsd:string\", @value: \"profiles_test\"}\n // role: \"Role/dataUpdater\"\n // scope: \"UserDatabase/7ebdfae5a02bc7e8f6d79sjjjsa4e179b1df9d4576a3b1d2e5ff3b4859\"\n // user: \"User/auth0%7C61790e11a3966d006906596a\"},\n\n//{ capability: null\n// if the capability id is null the user level of access for this database is the\nsame of the team\n //name: {@type: \"xsd:string\", @value: \"Collab002\"}\n //role: \"Role/dataReader\"\n // scope: \"UserDatabase/acfcc2db02b83792sssb15239ccdf586fc5b176846ffe4878b1aea6a36c8f\"\n //user: \"User/auth0%7C61790e11a3966d006906596a\"}]\n```\n\n#### getDefaultOrganization(params)\n\nGet a organization from parameters.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nparams\n\nobject\n\nThe parameters\n\n#### getOrgInvite(inviteId, orgName)\n\n\\-- TerminusX API --- Get the invitation info\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ninviteId\n\nstring\n\nThe invite id to retrieve.\n\norgName\n\nstring\n\nThe organization name.\n\n##### Examples\n\n```javascript\nconst fullInviteId=\"Organization/my_team_name/invitations/Invitation/7ad0c9eb82b6175bcda9c0dfc\n2ac51161ef5ba7cb0988d992c4bce82b3fa5d25\"\naccessControl.getOrgInvite(fullInviteId).then(result=>{\n console.log(result)\n})\n```\n\n#### getOrgUsers(orgName)\n\n\\-- TerminusX and TerminusDB API -- Get all the organization's users and roles,\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\norgName\n\nstring\n\nThe organization name.\n\n##### Examples\n\n```javascript\naccessControl.getOrgUsers().then(result=>{\n console.log(result)\n})\n\n//this function will return an array of capabilities with users and roles\n//-- TerminusX -- response array example\n//[{capability: \"Capability/3ea26e1d698821c570afe9cb4fe81a3......\"\n// email: {@type: \"xsd:string\", @value: \"user@terminusdb.com\"}\n// picture: {@type: \"xsd:string\",…}\n// role: \"Role/dataReader\"\n// scope: \"Organization/my_org_name\"\n// user: \"User/auth0%7C613f5dnndjdjkTTT\"}]\n//\n//\n// -- Local Installation -- response array example\n//[{ \"@id\":\"User/auth0%7C615462f8ab33f4006a6bee0c\",\n// \"capability\": [{\n// \"@id\":\"Capability/c52af34b71f6f8916ac0115ecb5fe0e31248ead8b1e3d100852015...\",\n// \"@type\":\"Capability\",\n// \"role\": [{\n// \"@id\":\"Role/admin\",\n// \"@type\":\"Role\",\n// \"action\": [\"instance_read_access\"],\n// \"name\":\"Admin Role\"\n// }],\n// \"scope\":\"Organization/@team\"}]]\n```\n\n#### getOrganization(organization)\n\n\\-- TerminusDB API --- Get an organization from the TerminusDB API.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\norganization\n\nstring\n\nThe organization\n\n#### getPendingOrgInvites(orgName)\n\n\\-- TerminusX API --- Get the pending invitations list.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\norgName\n\nstring\n\nThe organization name.\n\n##### Examples\n\n```javascript\nconst invitationList = accessControl.getPendingOrgInvites().then(result=>{\n console.log(invitationList)\n\n})\n//this will return an array of invitations object like this\n//[{@id: \"Organization/my_team_name/invitations/Invitation/7ad0c9eb82b6175bcda9c0dfc2ac51161ef5ba\ncb0988d992c4bce82b3fa5d25\"\n// @type: \"Invitation\"\n// creation_date: \"2021-10-22T11:13:28.762Z\"\n// email_to: \"new_user@terminusdb.com\"\n// invited_by: \"User/auth0%7C6162f8ab33567406a6bee0c\"\n// role: \"Role/dataReader\"\n// status: \"needs_invite\"}]\n```\n\n#### getTeamUserRole(orgName)\n\n\\-- TerminusX API --- Get the user role for a given organization or the default organization The user is identified by the jwt or the access token\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\norgName\n\nstring\n\nThe organization name.\n\n##### Examples\n\n```\naccessControl.getTeamUserRole().then(result=>{\n console.log(result)\n})\n\n//response object example\n{\"userRole\":\"Role/admin\"}\n```\n\n#### getTeamUserRoles(userName, orgName)\n\n\\-- TerminusX and TerminusDB API -- Get the user roles for a given organization or the default organization,\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nuserName\n\nstring\n\nThe organization name.\n\norgName\n\nstring\n\nThe organization name.\n\n##### Examples\n\n```\naccessControl.getTeamUserRole(\"myUser\").then(result=>{\n console.log(result)\n})\n\n//response object example\n{\n \"@id\": \"User/myUser\",\n \"capability\": [\n {\n \"@id\":\"Capability/server_access\",\n \"@type\":\"Capability\",\n \"role\": [{\n \"@id\":\"Role/reader\",\n \"@type\":\"Role\",\n \"action\": [\n \"instance_read_access\",\n ],\n \"name\":\"reader\"\n }],\n \"scope\":\"Organization/myteam\"\n }\n ],\n \"name\": \"myUser\"\n}\n```\n\n#### getUserInfo(orgName)\n\n\\-- TerminusX API -- Get the userinfo teams ownership and subscription\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\norgName\n\nstring\n\nThe organization name.\n\n##### Examples\n\n```\naccessControl.getUserInfo().then(result=>{\n console.log(result)\n})\n```\n\n#### ifOrganizationExists(orgName)\n\n\\-- TerminusX API --- Check if the organization exists. it is a Head call . IMPORTANT This does not work with the API-TOKEN.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\norgName\n\nstring\n\nThe organization name to check if exists.\n\n#### manageCapability(userName, resourceName, rolesArr, operation, scopeType)\n\n\\-- TerminusdDB API --- Grant/Revoke Capability\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nuserName\n\nstring\n\nthe document user id\n\nresourceName\n\nstring\n\nthe name of a (database or team)\n\nrolesArr\n\narray\n\nthe roles name list\n\noperation\n\ntypedef.CapabilityCommand\n\ngrant/revoke operation\n\nscopeType\n\ntypedef.ScopeType\n\nthe resource type (database or organization)\n\n##### Examples\n\n```\n//we add an user to an organization and manage users' access\n//the user myUser can access the Organization and all the database under the organization with \"reader\" Role\nclient.manageCapability(myUser,myteam,[reader],\"grant\",\"organization\").then(result=>{\n consol.log(result)\n})\n\n//the user myUser can access the database db__001 under the organization myteam\n//with \"writer\" Role\nclient.manageCapability(myUser,myteam/db__001,[writer],\"grant\",\"database\").then(result=>{\n consol.log(result)\n})\n```\n\n#### removeUserFromOrg(userId, orgName)\n\n\\-- TerminusX API -- Remove an user from an organization, only an admin user can remove an user from an organization\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nuserId\n\nstring\n\nThe id of the user to be removed. (this is the document user's @id)\n\norgName\n\nstring\n\nThe organization name in which the user is to be removed.\n\n##### Examples\n\n```\naccessControl.removeUserFromOrg(\"User/auth0%7C613f5dnndjdjkTTT\",\"my_org_name\").then(result=>{\n console.log(result)\n})\n```\n\n#### sendAccessRequest(email, affiliation, note, orgName)\n\n\\-- TerminusX API -- Get all the access request list for a specify organization\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nemail\n\nstring\n\nthe user email.\n\naffiliation\n\nstring\n\nthe user affiliation, company, university etc..\n\nnote\n\nstring\n\nthe message for the team admin\n\norgName\n\nstring\n\nThe organization name.\n\n##### Examples\n\n```\naccessControl.sendAccessRequest(\"myemail@terminusdb.com\",\n \"my_company\",\n \"please add me to your team\"\n).then(result=>{\n console.log(result)\n})\n```\n\n#### sendOrgInvite(userEmail, role, note, orgName)\n\n\\-- TerminusX API --- Send a new invitation\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nuserEmail\n\nstring\n\nThe email of user.\n\nrole\n\nstring\n\nThe role for user. (the document @id role like Role/collaborator)\n\nnote\n\nstring\n\nThe note to send with the invitation.\n\norgName\n\nstring\n\nThe organization name.\n\n##### Examples\n\n```\naccessControl.sendOrgInvite(\"new_user@terminusdb.com\",\"Role/admin\",\n\"please join myteam\").then(result=>{\n console.log(result)\n})\n```\n\n#### setApiKey(atokenpi)\n\nSets the API token for the object, to request a token create an account in https://terminusdb.com/\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\natokenpi\n\nstring\n\nThe API token to use to connect with TerminusX\n\n#### setApiToken(atokenpi)\n\nSets the API token for the object, to request a token create an account in https://terminusdb.com/\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\natokenpi\n\nstring\n\nThe API token to use to connect with TerminusX\n\n#### setJwtToken(jwt)\n\nSets the Jwt token for the object\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\njwt\n\nstring\n\nThe jwt api token to use\n\n#### updateOrgInviteStatus(inviteId, accepted, orgName)\n\n\\-- TerminusX API --- Accept /Reject invitation. if the invitation has been accepted we add the current user to the organization. the only user that can accept this invitation is the user registered with the invitation email, we indentify the user with the jwt token\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ninviteId\n\nstring\n\nThe invite id to updated.\n\naccepted\n\nboolean\n\nThe status of the invitation.\n\norgName\n\nstring\n\nThe organization name.\n\n##### Examples\n\n```javascript\nconst fullInviteId=\"Organization/my_team_name/invitations/Invitation/7ad0c9eb82b6175bcda9\nc0dfc2ac51161ef5ba7cb0988d992c4bce82b3fa5d25\"\naccessControl.updateOrgInviteStatus(fullInviteId,true).then(result=>{\n console.log(result)\n})\n```\n\n#### updateUserRole(userId, capabilityId, scope, role, orgName)\n\n\\-- TerminusX API -- Update user's a role for a resource (organization/database), (this api works only in terminusX)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nuserId\n\nstring\n\nThe user's id.\n\ncapabilityId\n\nstring\n\nThe capability id.\n\nscope\n\nstring\n\nThe resource name/id.\n\nrole\n\nstring\n\nThe user role to be updated.\n\norgName\n\nstring\n\nThe organization name.\n\n##### Examples\n\n```javascript\nconst dbId = \"UserDatabase/acfcc2db02b83792sssb15239ccdf586fc5b176846ffe4878b1aea6a36c8f\"\nconst capId= \"Capability/b395e8523d509dec6b33aefc9baed3b2e2bfadbd4c79d4ff9b20dce2b14e2edc\"\naccessControl.updateUserRole('User/auth0%7C61790e11a3966d006906596a',capId,dbId,\n\"Role/dataUpdater\").then(result=>{\n console.log(result)\n\n})\n```\n\n### View\n\n#### matchCell()\n\nCalled to test whether a specific cell is matched by a set of rules returns array of rules that matched\n\n#### matchColumn()\n\nCalled to test whether an entire column of results is matched by a set of rules returns array of rules that matched\n\n#### matchEdge()\n\nCalled to test whether a specific edge (source -> target) is matched by a set of rules returns array of rules that matched\n\n#### matchFrame()\n\nCalled to test whether a specific frame is matched by a set of rules\n\n#### matchNode()\n\nCalled to test whether a specific node is matched by a set of rules returns array of rules that matched\n\n#### matchRow()\n\nCalled to match an entire row of results is matched by a set of rules returns array of rules that matched\n\n#### rule()\n\nShorthand functions for accessing the pattern matching capabilities\n\n### WOQL\n\n#### Vars(varNames)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nvarNames\n\nstring\n\n##### Examples\n\n```javascript\nconst v = WOQL.Vars('var01', 'var02', 'var03');\ntriple(v.var01, v.var02, v.var03)\n```\n\n#### add\\_quad(subject, predicate, object, graphRef-)\n\nAdds quads according to the pattern \\[S,P,O,G\\]\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubject\n\nstring|Var\n\nThe IRI of a triple’s subject or a variable\n\npredicate\n\nstring|Var\n\nThe IRI of a property or a variable\n\nobject\n\nstring|Var\n\nThe IRI of a node or a variable, or a literal\n\ngraphRef-\n\ntypedef.GraphRef\n\nA valid graph resource identifier string\n\n#### add\\_triple(subject, predicate, object)\n\nAdds triples according to the the pattern \\[subject,predicate,object\\]\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubject\n\nstring|Var\n\nThe IRI of a triple’s subject or a variable\n\npredicate\n\nstring|Var\n\nThe IRI of a property or a variable\n\nobject\n\nstring|Var\n\nThe IRI of a node or a variable, or a literal\n\n#### added\\_quad(subject, predicate, object, graphRef-)\n\nCreates a pattern matching rule for the quad \\[S, P, O, G\\] (Subject, Predicate, Object, Graph) removed from the current commit\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubject\n\nstring|Var\n\nThe IRI of a triple’s subject or a variable\n\npredicate\n\nstring|Var\n\nThe IRI of a property or a variable\n\nobject\n\nstring|Var\n\nThe IRI of a node or a variable, or a literal\n\ngraphRef-\n\ntypedef.GraphRef\n\nA valid graph resource identifier string\n\n#### added\\_triple(subject, predicate, object)\n\nCreates a triple pattern matching rule for the triple \\[S, P, O\\] (Subject, Predicate, Object) added in the current layer\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubject\n\nstring|Var\n\nThe IRI of a triple’s subject or a variable\n\npredicate\n\nstring|Var\n\nThe IRI of a property or a variable\n\nobject\n\nstring|Var\n\nThe IRI of a node or a variable, or a literal\n\n#### all(subject, predicate, object, graphRef)\n\nGenerates a query that by default matches all triples in a graph - identical to star() except for order of arguments\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubject\n\nstring|Var\n\nThe IRI of a triple’s subject or a variable\n\npredicate\n\nstring|Var\n\nThe IRI of a property or a variable\n\nobject\n\nstring|Var\n\nThe IRI of a node or a variable, or a literal\n\ngraphRef\n\ntypedef.GraphRef\n\nthe resource identifier of a graph possible value are schema/{main - myschema - \\*} | instance/{main - myschema - \\*} | inference/{main - myschema - \\*}\n\n#### and(subqueries)\n\nLogical conjunction of the contained queries - all queries must match or the entire clause fails\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubqueries\n\nWOQLQuery\n\nA list of one or more woql queries to execute as a conjunction\n\n##### Examples\n\n```javascript\n//find triples that are of type scm:Journey, and have\n//a start_station Start, and that start_station is labeled Start_Label\nlet [Journey, Start, Start_Label] = vars(\"Journey\", \"Start\", \"Start_Label\")\nWOQL.and(\n WOQL.triple(Journey, \"rdf:type\", \"@schema:Journey\"),\n WOQL.triple(Journey, \"start_station\", Start),\n WOQL.triple(Start, \"label\", Start_Label))\n```\n\n#### as(source, target, type)\n\nImports the value identified by Source to a Target variable\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsource\n\nstring|number|Var\n\nSource\n\ntarget\n\nstring|Var\n\nTarget\n\ntype\n\nstring\n\ntype to cast value to string|number etc...\n\n##### Examples\n\n```javascript\nlet [First_Var, Second_Var] = vars('First_Var', 'Second_Var')\nWOQL.as(\"first var\", First_Var, \"string\").as(\"second var\", Second_Var)\nWOQL.as([\"first var\", First_Var, \"string\"], [\"second var\", Second_Var])\n```\n\n#### boolean(bool)\n\nGenerates explicitly a JSON-LD literal boolean from the input\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nbool\n\nboolean\n\ntrue | false\n\n##### Examples\n\n```\nboolean(true)\n//returns { \"@type\": \"xsd:boolean\", \"@value\": true }\n```\n\n#### client(client)\n\nUse instead to run your query woqlclient.query('myWOQLQuery')\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nclient\n\nWOQLClient\n\n#### comment(comment, subquery)\n\nAdds a text comment to a query - can also be used to wrap any part of a query to turn it off\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ncomment\n\nstring\n\ntext comment\n\nsubquery\n\nWOQLQuery\n\nquery that is \"commented out\"\n\n#### concat(varList, resultVarName)\n\ntakes a variable number of string arguments and concatenates them into a single string\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nvarList\n\narray|string|Var\n\na variable representing a list or a list of variables or strings - variables can be embedded in the string if they do not contain spaces\n\nresultVarName\n\nstring|Var\n\nA variable or string containing the output string\n\n##### Examples\n\n```javascript\nlet [first_name, last_name, full_name] = vars(\"first_name\", \"last_name\", \"full_name\")\nconcat([first_name, \" \", last_name], full_name)\n```\n\n#### count(countVarName, subquery)\n\nCreates a count of the results of the query\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ncountVarName\n\nstring|number|Var\n\nvariable or integer count\n\nsubquery\n\nWOQLQuery\n\n##### Examples\n\n```javascript\nlet [count, Person] = vars(\"count\", \"Person\")\nWOQL.count(count).triple(Person, \"rdf:type\", \"@schema:Person\")\n```\n\n#### date(date)\n\nGenerates explicitly a JSON-LD literal date from the imput\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ndate\n\nstring\n\nany date format string (YYYY-MM-DD)\n\n##### Examples\n\n```\ndate(\"2022-10-02\")\n//returns { \"@type\": \"xsd:date\", \"@value\": \"2022-10-02\" }\n```\n\n#### datetime(datetime)\n\nGenerates explicitly a JSON-LD literal datetime from the imput\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ndatetime\n\nstring\n\nany datetime format string (YYYY-MM-DDThh-mm-ssZ)\n\n##### Examples\n\n```\ndatetime(\"2022-10-19T14:17:12Z\")\n//returns { \"@type\": \"xsd:dateTime\", \"@value\": \"2022-10-19T14:17:12Z\" }\n```\n\n#### delete\\_document(IRI)\n\nDelete a document from the graph.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nIRI\n\nstring\n\nThe document id or a variable\n\n#### delete\\_quad(subject, predicate, object, graphRef)\n\nDeletes a single triple from the graph \\[Subject, Predicate, Object, Graph\\]\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubject\n\nstring|Var\n\nThe IRI of a triple’s subject or a variable\n\npredicate\n\nstring|Var\n\nThe IRI of a property or a variable\n\nobject\n\nstring|Var\n\nThe IRI of a node or a variable, or a literal\n\ngraphRef\n\ntypedef.GraphRef\n\nA valid graph resource identifier string\n\n##### Examples\n\n```python\nremove the class Person from the schema graph\nWOQL.delete_quad(\"Person\", \"rdf:type\", \"sys:Class\", \"schema\")\n```\n\n#### delete\\_triple(subject, predicate, object)\n\nDeletes a single triple from the default graph of the database\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubject\n\nstring|Var\n\nThe IRI of a triple’s subject or a variable\n\npredicate\n\nstring|Var\n\nThe IRI of a property or a variable\n\nobject\n\nstring|Var\n\nThe IRI of a node or a variable, or a literal\n\n##### Examples\n\n```\ndelete_triple(\"john\", \"age\", 42)\n```\n\n#### distinct(varNames)\n\nFilter the query to return only results that are distinct in the given variables\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nvarNames\n\nstring|Var\n\nthese variables are guaranteed to be unique as a tuple\n\n#### div(args)\n\nDivision - integer division - args are divided left to right\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nargs\n\nstring|number|Var\n\nnumbers for division\n\n##### Examples\n\n```javascript\nlet [result] = vars(\"result\")\nevaluate(div(10, 3), result)\n//result contains 3\n```\n\n#### divide(args)\n\nDivides numbers N1...Nn by each other left, to right precedence\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nargs\n\nstring|number|Var\n\nnumbers to tbe divided\n\n#### doc(object)\n\nProduces an encoded form of a document that can be used by a WOQL operation such as \\`WOQL.insert\\_document\\`.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nobject\n\nobject\n\nDocument to encode\n\n##### Examples\n\n```javascript\nconst doc = WOQL.doc({ \"@type\": \"Person\", name: \"Newperson\" })\n```\n\n#### dot(document, field, value)\n\nExtract the value of a key in a bound document.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ndocument\n\nstring|Var\n\nDocument which is being accessed.\n\nfield\n\nstring|Var\n\nThe field from which the document which is being accessed.\n\nvalue\n\nstring|Var\n\nThe value for the document and field.\n\n#### emerge(auto\\_eval)\n\nquery module allow you to use WOQL words as top level functions\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nauto\\_eval\n\n\\*\n\n#### eq(varName, varValue)\n\nMatches if a is equal to b\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nvarName\n\nstring|Var\n\nliteral, variable or id\n\nvarValue\n\nstring|Var\n\nliteral, variable or id\n\n#### eval(arithExp, resultVarName)\n\nEvaluates the passed arithmetic expression and generates or matches the result value\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\narithExp\n\nobject|WOQLQuery|string\n\nquery or JSON-LD representing the query\n\nresultVarName\n\nstring|Var\n\noutput variable\n\n#### evaluate(arithExp, resultVarName)\n\nEvaluates the passed arithmetic expression and generates or matches the result value\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\narithExp\n\nobject|WOQLQuery|string\n\nA WOQL query containing a valid WOQL Arithmetic Expression, which is evaluated by the function\n\nresultVarName\n\nstring|number|Var\n\nEither a variable, in which the result of the expression will be stored, or a numeric literal which will be used as a test of result of the evaluated expression\n\n##### Examples\n\n```javascript\nlet [result] = vars(\"result\")\nevaluate(plus(2, minus(3, 1)), result)\n```\n\n#### exp(varNum, expNum)\n\nExponent - raises varNum01 to the power of varNum02\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nvarNum\n\nstring|number|Var\n\na variable or numeric containing the number to be raised to the power of the second number\n\nexpNum\n\nnumber\n\na variable or numeric containing the exponent\n\n##### Examples\n\n```javascript\nlet [result] = vars(\"result\")\nevaluate(exp(3, 2), result)\n//result contains 9\n```\n\n#### floor(varNum)\n\nGenerates the nearest lower integer to the passed number\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nvarNum\n\nstring|number|Var\n\nVariable or numeric containing the number to be floored\n\n##### Examples\n\n```javascript\nlet [result] = vars(\"result\")\nevaluate(divide(floor(times(10, minus(2.1, plus(0.2, 1)))), 10), result)\n//result contains 0.9 - floating point error removed\n```\n\n#### from(graphRef-, query)\n\nSpecifies the database URL that will be the default database for the enclosed query\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ngraphRef-\n\ntypedef.GraphRef\n\nA valid graph resource identifier string\n\nquery\n\nWOQLQuery\n\nThe query\n\n#### get(asvars, queryResource)\n\nUse the document inteface to import documents\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nasvars\n\nVars|array.\n\nan array of AsVar variable mappings (see as for format below)\n\nqueryResource\n\nWOQLQuery\n\nan external resource (remote, file, post) to query\n\n##### Examples\n\n```python\nlet [a, b] = vars(\"a\", \"b\")\nget(as(\"a\", a).as(\"b\", b)).remote(\"http://my.url.com/x.csv\")\n//copies the values from column headed \"a\" into a variable a and from column\n//\"b\" into a variable b from remote CSV\n```\n\n#### graph(graphRef)\n\nSets the graph resource ID that will be used for subsequent chained function calls\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ngraphRef\n\ntypedef.GraphRef\n\nResource String identifying the graph which will be used for subsequent chained schema calls\n\n##### Examples\n\n```\nWOQL.graph(\"schema\")\n//equivalent to add_quad(\"MyClass\", \"label\", \"My Class Label\", \"schema/main\")\n```\n\n#### greater(varNum01, varNum02)\n\nCompares the value of v1 against v2 and returns true if v1 is greater than v2\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nvarNum01\n\nstring|number|Var\n\na variable or numeric containing the number to be compared\n\nvarNum02\n\nstring|number|Var\n\na variable or numeric containing the second comporator\n\n##### Examples\n\n```javascript\nlet [result] = vars(\"result\")\ngreater(1.2, 1.1).eq(result, literal(true, \"boolean\"))\n//result contains true\n```\n\n#### group\\_by(varList, patternVars, resultVarName, subquery)\n\nGroups the results of the contained subquery on the basis of identical values for Groupvars, extracts the patterns defined in PatternVars and stores the results in GroupedVar\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nvarList\n\narray|string|Var\n\nEither a single variable or an array of variables\n\npatternVars\n\narray|string|Var\n\nEither a single variable or an array of variables\n\nresultVarName\n\nstring|Var\n\noutput variable name\n\nsubquery\n\nWOQLQuery\n\nThe query whose results will be grouped\n\n##### Examples\n\n```javascript\n//subquery is an argument or a chained query\nlet [age, last_name, first_name, age_group, person] = vars(\"age\", \"last name\", \"first name\",\n\"age group\", \"person\")\ngroup_by(age, [last_name, first_name], age_group)\n .triple(person, \"first_name\", first_name)\n .triple(person, \"last_name\", last_name)\n .triple(person, \"age\", age)\n```\n\n#### idgen(prefix, inputVarList, resultVarName)\n\nGenerate a new IRI from the prefix and concatention of the variables\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nprefix\n\nstring\n\nA prefix for the IRI - typically formed of the doc prefix and the classtype of the entity (“doc:Person”)\n\ninputVarList\n\narray|string|Var\n\nAn array of variables and / or strings from which the unique hash will be generated\n\nresultVarName\n\nstring|Var\n\nVariable in which the unique ID is stored\n\n##### Examples\n\n```javascript\nlet [newid] = vars(\"newid\")\nidgen(\"doc:Person\", [\"John\", \"Smith\"], newid)\n```\n\n#### immediately(subquery)\n\nRuns the query without backtracking on side-effects\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubquery\n\nstring|WOQLQuery\n\nWOQL Query objects\n\n#### insert(classId, classType, graphRef)\n\nInserts a single triple into the database declaring the Node to have type Type, optionally into the specified graph\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nclassId\n\nstring|Var\n\nIRI string or variable containing the IRI of the node to be inserted\n\nclassType\n\nstring|Var\n\nIRI string or variable containing the IRI of the type of the node (class/document name)\n\ngraphRef\n\ntypedef.GraphRef\n\nOptional Graph resource identifier\n\n##### Examples\n\n```\ninsert(\"mydoc\", \"MyType\")\n//equivalent to add_triple(\"mydoc\", \"rdf:type\", \"@schema:MyType\")\n```\n\n#### insert\\_document(docjson, IRI)\n\nInsert a document in the graph.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ndocjson\n\nobject\n\nThe document to insert. Must either have an '@id' or have a class specified key.\n\nIRI\n\nstring\n\nAn optional identifier specifying the document location.\n\n##### Examples\n\n```javascript\nconst res = await client.query(\n WOQL.insert_document(WOQL.doc({ \"@type\" : \"Person\", \"label\": \"John\" }))\n)\n```\n\n#### into(graphRef-, subquery)\n\nSpecifies the graph resource to write the contained query into\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ngraphRef-\n\ntypedef.GraphRef\n\nA valid graph resource identifier string\n\nsubquery\n\nWOQLQuery\n\nThe query which will be written into the graph\n\n##### Examples\n\n```\n//Subq is an argument or a chained query\nusing(\"admin/minecraft\").into(\"instance/main\").add_triple(\"a\", \"rdf:type\", \"@schema:X\")\n//writes a single tripe (doc:a, rdf:type, scm:X) into the main instance graph\n```\n\n#### iri(val)\n\nExplicitly sets a value to be an IRI - avoiding automatic type marshalling\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nval\n\nstring\n\nstring which will be treated as an IRI\n\n#### isa(instanceIRI, classId)\n\nTests whether a given instance IRI has type Class, according to the current state of the DB\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ninstanceIRI\n\nstring|Var\n\nA string IRI or a variable that identify the class instance\n\nclassId\n\nstring|Var\n\nA Class IRI or a variable\n\n##### Examples\n\n```javascript\nlet [subject] = vars(\"subject\")\nisa(subject, \"Person\")\n```\n\n#### join(varList, glue, resultVarName)\n\nJoins a list variable together (Input) into a string variable (Output) by glueing the strings together with Glue\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nvarList\n\nstring|array|Var\n\na variable representing a list or a list of strings and / or variables\n\nglue\n\nstring|Var\n\nA variable (v:glue) or (glue) string representing the characters to put in between the joined strings in input\n\nresultVarName\n\nstring|Var\n\nA variable or string containing the output string\n\n##### Examples\n\n```javascript\nlet [sentence] = vars(\"sentence\")\njoin([\"joe\", \"has\", \"a\", \"hat\", \" \", sentence)\n```\n\n#### json(JSON\\_LD)\n\nGenerates a WOQLQuery object from the passed WOQL JSON - if an argument is passed, the query object is created from it, if none is passed, the current state is returned as a JSON-LD\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nJSON\\_LD\n\nobject\n\nJSON-LD woql document encoding a query\n\n#### length(inputVarList, resultVarName)\n\nCalculates the length of the list in va and stores it in vb\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ninputVarList\n\nstring|array\n\nEither a variable representing a list or a list of variables or literals\n\nresultVarName\n\nstring|Var\n\nA variable in which the length of the list is stored or the length of the list as a non-negative integer\n\n##### Examples\n\n```javascript\nlet [count] = vars(\"count\")\nlength([\"john\", \"joe\", \"frank\"], count)\n```\n\n#### less(varNum01, varNum02)\n\nCompares the value of v1 against v2 and returns true if v1 is less than v2\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nvarNum01\n\nstring|number|Var\n\na variable or numeric containing the number to be compared\n\nvarNum02\n\nstring|number|Var\n\na variable or numeric containing the second comporator\n\n##### Examples\n\n```javascript\nlet [result] = vars(\"result\")\nless(1, 1.1).eq(result, literal(true, \"boolean\"))\n//result contains true\n```\n\n#### lib()\n\nget the predefined library query \\[WOQLLibrary\\](/api/woqlLibrary.js?id=WOQLLibrary)\n\n##### Examples\n\n```python\n//get commits older than the specified commit id\nconst query = WOQL.lib().previousCommits('m8vpxewh2aovfauebfkbzwmj4qwr5lb')\n\n//return the commits of a specific branch starting from the head\n//you can add the limit (how many results to return.) and the start point\n//if a timestamp is given, gets the commits before the specified timestamp\n//WOQL.lib().commits(branch='main',limit=0,start=0,timestamp=0)\n\nconst query = WOQL.lib().commits('main',10,2,1630683082.9278786)\n\n//return the branches list with the timestamp and commits id\nconst query = WOQL.lib().branches()\n```\n\n#### like(stringA, stringB, distance)\n\nGenerates a string Leverstein distance measure between stringA and stringB\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nstringA\n\nstring|Var\n\nstring literal or variable representing a string to be compared\n\nstringB\n\nstring|Var\n\nstring literal or variable representing the other string to be compared\n\ndistance\n\nnumber|string|Var\n\nvariable representing the distance between the variables\n\n##### Examples\n\n```javascript\nlet [dist] = vars('dist')\nlike(\"hello\", \"hallo\", dist)\n//dist contains 0.7265420560747664\n```\n\n#### limit(limit, subquery)\n\nSpecifies a maximum number of results that will be returned from the subquery\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nlimit\n\nnumber|string\n\nA variable that refers to an non-negative integer or a non-negative integer\n\nsubquery\n\nWOQLQuery\n\nA subquery whose results will be limited\n\n##### Examples\n\n```javascript\nlet [a, b, c] = vars(\"a\", \"b\", \"c\")\nlimit(100).triple(a, b, c)\n//subquery is an argument or a chained query\nlimit(100,triple(a, b, c))\n```\n\n#### link(subject, predicate, object)\n\nCreates a pattern matching rule for a triple \\[Subject, Predicate, Object\\]\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubject\n\nstring|Var\n\nThe IRI of a triple’s subject or a variable\n\npredicate\n\nstring|Var\n\nThe IRI of a property or a variable\n\nobject\n\nstring|Var\n\nThe IRI of a node or a variable, or a literal\n\n#### literal(val, type)\n\nGenerates explicitly a JSON-LD string literal from the input\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nval\n\nstring\n\nany literal type\n\ntype\n\nstring\n\nan xsd or xdd type\n\n##### Examples\n\n```\nliteral(1, \"nonNegativeInteger\")\n//returns { \"@type\": \"xsd:nonNegativeInteger\", \"@value\": 1 }\n```\n\n#### lower(inputVarName, resultVarName)\n\nChanges a string to lower-case\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ninputVarName\n\nstring|Var\n\nstring or variable representing the non-lowercased string\n\nresultVarName\n\nstring|Var\n\nvariable that stores the lowercased string output\n\n##### Examples\n\n```javascript\nlet [lower] = var(\"l\")\nlower(\"aBCe\", lower)\n//lower contains \"abce\"\n```\n\n#### member(element, list)\n\nMatches if List includes Element\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nelement\n\nstring|object|Var\n\nEither a variable, IRI or any simple datatype\n\nlist\n\nstring|array|Var\n\nList (\\[string, literal\\] or string\\*) Either a variable representing a list or a list of variables or literals\n\n##### Examples\n\n```javascript\nlet [name] = vars(\"name\")\nmember(name, [\"john\", \"joe\", \"frank\"])\n```\n\n#### minus(args)\n\nSubtracts Numbers N1..Nn\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nargs\n\nstring|number|Var\n\nvariable or numeric containing the value that will be subtracted from\n\n##### Examples\n\n```javascript\nlet [result] = vars(\"result\")\nevaluate(minus(2.1, plus(0.2, 1)), result)\n```\n\n#### node(nodeid, chainType)\n\nSpecifies the identity of a node that can then be used in subsequent builder functions. Note that node() requires subsequent chained functions to complete the triples / quads that it produces - by itself it only generates the subject.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nnodeid\n\nstring|Var\n\nThe IRI of a node or a variable containing an IRI which will be the subject of the builder functions\n\nchainType\n\ntypedef.FuntionType\n\nOptional type of builder function to build (default is triple)\n\n##### Examples\n\n```\nnode(\"mydoc\").label(\"my label\")\n//equivalent to triple(\"mydoc\", \"label\", \"my label\")\n```\n\n#### not(subquery)\n\nLogical negation of the contained subquery - if the subquery matches, the query will fail to match\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubquery\n\nstring|WOQLQuery\n\nA subquery which will be negated\n\n##### Examples\n\n```javascript\nlet [subject, label] = vars(\"subject\", \"label\")\nnot().triple(subject, 'label', label)\n```\n\n#### nuke(graphRef)\n\nDeletes all triples in the passed graph (defaults to instance/main)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ngraphRef\n\ntypedef.GraphRef\n\nResource String identifying the graph from which all triples will be removed\n\n##### Examples\n\n```python\nnuke(\"schema/main\")\n//will delete everything from the schema/main graph\n```\n\n#### once(subquery)\n\nResults in one solution of the subqueries\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubquery\n\nstring|WOQLQuery\n\nWOQL Query objects\n\n#### opt(subquery)\n\nSpecifies that the Subquery is optional - if it does not match the query will not fail\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubquery\n\nWOQLQuery\n\nA subquery which will be optionally matched\n\n##### Examples\n\n```javascript\nlet [subject] = vars(\"subject\")\nopt(triple(subject, 'label', \"A\"))\n//Subq is an argument or a chained query\nopt().triple(subject, 'label', \"A\")\n```\n\n#### or(subqueries)\n\nCreates a logical OR of the arguments\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubqueries\n\nWOQLQuery\n\nA list of one or more woql queries to execute as alternatives\n\n##### Examples\n\n```javascript\nlet [Subject] = vars(\"Subject\")\nor(\n triple(Subject, 'label', \"A\"),\n triple(Subject, \"label\", \"a\")\n )\n```\n\n#### order\\_by(varNames)\n\nOrders the results of the contained subquery by a precedence list of variables\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nvarNames\n\nstring|Var|array\n\nA sequence of variables, by which to order the results, each optionally followed by either “asc” or “desc” to represent order as a list, by default it will sort the variable in ascending order\n\n##### Examples\n\n```javascript\nlet [A, B, C] = vars(\"A\", \"B\", \"C\")\nWOQL.order_by(A, [B, \"asc\"], [C, \"desc\"]).triple(A, B, C);\n```\n\n#### pad(inputVarName, pad, len, resultVarName)\n\nPads out the string input to be exactly len long by appending the pad character pad to form output\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ninputVarName\n\nstring|Var\n\nThe input string or variable in unpadded state\n\npad\n\nstring|Var\n\nThe characters to use to pad the string or a variable representing them\n\nlen\n\nnumber|string|Var\n\nThe variable or integer value representing the length of the output string\n\nresultVarName\n\nstring|Var\n\nstores output\n\n##### Examples\n\n```javascript\nlet [fixed] = vars(\"fixed length\")\npad(\"joe\", \" \", 8, fixed)\n//fixed contains \"joe \"\n```\n\n#### path(subject, pattern, object, resultVarName)\n\nPerforms a path regular expression match on the graph\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubject\n\nstring|Var\n\nAn IRI or variable that refers to an IRI representing the subject, i.e. the starting point of the path\n\npattern\n\nstring\n\n(string) - A path regular expression describing a pattern through multiple edges of the graph (see: https://terminusdb.com/docs/path-query-reference-guide)\n\nobject\n\nstring|Var\n\nAn IRI or variable that refers to an IRI representing the object, i.e. ending point of the path\n\nresultVarName\n\nstring|Var\n\nA variable in which the actual paths traversed will be stored\n\n##### Examples\n\n```javascript\nlet [person, grand_uncle, lineage] = vars(\"person\", \"grand uncle\", \"lineage\")\npath(person, \"((father|mother) {2,2}), brother)\", grand_uncle, lineage)\n```\n\n#### plus(args)\n\nAdds the numbers together\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nargs\n\nstring|number|Var\n\na variable or numeric containing the values to add\n\n##### Examples\n\n```javascript\nlet [result] = vars(\"result\")\nevaluate(plus(2, plus(3, 1)), result)\n```\n\n#### post(url, formatObj, source)\n\nIdentifies a resource as a local path on the client, to be sent to the server through a HTTP POST request, with the format defined through the options\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nurl\n\nstring\n\nThe Path on the server at which the file resource can be accessed\n\nformatObj\n\ntypedef.DataFormatObj\n\nimput options, optional\n\nsource\n\nstring\n\nIt defines the source of the file, it can be 'url','post'\n\n##### Examples\n\n```\npost(\"/.../.../\", {type:'csv'})\n```\n\n#### put(varsToExp, query, fileResource)\n\nUse the document inteface to import documents\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nvarsToExp\n\nVars|array.\n\nan array of AsVar variable mappings (see as for format below)\n\nquery\n\nWOQLQuery\n\nThe query which will be executed to produce the results\n\nfileResource\n\nstring\n\nan file resource local to the server\n\n#### quad(subject, predicate, object, graphRef)\n\nCreates a pattern matching rule for the quad \\[S, P, O, G\\] (Subject, Predicate, Object, Graph)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubject\n\nstring|Var\n\nThe IRI of a triple’s subject or a variable\n\npredicate\n\nstring|Var\n\nThe IRI of a property or a variable\n\nobject\n\nstring|Var\n\nThe IRI of a node or a variable, or a literal\n\ngraphRef\n\ntypedef.GraphRef\n\nA valid graph resource identifier string\n\n#### query()\n\nGenerates an empty WOQLQuery object\n\n##### Examples\n\n```javascript\nlet q = query()\n//then q.triple(1, 1) ...\n```\n\n#### re(pattern, inputVarName, resultVarList)\n\nMatches the regular expression defined in Patern against the Test string, to produce the matched patterns in Matches\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\npattern\n\nstring\n\nstring or variable using normal PCRE regular expression syntax with the exception that special characters have to be escaped twice (to enable transport in JSONLD)\n\ninputVarName\n\nstring|Var\n\nstring or variable containing the string to be tested for patterns with the regex\n\nresultVarList\n\nstring|array|object|Var\n\nvariable representing the list of matches or a list of strings or variables\n\n##### Examples\n\n```javascript\nlet [All, Sub] = vars(\"All\", \"Sub\")\nWOQL.re(\"h(.).*\", \"hello\", [All, Sub])\n//e contains 'e', llo contains 'llo'\n//p is a regex pattern (.*) using normal regular expression syntax, the only unusual\nthing is that special characters have to be escaped twice, s is the string to be matched\nand m is a list of matches:\n```\n\n#### read\\_document(IRI, output)\n\nRead a node identified by an IRI as a JSON-LD document\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nIRI\n\nstring\n\nThe document id or a variable to read\n\noutput\n\nstring\n\nVariable which will be bound to the document.\n\n##### Examples\n\n```javascript\nlet [person] = vars(\"Person\")\nconst query = WOQL.read_document(\n \"Person/0b4feda109d9d13c9da809090b342ad9e4d8185545ce05f7cd20b97fe458f547\",\n person\n);\nconst res = await client.query(query);\n```\n\n#### read\\_object()\n\nUse {@link #read\\_document|read\\_document} instead.\n\n#### remote(remoteObj, formatObj)\n\nIdentifies a remote resource by URL and specifies the format of the resource through the options\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nremoteObj\n\nobject\n\nThe URL at which the remote resource can be accessed\n\nformatObj\n\ntypedef.DataFormatObj\n\nThe format of the resource data {}\n\n##### Examples\n\n```\nremote({url:\"http://url.of.resource\"}, {type: \"csv\"})\n```\n\n#### removed\\_quad(subject, predicate, object, graphRef-)\n\nCreates a pattern matching rule for the quad \\[S, P, O, G\\] (Subject, Predicate, Object, Graph) removed from the current commit\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubject\n\nstring|Var\n\nThe IRI of a triple’s subject or a variable\n\npredicate\n\nstring|Var\n\nThe IRI of a property or a variable\n\nobject\n\nstring|Var\n\nThe IRI of a node or a variable, or a literal\n\ngraphRef-\n\ntypedef.GraphRef\n\nA valid graph resource identifier string\n\n#### removed\\_triple(subject, predicate, object)\n\nCreates a triple pattern matching rule for the triple \\[S, P, O\\] (Subject, Predicate, Object) added in the current commit\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubject\n\nstring|Var\n\nThe IRI of a triple’s subject or a variable\n\npredicate\n\nstring|Var\n\nThe IRI of a property or a variable\n\nobject\n\nstring|Var\n\nThe IRI of a node or a variable, or a literal\n\n#### select(varNames)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nvarNames\n\nstring|Var\n\nonly these variables are returned\n\n##### Examples\n\n```javascript\nlet [a, b, c] = vars(\"a\", \"b\", \"c\")\nWOQL.select(a, triple(a, b, c))\nFilters the query so that only the variables included in [V1...Vn] are returned in the bindings\n```\n\n#### size(resourceId, resultVarName)\n\nCalculates the size in bytes of the contents of the resource identified in ResourceID\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nresourceId\n\nstring|Var\n\nA valid resource identifier string (can refer to any graph / branch / commit / db)\n\nresultVarName\n\nstring|Var\n\nThe variable name\n\n##### Examples\n\n```javascript\nlet [varSize] = vars(\"varSize\")\nsize(\"admin/minecraft/local/branch/main/instance/main\", varSize)\n//returns the number of bytes in the main instance graph on the main branch\n```\n\n#### split(inputVarName, separator, resultVarName)\n\nSplits a string (Input) into a list strings (Output) by removing separator\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ninputVarName\n\nstring|Var\n\nA string or variable representing the unsplit string\n\nseparator\n\nstring|Var\n\nA string or variable containing a sequence of charatcters to use as a separator\n\nresultVarName\n\nstring|Var\n\nvariable that stores output list\n\n##### Examples\n\n```javascript\nlet [words] = vars(\"words\")\nsplit(\"joe has a hat\", \" \", words)\n```\n\n#### star(graph, subject, predicate, object)\n\nGenerates a query that by default matches all triples in a graph identified by \"graph\" or in all the current terminusDB's graph\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ngraph\n\nstring|boolean\n\nfalse or the resource identifier of a graph possible value are schema/{main - myschema - \\*} | instance/{main - myschema - \\*} | inference/{main - myschema - \\*}\n\nsubject\n\nstring|Var\n\nThe IRI of a triple’s subject or a variable, default value \"v:Subject\"\n\npredicate\n\nstring|Var\n\nThe IRI of a property or a variable, default value \"v:Predicate\"\n\nobject\n\nstring|Var\n\nThe IRI of a node or a variable, or a literal, default value \"v:Object\"\n\n##### Examples\n\n```\nstar(\"schema/main\")\n//will return every triple in schema/main graph\n```\n\n#### start(start, subquery)\n\nSpecifies an offset position in the results to start listing results from\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nstart\n\nnumber|string|Var\n\nA variable that refers to an interger or an integer literal\n\nsubquery\n\nWOQLQuery\n\nWOQL Query object, you can pass a subquery as an argument or a chained query\n\n##### Examples\n\n```javascript\nlet [a, b, c] = vars(\"a\", \"b\", \"c\")\nstart(100).triple(a, b, c)\n```\n\n#### string(val)\n\nGenerates explicitly a JSON-LD string literal from the input\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nval\n\nstring|boolean|number\n\nany primitive literal type\n\n##### Examples\n\n```\nstring(1)\n//returns { \"@type\": \"xsd:string\", \"@value\": \"1\" }\n```\n\n#### sub(classA, classB)\n\nReturns true if ClassA subsumes ClassB, according to the current DB schema\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nclassA\n\nstring\n\nClassA\n\nclassB\n\nstring\n\nClassB\n\n#### substr(string, before, length, after, substring)\n\nSubstring\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nstring\n\nstring|Var\n\nString or variable\n\nbefore\n\nnumber|Var\n\ninteger or variable (characters from start to begin)\n\nlength\n\nnumber|Var\n\ninteger or variable (length of substring)\n\nafter\n\nnumber|Var\n\ninteger or variable (number of characters after substring)\n\nsubstring\n\nstring|Var\n\nString or variable\n\n#### sum(subquery, total)\n\ncomputes the sum of the List of values passed. In contrast to other arithmetic functions, sum self-evaluates - it does not have to be passed to evaluate()\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubquery\n\nWOQLQuery\n\na subquery or (\\[string or numeric\\]) - a list variable, or a list of variables or numeric literals\n\ntotal\n\nstring|Var\n\nthe variable name with the sum result of the values in List\n\n##### Examples\n\n```javascript\nlet [total] = vars(\"total\")\nsum([2, 3, 4, 5], total)\n```\n\n#### times(args)\n\nMultiplies numbers N1...Nn together\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nargs\n\nstring|number|Var\n\na variable or numeric containing the value\n\n##### Examples\n\n```javascript\nlet [result] = vars(\"result\")\nevaluate(times(10, minus(2.1, plus(0.2, 1))), result)\n //result contains 9.000000000000002y\n```\n\n#### trim(inputStr, resultVarName)\n\nRemove whitespace from both sides of a string:\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ninputStr\n\nstring|Var\n\nA string or variable containing the untrimmed version of the string\n\nresultVarName\n\nstring|Var\n\nA string or variable containing the trimmed version of the string\n\n##### Examples\n\n```javascript\nlet [trimmed] = vars(\"trimmed\")\ntrim(\"hello \", trimmed)\n//trimmed contains \"hello\"\n```\n\n#### triple(subject, predicate, object)\n\nCreates a triple pattern matching rule for the triple \\[S, P, O\\] (Subject, Predicate, Object)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubject\n\nstring|Var\n\nThe IRI of a triple’s subject or a variable\n\npredicate\n\nstring|Var\n\nThe IRI of a property or a variable\n\nobject\n\nstring|Var\n\nThe IRI of a node or a variable, or a literal\n\n#### triple\\_count(resourceId, tripleCount)\n\nCalculates the number of triples of the contents of the resource identified in ResourceID\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nresourceId\n\nstring|Var\n\nA valid resource identifier string (can refer to any graph / branch / commit / db)\n\ntripleCount\n\nstring|number|Var\n\nAn integer literal with the size in bytes or a variable containing that integer\n\n##### Examples\n\n```javascript\nlet [count] = vars(\"count\")\ntriple_count(\"admin/minecraft/local/_commits\", count)\n//returns the number of bytes in the local commit graph\n```\n\n#### true()\n\nA function that always matches, always returns true\n\n##### Examples\n\n```\nwhen(true()).triple(\"a\", \"b\", \"c\")\n```\n\n#### type\\_of(elementId, elementType)\n\nReturns true if 'elementId' is of type 'elementType', according to the current DB schema\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nelementId\n\nstring|Var\n\nthe id of a schema graph element\n\nelementType\n\nstring|Var\n\nthe element type\n\n#### typecast(varName, varType, resultVarName)\n\nCasts the value of Input to a new value of type Type and stores the result in CastVar\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nvarName\n\nstring|number|object|Var\n\nEither a single variable or a literal of any basic type\n\nvarType\n\nstring|Var\n\nEither a variable or a basic datatype (xsd / xdd)\n\nresultVarName\n\nstring|Var\n\nsave the return variable\n\n##### Examples\n\n```javascript\nlet [time] = vars(\"time\")\ncast(\"22/3/98\", \"xsd:dateTime\", time)\n```\n\n#### unique(prefix, inputVarList, resultVarName)\n\nGenerate a new IRI from the prefix and a hash of the variables which will be unique for any given combination of variables\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nprefix\n\nstring\n\nA prefix for the IRI - typically formed of the doc prefix and the classtype of the entity (“doc:Person”)\n\ninputVarList\n\narray|string|Var\n\nAn array of variables and / or strings from which the unique hash will be generated\n\nresultVarName\n\nstring|Var\n\nVariable in which the unique ID is stored\n\n##### Examples\n\n```javascript\nlet [newid] = vars(\"newid\")\nunique(\"doc:Person\", [\"John\", \"Smith\"], newid)\n```\n\n#### update\\_document(docjson, IRI)\n\nUpdate a document identified by an IRI\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ndocjson\n\nobject\n\nThe document to update. Must either have an '@id' or have a class specified key.\n\nIRI\n\nstring\n\nAn optional identifier specifying the document location.\n\n#### update\\_quad(subject, predicate, newObject, graphRef)\n\nUpdate a pattern matching rule for the quad \\[S, P, O, G\\] (Subject, Predicate, Object, Graph)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubject\n\nstring|Var\n\nThe IRI of a triple’s subject or a variable\n\npredicate\n\nstring|Var\n\nThe IRI of a property or a variable\n\nnewObject\n\nstring|Var\n\nThe value to update or a literal\n\ngraphRef\n\ntypedef.GraphRef\n\nA valid graph resource identifier string\n\n#### update\\_triple(subject, predicate, newObjValue, oldObjValue)\n\nUpdate a pattern matching rule for the triple (Subject, Predicate, oldObjValue) with the new one (Subject, Predicate, newObjValue)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubject\n\nstring|Var\n\nThe IRI of a triple’s subject or a variable\n\npredicate\n\nstring|Var\n\nThe IRI of a property or a variable\n\nnewObjValue\n\nstring|Var\n\nThe value to update or a literal\n\noldObjValue\n\nstring|Var\n\nThe old value of the object\n\n#### upper(inputVarName, resultVarName)\n\nChanges a string to upper-case\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ninputVarName\n\nstring|Var\n\nstring or variable representing the uncapitalized string\n\nresultVarName\n\nstring|Var\n\nvariable that stores the capitalized string output\n\n##### Examples\n\n```javascript\nlet [allcaps] = vars(\"allcaps\")\nupper(\"aBCe\", allcaps)\n//upper contains \"ABCE\"\n```\n\n#### using(refPath, subquery)\n\nQuery running against any specific commit Id\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nrefPath\n\nstring\n\npath to specific reference Id or commit Id\n\nsubquery\n\nWOQLQuery\n\nsubquery for the specific commit point\n\n##### Examples\n\n```javascript\nlet [a, b, c] = vars(\"a\", \"b\", \"c\")\nWOQL.using(\"userName/dbName/local/commit|branch/commitID\").triple(a, b, c)\n```\n\n#### value(subject, predicate, objValue)\n\nCreates a pattern matching rule for a triple \\[Subject, Predicate, Object\\] add extra information about the type of the value object\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubject\n\nstring|Var\n\nThe IRI of a triple’s subject or a variable\n\npredicate\n\nstring|Var\n\nThe IRI of a property or a variable\n\nobjValue\n\nstring|number|boolean|Var\n\nan specific value\n\n#### vars(varNames)\n\nGenerates javascript variables for use as WOQL variables within a query\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nvarNames\n\nstring\n\n##### Examples\n\n```javascript\nconst [a, b, c] = WOQL.vars(\"a\", \"b\", \"c\")\n//a, b, c are javascript variables which can be used as WOQL variables in subsequent queries\n```\n\n### WOQLClient\n\n#### action(actionName, payload)\n\nSends an action to the server\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nactionName\n\nstring\n\nstructure of the action\n\npayload\n\nobject\n\na request body call\n\n#### addDocument(json, params, dbId, string, lastDataVersion, getDataVersion)\n\nto add a new document or a list of new documents into the instance or the schema graph.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\njson\n\nobject\n\nparams\n\ntypedef.DocParamsPost\n\nthe post parameters {@link #typedef.DocParamsPost}\n\ndbId\n\nstring\n\nthe dbid\n\nstring\n\nmessage\n\nthe insert commit message\n\nlastDataVersion\n\nstring\n\nthe last data version tracking id.\n\ngetDataVersion\n\nboolean\n\nIf true the function will return object having result and dataVersion.\n\n##### Examples\n\n```javascript\nconst json = [{ \"@type\" : \"Class\",\n \"@id\" : \"Coordinate\",\n \"@key\" : { '@type' : 'Hash',\n '@fields' : ['x','y'] },\n \"x\" : \"xsd:decimal\",\n \"y\" : \"xsd:decimal\" },\n { \"@type\" : \"Class\",\n \"@id\" : \"Country\",\n \"@key\" : { '@type' : 'Lexical',\n '@fields' : [name] },\n \"name\" : \"xsd:string\",\n \"perimeter\" : { \"@type\" : \"List\",\n \"@class\" : \"Coordinate\" } }]\nclient.addDocument(json,{\"graph_type\":\"schema\"},\"mydb\",\"add new schema documents\")\n\n//if we would like to override the entire schema\nconst json = [\n{\"@base\": \"terminusdb:///data/\",\n \"@schema\": \"terminusdb:///schema#\",\n \"@type\": \"@context\"\n },\n {\n \"@id\": \"Person\",\n \"@key\": {\n \"@type\": \"Random\"\n },\n \"@type\": \"Class\",\n \"name\": {\n \"@class\": \"xsd:string\",\n \"@type\": \"Optional\"\n }\n }]\n\n// client.addDocument(json,{\"graph_type\":\"schema\",\"full_replace:true\"},\n \"mydb\",\"update the all schema\");\n\n// Here we will pass true to show how to get dataVersion\n\nconst response = await client.addDocument(json, {\"graph_type\": \"schema\"},\n \"mydb\",\n \"add new schema\", '',\n true\n)\nconsole.log(response);\n\n // This will output:\n // {\n // result: [ ...... ],\n // dataVersion: 'branch:5fs681tlycnn6jh0ceiqcq4qs89pdfs'\n // }\n\n // Now we can use the data version we recieved as a response in previous\n // function call and used it is next function call as lastDataVersion\n\nconst response1 = await client.addDocument(json, {\"graph_type\": \"schema\"},\n \"mydb\",\n \"add new schema\", response.dataVersion,\n)\n```\n\n#### api()\n\nRetrieve the URL of the server’s API base that we are currently connected to\n\n##### Examples\n\n```javascript\nlet api_url = client.api()\n```\n\n#### apply(beforeVersion, afterVersion, message, matchFinalState, options)\n\nDiff two different commits and apply changes on the current branch/commit. If you would like to change branch or commit before apply use client.checkout(\"branchName\")\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nbeforeVersion\n\nstring\n\nBefore branch/commit to compare\n\nafterVersion\n\nstring\n\nAfter branch/commit to compare\n\nmessage\n\nstring\n\napply commit message\n\nmatchFinalState\n\nboolean\n\nthe default value is false\n\noptions\n\nobject\n\n{keep:{}} Options to send to the apply endpoint\n\n##### Examples\n\n```\nclient.checkout(\"mybranch\")\nclient.apply(\"mybranch\",\"mybranch_new\",\"merge main\").then(result=>{\n console.log(result)\n})\n```\n\n#### author()\n\nGets the string that will be written into the commit log for the current user\n\n##### Examples\n\n```\nclient.author()\n```\n\n#### branch(newBranchId, isEmpty)\n\nCreates a new branch with a TerminusDB database, starting from the current context of the client (branch / ref)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nnewBranchId\n\nstring\n\nlocal identifier of the new branch the ID of the new branch to be created\n\nisEmpty\n\nboolean\n\nif isEmpty is true it will create a empty branch.\n\n##### Examples\n\n```\nclient.branch(\"dev\")\n```\n\n#### checkout(branchId)\n\nGets/Sets the client’s internal branch context value (defaults to ‘main’)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nbranchId\n\nstring\n\nthe branch id to set the context to\n\n#### clonedb(cloneSource, newDbId, orgId)\n\nClones a remote repo and creates a local copy\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ncloneSource\n\ntypedef.CloneSourceDetails\n\nobject describing the source branch to be used as a base\n\nnewDbId\n\nstring\n\nid of the new cloned database on the local server\n\norgId\n\nstring\n\nid of the local organization that the new cloned database will be created in (in desktop mode this is always “admin”)\n\n##### Examples\n\n```python\nclient.clonedb({remote_url: \"https://my.terminusdb.com/myorg/mydb\", label \"Cloned DB\", comment: \"Cloned from mydb\"}, newid: \"mydb\")\n```\n\n#### connect(params)\n\nYou can call this to get the server info or override the start params configuration, this.connectionConfig.server will be used if present, or the promise will be rejected.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nparams\n\ntypedef.ParamsObj\n\nTerminusDB Server connection parameters\n\n##### Examples\n\n```\nclient.connect()\n```\n\n#### copy()\n\ncreates a copy of the client with identical internal state and context useful if we want to change context for a particular API call without changing the current client context\n\n##### Examples\n\n```javascript\nlet newClient = client.copy()\n```\n\n#### createDatabase(dbId, dbDetails, orgId)\n\nCreates a new database in TerminusDB server\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ndbId\n\nstring\n\nThe id of the new database to be created\n\ndbDetails\n\ntypedef.DbDetails\n\nobject containing details about the database to be created\n\norgId\n\nstring\n\noptional organization id - if absent default local organization id is used\n\n##### Examples\n\n```\n//remember set schema:true if you need to add a schema graph\nclient.createDatabase(\"mydb\", {label: \"My Database\", comment: \"Testing\", schema: true})\n```\n\n#### customHeaders(customHeaders)\n\nadd extra headers to your request\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ncustomHeaders\n\nobject\n\n#### databaseInfo(dbName)\n\nGets the database's details\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ndbName\n\nstring\n\nthe datbase name\n\n#### databases(dbList)\n\nSet/Get the organization's databases list (id, label, comment) that the current user has access to on the server.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ndbList\n\narray\n\na list of databases the user has access to on the server, each having:\n\n##### Examples\n\n```javascript\n//to get the list of all organization's databases\nasync function callGetDatabases(){\n await client.getDatabases()\n console.log(client.databases())\n}\n```\n\n#### db(dbId)\n\nSets / Gets the current database\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ndbId\n\nstring\n\nthe database id to set the context to\n\n##### Examples\n\n```\nclient.db(\"mydb\")\n```\n\n#### deleteBranch(branchId)\n\nDeletes a branch from database\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nbranchId\n\nstring\n\nlocal identifier of the branch\n\n#### deleteDatabase(dbId, orgId, force)\n\nDeletes a database from a TerminusDB server\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ndbId\n\nstring\n\nThe id of the database to be deleted\n\norgId\n\nstring\n\nthe id of the organization to which the database belongs (in desktop use, this will always be “admin”)\n\nforce\n\nboolean\n\n##### Examples\n\n```\nclient.deleteDatabase(\"mydb\")\n```\n\n#### deleteDocument(params, dbId, message, lastDataVersion, getDataVersion)\n\nto delete the document\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nparams\n\ntypedef.DocParamsDelete\n\ndbId\n\nstring\n\nthe database id\n\nmessage\n\nstring\n\nthe delete message\n\nlastDataVersion\n\nstring\n\nthe last data version tracking id.\n\ngetDataVersion\n\nboolean\n\nIf true the function will return object having result and dataVersion.\n\n##### Examples\n\n```javascript\nclient.deleteDocument({\"graph_type\":\"schema\",id:['Country','Coordinate']})\n\n\n// Here we will pass true to show how to get dataVersion\n\nconst response = await client.deleteDocument({\"graph_type\":\"schema\",id:['Country','Coordinate']},\n \"\",\n \"\",\n \"\",\n true\n)\nconsole.log(response);\n\n // This will output:\n // {\n // result: [ ...... ],\n // dataVersion: 'branch:5fs681tlycnn6jh0ceiqcq4qs89pdfs'\n // }\n\n // Now we can use the data version we recieved as a response in previous\n // function call and used it is next function call as lastDataVersion\n\nconst response1 = await client.deleteDocument({\"graph_type\":\"schema\",\n id:['Country','Coordinate']},\n \"\",\n \"\",\n response.dataVersion,\n)\n```\n\n#### dispatch()\n\nCommon request dispatch function\n\n#### fetch(remoteId)\n\nFetch updates to a remote database to a remote repository with the local database\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nremoteId\n\nstring\n\nif of the remote to fetch (eg: 'origin')\n\n#### generateCommitDescriptor(commitId)\n\nGenerates the json structure for commit descriptor\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ncommitId\n\nstring\n\na valid commit id o\n\n#### generateCommitInfo(msg, author)\n\nGenerates the json structure for commit messages\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nmsg\n\nstring\n\ntextual string describing reason for the change\n\nauthor\n\nstring\n\noptional author id string - if absent current user id will be used\n\n#### getBranches(dbId)\n\nget the database collections list\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ndbId\n\nstring\n\nthe database id\n\n##### Examples\n\n```\nclient.getBranches()\n```\n\n#### getClassDocuments(dbId)\n\nget all the Document Classes (no abstract or subdocument)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ndbId\n\nstring\n\n##### Examples\n\n```\nclient.getClassDocuments()\n```\n\n#### getClasses(dbId)\n\nget all the schema classes (documents,subdocuments,abstracts)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ndbId\n\nstring\n\nthe database id\n\n##### Examples\n\n```\nclient.getClasses()\n```\n\n#### getCommitsLog(start, count)\n\nget the database collections list\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nstart\n\nnumber\n\nwhere to start printing the commit information in the log (starting from the head of the current branch)\n\ncount\n\nnumber\n\nThe number of total commit log records to return\n\n##### Examples\n\n```\nclient.getCommitsLog(count=10)\n```\n\n#### getDatabases()\n\nGets the organization's databases list. If no organization has been set up, the function throws an exception\n\n##### Examples\n\n```javascript\nasync function callGetDatabases(){\n const dbList = await client.getDatabases()\n console.log(dbList)\n}\n```\n\n#### getDocument(params, dbId, branch, lastDataVersion, getDataVersion, query)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nparams\n\ntypedef.DocParamsGet\n\nthe get parameters, you can pass document query search template with the params\n\ndbId\n\nstring\n\nthe database id\n\nbranch\n\nstring\n\nthe database branch\n\nlastDataVersion\n\nstring\n\nthe last data version tracking id.\n\ngetDataVersion\n\nboolean\n\nIf true the function will return object having result and dataVersion.\n\nquery\n\nobject\n\ndocument query search template\n\n##### Examples\n\n```python\n//return the schema graph as a json array\nclient.getDocument({\"graph_type\":\"schema\",\"as_list\":true}).then(result={\n console.log(result)\n})\n\n//retutn the Country class document from the schema graph\nclient.getDocument({\"graph_type\":\"schema\",\"as_list\":true,\"id\":\"Country\"}).then(result={\n console.log(result)\n})\n\n//pass a document query template to query the document interface\nconst queryTemplate = { \"name\": \"Ireland\"}\nclient.getDocument({\"as_list\":true, \"@type\":\"Country\"\n query:queryTemplate}).then(result=>{\n console.log(result)\n})\n\n\n// Here we will pass true to show how to get dataVersion\nconst response = await client.getDocument({\"graph_type\":\"schema\",\"as_list\":true},\n \"\",\n \"\",\n \"\",\n true\n)\nconsole.log(response);\n\n // This will output:\n // {\n // result: [ ...... ],\n // dataVersion: 'branch:5fs681tlycnn6jh0ceiqcq4qs89pdfs'\n // }\n\n // Now we can use the data version we recieved as a response in previous\n // function call and used it is next function call as lastDataVersion\n\nconst response1 = await client.getDocument({\"graph_type\":\"schema\",\"as_list\":true},\n \"\",\n \"\",\n response.dataVersion,\n)\n```\n\n#### getDocumentHistory(id, historyParams)\n\nGet the document's history for a specific database or branch\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nid\n\nstring\n\nid of document to report history of\n\nhistoryParams\n\ntypedef.DocHistoryParams\n\n##### Examples\n\n```\n//this will return the last 5 commits for the Person/Anna document\nclient.checkout(\"mybranch\")\nclient.docHistory(\"Person/Anna\",{start:0,count:5}).then(result=>{\n console.log(result)\n})\n//this will return the last and the first commit for the Person/Anna document\nclient.docHistory(\"Person/Anna\",{updated:true,created:true}).then(result=>{\n console.log(result)\n})\n```\n\n#### getEnums(dbId)\n\nget all the Enum Objects\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ndbId\n\nstring\n\n##### Examples\n\n```\nclient.getEnums()\n```\n\n#### getJSONDiff(before, after, options)\n\nGet the patch of difference between two documents.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nbefore\n\nobject\n\nThe current state of JSON document\n\nafter\n\nobject\n\nThe updated state of JSON document\n\noptions\n\nobject\n\n{keep:{}} Options to send to the diff endpoint. The diff api outputs the changes between the input, in options you can list the properties that you would like to see in the diff result in any case.\n\n##### Examples\n\n```\nclient.getJSONDiff(\n { \"@id\": \"Person/Jane\", \"@type\": \"Person\", name: \"Jane\" },\n { \"@id\": \"Person/Jane\", \"@type\": \"Person\", name: \"Janine\" }\n ).then(diffResult=>{\n console.log(diffResult)\n})\n//result example\n//{'@id': 'Person/Jane',\n// name: { '@after': 'Janine', '@before': 'Jane', '@op': 'SwapValue' }}\n```\n\n#### getPrefixes(dbId)\n\nget the database prefixes object\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ndbId\n\nstring\n\nthe database id\n\n##### Examples\n\n```\nclient.getPrefixes()\n//return object example\n{\n'@base': 'terminusdb:///data/',\n'@schema': 'terminusdb:///schema#',\n'@type': 'Context'}\n```\n\n#### getSchema(dbId, branch)\n\nget the database schema in json format\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ndbId\n\nstring\n\nthe database id\n\nbranch\n\nstring\n\nspecific a branch/collection\n\n##### Examples\n\n```\nclient.getSchema()\n```\n\n#### getSchemaFrame(type, dbId)\n\nThe purpose of this method is to quickly discover the supported fields of a particular type.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ntype\n\nstring\n\nIf given, the type to get information for. If omitted, information for all types is returned\n\ndbId\n\nstring\n\nthe database id\n\n##### Examples\n\n```\nclient.getSchemaFrame(\"Country\")\n```\n\n#### getTriples(graphType)\n\nRetrieve the contents of a graph within a TerminusDB as triples, encoded in the turtle (ttl) format\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ngraphType\n\ntypedef.GraphType\n\ntype of graph to get triples from, either “instance” or “schema”\n\n##### Examples\n\n```javascript\nconst turtle = await client.getTriples(\"schema\", \"alt\")\n```\n\n#### getUserOrganizations()\n\nGet the list of the user's organizations and the database related\n\n##### Examples\n\n```\nasync funtion callGetUserOrganizations(){\n await getUserOrganizations()\n console.log(client.userOrganizations())\n}\n```\n\n#### getVersionDiff(beforeVersion, afterVersion, id, options)\n\nGet the patch of difference between branches or commits.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nbeforeVersion\n\nstring\n\nBefore branch/commit to compare\n\nafterVersion\n\nstring\n\nAfter branch/commit to compare\n\nid\n\nstring\n\nThe document id to be diffed, if it is omitted all the documents will be compared\n\noptions\n\ntypedef.DiffObject\n\n{keep:{},count:10,start:0} Options to send to the diff endpoint. The diff api outputs the changes between the input (branches or commits), in options you can list the properties that you would like to see in the diff result in any case.\n\n##### Examples\n\n```javascript\n//This is to view all the changes between two commits\nconst beforeCommit = \"a73ssscfx0kke7z76083cgswszdxy6l\"\nconst afterCommit = \"73rqpooz65kbsheuno5dsayh71x7wf4\"\n\nclient.getVersionDiff( beforeCommit, afterCommit).then(diffResult=>{\n console.log(diffResult)\n})\n\n//This is to view the changes between two commits but only for the given document\nclient.getVersionDiff( beforeCommit, afterCommit, \"Person/Tom\").then(diffResult=>{\n console.log(diffResult)\n})\n\n//This is to view the changes between a branch (head) and a commit for the given document\nclient.getVersionDiff(\"main\", afterCommit, \"Person/Tom\" ).then(diffResult=>{\n console.log(diffResult)\n})\n\n//This is to view the changes between two branches with the keep options\nconst options = {\"keep\":{\"@id\":true, \"name\": true}, start:0, count:10}\nclient.getVersionDiff(\"main\",\"mybranch\",options).then(diffResult=>{\n console.log(diffResult)\n})\n```\n\n#### getVersionObjectDiff(dataVersion, jsonObject, id, options)\n\nGet the patch of difference between two documents.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ndataVersion\n\nstring\n\nThe version from which to compare the object\n\njsonObject\n\nobject\n\nThe updated state of JSON document\n\nid\n\nstring\n\nThe document id to be diffed\n\noptions\n\nobject\n\n{keep:{}} Options to send to the diff endpoint the diff api outputs the changes between the input, but you can list the properties that you would like to see in the diff result in any case.\n\n##### Examples\n\n```javascript\nconst jsonObj = { \"@id\": \"Person/Jane\", \"@type\": \"Person\", name: \"Janine\" }\nclient.getVersionObjectDiff(\"main\",jsonObj\n \"Person/Jane\").then(diffResp=>{\n console.log(diffResp)\n})\n```\n\n#### hasDatabase(orgName, dbName)\n\nChecks if a database exists Returns true if a DB exists and false if it doesn't. Other results throw an exception.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\norgName\n\nstring\n\nthe organization id to set the context to\n\ndbName\n\nstring\n\nthe db name to set the context to\n\n##### Examples\n\n```javascript\nasync function executeIfDatabaseExists(f){\n const hasDB = await client.hasDatabase(\"admin\", \"testdb\")\n if (hasDB) {\n f()\n }\n}\n```\n\n#### info()\n\nGets TerminusDB Server Information\n\n##### Examples\n\n```\nclient.info()\n```\n\n#### insertTriples(graphType, turtle, commitMsg)\n\nAppends the passed turtle to the contents of a graph\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ngraphType\n\nstring\n\ntype of graph |instance|schema|inference|\n\nturtle\n\nstring\n\nis a valid set of triples in turtle format (OWL)\n\ncommitMsg\n\nstring\n\nTextual message describing the reason for the update\n\n#### localAuth(newCredential)\n\nSets/Gets set the database basic connection credential\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nnewCredential\n\ntypedef.CredentialObj\n\n##### Examples\n\n```\nclient.localAuth({user:\"admin\",\"key\":\"mykey\",\"type\":\"basic\"})\n```\n\n#### message(message, pathname)\n\nSends a message to the server\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nmessage\n\nstring\n\ntextual string\n\npathname\n\nstring\n\na server path to send the message to\n\n#### optimizeBranch(branchId)\n\nOptimize db branch\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nbranchId\n\nstring\n\nlocal identifier of the new branch\n\n#### organization(orgId)\n\nGets/Sets the client’s internal organization context value, if you change the organization name the databases list will be set to empty\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\norgId\n\nstring|boolean\n\nthe organization id to set the context to\n\n##### Examples\n\n```\nclient.organization(\"admin\")\n```\n\n#### patch(before, patch)\n\nApply a patch object to another object\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nbefore\n\nobject\n\nThe current state of JSON document\n\npatch\n\nobject\n\nThe patch object\n\n##### Examples\n\n```\nclient.patch(\n { \"@id\" : \"Person/Jane\", \"@type\" : \"Person\", \"name\" : \"Jane\"},\n { \"name\" : { \"@op\" : \"ValueSwap\", \"@before\" : \"Jane\", \"@after\": \"Janine\" }}\n ).then(patchResult=>{\n console.log(patchResult)\n})\n//result example\n//{ \"@id\" : \"Person/Jane\", \"@type\" : \"Person\", \"name\" : \"Jannet\"}\n```\n\n#### patchResource(patch, message)\n\nApply a patch object to the current resource\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\npatch\n\narray\n\nThe patch object\n\nmessage\n\nstring\n\nThe commit message\n\n##### Examples\n\n```javascript\nconst patch = [\n {\n \"@id\": \"Obj/id1\",\n \"name\": {\n \"@op\": \"SwapValue\",\n \"@before\": \"foo\",\n \"@after\": \"bar\"\n }\n },\n {\n \"@id\": \"Obj/id2\",\n \"name\": {\n \"@op\": \"SwapValue\",\n \"@before\": \"foo\",\n \"@after\": \"bar\"\n }\n }\n]\nclient.db(\"mydb\")\nclient.checkout(\"mybranch\")\nclient.patchResource(patch,\"apply patch to mybranch\").then(patchResult=>{\n console.log(patchResult)\n})\n// result example\n// [\"Obj/id1\",\n// \"Obj/id2\"]\n// or conflict error 409\n// {\n// \"@type\": \"api:PatchError\",\n// \"api:status\": \"api:conflict\",\n// \"api:witnesses\": [\n// {\n// \"@op\": \"InsertConflict\",\n// \"@id_already_exists\": \"Person/Jane\"\n// }\n//]\n//}\n```\n\n#### prepareRevisionControlArgs(rc\\_args)\n\nAdds an author string (from the user object returned by connect) to the commit message.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nrc\\_args\n\nobject\n\n#### pull(remoteSourceRepo)\n\nPull changes from a branch on a remote database to a branch on a local database\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nremoteSourceRepo\n\ntypedef.RemoteRepoDetails\n\nan object describing the source of the pull\n\n##### Examples\n\n```python\nclient.pull({remote: \"origin\", remote_branch: \"main\", message: \"Pulling from remote\"})\n```\n\n#### push(remoteTargetRepo)\n\nPush changes from a branch on a local database to a branch on a remote database\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nremoteTargetRepo\n\ntypedef.RemoteRepoDetails\n\nan object describing the target of the push {remote: \"origin\", \"remote\\_branch\": \"main\", \"author\": \"admin\", \"message\": \"message\"}\n\n##### Examples\n\n```python\nclient.push({remote: \"origin\", remote_branch: \"main\", message: \"Pulling from remote\"})\n```\n\n#### query(woql, commitMsg, allWitnesses, lastDataVersion, getDataVersion)\n\nExecutes a WOQL query on the specified database and returns the results\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nwoql\n\nWOQLQuery\n\nan instance of the WOQLQuery class\n\ncommitMsg\n\nstring\n\na message describing the reason for the change that will be written into the commit log (only relevant if the query contains an update)\n\nallWitnesses\n\nboolean\n\nlastDataVersion\n\nstring\n\nthe last data version tracking id.\n\ngetDataVersion\n\nboolean\n\nIf true the function will return object having result and dataVersion.\n\n##### Examples\n\n```javascript\nconst result = await client.query(WOQL.star())\n```\n\n#### queryDocument(query, params, dbId, branch, lastDataVersion, getDataVersion)\n\nUse {@link #getDocument} instead.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nquery\n\nobject\n\nthe query template\n\nparams\n\ntypedef.DocParamsGet\n\nthe get parameters\n\ndbId\n\nstring\n\nthe database id\n\nbranch\n\nstring\n\nthe database branch\n\nlastDataVersion\n\nstring\n\nthe last data version tracking id.\n\ngetDataVersion\n\nboolean\n\nIf true the function will return object having result and dataVersion.\n\n##### Examples\n\n```javascript\nconst query = {\n \"type\": \"Person\",\n \"query\": { \"age\": 42 },\n }\nclient.queryDocument(query, {\"as_list\":true})\n\n\n// Here we will pass true to show how to get dataVersion\nconst query = {\n \"type\": \"Person\",\n \"query\": { \"age\": 42 },\n }\n\nconst response = await client.queryDocument(query, {\"as_list\": true}, '', '','',true);\nconsole.log(response);\n\n // This will output:\n // {\n // result: [\n // {\n // '@id': 'Person/052d60ffbd114bf5e7331b03f07fcb7',\n // '@type': 'Person',\n // age: 42,\n // name: 'John',\n // },\n // ],\n // dataVersion: 'branch:5fs681tlycnn6jh0ceiqcq4qs89pdfs'\n // }\n\n // Now we can use the data version we recieved as a response in previous\n // query and used it is next query as lastDataVersion\n const query = {\n \"type\": \"Person\",\n \"query\": { \"age\": 18 },\n }\n\n const response1 = await client.queryDocument(query, {\"as_list\": true}, '',\n '',\n response.dataVersion\n );\n```\n\n#### rebase(rebaseSource)\n\nMerges the passed branch into the current one using the rebase operation\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nrebaseSource\n\nobject\n\njson describing the source branch to be used as a base\n\n##### Examples\n\n```python\n//from the branch head\nclient.rebase({rebase_from: \"admin/db_name/local/branch/branch_name\", message:\n\"Merging from dev\")\n//or from a commit id\nclient.rebase({rebase_from: \"admin/db_name/local/commit/9w8hk3y6rb8tjdy961de3i536ntkqd8\",\nmessage: \"Merging from dev\")\n```\n\n#### ref(commitId)\n\nSets / gets the current ref pointer (pointer to a commit within a branch) Reference ID or Commit ID are unique hashes that are created whenever a new commit is recorded\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ncommitId\n\nstring\n\nthe reference ID or commit ID\n\n##### Examples\n\n```\nclient.ref(\"mkz98k2h3j8cqjwi3wxxzuyn7cr6cw7\")\n```\n\n#### remoteAuth(newCredential)\n\nSets/Gets the jwt token for authentication we need this to connect 2 terminusdb server to each other for push, pull, clone actions\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nnewCredential\n\ntypedef.CredentialObj\n\n##### Examples\n\n```\nclient.remoteAuth({\"key\":\"dhfmnmjglkrelgkptohkn\",\"type\":\"jwt\"})\n```\n\n#### repo(repoId)\n\nGets / Sets the client’s internal repository context value (defaults to ‘local’)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nrepoId\n\ntypedef.RepoType|string\n\ndefault value is local\n\n##### Examples\n\n```\nclient.repo(\"origin\")\n```\n\n#### reset(commitPath)\n\nReset the current branch HEAD to the specified commit path\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ncommitPath\n\nstring\n\nThe commit path to set the current branch to\n\n#### resetBranch(branchId, commitId)\n\nReset branch to a commit id, Reference ID or Commit ID are unique hashes that are created whenever a new commit is recorded\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nbranchId\n\nstring\n\nlocal identifier of the new branch\n\ncommitId\n\nstring\n\nReference ID or Commit ID\n\n#### resource(resourceType, resourceId)\n\nGenerates a resource string for the required context of the current context for \"commits\" \"meta\" \"branch\" and \"ref\" special resources\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nresourceType\n\ntypedef.ResourceType\n\nthe type of resource string that is required - one of “db”, “meta”, “repo”, “commits”, “branch”, “ref”\n\nresourceId\n\nstring\n\ncan be used to specify a specific branch / ref - if not supplied the current context will be used\n\n##### Examples\n\n```javascript\nconst branch_resource = client.resource(\"branch\")\n```\n\n#### sendCustomRequest(requestType, customRequestURL, payload)\n\nCall a custom Api endpoit\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nrequestType\n\nstring\n\nThe current state of JSON document\n\ncustomRequestURL\n\nstring\n\nThe patch object\n\npayload\n\nobject\n\nthe request payload\n\n##### Examples\n\n```\nclient.sendCustomRequest(\"GET\", \"http://localhost:3030/changes/\").then(result=>{\n console.log(result)\n})\n```\n\n#### server()\n\nGets the current connected server url it can only be set creating a new WOQLCLient instance\n\n#### set(params)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nparams\n\ntypedef.ParamsObj\n\na object with connection params\n\n##### Examples\n\n```\nsets several of the internal state values in a single call\n(similar to connect, but only sets internal client state, does not communicate with server)\nclient.set({key: \"mypass\", branch: \"dev\", repo: \"origin\"})\n```\n\n#### setApiKey(accessToken)\n\nset the api key to access the cloud resources\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\naccessToken\n\nstring\n\n#### setSystemDb()\n\nSets the internal client context to allow it to talk to the server’s internal system database\n\n#### squashBranch(branchId, commitMsg)\n\nSquash branch commits\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nbranchId\n\nstring\n\nlocal identifier of the new branch\n\ncommitMsg\n\nstring\n\nTextual message describing the reason for the update\n\n#### updateDatabase(dbDoc)\n\nUpdate a database in TerminusDB server\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ndbDoc\n\ntypedef.DbDoc\n\nobject containing details about the database to be updated\n\n##### Examples\n\n```\nclient.updateDatabase({id: \"mydb\", label: \"My Database\", comment: \"Testing\"})\n```\n\n#### updateDocument(json, params, dbId, message, lastDataVersion, getDataVersion, compress, create)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\njson\n\nobject\n\nparams\n\ntypedef.DocParamsPut\n\nthe Put parameters {@link #typedef.DocParamsPut}\n\ndbId\n\n\\*\n\nthe database id\n\nmessage\n\n\\*\n\nthe update commit message\n\nlastDataVersion\n\nstring\n\nthe last data version tracking id.\n\ngetDataVersion\n\nboolean\n\nIf true the function will return object having result and dataVersion.\n\ncompress\n\nboolean\n\nIf true, the function will create a new document if it doesn't exist.\n\ncreate\n\nboolean\n\nPerform an \\*upsert\\* which inserts if the document is not present (also works on nested documents)\n\n##### Examples\n\n```javascript\nclient.updateDocument(\n{\n \"@id\": \"Person\",\n \"@key\": {\n \"@type\": \"Random\",\n },\n \"@type\": \"Class\",\n label: \"xsd:string\",\n },\n{ graph_type: \"schema\" }\n);\n\n\n// Here we will pass true to show how to get dataVersion\n\n const response = await client.updateDocument(\n {\n \"@id\": \"Person\",\n \"@key\": {\n \"@type\": \"Random\",\n },\n \"@type\": \"Class\",\n label: \"xsd:string\",\n },\n { graph_type: \"schema\" },\n \"\",\n \"\",\n \"\",\n true\n );\nconsole.log(response);\n\n // This will output:\n // {\n // result: [ ...... ],\n // dataVersion: 'branch:5fs681tlycnn6jh0ceiqcq4qs89pdfs'\n // }\n\n // Now we can use the data version we recieved as a response in previous\n // function call and used it is next function call as lastDataVersion\n\nconst response1 = await client.updateDocument(\n {\n \"@id\": \"Person\",\n \"@key\": {\n \"@type\": \"Random\",\n },\n \"@type\": \"Class\",\n label: \"xsd:string\",\n },\n { graph_type: \"schema\" },\n \"\",\n \"\",\n response.dataVersion\n );\n\n // update a document and create the linked document together\n // we are update the document \"Person/Person01\"\n // and create a new document {\"@type\": \"Person\",\"name\": \"child01\"} at the same time\n const response1 = await client.updateDocument(\n {\n \"@id\": \"Person/Person01\",\n \"@type\": \"Person\",\n \"name\": \"Person01\"\n \"children\":[{\"@type\": \"Person\",\"name\": \"child01\"}]\n },{create:true})\n```\n\n#### updateTriples(graphType, turtle, commitMsg)\n\nReplace the contents of the specified graph with the passed triples encoded in the turtle (ttl) format\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ngraphType\n\nstring\n\ntype of graph |instance|schema|inference|\n\nturtle\n\nstring\n\nstring encoding triples in turtle (ttl) format\n\ncommitMsg\n\nstring\n\nTextual message describing the reason for the update\n\n##### Examples\n\n```\nclient.updateTriples(\"schema\", \"alt\", turtle_string, \"dumping triples to graph alt\")\n```\n\n#### user()\n\nGets the current user object as returned by the connect capabilities response user has fields: \\[id, name, notes, author\\]\n\n#### userOrganization()\n\n#### userOrganizations(orgList)\n\nGet/Set the list of the user's organizations (id, organization, label, comment).\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\norgList\n\narray\n\na list of user's Organization\n\n##### Examples\n\n```\nasync funtion callGetUserOrganizations(){\n await client.getUserOrganizations()\n console.log(client.userOrganizations())\n}\n```\n\n### WOQLLibrary\n\n#### branches()\n\nGeneral Pattern 4: Retrieves Branches, Their ID, Head Commit ID, Head Commit Time (if present, new branches have no commits)\n\n#### commits(branch, limit, start, timestamp)\n\nget all the commits of a specific branch if a timestamp is given, gets all the commits before the specified timestamp\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nbranch\n\nstring\n\nthe branch name\n\nlimit\n\nnumber\n\nthe max number of result\n\nstart\n\nnumber\n\nthe start of the pagination\n\ntimestamp\n\nnumber\n\nUnix timestamp in seconds\n\n#### first\\_commit()\n\nFinds the id of the very first commit in a database's history This is useful for finding information about when, by who and why the database was created The first commit is the only commit in the database that does not have a parent commit\n\n#### previousCommits(commit\\_id, limit)\n\nget commits older than the specified commit id\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ncommit\\_id\n\nstring\n\nthe commit id\n\nlimit\n\nnumber\n\nthe max number of result\n\n### WOQLQuery\n\n#### addSubQuery()\n\nInternal library function which adds a subquery and sets the cursor\n\n#### addSubQuery(Subq)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nSubq\n\nWOQLQuery\n\n#### add\\_quad(subject, predicate, object, graphRef)\n\nAdds quads according to the pattern \\[S,P,O,G\\]\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubject\n\nstring|Var\n\nThe IRI of a triple’s subject or a variable\n\npredicate\n\nstring|Var\n\nThe IRI of a property or a variable\n\nobject\n\nstring|Var\n\nThe IRI of a node or a variable, or a literal\n\ngraphRef\n\ntypedef.GraphRef\n\nA valid graph resource identifier string\n\n#### add\\_triple(subject, predicate, object)\n\nAdds triples according to the the pattern \\[subject,predicate,object\\]\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubject\n\nstring|Var\n\nThe IRI of a triple’s subject or a variable\n\npredicate\n\nstring|Var\n\nThe IRI of a property or a variable\n\nobject\n\nstring|Var\n\nThe IRI of a node or a variable, or a literal\n\n#### added\\_quad(subject, predicate, object, graphRef-)\n\nCreates a pattern matching rule for the quad \\[S, P, O, G\\] (Subject, Predicate, Object, Graph) removed from the current commit\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubject\n\nstring|Var\n\nThe IRI of a triple’s subject or a variable\n\npredicate\n\nstring|Var\n\nThe IRI of a property or a variable\n\nobject\n\nstring|Var\n\nThe IRI of a node or a variable, or a literal\n\ngraphRef-\n\ntypedef.GraphRef\n\nA valid graph resource identifier string\n\n#### added\\_triple(subject, predicate, object)\n\nCreates a triple pattern matching rule for the triple \\[S, P, O\\] (Subject, Predicate, Object) added in the current layer\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubject\n\nstring|Var\n\nThe IRI of a triple’s subject or a variable\n\npredicate\n\nstring|Var\n\nThe IRI of a property or a variable\n\nobject\n\nstring|Var\n\nThe IRI of a node or a variable, or a literal\n\n#### all(Subj, Pred, Obj, Graph)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nSubj\n\nstring|Var\n\nThe IRI of a triple’s subject or a variable\n\nPred\n\nstring|Var\n\nThe IRI of a property or a variable\n\nObj\n\nstring|Var\n\nThe IRI of a node or a variable, or a literal\n\nGraph\n\ntypedef.GraphRef\n\nthe resource identifier of a graph possible\n\n#### all(Subj, Pred, Obj, Graph)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nSubj\n\nstring|Var\n\nThe IRI of a triple’s subject or a variable\n\nPred\n\nstring|Var\n\nThe IRI of a property or a variable\n\nObj\n\nstring|Var\n\nThe IRI of a node or a variable, or a literal\n\nGraph\n\ntypedef.GraphRef\n\nthe resource identifier of a graph possible\n\n#### and(subqueries)\n\nLogical conjunction of the contained queries - all queries must match or the entire clause fails\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubqueries\n\nWOQLQuery\n\nA list of one or more woql queries to execute as a conjunction\n\n#### arop()\n\nWraps arithmetic operators in the appropriate json-ld\n\n#### as(varList)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nvarList\n\narray|string|Var\n\nvariable number of arguments\n\n#### asv()\n\nWraps the elements of an AS variable in the appropriate json-ld\n\n#### boolean(tf)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ntf\n\nboolean\n\n#### boolean(tf)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ntf\n\nboolean\n\n#### cleanGraph()\n\nTransforms a graph filter or graph id into the proper json-ld form\n\n#### cleanObject()\n\nTransforms whatever is passed in as the object of a triple into the appropriate json-ld form (variable, literal or id)\n\n#### cleanPredicate()\n\nTransforms whatever is passed in as the predicate (id or variable) into the appropriate json-ld form\n\n#### cleanSubject()\n\nTransforms whatever is passed in as the subject into the appropriate json-ld for variable or id\n\n#### comment(comment, subquery)\n\nAdds a text comment to a query - can also be used to wrap any part of a query to turn it off\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ncomment\n\nstring\n\ntext comment\n\nsubquery\n\nWOQLQuery\n\nquery that is \"commented out\"\n\n#### compilePathPattern()\n\nTurns a textual path pattern into a JSON-LD description\n\n#### concat(varList, resultVarName)\n\ntakes a variable number of string arguments and concatenates them into a single string\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nvarList\n\narray|string|Var\n\na variable representing a list or a list of variables or strings - variables can be embedded in the string if they do not contain spaces\n\nresultVarName\n\nstring|Var\n\nA variable or string containing the output string\n\n#### containsUpdate()\n\nDoes this query contain an update\n\n#### context()\n\nsets the value of the current json-ld context on a full query scope\n\n#### count(countVarName, subquery)\n\nCreates a count of the results of the query\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ncountVarName\n\nstring|number|Var\n\nvariable or integer count\n\nsubquery\n\nWOQLQuery\n\n#### dataList()\n\ntakes input that can be either a string (variable name) or an array - each element of the array is a member of the list\n\n#### dataValueList()\n\nWraps data values\n\n#### delete\\_document(IRI)\n\nDelete a document from the graph.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nIRI\n\nstring\n\nThe document id or a variable\n\n#### delete\\_quad(subject, predicate, object, graphRef)\n\nDeletes a single triple from the graph \\[Subject, Predicate, Object, Graph\\]\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubject\n\nstring|Var\n\nThe IRI of a triple’s subject or a variable\n\npredicate\n\nstring|Var\n\nThe IRI of a property or a variable\n\nobject\n\nstring|Var\n\nThe IRI of a node or a variable, or a literal\n\ngraphRef\n\ntypedef.GraphRef\n\nA valid graph resource identifier string\n\n#### delete\\_triple(subject, predicate, object)\n\nDeletes a single triple from the default graph of the database\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubject\n\nstring|Var\n\nThe IRI of a triple’s subject or a variable\n\npredicate\n\nstring|Var\n\nThe IRI of a property or a variable\n\nobject\n\nstring|Var\n\nThe IRI of a node or a variable, or a literal\n\n#### distinct(varNames)\n\nFilter the query to return only results that are distinct in the given variables\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nvarNames\n\nstring|Var\n\nthese variables are guaranteed to be unique as a tuple\n\n#### div(args)\n\nDivision - integer division - args are divided left to right\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nargs\n\nstring|number|Var\n\nnumbers for division\n\n#### divide(args)\n\nDivides numbers N1...Nn by each other left, to right precedence\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nargs\n\nstring|number|Var\n\nnumbers to tbe divided\n\n#### dot(document, field, value)\n\nExtract the value of a key in a bound document.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ndocument\n\nstring|Var\n\nDocument which is being accessed.\n\nfield\n\nstring|Var\n\nThe field from which the document which is being accessed.\n\nvalue\n\nstring|Var\n\nThe value for the document and field.\n\n#### eq(varName, varValue)\n\nMatches if a is equal to b\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nvarName\n\nstring|Var\n\nliteral, variable or id\n\nvarValue\n\nstring|Var\n\nliteral, variable or id\n\n#### eval(arithExp, resultVarName)\n\nEvaluates the passed arithmetic expression and generates or matches the result value\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\narithExp\n\nobject|WOQLQuery|string\n\nquery or JSON-LD representing the query\n\nresultVarName\n\nstring|Var\n\noutput variable\n\n#### execute()\n\nUse instead woqlclient.query('myWOQLQuery')\n\n#### exp(varNum, expNum)\n\nExponent - raises varNum01 to the power of varNum02\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nvarNum\n\nstring|number|Var\n\na variable or numeric containing the number to be raised to the power of the second number\n\nexpNum\n\nnumber\n\na variable or numeric containing the exponent\n\n#### expandVariable(varname)\n\nTransforms strings that start with v: into variable json-ld structures\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nvarname\n\nunknown\n\nwill be transformed if it starts with v:\n\n#### findLastProperty(json)\n\nFinds the last woql element that has a subject in that is a property id used for triplebuilder to chain further calls - when they may be inside ands or ors or subqueries\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\njson\n\nobject\n\n#### findLastSubject(json)\n\nFinds the last woql element that has a subject in it and returns the json for that used for triplebuilder to chain further calls - when they may be inside ands or ors or subqueries\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\njson\n\nobject\n\n#### floor(varNum)\n\nGenerates the nearest lower integer to the passed number\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nvarNum\n\nstring|number|Var\n\nVariable or numeric containing the number to be floored\n\n#### from(graphRef-, query)\n\nSpecifies the database URL that will be the default database for the enclosed query\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ngraphRef-\n\ntypedef.GraphRef\n\nA valid graph resource identifier string\n\nquery\n\nWOQLQuery\n\nThe query\n\n#### get(asvars, queryResource)\n\nUse the document inteface to import documents\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nasvars\n\nVars|array.\n\nan array of AsVar variable mappings (see as for format below)\n\nqueryResource\n\nWOQLQuery\n\nan external resource (remote, file, post) to query\n\n#### getContext()\n\nRetrieves the value of the current json-ld context\n\n#### getLimit()\n\nFunctions to manipulate and check the paging related properties of a query\n\n#### getPagingProperty()\n\nReturns the value of one of the 'paging' related properties (limit, start,...)\n\n#### graph(graphRef)\n\nSets the graph resource ID that will be used for subsequent chained function calls\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ngraphRef\n\ntypedef.GraphRef\n\nResource String identifying the graph which will be used for subsequent chained schema calls\n\n#### graph(graphRef)\n\nSets the graph resource ID that will be used for subsequent chained function calls\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ngraphRef\n\ntypedef.GraphRef\n\nResource String identifying the graph which will be used for subsequent chained schema calls\n\n#### greater(varNum01, varNum02)\n\nCompares the value of v1 against v2 and returns true if v1 is greater than v2\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nvarNum01\n\nstring|number|Var\n\na variable or numeric containing the number to be compared\n\nvarNum02\n\nstring|number|Var\n\na variable or numeric containing the second comporator\n\n#### group\\_by(gvarlist, groupedvar, output, groupquery)\n\nGroups the results of the contained subquery on the basis of identical values for Groupvars, extracts the patterns defined in PatternVars and stores the results in GroupedVar\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ngvarlist\n\narray|string|Var\n\nEither a single variable or an array of variables\n\ngroupedvar\n\narray|string|Var\n\nEither a single variable or an array of variables\n\noutput\n\nstring|Var\n\noutput variable name\n\ngroupquery\n\nWOQLQuery\n\nThe query whose results will be grouped\n\n#### idgen(prefix, inputVarList, outputVar)\n\nGenerates the node's ID combined the variable list with a specific prefix (URL base). If the input variables's values are the same, the output value will be the same.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nprefix\n\nstring\n\ninputVarList\n\nstring|array\n\nthe variable input list for generate the id\n\noutputVar\n\nstring\n\nthe output variable name\n\n#### immediately(subquery)\n\nRuns the query without backtracking on side-effects\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubquery\n\nstring|WOQLQuery\n\nWOQL Query objects\n\n#### insert(id, type, refGraph)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nid\n\nstring|Var\n\nIRI string or variable containing\n\ntype\n\nstring|Var\n\nIRI string or variable containing the IRI of the\n\nrefGraph\n\ntypedef.GraphRef\n\nOptional Graph resource identifier\n\n#### insert(id, type, refGraph)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nid\n\nstring|Var\n\nIRI string or variable containing\n\ntype\n\nstring|Var\n\nIRI string or variable containing the IRI of the\n\nrefGraph\n\ntypedef.GraphRef\n\nOptional Graph resource identifier\n\n#### insert\\_document(docjson, IRI)\n\nInsert a document in the graph.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ndocjson\n\nobject\n\nThe document to insert. Must either have an '@id' or have a class specified key.\n\nIRI\n\nstring\n\nAn optional identifier specifying the document location.\n\n#### into(graphRef-, subquery)\n\nSpecifies the graph resource to write the contained query into\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ngraphRef-\n\ntypedef.GraphRef\n\nA valid graph resource identifier string\n\nsubquery\n\nWOQLQuery\n\nThe query which will be written into the graph\n\n#### iri(s)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ns\n\nstring\n\n#### iri(s)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ns\n\nstring\n\n#### isa(instanceIRI, classId)\n\nTests whether a given instance IRI has type Class, according to the current state of the DB\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ninstanceIRI\n\nstring|Var\n\nA string IRI or a variable that identify the class instance\n\nclassId\n\nstring|Var\n\nA Class IRI or a variable\n\n#### jlt()\n\nWraps the passed value in a json-ld literal carriage\n\n#### jobj()\n\nTransforms a javascript representation of a query into a json object if needs be\n\n#### join(varList, glue, resultVarName)\n\nJoins a list variable together (Input) into a string variable (Output) by glueing the strings together with Glue\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nvarList\n\nstring|array|Var\n\na variable representing a list or a list of strings and / or variables\n\nglue\n\nstring|Var\n\nA variable (v:glue) or (glue) string representing the characters to put in between the joined strings in input\n\nresultVarName\n\nstring|Var\n\nA variable or string containing the output string\n\n#### json(json)\n\nconverts back and forward from json if the argument is present, the current query is set to it, if the argument is not present, the current json version of this query is returned\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\njson\n\nobject\n\na query in json format\n\n#### length(inputVarList, resultVarName)\n\nCalculates the length of the list in va and stores it in vb\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ninputVarList\n\nstring|array\n\nEither a variable representing a list or a list of variables or literals\n\nresultVarName\n\nstring|Var\n\nA variable in which the length of the list is stored or the length of the list as a non-negative integer\n\n#### less(varNum01, varNum02)\n\nCompares the value of v1 against v2 and returns true if v1 is less than v2\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nvarNum01\n\nstring|number|Var\n\na variable or numeric containing the number to be compared\n\nvarNum02\n\nstring|number|Var\n\na variable or numeric containing the second comporator\n\n#### like(stringA, stringB, distance)\n\nGenerates a string Leverstein distance measure between stringA and stringB\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nstringA\n\nstring|Var\n\nstring literal or variable representing a string to be compared\n\nstringB\n\nstring|Var\n\nstring literal or variable representing the other string to be compared\n\ndistance\n\nnumber|string|Var\n\nvariable representing the distance between the variables\n\n#### limit(limit, subquery)\n\nSpecifies a maximum number of results that will be returned from the subquery\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nlimit\n\nnumber|string\n\nA variable that refers to an non-negative integer or a non-negative integer\n\nsubquery\n\nWOQLQuery\n\nA subquery whose results will be limited\n\n#### link(subject, predicate, object)\n\nCreates a pattern matching rule for triple \\[Subject, Predicate, Object\\]\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubject\n\nstring|Var\n\nThe IRI of a triple’s subject or a variable\n\npredicate\n\nstring|Var\n\nThe IRI of a property or a variable\n\nobject\n\nstring|Var\n\nThe IRI of a node or a variable, or a literal\n\n#### literal(s, t)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ns\n\nany\n\nt\n\nstring\n\n#### literal(s, t)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ns\n\nany\n\nt\n\nstring\n\n#### loadDefaultVocabulary()\n\nvocabulary elements that can be used without prefixes in woql.js queries\n\n#### lower(inputVarName, resultVarName)\n\nChanges a string to lower-case\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ninputVarName\n\nstring|Var\n\nstring or variable representing the non-lowercased string\n\nresultVarName\n\nstring|Var\n\nvariable that stores the lowercased string output\n\n#### member(element, list)\n\nMatches if List includes Element\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nelement\n\nstring|object|Var\n\nEither a variable, IRI or any simple datatype\n\nlist\n\nstring|array|Var\n\nList (\\[string, literal\\] or string\\*) Either a variable representing a list or a list of variables or literals\n\n#### minus(args)\n\nSubtracts Numbers N1..Nn\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nargs\n\nstring|number|Var\n\nvariable or numeric containing the value that will be subtracted from\n\n#### node(nodeid, chainType)\n\nSpecifies the identity of a node that can then be used in subsequent builder functions. Note that node() requires subsequent chained functions to complete the triples / quads that it produces - by itself it only generates the subject.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nnodeid\n\nstring|Var\n\nThe IRI of a node or a variable containing an IRI which will be the subject of the builder functions\n\nchainType\n\ntypedef.FuntionType\n\nOptional type of builder function to build (default is triple)\n\n#### node(node, type)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nnode\n\nstring|Var\n\nThe IRI of a node or a variable containing an IRI which will be the subject of the builder functions\n\ntype\n\ntypedef.FuntionType\n\nOptional type of builder function to build (default is triple)\n\n#### not(subquery)\n\nLogical negation of the contained subquery - if the subquery matches, the query will fail to match\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubquery\n\nstring|WOQLQuery\n\nA subquery which will be negated\n\n#### nuke(graphRef)\n\nDeletes all triples in the passed graph (defaults to instance/main)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ngraphRef\n\ntypedef.GraphRef\n\nResource String identifying the graph from which all triples will be removed\n\n#### nuke(graphRef)\n\nDeletes all triples in the passed graph (defaults to instance/main)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ngraphRef\n\ntypedef.GraphRef\n\nResource String identifying the graph from which all triples will be removed\n\n##### Examples\n\n```python\nnuke(\"schema/main\")\n//will delete everything from the schema/main graph\n```\n\n#### once(subquery)\n\nResults in one solution of the subqueries\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubquery\n\nstring|WOQLQuery\n\nWOQL Query objects\n\n#### opt(subquery)\n\nSpecifies that the Subquery is optional - if it does not match the query will not fail\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubquery\n\nWOQLQuery\n\nA subquery which will be optionally matched\n\n#### or(subqueries)\n\nCreates a logical OR of the arguments\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubqueries\n\nWOQLQuery\n\nA list of one or more woql queries to execute as alternatives\n\n#### order\\_by(orderedVarlist)\n\nOrders the results of the contained subquery by a precedence list of variables\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\norderedVarlist\n\nstring|Var|array\n\nA sequence of variables, by which to order the results, each optionally followed by either “asc” or “desc” to represent order as a list, by default it will sort the variable in ascending order\n\n#### pad(inputVarName, pad, len, resultVarName)\n\nPads out the string input to be exactly len long by appending the pad character pad to form output\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ninputVarName\n\nstring|Var\n\nThe input string or variable in unpadded state\n\npad\n\nstring|Var\n\nThe characters to use to pad the string or a variable representing them\n\nlen\n\nnumber|string|Var\n\nThe variable or integer value representing the length of the output string\n\nresultVarName\n\nstring|Var\n\nstores output\n\n#### parameterError()\n\nBasic Error handling\n\n#### parameterError(msg)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nmsg\n\nstring\n\n#### path(subject, pattern, object, resultVarName)\n\nPerforms a path regular expression match on the graph\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubject\n\nstring|Var\n\nAn IRI or variable that refers to an IRI representing the subject, i.e. the starting point of the path\n\npattern\n\nstring\n\n(string) - A path regular expression describing a pattern through multiple edges of the graph (see: https://terminusdb.com/docs/path-query-reference-guide)\n\nobject\n\nstring|Var\n\nAn IRI or variable that refers to an IRI representing the object, i.e. ending point of the path\n\nresultVarName\n\nstring|Var\n\nA variable in which the actual paths traversed will be stored\n\n#### plus(args)\n\nAdds the numbers together\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nargs\n\nstring|number|Var\n\na variable or numeric containing the values to add\n\n#### post(url, formatObj, source)\n\nIdentifies a resource as a local path on the client, to be sent to the server through a HTTP POST request, with the format defined through the options\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nurl\n\nstring\n\nThe Path on the server at which the file resource can be accessed\n\nformatObj\n\ntypedef.DataFormatObj\n\nimput options, optional\n\nsource\n\nstring\n\nIt defines the source of the file, it can be 'url','post'\n\n#### prettyPrint(clang)\n\nReturns a script version of the query\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nclang\n\nstring\n\neither \"js\" or \"python\"\n\n#### put(varsToExp, query, fileResource)\n\nUse the document inteface to import documents\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nvarsToExp\n\nVars|array.\n\nan array of AsVar variable mappings (see as for format below)\n\nquery\n\nWOQLQuery\n\nThe query which will be executed to produce the results\n\nfileResource\n\nstring\n\nan file resource local to the server\n\n#### quad(subject, predicate, object, graphRef)\n\nCreates a pattern matching rule for the quad \\[S, P, O, G\\] (Subject, Predicate, Object, Graph)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubject\n\nstring|Var\n\nThe IRI of a triple’s subject or a variable\n\npredicate\n\nstring|Var\n\nThe IRI of a property or a variable\n\nobject\n\nstring|Var\n\nThe IRI of a node or a variable, or a literal\n\ngraphRef\n\ntypedef.GraphRef\n\nA valid graph resource identifier string\n\n#### re(pattern, inputVarName, resultVarList)\n\nMatches the regular expression defined in Patern against the Test string, to produce the matched patterns in Matches\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\npattern\n\nstring\n\nstring or variable using normal PCRE regular expression syntax with the exception that special characters have to be escaped twice (to enable transport in JSONLD)\n\ninputVarName\n\nstring|Var\n\nstring or variable containing the string to be tested for patterns with the regex\n\nresultVarList\n\nstring|array|object|Var\n\nvariable representing the list of matches or a list of strings or variables\n\n#### read\\_document(IRI, output)\n\nRead a node identified by an IRI as a JSON-LD document\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nIRI\n\nstring\n\nThe document id or a variable to read\n\noutput\n\nstring\n\nVariable which will be bound to the document.\n\n#### remote(remoteObj, formatObj)\n\nIdentifies a remote resource by URL and specifies the format of the resource through the options\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nremoteObj\n\nobject\n\nThe URL at which the remote resource can be accessed\n\nformatObj\n\ntypedef.DataFormatObj\n\nThe format of the resource data {}\n\n#### removed\\_quad(subject, predicate, object, graphRef-)\n\nCreates a pattern matching rule for the quad \\[S, P, O, G\\] (Subject, Predicate, Object, Graph) removed from the current commit\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubject\n\nstring|Var\n\nThe IRI of a triple’s subject or a variable\n\npredicate\n\nstring|Var\n\nThe IRI of a property or a variable\n\nobject\n\nstring|Var\n\nThe IRI of a node or a variable, or a literal\n\ngraphRef-\n\ntypedef.GraphRef\n\nA valid graph resource identifier string\n\n#### removed\\_triple(subject, predicate, object)\n\nCreates a triple pattern matching rule for the triple \\[S, P, O\\] (Subject, Predicate, Object) added in the current commit\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubject\n\nstring|Var\n\nThe IRI of a triple’s subject or a variable\n\npredicate\n\nstring|Var\n\nThe IRI of a property or a variable\n\nobject\n\nstring|Var\n\nThe IRI of a node or a variable, or a literal\n\n#### select(varNames)\n\nFilters the query so that only the variables included in \\[V1...Vn\\] are returned in the bindings\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nvarNames\n\nstring|Var\n\nonly these variables are returned\n\n#### setPagingProperty()\n\nSets the value of one of the paging\\_transitive\\_properties properties\n\n#### setVocabulary()\n\nProvides the query with a 'vocabulary' a list of well known predicates that can be used without prefixes mapping: id: prefix:id ...\n\n#### size(resourceId, resultVarName)\n\nCalculates the size in bytes of the contents of the resource identified in ResourceID\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nresourceId\n\nstring|Var\n\nA valid resource identifier string (can refer to any graph / branch / commit / db)\n\nresultVarName\n\nstring|Var\n\nThe variable name\n\n#### split(inputVarName, separator, resultVarName)\n\nSplits a string (Input) into a list strings (Output) by removing separator\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ninputVarName\n\nstring|Var\n\nA string or variable representing the unsplit string\n\nseparator\n\nstring|Var\n\nA string or variable containing a sequence of charatcters to use as a separator\n\nresultVarName\n\nstring|Var\n\nvariable that stores output list\n\n#### star()\n\nSimple composite functions which produce WOQL queries\n\n#### star(graph, subject, predicate, object)\n\nGenerates a query that by default matches all triples in a graph identified by \"graph\" or in all the current terminusDB's graph\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ngraph\n\nstring|boolean\n\nfalse or the resource identifier of a graph possible value are schema/{main - myschema - \\*} | instance/{main - myschema - \\*} | inference/{main - myschema - \\*}\n\nsubject\n\nstring|Var\n\nThe IRI of a triple’s subject or a variable, default value \"v:Subject\"\n\npredicate\n\nstring|Var\n\nThe IRI of a property or a variable, default value \"v:Predicate\"\n\nobject\n\nstring|Var\n\nThe IRI of a node or a variable, or a literal, default value \"v:Object\"\n\n#### start(start, subquery)\n\nSpecifies an offset position in the results to start listing results from\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nstart\n\nnumber|string|Var\n\nA variable that refers to an interger or an integer literal\n\nsubquery\n\nWOQLQuery\n\nWOQL Query object, you can pass a subquery as an argument or a chained query\n\n#### string(s)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ns\n\nstring\n\n#### string(s)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ns\n\nstring\n\n#### sub(classA, classB)\n\nReturns true if ClassA subsumes ClassB, according to the current DB schema\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nclassA\n\nstring\n\nClassA\n\nclassB\n\nstring\n\nClassB\n\n#### substr(string, before, length, after, subString)\n\nSubstring\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nstring\n\nstring|Var\n\nString or variable\n\nbefore\n\nnumber|Var\n\ninteger or variable (characters from start to begin)\n\nlength\n\nnumber|Var\n\ninteger or variable (length of substring)\n\nafter\n\nnumber|Var\n\ninteger or variable (number of characters after substring)\n\nsubString\n\nstring|Var\n\nString or variable\n\n#### sum(subquery, total)\n\ncomputes the sum of the List of values passed. In contrast to other arithmetic functions, sum self-evaluates - it does not have to be passed to evaluate()\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubquery\n\nWOQLQuery\n\na subquery or (\\[string or numeric\\]) - a list variable, or a list of variables or numeric literals\n\ntotal\n\nstring|Var\n\nthe variable name with the sum result of the values in List\n\n#### times(args)\n\nMultiplies numbers N1...Nn together\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nargs\n\nstring|number|Var\n\na variable or numeric containing the value\n\n#### trim(inputStr, resultVarName)\n\nRemove whitespace from both sides of a string:\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ninputStr\n\nstring|Var\n\nA string or variable containing the untrimmed version of the string\n\nresultVarName\n\nstring|Var\n\nA string or variable containing the trimmed version of the string\n\n#### triple(subject, predicate, object)\n\nCreates a triple pattern matching rule for the triple \\[S, P, O\\] (Subject, Predicate, Object)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubject\n\nstring|Var\n\nThe IRI of a triple’s subject or a variable\n\npredicate\n\nstring|Var\n\nThe IRI of a property or a variable\n\nobject\n\nstring|Var\n\nThe IRI of a node or a variable, or a literal\n\n#### triple\\_count(resourceId, tripleCount)\n\nCalculates the number of triples of the contents of the resource identified in ResourceID\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nresourceId\n\nstring|Var\n\nA valid resource identifier string (can refer to any graph / branch / commit / db)\n\ntripleCount\n\nstring|number|Var\n\nAn integer literal with the size in bytes or a variable containing that integer\n\n#### true()\n\nA function that always matches, always returns true\n\n#### type\\_of(elementId, elementType)\n\nReturns true if 'elementId' is of type 'elementType', according to the current DB schema\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nelementId\n\nstring|Var\n\nthe id of a schema graph element\n\nelementType\n\nstring|Var\n\nthe element type\n\n#### typecast(varName, varType, resultVarName)\n\nCasts the value of Input to a new value of type Type and stores the result in CastVar\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nvarName\n\nstring|number|object|Var\n\nEither a single variable or a literal of any basic type\n\nvarType\n\nstring|Var\n\nEither a variable or a basic datatype (xsd / xdd)\n\nresultVarName\n\nstring|Var\n\nsave the return variable\n\n#### unique(prefix, inputVarList, resultVarName)\n\nGenerate a new IRI from the prefix and a hash of the variables which will be unique for any given combination of variables\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nprefix\n\nstring\n\nA prefix for the IRI - typically formed of the doc prefix and the classtype of the entity (“doc:Person”)\n\ninputVarList\n\narray|string|Var\n\nAn array of variables and / or strings from which the unique hash will be generated\n\nresultVarName\n\nstring|Var\n\nVariable in which the unique ID is stored\n\n#### update\\_document(docjson, IRI)\n\nUpdate a document identified by an IRI\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ndocjson\n\nobject\n\nThe document to update. Must either have an '@id' or have a class specified key.\n\nIRI\n\nstring\n\nAn optional identifier specifying the document location.\n\n#### update\\_quad(subject, predicate, newObject, graphRef)\n\nUpdate a pattern matching rule for the quad \\[S, P, O, G\\] (Subject, Predicate, Object, Graph)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubject\n\nstring|Var\n\nThe IRI of a triple’s subject or a variable\n\npredicate\n\nstring|Var\n\nThe IRI of a property or a variable\n\nnewObject\n\nstring|Var\n\nThe value to update or a literal\n\ngraphRef\n\ntypedef.GraphRef\n\nA valid graph resource identifier string\n\n#### update\\_quad(subject, predicate, newObject, graph)\n\nUpdate a pattern matching rule for the quad \\[S, P, O, G\\] (Subject, Predicate, Object, Graph)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubject\n\nstring\n\nThe IRI of a triple’s subject or a variable\n\npredicate\n\nstring\n\nThe IRI of a property or a variable\n\nnewObject\n\nstring\n\nThe value to update or a literal\n\ngraph\n\nstring\n\nthe resource identifier of a graph possible value are schema/{main - myschema - \\*} | instance/{main - myschema - \\*} | inference/{main - myschema - \\*}\n\n#### update\\_triple(subject, predicate, newObjValue, oldObjValue)\n\nUpdate a pattern matching rule for the triple (Subject, Predicate, oldObjValue) with the new one (Subject, Predicate, newObjValue)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubject\n\nstring|Var\n\nThe IRI of a triple’s subject or a variable\n\npredicate\n\nstring|Var\n\nThe IRI of a property or a variable\n\nnewObjValue\n\nstring|Var\n\nThe value to update or a literal\n\noldObjValue\n\nstring|Var\n\nThe old value of the object\n\n#### update\\_triple(subject, predicate, newObjValue, oldObjValue)\n\nUpdate a pattern matching rule for the triple (Subject, Predicate, oldObjValue) with the new one (Subject, Predicate, newObjValue)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubject\n\nstring|Var\n\nThe IRI of a triple’s subject or a variable\n\npredicate\n\nstring|Var\n\nThe IRI of a property or a variable\n\nnewObjValue\n\nstring|Var\n\nThe value to update or a literal\n\noldObjValue\n\nstring|Var\n\nThe old value of the object\n\n#### updated()\n\n#### updated()\n\nCalled to inidicate that this query will cause an update to the DB\n\n#### upper(inputVarName, resultVarName)\n\nChanges a string to upper-case\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ninputVarName\n\nstring|Var\n\nstring or variable representing the uncapitalized string\n\nresultVarName\n\nstring|Var\n\nvariable that stores the capitalized string output\n\n#### using(refPath, subquery)\n\nQuery running against any specific commit Id\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nrefPath\n\nstring\n\npath to specific reference Id or commit Id\n\nsubquery\n\nWOQLQuery\n\nsubquery for the specific commit point\n\n#### value(subject, predicate, objValue)\n\nCreates a pattern matching rule for triple \\[Subject, Predicate, Object\\] add extra information about the type of the value object\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nsubject\n\nstring|Var\n\nThe IRI of a triple’s subject or a variable\n\npredicate\n\nstring|Var\n\nThe IRI of a property or a variable\n\nobjValue\n\nstring|number|boolean|Var\n\nan specific value\n\n#### valueList()\n\ntakes a list of input that can be any value\n\n#### vlist()\n\ncreates an unadorned variable name list\n\n#### wform(opts)\n\nJSON LD Format Descriptor\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nopts\n\nobject\n\n#### wrapCursorWithAnd()\n\nContains definitions of the WOQL functions which map directly to JSON-LD types All other calls and queries can be composed from these" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "TerminusDB JavaScript Client Reference Guide", + "description": "TerminusDB JavaScript Client Reference Guide", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "terminusdb-client" + }, + "slug": "python", + "body": { + "@type": "Body", + "value": "## terminusdb\\_client\n\n### Client\n\n#### \\_\\_init\\_\\_(server\\_url, user\\_agent, \\*\\*kwargs)\n\nThe Client constructor.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nserver\\_url\n\nstr\n\nURL of the server that this client will connect to.\n\nuser\\_agent\n\noptional, str\n\nUser agent header when making requests. Defaults to terminusdb-client-python with the version appended.\n\n\\*\\*kwargs\n\nExtra configuration options\n\n#### \\_check\\_connection()\n\nRaise connection InterfaceError if not connected Defaults to check if a db is connected\n\n#### \\_generate\\_commit(msg, author)\n\nPack the specified commit info into a dict format expected by the server.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nmsg\n\nstr\n\nCommit message.\n\nauthor\n\nstr\n\nCommit author.\n\n##### Examples\n\n```\n>>> client = Client(\"http://127.0.0.1:6363/\")\n>>> client._generate_commit(\"\", \"\")\n{'author': '', 'message': ''}\n```\n\n#### \\_get\\_prefixes()\n\nGet the prefixes for a given database\n\n#### add\\_role(role)\n\nAdd a new role\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nrole\n\ndict\n\nThe role dict\n\n##### Examples\n\n```\n>>> client = Client(\"http://127.0.0.1:6363\")\n>>> client.connect(key=\"root\", team=\"admin\", user=\"admin\", db=\"example_db\")\n>>> role = {\n \"name\": \"Grand Pubah\",\n \"action\": [\n \"branch\",\n \"class_frame\",\n \"clone\",\n \"commit_read_access\",\n \"commit_write_access\",\n \"create_database\",\n \"delete_database\",\n \"fetch\",\n \"instance_read_access\",\n \"instance_write_access\",\n \"manage_capabilities\",\n \"meta_read_access\",\n \"meta_write_access\",\n \"push\",\n \"rebase\",\n \"schema_read_access\",\n \"schema_write_access\"\n ]\n }\n>>> client.add_role(role)\n```\n\n#### add\\_user(username, password)\n\nAdd a new user\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nusername\n\nstr\n\nThe username of the user\n\npassword\n\nstr\n\nThe user's password\n\n#### apply(before\\_version, after\\_object, branch)\n\nDiff two different commits and apply changes on branch\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nbefore\\_version\n\nstring\n\nBefore branch/commit to compare\n\nafter\\_object\n\nstring\n\nAfter branch/commit to compare\n\nbranch\n\nstring\n\nBranch to apply to. Optional.\n\n#### change\\_capabilities(capability\\_change)\n\nChange the capabilities of a certain user\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ncapability\\_change\n\ndict\n\nDict for the capability change request. Example: { \"operation\": \"revoke\", \"scope\": \"UserDatabase/f5a0ef94469b32e1aee321678436c7dfd5a96d9c476672b3282ae89a45b5200e\", \"user\": \"User/admin\", \"roles\": \\[ \"Role/consumer\", \"Role/admin\" \\] }\n\n#### change\\_role(role)\n\nChange role actions for a particular role\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nrole\n\ndict\n\nRole dict\n\n##### Examples\n\n```\n>>> client = Client(\"http://127.0.0.1:6363\")\n>>> client.connect(key=\"root\", team=\"admin\", user=\"admin\", db=\"example_db\")\n>>> role = {\n \"name\": \"Grand Pubah\",\n \"action\": [\n \"branch\",\n \"class_frame\",\n \"clone\",\n \"commit_read_access\",\n \"commit_write_access\",\n \"create_database\",\n \"delete_database\",\n \"fetch\",\n \"instance_read_access\",\n \"instance_write_access\",\n \"manage_capabilities\",\n \"meta_read_access\",\n \"meta_write_access\",\n \"push\",\n \"rebase\",\n \"schema_read_access\",\n \"schema_write_access\"\n ]\n }\n>>> client.change_role(role)\n```\n\n#### change\\_user\\_password(username, password)\n\nChange user's password\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nusername\n\nstr\n\nThe username of the user\n\npassword\n\nstr\n\nThe new password\n\n#### clonedb(clone\\_source, newid, Description, remote\\_auth)\n\nClone a remote repository and create a local copy.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nclone\\_source\n\nstr\n\nThe source url of the repo to be cloned.\n\nnewid\n\nstr\n\nIdentifier of the new repository to create.\n\nDescription\n\nstr, optional\n\nOptional description about the cloned database.\n\nremote\\_auth\n\nstr, optional\n\nOptional remote authorization (uses client remote auth otherwise)\n\n##### Examples\n\n```\n>>> client = Client(\"http://127.0.0.1:6363/\")\n>>> client.clonedb(\"http://terminusdb.com/some_user/test_db\", \"my_test_db\")\n```\n\n#### close()\n\nUndo connect and close the connection.\n\n#### commit()\n\nNot implementated: open transactions currently not suportted. Please check back later.\n\n#### connect(team, db, remote\\_auth, key, user, use\\_token, jwt\\_token, api\\_token, branch, ref, repo, \\*\\*kwargs)\n\nConnect to a Terminus server at the given URI with an API key.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nteam\n\nstr\n\nName of the team, default to be \"admin\"\n\ndb\n\noptional, str\n\nName of the database connected\n\nremote\\_auth\n\noptional, dict\n\nRemote Auth setting\n\nkey\n\noptional, str\n\nAPI key for connecting, default to be \"root\"\n\nuser\n\noptional, str\n\nName of the user, default to be \"admin\"\n\nuse\\_token\n\nbool\n\nUse token to connect. If both \\`jwt\\_token\\` and \\`api\\_token\\` is not provided (None), then it will use the ENV variable TERMINUSDB\\_ACCESS\\_TOKEN to connect as the API token\n\njwt\\_token\n\noptional, str\n\nThe Bearer JWT token to connect. Default to be None.\n\napi\\_token\n\noptional, strs\n\nThe API token to connect. Default to be None.\n\nbranch\n\noptional, str\n\nBranch to be connected, default to be \"main\"\n\nref\n\noptional, str\n\nRef setting\n\nrepo\n\noptional, str\n\nLocal or remote repo, default to be \"local\"\n\n\\*\\*kwargs\n\nExtra configuration options.\n\n##### Examples\n\n```\n>>> client = Client(\"http://127.0.0.1:6363\")\n>>> client.connect(key=\"root\", team=\"admin\", user=\"admin\", db=\"example_db\")\n```\n\n#### copy()\n\nCreate a deep copy of this client.\n\n##### Examples\n\n```\n>>> client = Client(\"http://127.0.0.1:6363/\")\n>>> clone = client.copy()\n>>> assert client is not clone\n```\n\n#### create\\_branch(new\\_branch\\_id, empty)\n\nCreate a branch starting from the current branch.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nnew\\_branch\\_id\n\nstr\n\nNew branch identifier.\n\nempty\n\nbool\n\nCreate an empty branch if true (no starting commit)\n\n#### create\\_database(dbid, team, label, description, prefixes, include\\_schema)\n\nCreate a TerminusDB database by posting a terminus:Database document to the Terminus Server.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ndbid\n\nstr\n\nUnique identifier of the database.\n\nteam\n\nstr, optional\n\nID of the Team in which to create the DB (defaults to 'admin')\n\nlabel\n\nstr, optional\n\nDatabase name.\n\ndescription\n\nstr, optional\n\nDatabase description.\n\nprefixes\n\ndict, optional\n\nOptional dict containing \\`\\`\"@base\"\\`\\` and \\`\\`\"@schema\"\\`\\` keys. @base (str) IRI to use when \\`\\`doc:\\`\\` prefixes are expanded. Defaults to \\`\\`terminusdb:///data\\`\\`. @schema (str) IRI to use when \\`\\`scm:\\`\\` prefixes are expanded. Defaults to \\`\\`terminusdb:///schema\\`\\`.\n\ninclude\\_schema\n\nbool\n\nIf \\`\\`True\\`\\`, a main schema graph will be created, otherwise only a main instance graph will be created.\n\n##### Examples\n\n```\n>>> client = Client(\"http://127.0.0.1:6363/\")\n>>> client.create_database(\"someDB\", \"admin\", \"Database Label\", \"My Description\")\n```\n\n#### create\\_organization(org)\n\nAdd a new organization\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\norg\n\nstr\n\nThe id of the organization\n\n#### delete\\_branch(branch\\_id)\n\nDelete a branch\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nbranch\\_id\n\nstr\n\nBranch to delete\n\n#### delete\\_database(dbid, team, force)\n\nDelete a TerminusDB database.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ndbid\n\nstr\n\nID of the database to delete\n\nteam\n\nstr, optional\n\nthe team in which the database resides (defaults to \"admin\")\n\nforce\n\nbool\n\n##### Examples\n\n```\n>>> client = Client(\"http://127.0.0.1:6363/\")\n>>> client.delete_database(\"\", \"\")\n```\n\n#### delete\\_document(document, graph\\_type, commit\\_msg, last\\_data\\_version)\n\nDelete the specified document(s)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ndocument\n\nstr or list of str\n\nDocument(s) (as dictionary or DocumentTemplate objects) or id(s) of document(s) to be updated.\n\ngraph\\_type\n\nGraphType\n\nGraph type, either GraphType.INSTANCE or GraphType.SCHEMA.\n\ncommit\\_msg\n\nstr\n\nCommit message.\n\nlast\\_data\\_version\n\nstr\n\nLast version before the update, used to check if the document has been changed unknowingly\n\n#### delete\\_organization(org)\n\nDeletes a specific organization\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\norg\n\nstr\n\nThe id of the organization\n\n#### delete\\_user(username)\n\nDelete a user\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nusername\n\nstr\n\nThe username of the user\n\n#### diff()\n\nDEPRECATED\n\n##### Examples\n\n```\n>>> client = Client(\"http://127.0.0.1:6363/\")\n>>> client.connect(user=\"admin\", key=\"root\", team=\"admin\", db=\"some_db\")\n>>> result = client.diff({ \"@id\" : \"Person/Jane\", \"@type\" : \"Person\", \"name\" : \"Jane\"}, { \"@id\" : \"Person/Jane\", \"@type\" : \"Person\", \"name\" : \"Janine\"})\n>>> result.to_json = '{ \"name\" : { \"@op\" : \"SwapValue\", \"@before\" : \"Jane\", \"@after\": \"Janine\" }}'\n```\n\n#### diff\\_object(before\\_object, after\\_object)\n\nDiff two different objects.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nbefore\\_object\n\nstring\n\nBefore object to compare\n\nafter\\_object\n\nstring\n\nAfter object to compare\n\n#### diff\\_version(before\\_version, after\\_version)\n\nDiff two different versions. Can either be a branch or a commit\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nbefore\\_version\n\nstring\n\nCommit or branch of the before version to compare\n\nafter\\_version\n\nstring\n\nCommit or branch of the after version to compare\n\n#### fetch(remote\\_id)\n\nFatch the brach from a remote\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nremote\\_id\n\nstr\n\nid of the remote\n\n#### get\\_all\\_branches()\n\nGet all the branches available in the database.\n\n#### get\\_all\\_documents(graph\\_type, skip, count, as\\_list, get\\_data\\_version, kwargs)\n\nRetrieves all avalibale the documents\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ngraph\\_type\n\nGraphType, optional\n\nGraph type, either GraphType.INSTANCE or GraphType.SCHEMA.\n\nskip\n\nint\n\nThe starting posiion of the returning results, default to be 0\n\ncount\n\nint or None\n\nThe maximum number of returned result, if None (default) it will return all of the avalible result.\n\nas\\_list\n\nbool\n\nIf the result returned as list rather than an iterator.\n\nget\\_data\\_version\n\nbool\n\nIf the version of the document(s) should be obtained. If True, the method return the result and the version as a tuple.\n\nkwargs\n\nAdditional boolean flags for retriving. Currently avaliable: \"prefixed\", \"unfold\"\n\n#### get\\_available\\_roles()\n\nGet the available roles for the current authenticated user\n\n#### get\\_class\\_frame(class\\_name)\n\nGet the frame of the class of class\\_name. Provide information about all the avaliable properties of that class.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nclass\\_name\n\nstr\n\nName of the class\n\n#### get\\_commit\\_history(max\\_history)\n\nGet the whole commit history. Commit history - Commit id, author of the commit, commit message and the commit time, in the current branch from the current commit, ordered backwards in time, will be returned in a dictionary in the follow format: \\`\\`\\` { \"commit\\_id\": { \"author\": \"commit\\_author\", \"message\": \"commit\\_message\", \"timestamp: \" } } \\`\\`\\`\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nmax\\_history\n\nint, optional\n\nmaximum number of commit that would return, counting backwards from your current commit. Default is set to 500. It needs to be nop-negative, if input is 0 it will still give the last commit.\n\n#### get\\_database()\n\nReturns metadata (id, organization, label, comment) about the requested database Parameters ---------- dbid : str The id of the database team : str The organization of the database (default self.team)\n\n#### get\\_databases()\n\nReturns a list of database metadata records for all databases the user has access to\n\n#### get\\_document(iri\\_id, graph\\_type, get\\_data\\_version, kwargs)\n\nRetrieves the document of the iri\\_id\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\niri\\_id\n\nstr\n\nIri id for the document that is to be retrieved\n\ngraph\\_type\n\nGraphType\n\nGraph type, either GraphType.INSTANCE or GraphType.SCHEMA.\n\nget\\_data\\_version\n\nbool\n\nIf the data version of the document(s) should be obtained. If True, the method return the result and the version as a tuple.\n\nkwargs\n\nAdditional boolean flags for retriving. Currently avaliable: \"prefixed\", \"minimized\", \"unfold\"\n\n#### get\\_documents\\_by\\_type(doc\\_type, graph\\_type, skip, count, as\\_list, get\\_data\\_version, kwargs)\n\nRetrieves the documents by type\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ndoc\\_type\n\nstr\n\nSpecific type for the docuemnts that is retriving\n\ngraph\\_type\n\nGraphType, optional\n\nGraph type, either GraphType.INSTANCE or GraphType.SCHEMA.\n\nskip\n\nint\n\nThe starting posiion of the returning results, default to be 0\n\ncount\n\nint or None\n\nThe maximum number of returned result, if None (default) it will return all of the avalible result.\n\nas\\_list\n\nbool\n\nIf the result returned as list rather than an iterator.\n\nget\\_data\\_version\n\nbool\n\nIf the version of the document(s) should be obtained. If True, the method return the result and the version as a tuple.\n\nkwargs\n\nAdditional boolean flags for retriving. Currently avaliable: \"prefixed\", \"unfold\"\n\n#### get\\_existing\\_classes()\n\nGet all the existing classes (only ids) in a database.\n\n#### get\\_organization(org)\n\nReturns a specific organization\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\norg\n\nstr\n\nThe id of the organization\n\n#### get\\_organization\\_user(org, username)\n\nReturns user info related to an organization.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\norg\n\nstr\n\nusername\n\nstr\n\n#### get\\_organization\\_user\\_databases(org, username)\n\nReturns the databases available to a user which are inside an organization\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\norg\n\nstr\n\nusername\n\nstr\n\n#### get\\_organization\\_users(org)\n\nReturns a list of users in an organization.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\norg\n\nstr\n\n#### get\\_organizations()\n\nReturns a list of organizations in the database.\n\n#### get\\_triples(graph\\_type)\n\nRetrieves the contents of the specified graph as triples encoded in turtle format\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ngraph\\_type\n\nGraphType\n\nGraph type, either GraphType.INSTANCE or GraphType.SCHEMA.\n\n#### get\\_user(username)\n\nGet a user\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nusername\n\nstr\n\nThe username of the user\n\n#### get\\_users()\n\nGet all users\n\n#### has\\_database(dbid, team)\n\nCheck whether a database exists\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ndbid\n\nstr\n\nThe id of the database\n\nteam\n\nstr\n\nThe organization of the database (default self.team)\n\n#### has\\_doc(doc\\_id, graph\\_type)\n\nCheck if a certain document exist in a database\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ndoc\\_id\n\nstr\n\nId of document to be checked.\n\ngraph\\_type\n\nGraphType\n\nGraph type, either GraphType.INSTANCE or GraphType.SCHEMA.\n\n#### info()\n\nGet info of a TerminusDB database server\n\n#### insert\\_document(document, graph\\_type, full\\_replace, commit\\_msg, last\\_data\\_version, compress, raw\\_json)\n\nInserts the specified document(s)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ndocument\n\ndict or list of dict\n\nDocument(s) to be inserted.\n\ngraph\\_type\n\nGraphType\n\nGraph type, either GraphType.INSTANCE or GraphType.SCHEMA.\n\nfull\\_replace\n\nbool\n\nIf True then the whole graph will be replaced. WARNING: you should also supply the context object as the first element in the list of documents if using this option.\n\ncommit\\_msg\n\nstr\n\nCommit message.\n\nlast\\_data\\_version\n\nstr\n\nLast version before the update, used to check if the document has been changed unknowingly\n\ncompress\n\nstr or int\n\nIf it is an integer, size of the data larger than this (in bytes) will be compress with gzip in the request (assume encoding as UTF-8, 0 = always compress). If it is \\`never\\` it will never compress the data.\n\nraw\\_json\n\nbool\n\nUpdate as raw json\n\n#### insert\\_triples(graph\\_type, content, commit\\_msg)\n\nInserts into the specified graph with the triples encoded in turtle format.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ngraph\\_type\n\nGraphType\n\nGraph type, either GraphType.INSTANCE or GraphType.SCHEMA.\n\ncontent\n\nValid set of triples in Turtle or Trig format.\n\ncommit\\_msg\n\nstr\n\nCommit message.\n\n#### list\\_databases()\n\nReturns a list of database ids for all databases the user has access to\n\n#### log()\n\nGet commit history of a database Parameters ---------- team : str, optional The team from which the database is. Defaults to the class property. db : str, optional The database. Defaults to the class property. start : int, optional Commit index to start from. Defaults to 0. count : int, optional Amount of commits to get. Defaults to -1 which gets all.\n\n#### ok()\n\nCheck whether the TerminusDB server is still OK. Status is not OK when this function returns false or throws an exception (mostly ConnectTimeout)\n\n#### optimize(path)\n\nOptimize the specified path.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\npath\n\nstring\n\nPath to optimize, for instance admin/database/\\_meta for the repo graph.\n\n##### Examples\n\n```\n>>> client = Client(\"http://127.0.0.1:6363/\")\n>>> client.optimize('admin/database') # optimise database branch (here main)\n>>> client.optimize('admin/database/_meta') # optimise the repository graph (actually creates a squashed flat layer)\n>>> client.optimize('admin/database/local/_commits') # commit graph is optimised\n```\n\n#### patch(before, patch)\n\nApply the patch object to the before object and return an after object. Note that this change does not commit changes to the graph.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nbefore\n\ndict\n\nObject before to patch\n\npatch\n\nPatch\n\nPatch object to apply to the dict\n\n##### Examples\n\n```\n>>> client = Client(\"http://127.0.0.1:6363/\")\n>>> client.connect(user=\"admin\", key=\"root\", team=\"admin\", db=\"some_db\")\n>>> patch_obj = Patch(json='{\"name\" : { \"@op\" : \"ValueSwap\", \"@before\" : \"Jane\", \"@after\": \"Janine\" }}')\n>>> result = client.patch({ \"@id\" : \"Person/Jane\", \"@type\" : Person\", \"name\" : \"Jane\"}, patch_obj)\n>>> print(result)\n'{ \"@id\" : \"Person/Jane\", \"@type\" : Person\", \"name\" : \"Janine\"}'\n```\n\n#### patch\\_resource()\n\nApply the patch object to the given resource\n\n##### Examples\n\n```\n>>> client = Client(\"http://127.0.0.1:6363/\")\n>>> client.connect(user=\"admin\", key=\"root\", team=\"admin\", db=\"some_db\")\n>>> patch_obj = Patch(json='{\"name\" : { \"@op\" : \"ValueSwap\", \"@before\" : \"Jane\", \"@after\": \"Janine\" }}')\n>>> result = client.patch_resource(patch_obj,branch=\"main\")\n>>> print(result)\n'[\"Person/Jane\"]'\n```\n\n#### pull(remote, remote\\_branch, message, author)\n\nPull updates from a remote repository to the current database.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nremote\n\nstr\n\nremote to pull from, default \"origin\"\n\nremote\\_branch\n\nstr, optional\n\nremote branch to pull from, default to be your current barnch\n\nmessage\n\nstr, optional\n\noptional commit message\n\nauthor\n\nstr, optional\n\noption to overide the author of the operation\n\n##### Examples\n\n```\n>>> client = Client(\"http://127.0.0.1:6363/\")\n>>> client.pull()\n```\n\n#### push(remote, remote\\_branch, message, author, remote\\_auth)\n\nPush changes from a branch to a remote repo\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nremote\n\nstr\n\nremote to push to, default \"origin\"\n\nremote\\_branch\n\nstr, optional\n\nremote branch to push to, default to be your current barnch\n\nmessage\n\nstr, optional\n\noptional commit message\n\nauthor\n\nstr, optional\n\noption to overide the author of the operation\n\nremote\\_auth\n\ndict, optional\n\noptional remote authorization (uses client remote auth otherwise)\n\n##### Examples\n\n```\n>>> Client(server=\"http://localhost:6363\").push(remote=\"origin\", remote_branch = \"main\", author = \"admin\", message = \"commit message\"})\n```\n\n#### query(woql\\_query, commit\\_mg, get\\_data\\_version, last\\_data\\_version, file\\_dict)\n\nUpdates the contents of the specified graph with the triples encoded in turtle format Replaces the entire graph contents\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nwoql\\_query\n\ndict or WOQLQuery object\n\nA woql query as an object or dict\n\ncommit\\_mg\n\nstr\n\nA message that will be written to the commit log to describe the change\n\nget\\_data\\_version\n\nbool\n\nIf the data version of the query result(s) should be obtained. If True, the method return the result and the version as a tuple.\n\nlast\\_data\\_version\n\nstr\n\nLast version before the update, used to check if the document has been changed unknowingly\n\nfile\\_dict\n\n\\*\\*deprecated\\*\\*\n\nFile dictionary to be associated with post name => filename, for multipart POST\n\n##### Examples\n\n```\n>>> Client(server=\"http://localhost:6363\").query(woql, \"updating graph\")\n```\n\n#### query\\_document(document\\_template, graph\\_type, as\\_list, get\\_data\\_version)\n\nRetrieves all documents that match a given document template\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ndocument\\_template\n\ndict\n\nTemplate for the document that is being retrived\n\ngraph\\_type\n\nGraphType\n\nGraph type, either GraphType.INSTANCE or GraphType.SCHEMA.\n\nas\\_list\n\nbool\n\nIf the result returned as list rather than an iterator.\n\nget\\_data\\_version\n\nbool\n\nIf the data version of the document(s) should be obtained. If True, the method return the result and the version as a tuple.\n\n#### rebase(branch, rebase\\_source, message, author)\n\nRebase the current branch onto the specified remote branch. Need to specify one of 'branch','commit' or the 'rebase\\_source'.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nbranch\n\nstr, optional\n\nthe branch for the rebase\n\nrebase\\_source\n\nstr, optional\n\nthe source branch for the rebase\n\nmessage\n\nstr, optional\n\nthe commit message\n\nauthor\n\nstr, optional\n\nthe commit author\n\n##### Examples\n\n```\n>>> client = Client(\"http://127.0.0.1:6363/\")\n>>> client.rebase(\"the_branch\")\n```\n\n#### replace\\_document(document, graph\\_type, commit\\_msg, last\\_data\\_version, compress, create, raw\\_json)\n\nUpdates the specified document(s)\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ndocument\n\ndict or list of dict\n\nDocument(s) to be updated.\n\ngraph\\_type\n\nGraphType\n\nGraph type, either GraphType.INSTANCE or GraphType.SCHEMA.\n\ncommit\\_msg\n\nstr\n\nCommit message.\n\nlast\\_data\\_version\n\nstr\n\nLast version before the update, used to check if the document has been changed unknowingly\n\ncompress\n\nstr or int\n\nIf it is an integer, size of the data larger than this (in bytes) will be compress with gzip in the request (assume encoding as UTF-8, 0 = always compress). If it is \\`never\\` it will never compress the data.\n\ncreate\n\nbool\n\nCreate the document if it does not yet exist.\n\nraw\\_json\n\nbool\n\nUpdate as raw json\n\n#### reset(commit, soft, use\\_path)\n\nReset the current branch HEAD to the specified commit path. If \\`soft\\` is not True, it will be a hard reset, meaning reset to that commit in the backend and newer commit will be wipped out. If \\`soft\\` is True, the client will only reference to that commit and can be reset to the newest commit when done.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ncommit\n\nstring\n\nCommit id or path to the commit (if use\\_path is True), for instance '234980523ffaf93' or 'admin/database/local/commit/234980523ffaf93'. If not provided, it will reset to the newest commit (useful when need to go back after a soft reset).\n\nsoft\n\nbool\n\nFlag indicating if the reset if soft, that is referencing to a previous commit instead of resetting to a previous commit in the backend and wipping newer commits.\n\nuse\\_path\n\nbool\n\nWheather or not the commit given is an id or path. Default using id and use\\_path is False.\n\n##### Examples\n\n```\n>>> client = Client(\"http://127.0.0.1:6363/\")\n>>> client.reset('234980523ffaf93')\n>>> client.reset('admin/database/local/commit/234980523ffaf93', use_path=True)\n```\n\n#### rollback()\n\nCurently not implementated. Please check back later.\n\n#### set\\_db(dbid, team)\n\nSet the connection to another database. This will reset the connection.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ndbid\n\nstr\n\nDatabase identifer to set in the config.\n\nteam\n\nstr\n\nTeam identifer to set in the config. If not passed in, it will use the current one.\n\n##### Examples\n\n```\n>>> client = Client(\"http://127.0.0.1:6363\")\n>>> client.set_db(\"database1\")\n'database1'\n```\n\n#### squash(message, author, reset)\n\nSquash the current branch HEAD into a commit\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\nmessage\n\nstring\n\nMessage for the newly created squash commit\n\nauthor\n\nstring\n\nAuthor of the commit\n\nreset\n\nbool\n\nPerform reset after squash\n\n##### Examples\n\n```\n>>> client = Client(\"http://127.0.0.1:6363/\")\n>>> client.connect(user=\"admin\", key=\"root\", team=\"admin\", db=\"some_db\")\n>>> client.squash('This is a squash commit message!')\n```\n\n#### update\\_document(document, graph\\_type, commit\\_msg, last\\_data\\_version, compress)\n\nUpdates the specified document(s). Add the document if not existed.\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ndocument\n\ndict or list of dict\n\nDocument(s) to be updated.\n\ngraph\\_type\n\nGraphType\n\nGraph type, either GraphType.INSTANCE or GraphType.SCHEMA.\n\ncommit\\_msg\n\nstr\n\nCommit message.\n\nlast\\_data\\_version\n\nstr\n\nLast version before the update, used to check if the document has been changed unknowingly\n\ncompress\n\nstr or int\n\nIf it is an integer, size of the data larger than this (in bytes) will be compress with gzip in the request (assume encoding as UTF-8, 0 = always compress). If it is \\`never\\` it will never compress the data.\n\n#### update\\_triples(graph\\_type, content, commit\\_msg)\n\nUpdates the contents of the specified graph with the triples encoded in turtle format. Replaces the entire graph contents\n\n##### Parameters\n\n**Name**\n\n**Type**\n\n**Description**\n\ngraph\\_type\n\nGraphType\n\nGraph type, either GraphType.INSTANCE or GraphType.SCHEMA.\n\ncontent\n\nValid set of triples in Turtle or Trig format.\n\ncommit\\_msg\n\nstr\n\nCommit message." + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "TerminusDB Python Client reference guide", + "description": "TerminusDB Python Client reference guide", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "GraphQL Query Reference Guide" + }, + "slug": "graphql-query-reference", + "body": { + "@type": "Body", + "value": "GraphQL queries are composed of:\n\n* Queries\n* Arguments\n* Fields\n\nEach Class in TerminusDB automatically generates a top-level Query. Each property of the class automatically generates both arguments and fields.\n\nThe names of the types of arguments and fields are generated automatically [subject to name mapping](/docs/graphql-naming-conventions-reference/).\n\nIn turn, each property which is an edge leading to a new object of a class will have its own field with arguments.\n\nEach concrete data query will be terminal and will generate a specific field parameter for search.\n\n## Example\n\nFor example, using the following TerminusDB schema:\n\n```\n{ \"@type\" : \"Class\",\n \"@id\" : \"Person\",\n \"name\" : \"xsd:string\",\n \"dob\" : \"xsd:dateTime\",\n \"friend\" : {\"@type\" : \"Set\", \"@class\" : \"Person\" }}\n```\n\nTerminusDB will generate the following GraphQL class.\n\n```\ntype Query {\n Person(\n id: ID\n \"\"\"skip N elements\"\"\"\n offset: Int\n \"\"\"limit results to N elements\"\"\"\n limit: Int\n filter: Person_Filter\n \"\"\"order by the given fields\"\"\"\n orderBy: Person_Ordering\n ): [Person!]!\n}\ntype Person {\n dob: DateTime!\n friend(\n id: ID\n \"\"\"skip N elements\"\"\"\n offset: Int\n \"\"\"limit results to N elements\"\"\"\n limit: Int\n filter: Person_Filter\n \"\"\"order by the given fields\"\"\"\n orderBy: Person_Ordering\n ): [Person!]!\n name: String!\n id: ID!\n}\n```\n\nThe `Person` query, allows you to query for a person at the top level, along with a number of arguments, including: a `filter` (for search), a `limit` for reducing to a defined length of results, an `offset`, for obtaining results starting from some offset (for use in _paging_) and an `orderBy` to obtain the results in a defined order.\n\nIn addition, we have the various _fields_ of a `Person` object, each of which may have arguments if they are objects or simple data types for terminal fields.\n\nOne can use such a query by using the [GraphQL endpoint](/docs/connecting-to-graphql-reference/).\n\n## Arguments\n\nArguments are restrictions or meta-fields about the query. These can be used to limit results, or filter to specific results, as well as perform ordering.\n\n### `id`\n\nThe id of an object can be directly supplied, in order to ensure that we only obtain the specific object of interest.\n\nA person might be retrieved by supplying the id as a variable in the following way:\n\n```\nquery Person(id:$id){\n name\n}\n```\n\n### `offset`\n\nGraphQL will retrieve all objects in the database for a given class type, unless `offset` and `limit` are supplied. `offset` will start a query from a given result offset, allowing the query user to _page_ results.\n\n```\nquery Person(limit: 3 offset: 3){\n name\n Person(\n id: ID\n \"\"\"skip N elements\"\"\"\n offset: Int\n \"\"\"limit results to N elements\"\"\"\n limit: Int\n filter: Person_Filter\n \"\"\"order by the given fields\"\"\"\n orderBy: Person_Ordering\n ): [Person!]!\n}\n```\n\nThis query retrieves the second page of a 3-object page of persons.\n\n### `limit`\n\nGraphQL will retrieve all objects in the database for a given class type, unless `offset` and `limit` are supplied. `limit` will only find the limit-number of results, allowing the query user to _page_ results.\n\n```\nquery Person(limit: 3 offset: 3){\n name\n}\n```\n\nThis query retrieves the second page of a 3-object page of persons.\n\n### `orderBy`\n\nThe orderBy filter allows the user to order results according to some data in the object. For instance, to create an ordering on people, we might write:\n\n```\nquery Person(limit: 3 offset: 3, orderBy: { dob: DESC, name: ASC}){\n name\n dob\n}\n```\n\nThis will yield Persons from youngest to oldest, ordering by name in the event of a \"tie\" on date of birth.\n\n## `filter`\n\nFilters allow you to restrict to specific results by reducing the set to those objects which match the filter fields.\n\nEach filter is an input object, defined for the specific class and generated automatically by TerminusDB. The `Person` object defined above gets the input objects:\n\n```\ninput Person_Filter {\n dob: DateTimeFilterInputObject\n friend: Person_Collection_Filter\n name: StringFilterInputObject\n _and: [Person_Filter!]\n _or: [Person_Filter!]\n _not: Person_Filter\n}\ninput Person_Collection_Filter {\n someHave: Person_Filter\n allHave: Person_Filter\n}\ninput StringFilterInputObject {\n eq: String\n ne: String\n lt: String\n le: String\n gt: String\n ge: String\n regex: String\n startsWith: String\n allOfTerms: [String!]\n anyOfTerms: [String!]\n}\ninput DateTimeFilterInputObject {\n eq: DateTime\n ne: DateTime\n lt: DateTime\n le: DateTime\n gt: DateTime\n ge: DateTime\n}\n```\n\nFilters can apply to immediate values, such as the `dob` (date of birth), which can be restricted using a time comparison, or they can be filters on linked objects, such as the `Person_Collection_Filter` which allows us to compare with our friends.\n\nIn GraphQL we might write a simple query over people as:\n\n```\nquery Person(orderBy: { name: ASC},\n filter: { name: {regex: \"(Joe|Joseph)\"},\n _and: [{friend:\n {someHave:\n {name: {regex: \"(Jim|James)\"}}}}]}){\n name\n dob\n}\n```\n\nThis finds name and date of birth of all people who have a name which contains \"Joe\" or \"Joesph\" and who are friends with someone named \"Jim\" or \"James\", in order of ascending name.\n\n## Filter Builtin Types\n\nFilters have to work with all of the GraphQL base types, along with the extensions which TerminusDB currently supports (`DateTime`, and `BigInt`).\n\n### BigIntFilterInputObject\n\nBig integers use the widely available `BigInt` type extension to GraphQL.\n\nThe Filters available for BigInt are:\n\n* `eq`: Equality\n* `ne`: disequality\n* `lt`: Less than\n* `le`: Less than or equal\n* `gt`: Greater than\n* `ge`: Greater than or equal\n\nWhen a field of an object refers to a `BigInt`, we can filter it by writing a query along the following lines:\n\n```\nquery {\n Event(filter : { years_since_big_bang : { ge : \"8000000000\"}}){\n event_name\n years_since_big_bang\n }\n}\n```\n\n### DateTimeFilterInputObject\n\nDate time objects use the widely available `DateTime` type extension to GraphQL.\n\nThe Filters available for BigInt are:\n\n* `eq`: Equality\n* `ne`: disequality\n* `lt`: Less than\n* `le`: Less than or equal\n* `gt`: Greater than\n* `ge`: Greater than or equal\n\n```\nquery {\n Event(filter : { date_of_event : { ge : \"2000-01-01T00:00:00Z\"}}){\n event_name\n date_of_event\n }\n}\n```\n\n### StringFilterInputObject\n\nStrings are native GraphQL types. TerminusDB exposes the following filter options for strings:\n\n* `eq`: Equality\n* `ne`: Disequality\n* `lt`: Less than\n* `le`: Less than or equal\n* `gt`: Greater than\n* `ge`: Greater than or equal\n* `regex`: Matches regex\n* `startsWith`: Matches the string prefix\n* `allOfTerms`: Contains all terms in the list of terms\n* `anyOfTerms`: Contains any of the terms in the list of terms\n\nA query filter using strings could be written as follows:\n\n```\nquery {\n Event(filter : { event_name : { regex : \"[Cc]elstial [Ee]vent\"}}){\n event_name\n }\n}\n```\n\n### BooleanFilterInputObject\n\nBooleans are native GraphQL types. TerminusDB exposes the following filter options:\n\n* `eq`: Equality\n* `ne`: Disequality\n\nA query filter using booleans could be written as follows:\n\n```\nquery {\n Event(filter : { is_super_nova : { eq : true}}){\n event_name\n }\n}\n```\n\n### SmallIntegerFilterInputObject\n\nIntegers (signed, 32-bit integers) are native GraphQL types. TerminusDB exposes the following filter options:\n\n* `eq`: Equality\n* `ne`: disequality\n* `lt`: Less than\n* `le`: Less than or equal\n* `gt`: Greater than\n* `ge`: Greater than or equal\n\nA query filter using booleans could be written as follows:\n\n```\nquery {\n Civilization(filter : { kardashev_scale : { ge : 3}}){\n name\n kardashev_scale\n }\n}\n```\n\n### `_and`\n\nThe `_and` filter combinator allows us to chain constraints. It takes two filter objects relevant at the current level.\n\nWe can find all civilizations of a high Kardashev scale using a query such as:\n\n```\nquery {\n Civilization(filter : {_and : [{ kardashev_scale : { le : 5}}\n { kardashev_scale : { ge : 3}}]){\n name\n kardashev_scale\n }\n}\n```\n\n### `_or`\n\nThe `_or` filter combinator allows us to make choices of constraints. It takes two filter objects relevant at the current level. It is implicitly combined as if with `_and`, with any filters at the current level. We can find all civilizations of a high Kardashev scale, which is also a galactic civilisation using a query such as:\n\n```\nquery {\n Civilization(filter : { galactic_scale : {eq : true},\n _or : [{ kardashev_scale : { eq : 2}}\n { kardashev_scale : { eq : 3}}]){\n name\n kardashev_scale\n }\n}\n```\n\n### `_not`\n\nThe `_not` operator allows us to combine other constraints with _dis-constraints_, which remove any elements which match its sub-filter. We can ask for galactic civilizations which have not mastered energy acquisition at level 3 on the Kardashev scale.\n\n```\nquery {\n Civilization(filter : { galactic_scale : {eq : true},\n _not : { kardashev_scale : { eq : 3}}}){\n name\n kardashev_scale\n }\n}\n```\n\n## Fields\n\nEach TerminusDB class has associated with it, some number of fields. These fields include each field that is defined in the class. For instance, given the TerminusDB class:\n\n```\n{ \"@type\" : \"Class\",\n \"@id\" : \"Person\",\n \"name\" : \"xsd:string\",\n \"dob\" : \"xsd:dateTime\",\n \"friend\" : {\"@type\" : \"Set\", \"@class\" : \"Person\" }}\n```\n\nWe have a query field for each of `name`, `dob` and `friend`. However we also have the following specially defined fields:\n\n### `_id`\n\nThis returns the fully qualified URI of the given instance of the `Person` class being returned.\n\n### `_type`\n\nThis returns the class at which this instance is instantiated. This is useful when a super-class is queried, as we can obtain what concrete subclass it corresponds to.\n\n### Backlinks\n\n`_PROPERTY_of_CLASS`\n\nThe _backlink_ is a way to find all instances that _point_ to a given class. The backlink is generated automatically for every edge which terminates at the current class. For example, with the Person class:\n\n```\n{ \"@type\" : \"Class\",\n \"@id\" : \"Person\",\n \"name\" : \"xsd:string\",\n \"dob\" : \"xsd:dateTime\",\n \"friend\" : {\"@type\" : \"Set\", \"@class\" : \"Person\" }}\n```\n\nWe automatically get the backlink `_friend_of_Person` that says which people view us as their friends. For instance, we can construct the following query:\n\n```\n{\n Person{\n name\n _friend_of_Person{\n name\n }\n }\n}\n```\n\nThis will find the name of every person who views the top level `Person` us as their friend (i.e. has a `friend` link to the current person).\n\n### Path Queries\n\n`_path_to_CLASS`\n\nA path query allows us to use regular graph expressions to follow links from the current object to another object of `CLASS`. Using the `Person` example:\n\n```\n{ \"@type\" : \"Class\",\n \"@id\" : \"Person\",\n \"name\" : \"xsd:string\",\n \"dob\" : \"xsd:dateTime\",\n \"friend\" : {\"@type\" : \"Set\", \"@class\" : \"Person\" }}\n```\n\nWe can find everyone within 2-degrees of separation with the following path query:\n\n```\n{\n Person{\n name\n _path_to_Person(path: \"friend{1,3}\"){\n name\n }\n }\n}\n```\n\nSee the [complete syntax for path queries](/docs/path-query-reference-guide/) for more details on the semantics of the path argument." + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "GraphQL Query Reference Guide", + "description": "A GraphQL query reference guide explaining the workings of GraphQL queries with TerminusDB and TerminusCMS", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Connecting to GraphQL Reference Guide" + }, + "slug": "connecting-to-graphql-reference", + "body": { + "@type": "Body", + "value": "TerminusDB hosts a GraphQL endpoint at:\n\n```\nSERVERNAME/api/graphql/ORG/DATAPRODUCT\n```\n\nFor instance, with a data product named `admin/people`, and a locally installed TerminusDB, you can query it at:\n\n```\nhttp://127.0.0.1:6363/api/graphql/admin/people\n```\n\nFor TerminusCMS you can use the following URL:\n\n```\nhttps://cloud.terminusdb.com/ORG/api/graphql/ORG/DATA_PRODUCT\n```\n\nWhere `ORG` is your organization, and `DATA_PRODUCT` is the name of your data product.\n\n## Authentication\n\nSince TerminusDB requires authentication to access data products, you will need to use the authentication method that has been configured for your server.\n\n### Basic Auth\n\nUsing Basic Auth, the default method in locally installed TerminusDBs, you can supply the Authorization header, with your basic auth. (To generate a Basic Auth string, see [Basic Auth Generator](https://www.blitter.se/utils/basic-authentication-header-generator/)).\n\nFor example, if you would like to connect to `admin/people` with the apollo client to download the associated GraphQL schema, simply use:\n\n```\nnpx apollo client:download-schema --endpoint=http://127.0.0.1:6363/api/graphql/admin/people schema.graphql --header='Authorization: Basic YWRtaW46cm9vdA=='\n```\n\n### TerminusCMS\n\nIn TerminusCMS you can use an API key with the following header.\n\nFor instance, with the apollo client, you can download your schema as follows:\n\n```\nnpx apollo client:download-schema --endpoint=https://cloud.terminusdb.com/TEAM/api/graphql/TEAM/people schema.graphql --header=\"Authorization: Token $(cat ~/my_token_file)\"\n```\n\nWhere `my_token_file` contains an API token for TerminusCMS.\n\n## GraphiQL\n\n![GraphiQL interface screen shot](https://assets.terminusdb.com/docs/how-to-query-graphql.png)\n\nTerminusDB ships with a GraphiQL graphical GraphQL query interface and schema browser. This is a quick way to get acquainted with GraphQL in TerminusDB.\n\nYou can reach this browser at:\n\n```\nhttp://127.0.0.1:6363/api/graphiql/admin/people\n```\n\nYou will also need to set your Authorization header in the Header dialog box at the bottom center.\n\nFor instance, in the default install, as:\n\n```\n{\n \"Authorization\": \"Basic YWRtaW46cm9vdA==\"\n}\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Connecting to GraphQL Reference Guide", + "description": "A reference guide detailing connecting to GraphQL with TerminusDB and TerminusCMS.", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + }, + "media": [ + { + "@type": "Media", + "alt": "GraphiQL interface screen shot", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "GraphiQL interface screen shot" + }, + "value": "https://assets.terminusdb.com/docs/how-to-query-graphql.png" + } + ] + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "GraphQL Naming Conventions Reference Guide" + }, + "slug": "graphql-naming-conventions-reference", + "body": { + "@type": "Body", + "value": "TerminusDB has its own flexible schema language which is designed to be compatible with RDF. The RDF world identifies resources with IRIs which are flexible, and use a relatively large space of available characters.\n\nGraphQL, by contrast, has a very restrictive allowed character set for naming. Essentially only Alphanumeric characters using un-accented Latin. That is, it is essentially restricted to `[A-Z][a-z][0-9][_]`.\n\nBecause of this, we have some naming conventions to translate automatically from TerminusDB classes and properties to GraphQL named classes and properties. While we have endevoured to do so in a way that is unlikely to create naming collisions, these are never-the-less possible.\n\nTerminusDB generates GraphQL schema automatically as a mapping from TerminusDB. TerminusDB's definition language is a strict super-set of GraphQL and so is able to faithfully represent GraphQL features.\n\nFor each class in TerminusDB, there is a range of classes that are defined automatically by TerminusDB in the associated GraphQL schema.\n\n## Underscore as reserved\n\nWhen names are likely to create conflicts with user-defined names, TerminusDB will typically use an `_` at the beginning to avoid naming conflicts. This is done on filter fields that share the same object level with user-defined properties for instance: `_and`, `_or` and `_not`.\n\n## Translation\n\nAll names of GraphQL classes in TerminusDB and all properties of TerminusDB classes, as well as all enums, are translated to viable GraphQL names. This is done by replacing each non-representable character with an `_`. In addition, underscores at the beginning of a class name or property are disallowed. This is to ensure there are no collisions with TerminusDB's own auto-generated properties and classes.\n\nShould a collision arise, TerminusDB should give a GraphQL error on retrieval of the schema. In future, we will allow this check to occur at schema submission time, and will also allow explicit renaming in TerminusDB classes.\n\nFor instance, the TerminusDB class is defined as:\n\n```\n{ \"@type\" : \"Class\",\n \"@id\" : \"Galactic-Civilisation\",\n \"name\" : \"xsd:string\",\n \"kardashev-scale\" : \"xsd:integer\" }\n```\n\nwill be translated to:\n\n```\ntype Query {\n Galatic_Civilisation(\n id: ID\n \"\"\"skip N elements\"\"\"\n offset: Int\n \"\"\"limit results to N elements\"\"\"\n limit: Int\n filter: Galactic_Civilisation_Filter\n \"\"\"order by the given fields\"\"\"\n orderBy: Galactic_Civilisation_Ordering\n ): [GalaticCivilsiation!]!\n name : String!\n kardashev_scale: BigInt!\n}\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "GraphQL Naming Conventions Reference Guide", + "description": "A reference guide detail the GraphQL naming conventions in TerminusDB and TerminusCMS.", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "System Graph Interface to GraphQL" + }, + "slug": "system-graph-graphql-interface-reference", + "body": { + "@type": "Body", + "value": "TerminusDB also exposes its internal working graphs, the system graph, the meta graph, and the commit-graph. These three graphs can be queried with a self-documenting GraphQL interface by going to the appropriate API for a data product.\n\n## System Graph\n\nFor instance, to get _only_ system graph access, you can use the following endpoint:\n\n```\nhttp://127.0.0.1:6363/api/graphql/_system\n```\n\n## Meta Graph\n\nTo get the System Graph and Meta graph which belongs to a specific data product you can use the following endpoint:\n\n```\nhttp://127.0.0.1:6363/api/graphql/ORG/DATA_PRODUCT/_meta\n```\n\n## Commit Graph\n\nTo get access to branches, commits, commit logs, as well as the meta and system graph, you can use the following endpoint:\n\n```\nhttp://127.0.0.1:6363/api/graphql/ORG/DATA_PRODUCT/local/_commits\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "System Graph Interface to GraphQL", + "description": "TerminusCMS and TerminusDB technical documentation - System Graph Interface to GraphQL", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Connect with Apollo Client" + }, + "slug": "connect-with-apollo-client", + "body": { + "@type": "Body", + "value": "1. Install dependencies\n\n```\n npm install @apollo/client graphql\n```\n\n2. Initialize ApolloClient and Connect with TerminusDB\n\nImport the required dependencies needed -\n\n```python\nimport { ApolloClient, InMemoryCache, ApolloProvider, gql,HttpLink,ApolloLink } from '@apollo/client';\n```\n\nOr\n\n```javascript\nconst Apollo = require( '@apollo/client');\n\nconst { ApolloClient, InMemoryCache, concat, gql,HttpLink,ApolloLink } = Apollo\n```\n\nInitialize ApolloClient by passing its constructor with a configuration object with the TerminusDB server endpoint, user credentials and cache fields.\n\n> Extra information about the Apollo client cache can be found on their [website](https://www.apollographql.com/docs/react/caching/overview)\n\n### Connect with TerminusDB Local\n\n```javascript\nconst orgName = \"myOrganizationName\"\nconst dbName = \"myDBname\"\nconst myBranch = \"main\"\n\nconst user = \"admin\"\nconst password = \"mypass\"\nconst userPassEnc = btoa(`${user}:${password}`)\n\nconst terminusdbURL = `http://127.0.0.1:6363/api/graphql/${orgName}/${dbName}/local/branch/${myBranch}/`\n\nconst httpLink = new HttpLink({ uri: terminusdbURL });\nconst authMiddleware = new ApolloLink((operation, forward) => {\n // add the authorization to the headers\n operation.setContext(({ headers = {} }) => ({\n headers: {\n ...headers,\n authorization: `Basic ${userPassEnc}`}\n }));\n return forward(operation);\n})\n\nconst cache = new InMemoryCache({\n addTypename: false\n});\n\nconst value = concat(authMiddleware, httpLink)\n\nconst apolloClient = new ApolloClient({\n cache:cache,\n link: value, \n});\n\n// Query your database\n\napolloClient\n .query({\n query: gql`\n query{\n Person{\n _id\n name\n }\n }\n `,\n })\n .then((result) => console.log(result.data))\n .catch(err =>console.log(err.message));\n```\n\n### Connect with TerminusCMS\n\n> You will need to [get your API key](/docs/how-to-connect-terminuscms/) to connect with terminusCMS\n\n```javascript\nconst orgName = \"myOrganizationName\"\nconst dbName = \"myDBname\"\nconst myBranch = \"main\"\n\nconst myAPIToken = 'replaceYourToken'\n\nconst terminusdbURL = `https://cloud.terminusdb.com/${orgName}/api/graphql/${orgName}/${dbName}/local/branch/${myBranch}/`\n\nconst httpLink = new HttpLink({ uri: terminusdbURL });\nconst authMiddleware = new ApolloLink((operation, forward) => {\n // add the authorization to the headers\n operation.setContext(({ headers = {} }) => ({\n headers: {\n ...headers,\n authorization: `Token ${myAPIToken}`}\n }));\n return forward(operation);\n})\n\nconst cache = new InMemoryCache({\n addTypename: false\n});\n\nconst value = concat(authMiddleware, httpLink)\n\nconst apolloClient = new ApolloClient({\n cache:cache,\n link: value, \n});\n\n// Query your database\n\napolloClient\n .query({\n query: gql`\n query{\n Person{\n _id\n name\n }\n }\n `,\n })\n .then((result) => console.log(result.data))\n .catch(err =>console.log(err.message));\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Connect with Apollo Client to use GraphQL with TerminusCMS", + "description": "A reference guide to get you up and running with TerminusDB & TerminusCMS using GraphQL and Apollo Client", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "OpenAPI spec" + }, + "slug": "openapi", + "body": { + "@type": "Body", + "value": "" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "TerminusCMS/DB documentation", + "description": "The documentation of TerminusCMS and TerminusDB" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Access Control Reference Guide" + }, + "slug": "js-access-control", + "body": { + "@type": "Body", + "value": "**License**: Apache Version 2\n\n## new AccessControl()\n\nAccessControl is a driver to work with the TerminusDB and TerminusCMS access control API.\n\nFor credentials, you can use a JWT token, an API token or basic authentication with username and password.\n\n**Example**\n\n```javascript\n//connect with the API token\n//(to request a token create an account in https://terminusdb.com/)\nconst accessContol = new AccessControl(\"https://servername.com\",\n{organization:\"my_team_name\",\ntoken:\"dGVybWludXNkYjovLy9kYXRhL2tleXNfYXB........\"})\naccessControl.getOrgUsers().then(result=>{\n console.log(result)\n})\n\n//connect with the jwt token this type of connection is only for the dashboard\n//or for application integrate with our login workflow\nconst accessContol = new AccessControl(\"https://servername.com\",\n{organization:\"my_team_name\",\njwt:\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IkpXUjBIOXYyeTFORUd........\"})\naccessControl.getOrgUsers().then(result=>{\n console.log(result)\n})\n\n//if the jwt is expired you can change it with\naccessControl.setJwtToken(\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IkpXUjBIOXYy\neTFORUd.......\")\n\n//connect with the base authentication this type of connection is only for the local installation\nconst accessContol = new AccessControl(\"http://localhost:6363\",\n{organization:\"my_team_name\", user:\"admin\"\nkey:\"mykey\"})\naccessControl.getOrgUsers().then(result=>{\n console.log(result)\n})\n```\n\n## getDefaultOrganization\n\n##### accessControl.getDefaultOrganization(params) ⇒ `string` | `undefined`\n\nGet a organization from parameters.\n\n**Returns**: `string` | `undefined` - - organization\n\nParam\n\nType\n\nDescription\n\nparams\n\n`object`\n\nThe parameters\n\n## setJwtToken\n\n##### accessControl.setJwtToken(jwt)\n\nSets the Jwt token for the object\n\nParam\n\nType\n\nDescription\n\njwt\n\n`string`\n\nThe jwt api token to use\n\n## setApiToken\n\n##### accessControl.setApiToken(atokenpi)\n\nSets the API token for the object. Create a TerminusCMS account to [get your API token](/docs/how-to-connect-terminuscms/).\n\nParam\n\nType\n\nDescription\n\natokenpi\n\n`string`\n\nThe API token to use to connect with TerminusCMS\n\n## setApiKey\n\n##### accessControl.setApiKey(atokenpi)\n\nSets the API token for the object, to request a token create an account in https://terminusdb.com/\n\nParam\n\nType\n\nDescription\n\natokenpi\n\n`string`\n\nThe API token to use to connect with TerminusCMS\n\n## getAPIUrl\n\n##### accessControl.getAPIUrl(cloudAPIUrl) ⇒ `string`\n\nGet a API url from cloudAPIUrl\n\n**Returns**: `string` - apiUrl\n\nParam\n\nType\n\nDescription\n\ncloudAPIUrl\n\n`string`\n\nThe base url for cloud\n\n## customHeaders\n\n##### accessControl.customHeaders(customHeaders) ⇒ `object`\n\nadd extra headers to your request\n\nParam\n\nType\n\ncustomHeaders\n\n`object`\n\n## getOrganization\n\n##### accessControl.getOrganization(organization) ⇒ `object`\n\n\\-- TerminusDB API --- Get an organization from the TerminusDB API.\n\n**Returns**: `object` - - organization\n\nParam\n\nType\n\nDescription\n\norganization\n\n`string`\n\nThe organization\n\n## getAllOrganizations\n\n##### accessControl.getAllOrganizations() ⇒ `Promise`\n\n\\-- TerminusDB API --- This end point works in basic authentication, admin user Get list of organizations\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\n## createOrganization\n\n##### accessControl.createOrganization(orgName) ⇒ `Promise`\n\n\\-- TerminusDB API --- This end point works in basic authentication, admin user Create an organization\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\norgName\n\n`string`\n\nThe organization name to create\n\n**Example**\n\n```\naccessControl.createOrganization(\"my_org_name\").then(result=>{\n console.log(result)\n})\n```\n\n## deleteOrganization\n\n##### accessControl.deleteOrganization(orgName) ⇒ `Promise`\n\n\\-- TerminusDB API --- Delete an Organization\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\norgName\n\n`string`\n\nThe organization name to delete\n\n**Example**\n\n```\naccessControl.createOrganization(\"my_org_name\").then(result=>{\n console.log(result)\n})\n```\n\n## createRole\n\n##### accessControl.createRole(\\[name\\], \\[actions\\]) ⇒ `Promise`\n\n\\--TerminusDB API --- basic authentication, admin user. Create a new role in the system database.\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\n\\[name\\]\n\n`string`\n\nThe role name.\n\n\\[actions\\]\n\n`typedef.RolesActions`\n\nA list of actions\n\n**Example**\n\n```\naccessControl.createRole(\"Reader\",[ACTIONS.INSTANCE_READ_ACCESS]).then(result=>{\n console.log(result)\n})\n```\n\n## deleteRole\n\n##### accessControl.deleteRole(\\[name\\]) ⇒ `Promise`\n\n\\-- TerminusDB API --- basic Authentication, admin user. Delete role in the system database, (this api is enabled only in the local installation)\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\n\\[name\\]\n\n`string`\n\nThe role name.\n\n**Example**\n\n```\naccessControl.deleteRole(\"Reader\").then(result=>{\n console.log(result)\n})\n```\n\n## getAllUsers\n\n##### accessControl.getAllUsers() ⇒ `Promise`\n\n\\-- TerminusDB API --- basic Authentication, admin user. Return the list of all the users (this api is enabled only in the local installation)\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected. \n**Example**\n\n```\naccessControl.getAllUsers().then(result=>{\n console.log(result)\n})\n```\n\n## createUser\n\n##### accessControl.createUser(name, \\[password\\]) ⇒ `Promise`\n\n\\-- TerminusDB API --- basic Authentication, admin user. Add the user into the system database\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\nname\n\n`string`\n\nthe user name\n\n\\[password\\]\n\n`string`\n\nyou need the password for basic authentication\n\n**Example**\n\n```\naccessControl.deleteUser(userId).then(result=>{\n console.log(result)\n})\n```\n\n## deleteUser\n\n##### accessControl.deleteUser(userId) ⇒ `Promise`\n\n\\-- TerminusDB API --- basic Authentication, admin user. Remove the user from the system database.\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\nuserId\n\n`string`\n\nthe document user id\n\n**Example**\n\n```\naccessControl.deleteUser(userId).then(result=>{\n console.log(result)\n})\n```\n\n## manageCapability\n\n##### accessControl.manageCapability(userName, resourceName, rolesArr, operation, scopeType) ⇒ `Promise`\n\n\\-- TerminusDB API --- Grant/Revoke Capability\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\nuserName\n\n`string`\n\nthe document user id\n\nresourceName\n\n`string`\n\nthe name of a (database or team)\n\nrolesArr\n\n`array`\n\nthe roles name list\n\noperation\n\n`typedef.CapabilityCommand`\n\ngrant/revoke operation\n\nscopeType\n\n`typedef.ScopeType`\n\nthe resource type (database or organization)\n\n**Example**\n\n```\n//we add an user to an organization and manage users' access\n//the user myUser can access the Organization and all the database under the organization with \"reader\" Role\nclient.manageCapability(myUser,myteam,[reader],\"grant\",\"organization\").then(result=>{\n consol.log(result)\n})\n\n//the user myUser can access the database db__001 under the organization myteam\n//with \"writer\" Role\nclient.manageCapability(myUser,myteam/db__001,[writer],\"grant\",\"database\").then(result=>{\n consol.log(result)\n})\n```\n\n## getAccessRoles\n\n##### accessControl.getAccessRoles() ⇒ `Promise`\n\n\\--TerminusCMS and TerminusDB API --- Get all the system database roles types.\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\n## getOrgUsers\n\n##### accessControl.getOrgUsers(\\[orgName\\]) ⇒ `Promise`\n\n\\-- TerminusCMS and TerminusDB API -- Get all the organization's users and roles,\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\n\\[orgName\\]\n\n`string`\n\nThe organization name.\n\n**Example**\n\n```javascript\naccessControl.getOrgUsers().then(result=>{\n console.log(result)\n})\n\n//this function will return an array of capabilities with users and roles\n//-- TerminusCMS -- response array example\n//[{capability: \"Capability/3ea26e1d698821c570afe9cb4fe81a3......\"\n// email: {@type: \"xsd:string\", @value: \"user@terminusdb.com\"}\n// picture: {@type: \"xsd:string\",…}\n// role: \"Role/dataReader\"\n// scope: \"Organization/my_org_name\"\n// user: \"User/auth0%7C613f5dnndjdjkTTT\"}]\n//\n//\n// -- Local Installation -- response array example\n//[{ \"@id\":\"User/auth0%7C615462f8ab33f4006a6bee0c\",\n// \"capability\": [{\n// \"@id\":\"Capability/c52af34b71f6f8916ac0115ecb5fe0e31248ead8b1e3d100852015...\",\n// \"@type\":\"Capability\",\n// \"role\": [{\n// \"@id\":\"Role/admin\",\n// \"@type\":\"Role\",\n// \"action\": [\"instance_read_access\"],\n// \"name\":\"Admin Role\"\n// }],\n// \"scope\":\"Organization/@team\"}]]\n```\n\n## getTeamUserRoles\n\n##### accessControl.getTeamUserRoles(\\[userName\\], \\[orgName\\]) ⇒ `Promise`\n\n\\-- TerminusCMS and TerminusDB API -- Get the user roles for a given organization or the default organization,\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\n\\[userName\\]\n\n`string`\n\nThe organization name.\n\n\\[orgName\\]\n\n`string`\n\nThe organization name.\n\n**Example**\n\n```\naccessControl.getTeamUserRole(\"myUser\").then(result=>{\n console.log(result)\n})\n\n//response object example\n{\n \"@id\": \"User/myUser\",\n \"capability\": [\n {\n \"@id\":\"Capability/server_access\",\n \"@type\":\"Capability\",\n \"role\": [{\n \"@id\":\"Role/reader\",\n \"@type\":\"Role\",\n \"action\": [\n \"instance_read_access\",\n ],\n \"name\":\"reader\"\n }],\n \"scope\":\"Organization/myteam\"\n }\n ],\n \"name\": \"myUser\"\n}\n```\n\n## ifOrganizationExists\n\n##### accessControl.ifOrganizationExists(orgName) ⇒ `Promise`\n\n\\-- TerminusCMS API --- Check if the organization exists. it is a Head call . IMPORTANT This does not work with the API-TOKEN.\n\n**Returns**: `Promise` - A promise that returns the call status object, 200: if the organization exists and 404: if the organization does not exist\n\nParam\n\nType\n\nDescription\n\norgName\n\n`string`\n\nThe organization name to check if exists.\n\n## createOrganizationRemote\n\n##### accessControl.createOrganizationRemote(orgName) ⇒ `Promise`\n\n\\-- TerminusCMS API ---\n\nIMPORTANT This does not work with the API-TOKEN. Create an organization\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\norgName\n\n`string`\n\nThe organization name to create\n\n**Example**\n\n```\naccessControl.createOrganization(\"my_org_name\").then(result=>{\n console.log(result)\n})\n```\n\n## getPendingOrgInvites\n\n##### accessControl.getPendingOrgInvites(\\[orgName\\]) ⇒ `Promise`\n\n\\-- TerminusCMS API ---\n\nGet the pending invitations list.\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\n\\[orgName\\]\n\n`string`\n\nThe organization name.\n\n**Example**\n\n```javascript\nconst invitationList = accessControl.getPendingOrgInvites().then(result=>{\n console.log(invitationList)\n\n})\n//this will return an array of invitations object like this\n//[{@id: \"Organization/my_team_name/invitations/Invitation/7ad0c9eb82b6175bcda9c0dfc2ac51161ef5ba\ncb0988d992c4bce82b3fa5d25\"\n// @type: \"Invitation\"\n// creation_date: \"2021-10-22T11:13:28.762Z\"\n// email_to: \"new_user@terminusdb.com\"\n// invited_by: \"User/auth0%7C6162f8ab33567406a6bee0c\"\n// role: \"Role/dataReader\"\n// status: \"needs_invite\"}]\n```\n\n## sendOrgInvite\n\n##### accessControl.sendOrgInvite(userEmail, role, \\[note\\], \\[orgName\\]) ⇒ `Promise`\n\n\\-- TerminusCMS API ---\n\nSend a new invitation\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\nuserEmail\n\n`string`\n\nThe email of user.\n\nrole\n\n`string`\n\nThe role for user. (the document @id role like Role/collaborator)\n\n\\[note\\]\n\n`string`\n\nThe note to send with the invitation.\n\n\\[orgName\\]\n\n`string`\n\nThe organization name.\n\n**Example**\n\n```\naccessControl.sendOrgInvite(\"new_user@terminusdb.com\",\"Role/admin\",\n\"please join myteam\").then(result=>{\n console.log(result)\n})\n```\n\n## getOrgInvite\n\n##### accessControl.getOrgInvite(inviteId, \\[orgName\\]) ⇒ `Promise`\n\n\\-- TerminusCMS API --- Get the invitation info\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\ninviteId\n\n`string`\n\nThe invite id to retrieve.\n\n\\[orgName\\]\n\n`string`\n\nThe organization name.\n\n**Example**\n\n```javascript\nconst fullInviteId=\"Organization/my_team_name/invitations/Invitation/7ad0c9eb82b6175bcda9c0dfc\n2ac51161ef5ba7cb0988d992c4bce82b3fa5d25\"\naccessControl.getOrgInvite(fullInviteId).then(result=>{\n console.log(result)\n})\n```\n\n## deleteOrgInvite\n\n##### accessControl.deleteOrgInvite(inviteId, \\[orgName\\]) ⇒ `Promise`\n\n\\-- TerminusCMS API ---\n\nDelete an invitation\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\ninviteId\n\n`string`\n\nThe invite id to delete.\n\n\\[orgName\\]\n\n`string`\n\nThe organization name.\n\n**Example**\n\n```javascript\nconst fullInviteId=\"Organization/my_team_name/invitations/Invitation/7ad0c9eb82b6175bcda9\nc0dfc2ac51161ef5ba7cb0988d992c4bce82b3fa5d25\"\naccessControl.deleteOrgInvite(fullInviteId).then(result=>{\n console.log(result)\n})\n```\n\n## updateOrgInviteStatus\n\n##### accessControl.updateOrgInviteStatus(inviteId, accepted, \\[orgName\\]) ⇒ `Promise`\n\n\\-- TerminusCMS API ---\n\nAccept /Reject invitation. if the invitation has been accepted we add the current user to the organization.\n\nThe only user that can accept this invitation is the user registered with the invitation email, we indentify the user with the JWT token\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\ninviteId\n\n`string`\n\nThe invite id to updated.\n\naccepted\n\n`boolean`\n\nThe status of the invitation.\n\n\\[orgName\\]\n\n`string`\n\nThe organization name.\n\n**Example**\n\n```javascript\nconst fullInviteId=\"Organization/my_team_name/invitations/Invitation/7ad0c9eb82b6175bcda9\nc0dfc2ac51161ef5ba7cb0988d992c4bce82b3fa5d25\"\naccessControl.updateOrgInviteStatus(fullInviteId,true).then(result=>{\n console.log(result)\n})\n```\n\n## getTeamUserRole\n\n##### accessControl.getTeamUserRole(\\[orgName\\]) ⇒ `Promise`\n\n\\-- TerminusCMS API ---\n\nGet the user role for a given organization or the default organization The user is identified by the jwt or the access token\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\n\\[orgName\\]\n\n`string`\n\nThe organization name.\n\n**Example**\n\n```\naccessControl.getTeamUserRole().then(result=>{\n console.log(result)\n})\n\n//response object example\n{\"userRole\":\"Role/admin\"}\n```\n\n## removeUserFromOrg\n\n##### accessControl.removeUserFromOrg(userId, \\[orgName\\]) ⇒ `Promise`\n\n\\-- TerminusCMS API -- Remove an user from an organization, only an admin user can remove an user from an organization\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\nuserId\n\n`string`\n\nThe id of the user to be removed. (this is the document user's @id)\n\n\\[orgName\\]\n\n`string`\n\nThe organization name in which the user is to be removed.\n\n**Example**\n\n```\naccessControl.removeUserFromOrg(\"User/auth0%7C613f5dnndjdjkTTT\",\"my_org_name\").then(result=>{\n console.log(result)\n})\n```\n\n## getDatabaseRolesOfUser\n\n##### accessControl.getDatabaseRolesOfUser(userId, \\[orgName\\]) ⇒ `Promise`\n\n\\-- TerminusCMS API --\n\nGet the user's role for every databases under the organization\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\nuserId\n\n`string`\n\nThe user's id.\n\n\\[orgName\\]\n\n`string`\n\nThe organization name.\n\n**Example**\n\n```\naccessControl.getDatabaseRolesOfUser('User/auth0%7C61790e366377Yu6596a').then(result=>{\n console.log(result)\n})\n\n//this is a capabilities list of databases and roles\n//[ {capability: \"Capability/b395e8523d509dec6b33aefc9baed3b2e2bfadbd4c79d4ff9b20dce2b14e2edc\"\n//if there is an id we have a user specific capabality for this database\n // name: {@type: \"xsd:string\", @value: \"profiles_test\"}\n // role: \"Role/dataUpdater\"\n // scope: \"UserDatabase/7ebdfae5a02bc7e8f6d79sjjjsa4e179b1df9d4576a3b1d2e5ff3b4859\"\n // user: \"User/auth0%7C61790e11a3966d006906596a\"},\n\n//{ capability: null\n// if the capability id is null the user level of access for this database is the\nsame of the team\n //name: {@type: \"xsd:string\", @value: \"Collab002\"}\n //role: \"Role/dataReader\"\n // scope: \"UserDatabase/acfcc2db02b83792sssb15239ccdf586fc5b176846ffe4878b1aea6a36c8f\"\n //user: \"User/auth0%7C61790e11a3966d006906596a\"}]\n```\n\n## createUserRole\n\n##### accessControl.createUserRole(userId, scope, role, \\[orgName\\]) ⇒ `Promise`\n\n\\-- TerminusCMS API --\n\nCreate a user's a role for a resource (organization/database)\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\nuserId\n\n`string`\n\nThe user's id.\n\nscope\n\n`string`\n\nThe resource name/id.\n\nrole\n\n`string`\n\nThe user role to be assigned.\n\n\\[orgName\\]\n\n`string`\n\nThe organization name.\n\n**Example**\n\n```javascript\nconst dbId = \"UserDatabase/acfcc2db02b83792sssb15239ccdf586fc5b176846ffe4878b1aea6a36c8f\"\naccessControl.assignUserRole('User/auth0%7C61790e11a3966d006906596a',dbId,\n\"Role/collaborator\").then(result=>{\n console.log(result)\n\n})\n```\n\n## updateUserRole\n\n##### accessControl.updateUserRole(userId, capabilityId, scope, role, \\[orgName\\]) ⇒ `Promise`\n\n\\-- TerminusCMS API --\n\nUpdate user's a role for a resource (organization/database), (this api works only in TerminusCMS)\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\nuserId\n\n`string`\n\nThe user's id.\n\ncapabilityId\n\n`string`\n\nThe capability id.\n\nscope\n\n`string`\n\nThe resource name/id.\n\nrole\n\n`string`\n\nThe user role to be updated.\n\n\\[orgName\\]\n\n`string`\n\nThe organization name.\n\n**Example**\n\n```javascript\nconst dbId = \"UserDatabase/acfcc2db02b83792sssb15239ccdf586fc5b176846ffe4878b1aea6a36c8f\"\nconst capId= \"Capability/b395e8523d509dec6b33aefc9baed3b2e2bfadbd4c79d4ff9b20dce2b14e2edc\"\naccessControl.updateUserRole('User/auth0%7C61790e11a3966d006906596a',capId,dbId,\n\"Role/dataUpdater\").then(result=>{\n console.log(result)\n\n})\n```\n\n## accessRequestsList\n\n##### accessControl.accessRequestsList(\\[orgName\\]) ⇒ `Promise`\n\n\\-- TerminusCMS API --\n\nGet all the access request list for a specify organization\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\n\\[orgName\\]\n\n`string`\n\nThe organization name.\n\n**Example**\n\n```\naccessControl.accessRequestsList().then(result=>{\n console.log(result)\n})\n```\n\n## sendAccessRequest\n\n##### accessControl.sendAccessRequest(\\[email\\], \\[affiliation\\], \\[note\\], \\[orgName\\]) ⇒ `Promise`\n\n\\-- TerminusCMS API --\n\nGet all the access request list for a specify organization\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\n\\[email\\]\n\n`string`\n\nthe user email.\n\n\\[affiliation\\]\n\n`string`\n\nthe user affiliation, company, university etc..\n\n\\[note\\]\n\n`string`\n\nthe message for the team admin\n\n\\[orgName\\]\n\n`string`\n\nThe organization name.\n\n**Example**\n\n```\naccessControl.sendAccessRequest(\"myemail@terminusdb.com\",\n \"my_company\",\n \"please add me to your team\"\n).then(result=>{\n console.log(result)\n})\n```\n\n## deleteAccessRequest\n\n##### accessControl.deleteAccessRequest(\\[orgName\\]) ⇒ `Promise`\n\n\\-- TerminusCMS API --\n\nDelete an access request to join your team, only an admin user can delete it\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\n\\[orgName\\]\n\n`string`\n\nThe organization name.\n\n**Example**\n\n```\naccessControl.deleteAccessRequest(\"djjdshhsuuwewueueuiHYHYYW.......\").then(result=>{\n console.log(result)\n})\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Access Control Reference Guide", + "description": "A driver to manage access control with the JS Client ", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "TerminusCMS Data Types" + }, + "slug": "terminuscms-data-types", + "body": { + "@type": "Body", + "value": "**Type**\n\n**W3C spec**\n\n**Description**\n\n`xsd:string`\n\n[W3C](https://www.w3.org/TR/xmlschema-2/#string)\n\nCharacter strings (but not all Unicode character strings)\n\n`xsd:boolean`\n\n[W3C](https://www.w3.org/TR/xmlschema-2/#boolean)\n\ntrue, false\n\n`xsd:decimal`\n\n[W3C](https://www.w3.org/TR/xmlschema-2/#decimal)\n\nEquivalent to `xsd:double`\n\n`xsd:integer`\n\n[W3C](https://www.w3.org/TR/xmlschema-2/#integer)\n\nArbitrary-size integer numbers\n\n## IEEE floating-point numbers\n\n**Type**\n\n**W3C spec**\n\n**Description**\n\n`xsd:double`\n\n[W3C](https://www.w3.org/TR/xmlschema-2/#double)\n\n64-bit floating point numbers incl. ∓Inf, ∓0, NaN\n\n`xsd:float`\n\n[W3C](https://www.w3.org/TR/xmlschema-2/#float)\n\n32-bit floating point numbers incl. ∓Inf, ∓0, NaN\n\n## Time and date\n\n**Type**\n\n**W3C spec**\n\n**Description**\n\n`xsd:date`\n\n[W3C](https://www.w3.org/TR/xmlschema-2/#date)\n\nDates (yyyy-mm-dd) with or without timezone\n\n`xsd:time`\n\n[W3C](https://www.w3.org/TR/xmlschema-2/#time)\n\nTimes (`hh:mm:ss.sss`) with or without timezone\n\n`xsd:dateTime`\n\n[W3C](https://www.w3.org/TR/xmlschema-2/#dateTime)\n\nDate and time with or without timezone\n\n`xsd:dateTimeStamp`\n\n\\-\n\nDate and time with required timezone\n\n## Recurring and partial dates\n\n**Type**\n\n**W3C spec**\n\n**Description**\n\n`xsd:gYear`\n\n[W3C](https://www.w3.org/TR/xmlschema-2/#gYear)\n\nGregorian calendar year\n\n`xsd:gMonth`\n\n[W3C](https://www.w3.org/TR/xmlschema-2/#gMonth)\n\nGregorian calendar month\n\n`xsd:gDay`\n\n[W3C](https://www.w3.org/TR/xmlschema-2/#gDay)\n\nGregorian calendar day of the month\n\n`xsd:gYearMonth`\n\n[W3C](https://www.w3.org/TR/xmlschema-2/#gYearMonth)\n\nGregorian calendar year and month\n\n`xsd:gMonthDay`\n\n[W3C](https://www.w3.org/TR/xmlschema-2/#gMonthDay)\n\nGregorian calendar month and day\n\n`xsd:duration`\n\n[W3C](https://www.w3.org/TR/xmlschema-2/#duration)\n\nDuration of time\n\n`xsd:yearMonthDuration`\n\n\\-\n\nDuration of time (months and years only)\n\n`xsd:dayTimeDuration`\n\n\\-\n\nDuration of time (days, hours, minutes, seconds only)\n\n## Limited-range integer numbers\n\n**Type**\n\n**W3C spec**\n\n**Description**\n\n`xsd:byte`\n\n[W3C](https://www.w3.org/TR/xmlschema-2/#byte)\n\n\\-128…+127 (8 bit)\n\n`xsd:short`\n\n[W3C](https://www.w3.org/TR/xmlschema-2/#short)\n\n\\-32768…+32767 (16 bit)\n\n`xsd:int`\n\n[W3C](https://www.w3.org/TR/xmlschema-2/#int)\n\n\\-2147483648…+2147483647 (32 bit)\n\n`xsd:long`\n\n[W3C](https://www.w3.org/TR/xmlschema-2/#long)\n\n\\-9223372036854775808…+9223372036854775807 (64 bit)\n\n`xsd:unsignedByte`\n\n[W3C](https://www.w3.org/TR/xmlschema-2/#unsignedByte)\n\n0…255 (8 bit)\n\n`xsd:unsignedShort`\n\n[W3C](https://www.w3.org/TR/xmlschema-2/#unsignedShort)\n\n0…65535 (16 bit)\n\n`xsd:unsignedInt`\n\n[W3C](https://www.w3.org/TR/xmlschema-2/#unsignedInt)\n\n0…4294967295 (32 bit)\n\n`xsd:unsignedLong`\n\n[W3C](https://www.w3.org/TR/xmlschema-2/#unsignedLong)\n\n0…18446744073709551615 (64 bit)\n\n`xsd:positiveInteger`\n\n[W3C](https://www.w3.org/TR/xmlschema-2/#positiveInteger)\n\nInteger numbers >0\n\n`xsd:nonNegativeInteger`\n\n[W3C](https://www.w3.org/TR/xmlschema-2/#nonNegativeInteger)\n\nInteger numbers ≥0\n\n`xsd:negativeInteger`\n\n[W3C](https://www.w3.org/TR/xmlschema-2/#negativeInteger)\n\nInteger numbers <0\n\n`xsd:nonPositiveInteger`\n\n[W3C](https://www.w3.org/TR/xmlschema-2/#nonPositiveInteger)\n\nInteger numbers ≤0\n\n## Encoded binary data\n\n**Type**\n\n**W3C spec**\n\n**Description**\n\n`xsd:hexBinary`\n\n[W3C](https://www.w3.org/TR/xmlschema-2/#hexBinary)\n\nHex-encoded binary data\n\n`xsd:base64Binary`\n\n[W3C](https://www.w3.org/TR/xmlschema-2/#base64Binary)\n\nBase64-encoded binary data\n\n## Miscellaneous XSD types\n\n**Type**\n\n**W3C spec**\n\n**Description**\n\n`xsd:anyURI`\n\n[W3C](https://www.w3.org/TR/xmlschema-2/#anyURI)\n\nAbsolute or relative URIs and IRIs\n\n`xsd:language`\n\n[W3C](https://www.w3.org/TR/xmlschema-2/#language)\n\nLanguage tags per [BCP47](https://en.wikipedia.org/wiki/IETF_language_tag)\n\n`xsd:normalizedString`\n\n[W3C](https://www.w3.org/TR/xmlschema-2/#normalizedString)\n\nWhitespace-normalized strings\n\n`xsd:token`\n\n[W3C](https://www.w3.org/TR/xmlschema-2/#token)\n\nTokenized strings\n\n`xsd:NMTOKEN`\n\n[W3C](https://www.w3.org/TR/xmlschema-2/#NMTOKEN)\n\nXML NMTOKENs\n\n`xsd:Name`\n\n[W3C](https://www.w3.org/TR/xmlschema-2/#Name)\n\nXML Names\n\n`xsd:NCName`\n\n[W3C](https://www.w3.org/TR/xmlschema-2/#NCName)\n\nXML NCNames" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "TerminusCMS and TerminusDB Data Types", + "description": "The core data types for TerminusDB and TerminusCMS.", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Document Insertion Reference Guide" + }, + "slug": "document-insertion", + "body": { + "@type": "Body", + "value": "The document interface consists of two endpoints. The first endpoint, `document`, is how we get documents into and out of TerminusDB. Since schemas consist of documents too, this is also how you'd update the schema.\n\nThe second endpoint, `schema`, is how we can easily get schema information out of TerminusDB. While technically it is possible to get all schema information through the document interface, the schema interface is more convenient for this purpose, as it takes class inheritance into account to give a complete image of all the properties that are usable on a certain class.\n\n## The document endpoint\n\n### Getting documents\n\nAll document retrieval is done through GET requests on the following endpoint:\n\n```\nGET /api/document/\n```\n\nWhere resource path is the usual strings like `admin/foo` for database foo, or `_system` for the system graph, or `admin/foo/_meta` for the metadata graph of the foo database, etc.\n\nBy default, this will return a stream of all documents to be found at this location. What exactly is returned can be modified using parameters, which are to be provided as query parameters.\n\n#### Parameters\n\nparameter\n\ndefault\n\nexplanation\n\ngraph\\_type\n\neither instance or schema. Used to switch between getting documents from the instance or the schema graph.\n\ntype\n\nIf given, only documents of the given type are returned.\n\nid\n\nIf given, only the document with the given ID is returned.\n\nprefixed\n\ntrue\n\nIf true (the default), return IRIs using a prefixed notation wherever possible. If false, full IRIs are used.\n\nminimized\n\nfalse\n\nIf true, forego pretty printing, and return the documents with very little whitespace. Each json document will be on its own line.\n\nunfold\n\ntrue\n\nIf true (the default), any subdocuments contained in the returned document are returned too. If false, these are referred to by their ID instead.\n\nskip\n\n0\n\nHow many results to skip\n\ncount\n\nHow many results to return. If this option is absent, all results are returned.\n\nas\\_list\n\nfalse\n\nIf true, don't return a stream of json objects, but a list. This makes parsing the json easier in some environments.\n\n#### Alternate query mechanism\n\nThe above table shows parameters that are supposed to be provided as query parameters. There's however another mechanism, where instead, the parameters are passed in as a posted JSON document. In this calling style, an additional parameter is allowed, `\"query\"`, by which the returned documents are filtered by matching against some template.\n\nThe alternative method uses a POST rather than a get, specifies the header `X-HTTP-Method-Override: GET`, and posts a JSON document with the various query parameters instead:\n\n```\n{\n \"@rdf:type\": \"Person\",\n \"count\": 10,\n \"query\": { \"age\": 42 },\n}\n```\n\nThe above example would find the first 10 documents of class `Person`, whose age is 42.\n\nThis may provide a more convenient style for querying from a library, especially when a (large) query document has to be provided for filtering purposes. However, unlike a pure GET request with query parameters, a POST with a method override does not result in a page that can be bookmarked in a browser. If that is desirable, the GET style is better.\n\n### Posting documents\n\nAll new document submission is done through POST requests on the following endpoint:\n\n```\nPOST /api/document/\n```\n\nWhere resource path is the usual strings like `admin/foo` for database foo, or `_system` for the system graph, or `admin/foo/_meta` for the metadata graph of the foo database, etc.\n\nThe documents to be submitted are given as post data. Multiple documents can be specified at once, either as a stream of JSON objects or as a JSON list containing the documents to be inserted. If a document is specified that already exists, and overwrite is false (the default), an error is returned.\n\n#### Parameters\n\nparameter\n\ndefault\n\nexplanation\n\nauthor\n\nThe commit author\n\nmessage\n\nThe commit message\n\ngraph\\_type\n\ninstance\n\neither instance or schema. Used to switch between submitting to the instance or the schema graph.\n\nfull\\_replace\n\nfalse\n\nIf true, all existing documents are deleted before inserting the posted documents. This allows the full replacement of the contents of a database. This is especially useful for replacing the schema.\n\nraw\\_json\n\nfalse\n\nIf true, the input documents are treated as raw JSON , inserted as type `sys:JSONDocument` and are not subject to schema restrictions.\n\n#### Result\n\nAfter a successful post, the result will be a list of ids of the newly added documents.\n\n### Replacing documents\n\nExisting documents can be replaced through a PUT request on the following endpoint:\n\n```\nPUT /api/document/\n```\n\nWhere resource path is the usual strings like `admin/foo` for database foo, or `_system` for the system graph, or `admin/foo/_meta` for the metadata graph of the foo database, etc.\n\nThe documents to be submitted are given as post data. Multiple documents can be specified at once, either as a stream of JSON objects or as a JSON list containing the documents to be replaced. If a document is specified that does not exist in the database, an error is returned unless `create` is set to `true` in which case it is inserted.\n\n#### Parameters\n\nparameter\n\ndefault\n\nexplanation\n\nauthor\n\nThe commit author\n\nmessage\n\nThe commit message\n\ngraph\\_type\n\ninstance\n\neither instance or schema. Used to switch between submitting to the instance or the schema graph.\n\ncreate\n\nfalse\n\ninsert if the document was not already in the database.\n\nraw\\_json\n\nfalse\n\nIf true, the replaced documents are treated as raw JSON , they must be replacing a document of type `sys:JSONDocument` and they are not subject to schema restrictions.\n\n### Deleting documents\n\nExisting documents can be deleted through a DELETE request on the following endpoint:\n\n```\nDELETE /api/document/\n```\n\nWhere resource path is the usual strings like `admin/foo` for database foo, or `_system` for the system graph, or `admin/foo/_meta` for the metadata graph of the foo database, etc.\n\n#### Parameters\n\nparameter\n\ndefault\n\nexplanation\n\nauthor\n\nThe commit author\n\nmessage\n\nThe commit message\n\ngraph\\_type\n\ninstance\n\neither instance or schema. Used to switch between submitting to the instance or the schema graph.\n\nid\n\nIf given, the document to delete. If not given, it is expected that the post data will contain a list of ids to delete.\n\nnuke\n\nfalse\n\nIf true, delete everything at this resource location (dangerous!).\n\n#### Specifying what documents to delete\n\nAs shown above, deleting a single document can be done through query parameters alone. If multiple documents are to be deleted at once, a document has to be posted of the following format:\n\n```\n[ \"..id 1..\",\n \"..id 2..\",\n ...\n]\n```\n\nIn other words, a JSON list of document IDs.\n\n### ID Capture for Doc Insert & Replace\n\nWhen inserting or replacing several documents at once, it may occur that some of these documents need to refer to each other. However, at insertion time, you may not know what the IDs of the new documents are going to be. This is especially the case for document types that generate their identifier randomly, but even for non-random key types, it may be convenient to rely on the server's ID generation algorithm, rather than trying to predict what IDs will get generated. Therefore, in order to support cross-references between newly inserted documents, the document interface allows you to capture newly generated document IDs in a variable, and then refer to that variable later in other documents.\n\n#### Capturing an identifier into a variable\n\nWhen inserting or replacing a document that we want to refer to in another document inserted in the same operation, you can use a `@capture` key in the document to associate the newly generated identifier with a variable. For example,\n\n```\n{ \"@type\": \"Person\",\n \"@capture\": \"Id_Tom\",\n \"name\": \"Tom\"\n}\n```\n\nThis will store the newly generated ID in a variable called `ID_Tom` for the duration of the document insert/replace operation.\n\nIt is allowed to capture an ID and then never actually refer to it.\n\nIt is an error to capture the same variable twice. Doing so will result in a `api:CaptureIdAlreadyBound` error with the following shape:\n\n```\n{\"@type\": \"api:CaptureIdAlreadyBound\",\n \"api:capture\": \"..capture id..\",\n \"api:document\": {..document where previously captured variable was captured again..}\n```\n\n#### Referring to an identifier using a variable\n\nWhen inserting or replacing a document that needs to refer to another document inserted in the same operation, you can use a json dictionary of the form `{\"@ref\": \"..id..\"}` in place of an ordinary id. For example,\n\n```\n{ \"@type\": \"Person\",\n \"name\": \"Jerry\",\n \"rival\": {\"@ref\": \"Id_Tom\"}\n}\n```\n\nIt is an error to refer to a variable that is never captured. Doing so will result in a `api:NotAllCapturesFound` error of the following shape:\n\n```\n{ \"@type\": \"api:NotAllCapturesFound\",\n \"api:captures\": [..list of capture ids that were referenced but not found..]\n}\n```\n\n#### Ordering of documents\n\nID captures and ID references can be done in any order. That means that when you are submitting several documents, you're allowed to refer to a captured ID in an earlier document. This also allows you to do cross-references, where two documents refer to each other:\n\n```\n{ \"@type\": \"Person\",\n \"@capture\": \"Id_Tom\",\n \"name\": \"Tom\",\n \"rival\": {\"@ref\": \"Id_Jerry\"}\n}\n{ \"@type\": \"Person\",\n \"@capture\": \"Id_Jerry\",\n \"name\": \"Jerry\",\n \"rival\": {\"@ref\": \"Id_Tom\"}\n}\n```\n\nIn this example, Tom refers to Jerry, even though at that point in the submitted document stream, Jerry has not yet been processed. This is not a problem - both Tom and Jerry will get inserted referring to each other.\n\n#### Self-reference\n\nUsing ID capture, it is possible to create a document that refers to itself:\n\n```\n{ \"@type\": \"Person\",\n \"@capture\": \"Captured_Id\",\n \"name\": \"Elmo\",\n \"friend\": {\"@ref\": \"Captured_Id\"}\n}\n```\n\nThis will make Elmo be his own friend.\n\n#### ID capture only works within a single operation\n\nIt is important to keep in mind that the ID capture mechanism only works within a single call to the document api. It is not possible to capture an ID in one operation, and then refer to it in a second operation. The `@capture` and `@ref` instructions do not get saved into the database. They are processed immediately and are then forgotten.\n\nIf you need to refer to a document already in the database, the only way to do so is by referring to its ID.\n\n## The schema endpoint\n\nThe schema endpoint can be used to query information about classes in a resource. These queries happen through a GET on the following endpoint:\n\n```\nGET /api/schema/\n```\n\nWhere resource path is the usual strings like `admin/foo` for database foo, or `_system` for the system graph, or `admin/foo/_meta` for the metadata graph of the foo database, etc.\n\nThe purpose of this endpoint is to quickly discover the supported fields of a particular type. The primary envisioned use case for this is the automatic generation of forms and other UI elements, as well as client code generation.\n\n#### Parameters\n\nparameter\n\ndefault\n\nexplanation\n\ntype\n\nIf given, the type to get information for. If omitted, information for all types is returned.\n\n#### Result\n\nThe result of this GET is a stream of documents describing all the types in a particular resource.\n\n### Schema-checking and schemaless mode\n\nThe schema endpoint can also be used to switch between schema checking and schemaless mode.\n\nSwitching between checking or not checking does not delete the schema itself. After disabling schema checking it is still possible to update the schema or to query it through the schema endpoint. However, when disabled, it is possible to submit documents that do not match the schema. Re-enabling schema checking is only possible if all the documents in the given resource match the current schema.\n\n```\nPOST /api/schema/\n```\n\n#### Parameters\n\nparameter\n\ndefault\n\nexplanation\n\nauthor\n\nThe commit author\n\nmessage\n\nThe commit message\n\nschema\\_checking\n\nValue should be either enabled or disabled\n\n## The apply endpoint\n\nThe schema endpoint can be used to query information about classes in a resource. These queries happen through a GET on the following endpoint:\n\n```\nPOST /api/schema/\n```\n\nWhere resource path is the usual strings like `admin/foo` for database foo, or `admin/foo/local/branch/dev` for the `dev` branch of `admin/foo`.\n\nThe purpose of this endpoint is to take the difference between any two commits and apply them to a branch.\n\n#### Parameters\n\nparameter\n\ndefault\n\nexplanation\n\nbefore\\_commit\n\nThe first commit to compare in order to produce a diff\n\nafter\\_commit\n\nThe last commit to compare in order to produce a diff\n\ncommit\\_info\n\nA JSON document with author and message\n\nmatch\\_final\\_state\n\ntrue\n\nIgnores conflicts if the final state would remain the same\n\ntype\n\nsquash\n\nWhat type of application to perform - currently can only be squash\n\n#### Result\n\nThe result of this POST request is either an updated branch with a successful application of the difference between two commits, or an error giving the reason for an unresolvable conflict.\n\n## Further Reading\n\n**\\*_[](/docs/documents-explanation/)_**_[Documents in a knowledge graph and how to use them](/docs/documents-explanation/)_[\\*](/docs/documents-explanation/)." + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "TerminusCMS/DB Document Insertion Reference Guide", + "description": "A reference guide for the TerminusCMS/DB document interface." + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "TerminusCMS Dashboard Reference Guide" + }, + "slug": "terminuscms-dashboard-reference", + "body": { + "@type": "Body", + "value": "## Overview\n\nThe TerminusCMS dashboard is a place to -\n\n* Manage your teams and collaborators\n* Manage your data products/projects\n* Model schema or edit in code\n* Manual data and content curation\n* Test and build queries\n* Collaborate on other user's TerminusCMS projects\n* Manage, review, and accept or reject change requests.\n\nFor details about how to achieve any of the list above, please take a look at the [product tour](/docs/product-tour/).\n\nTerminusCMS is structured in such a way -\n\n![How teams, users and projects are structured.](https://assets.terminusdb.com/docs/teams-users-and-projects2.png)\n\nWhen you sign up for TerminusCMS is automatically generates a team for you based on your login credentials. You can create other teams too. You will be an admin user for any of your teams.\n\nYou can then invite collaborators to your team. The permissions you grant them for the team will be applied to all projects within that team.\n\nProjects/data products created within that team will be available to you and any collaborators invited.\n\nYou can have several teams with different projects and collaborators.\n\n## Managing Teams & Collaborators\n\n### Teams\n\nTeams are a way to group your projects and team members. For example you may have different teams in your organization looking after different functions, so you could have teams for Personnel, Marketing, Finance, and Operations for example. These teams would include the relevant people and projects.\n\n[Learn how to create a team here](/docs/create-a-team-with-terminuscms/).\n\n### Collaborators/Users\n\nCollaborators are invited by the team admin to work with the projects within that team. Invites are sent via email. The email contains a link that takes that user to the dashboard sign up page. Upon signing up or logging in, the user can accept or reject the invitation. Once accepted that user will be able to work with the project in the team with the permissions granted by the admin.\n\n### Permissions\n\nThere are [five permission levels](/docs/invite-users-using-terminuscms/) for users ranging from admin down to info reader. The team permissions for a user are inherited by the projects within that team.\n\nIndividual project permissions can be granted in the team management section. Project-specific permissions can only be higher than team permissions. For example, if you want a user to be a collaborator for one project, set their team privilege to a lower permission level such as info-reader or data-reader.\n\n## Managing Projects/Data Products\n\nWhen you select a team you can create new projects or manage existing ones by selecting a project from the list on the left. Once a project is created or selected you will be directed to the project/data product management screen. Here you can clone, branch, reset and squash main or any branches, and delete the project.\n\n## Model Schema\n\nThe second icon with three circles on the left takes you to the screen to model and build the project schemas. The screen has two tabs, one for building the schema with a UI, the other for constructing it in JSON.\n\nFor more informaiton about schema modeling, visit the [how-to model schema guide](/docs/model-schema/).\n\n## Manual Data Entry & Content Curation\n\nThe third icon, the document with a tick, takes you to the document curation section. On the left and in the main section of the screen it will list all of the documents within the project schema. Here you can click through to view, sort, and filter existing documents. Or add, edit, and delete documents.\n\nTerminusCMS automatically constructs document frames from the schema. These frames are rendered as forms in the dashboard and all users to add and edit data and content directly into the backend.\n\nTerminusCMS comes with change requests workflows for data and content curation.\n\n### TerminusCMS Change Request Workflows\n\nChange request workflows in TerminusCMS are an automated process. When a user tries to edit, delete, or add a document they are prompted to create a change request by giving it a name and description. The change request creates a new branch of the data where the user can make changes away from main. They can exit the change request and pick it up later, or submit it for review. A review can accept and merge the change request, or reject and delete it.\n\nTo ensure that other changes don't get stamped the change request workflows check the database to see if it has changed since the branch was created, and if so, update the change request with the latest changes prior to it being reviewed and merged.\n\n## Query Playgrounds\n\nThe TerminusCMS dashboards come with WOQL and GraphQL query playgrounds.\n\n### WOQL Query Playground\n\nWOQL is a Datalog query language. More information about WOQL can be found in the [WOQL how-to guide](/docs/woql-basics/). The query language is based on two rules, tripples and unification. This blog post explains [WOQL's methodology](https://terminusdb.com/blog/the-power-of-web-object-query-language/).\n\nThe playground features query panels to write your schema. You can have several panels open to tweak your query. To aid you in building your query, listed on the left are the documents within the schema, you can select one which expands to show the properties of each document. Clicking on one will add create a new query panel with a WOQL query for that document property.\n\n### GraphQL Query Playground\n\nGraphQL is typically an API language, but TerminusCMS has incorporated some of WOQLs features to allow you to perform graph queries using GraphQL. The playground features a query input area and a results panel. The playground is tab based and you can have many tabs open to experiment and tweak queries.\n\nTerminusCMS automatically generates the GraphQL schema from the project's schema. This enables features such as autofill and a dropdown of classes and properties.\n\nFor more information about querying with GraphQL, visit the [GraphQL Query how-to guide](/docs/graphql-basics/)." + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "TerminusCMS Dashboard Reference Guide", + "description": "A conceptual overview of the TerminusCMS dashboard describing its features and their purpose.", + "og_image": "https://assets.terminusdb.com/docs/document-explorer-home.png" + }, + "media": [ + { + "@type": "Media", + "alt": "How teams, users and projects are structured.", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "How teams, users and projects are structured." + }, + "value": "https://assets.terminusdb.com/docs/teams-users-and-projects2.png" + } + ] + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "JSON Diff and Patch with TerminusDB and TerminusCMS" + }, + "slug": "json-diff-and-patch", + "body": { + "@type": "Body", + "value": "JSON objects are a common way of representing data for software development. The serialization of JSON is simple and facilitates communication via networks and storage in databases. Almost all modern programming languages support JSON objects natively.\n\nWhen objects are modified in distributed systems, it is useful to compare versions of an object to see what has changed. This is where **diff** and **patch** come in.\n\n#### Diff\n\nA **diff** takes two JSON objects and presents any differences between them. Diff has several uses. A key use is displaying a clear summary of differences between large objects, enhancing the visibility of changes. This enables manual, user-interface assisted, or client actions to resolve differences. Actions include:\n\n* Retain the original object.\n* Change to the new (or latest) version of the object.\n* Create a new version of the object.\n\n#### Patch\n\nA **patch** applies a diff to two objects to obtain a new object with any differences highlighted. A patch is applied individually or in bulk to a patch endpoint that will apply the patch to the specified data product.\n\n## Public Endpoint\n\nUse our public endpoints for each operation:\n\n**JSON Diff**\n\n```\nhttps://cloud.terminusdb.com/jsondiff\n```\n\n**JSON Patch**\n\n```\nhttps://cloud.terminusdb.com/jsonpatch\n```\n\nSee [Diff and Patch Endpoints](#diffandpatchendpoints) for more information, and examples of [diff](#diffexamplesusingcurl) and [patch](#patchexamplesusingcurl) using curl.\n\n## Diff & Patch with Client\n\nUse JSON Diff and Patch with a TerminusDB JavaScript or Python client to find and handle changes in TerminusDB schemas and documents, JSON schemas, and other document databases such as MongoDB.\n\n### Requirements\n\nInstall a [JavaScript](/docs/install-terminusdb-js-client/) or [Python](/docs/install-the-python-client/) TerminusDB client.\n\n### Get started\n\nGet started with the simple steps below.\n\n> If using **TerminusCMS with Python**, connect to your TerminusCMS cloud instance first - see [Connect with the Python Client](/docs/connect-with-python-client/) for instructions if required.\n\n1. [Create an endpoint](#createanendpoint)\n \n2. [Apply a diff to obtain a patch](#applyadifftoobtainapatch)\n \n3. [Review the patch](#reviewthepatch)\n \n4. [Apply the patch](#applythepatch)\n \n\n### Create an endpoint\n\nCreate a client endpoint with `WOQLClient`.\n\n#### Create an endpoint with the JavaScript Client\n\n```javascript\nconst TerminusClient = require(\"@terminusdb/terminusdb-client\");\n\nvar client = new TerminusClient.WOQLClient(\"http://127.0.0.1:6363\")\n```\n\n#### Create an endpoint with the Python Client\n\n```python\nfrom terminusdb_client import WOQLClient\n\nclient = WOQLClient(\"http://localhost:6363/\")\n```\n\n### Apply a diff to obtain a patch\n\nGet the difference/s between two hypothetical documents - `Doc1` and `Doc2`.\n\n#### Apply Diff - JS\n\nUse `getDiff`\n\n```javascript\nlet result_patch = await client.getDiff(Doc1, Doc2)\n```\n\n#### Apply Diff - Python\n\nUse`diff`\n\n```\nresult_patch = client.diff(Doc1, Doc2)\n```\n\n### Review the patch\n\nPrint the contents of a patch.\n\n#### Review - JS\n\n```\nconsole.log(result_patch)\n```\n\n#### Review - Python\n\nExample uses`pprint` (`from pprint import pprint`)\n\n```\npprint(result_patch.content)\n```\n\n### Apply the patch\n\nApply the patch to `Doc1`.\n\n#### Apply - JS\n\n```javascript\nlet after_patch = await client.patch(Doc1, result_patch);\n```\n\n#### Apply - Python\n\n```\nafter_patch = client.patch(Doc1, result_patch)\n```\n\n## JSON Diff and Patch Operations\n\nThe available JSON Diff and Patch operations with some examples using `curl`.\n\nDiff can take the paramters `keep` which specifies a document describing which fields _must_ be copied in the final object, and a `copy_value` boolean flag, which specifies whether to specify the exact value in a copy operation.\n\n### Copy Diff\n\nCopy is implicit. All properties which are not specifically mentioned will be considered part of an implicit copy. This will make patches more compressed and easier to specify by hand.\n\n### Mandatory Diff\n\n`@before`/`@after` instructions contain objects specified as tightly as required to obtain ids, or as ids.\n\n```\n{ '@id' : \"Person/jim\",\n 'date_of_birth' : { '@op' : 'SwapValue',\n '@before' : \"1928-03-05\",\n '@after' : \"1938-03-05\"\n }}\n```\n\n### Optional Diff\n\nOptional diffs also contain `@before`/`@after` designations, but potentially `null` fields to describe missing elements.\n\n```\n{ '@id' : \"Object/my_object\",\n 'name' : { '@op' : 'SwapValue',\n '@before' : null,\n '@after' : \"Jim\" }}\n```\n\n### Set Diff / Cardinality Diff\n\nSet requires the ability to explicitly remove or add elements - we can do this by maintaining a `@before`/`@after` with a list of those which exist _only_ on the left, and _only_ on the right.\n\n### List Diff\n\nThe list diff requires swaps at a position. We use, `@copy`, `@swap` and `@keep`.\n\n#### Copy List\n\nCopy the previous list from `From_Position` to `To_Position`.\n\n```\n{ \"@op\" : \"CopyList\",\n \"@to\" : To_Position,\n \"@rest\" : Diff }\n```\n\n#### Swap List\n\nSwap out the list starting from the current point from `Previous` to `Next`. This can be used to extend, or drop elements as well as do full replacement.\n\n```\n{ \"@op\" : \"SwapList\",\n \"@before\" : Previous,\n \"@after\" : Next,\n \"@rest\" : Diff }\n```\n\n#### Patch List\n\nPatch the list starting from the current point with the patch list in `\"@patch\"`. The patch must be less than or equal to the length of the list.\n\n```\n{ \"@op\" : \"PatchList\",\n \"@patch\" : Patch,\n \"@rest\" : Diff }\n```\n\n#### Example:\n\n```\nvar Patch =\n{ '@id' : \"TaskList/my_tasks\",\n 'tasks' : { '@op' : \"CopyList\", % Replace List\n '@to' : 2,\n '@rest' : { '@op' : \"PatchList\",\n '@patch' : [{ '@op' : \"SwapValue\",\n '@before' : \"Task/shopping\",\n '@after' : \"Task/climbing\"},\n { '@op' : \"SwapValue\",\n '@before' : \"Task/cleaning\",\n '@after' : \"Task/dining\"},\n { '@op' : \"SwapValue\",\n '@before' : \"Task/fishing\",\n '@after' : \"Task/travelling\"}],\n '@rest' : { '@op' : \"KeepList\" } } }}\nvar Before =\n{ '@id' : \"TaskList/my_tasks\",\n 'tasks' : [\"Task/driving\", \"Task/reading\", \"Task/shopping\",\n \"Task/cleaning\",\"Task/fishing\", \"Task/arguing\"] }\nvar After =\n{ '@id' : \"TaskList/my_tasks\",\n 'tasks' : [\"Task/driving\", \"Task/reading\", \"Task/climbing\",\n \"Task/dining\", \"Task/travelling\", \"Task/arguing\"] }\n```\n\n### Array Diff\n\nArrays will allow index swapping or \"shrink\" and \"grow\".\n\n### Force Diff\n\nA \"Force Diff\" will set the value of a location regardless of the current read-state. This is a potentially unsafe operation as there is no guarantee we are seeing the object state version we think we are.\n\n```\n{ '@id' : \"Employee/012\" ,\n 'name' : { '@op' : 'ForceValue',\n '@after' : \"Jake\" }}\n```\n\n### Table Diff\n\nA Table diff specifies the differences and similarities between the two tables. These tables _need not_ have the same dimensions. In order to describe these differences, we use a `ModifyTable` patch. The `ModifyTable` patch is comprised of `copies`, `deletes`, `inserts` and `moves`.\n\n`copies` give the sections of the table which can be copied verbatim. `deletes` gives all segments which are to be removed from the original. `inserts` gives all segments which are to be inserted into the new table.\n\n`moves` specifies segments that are the same in both tables, but have moved location. This is particularly useful as moving rows and columns is a typical operation in a table (such as a CSV or Excel document).\n\n#### Example Table\n\nGiven the following table:\n\n```\n[['Job Title','Company','Location','Company Size','Company Industry'],\n ['Sr. Mgt.','Boeing','USA','Large','Aerospace'],\n ['Data Architect','Airbus','France','Large','Aerospace'],\n ['Founder','Ellie Tech','Sweden','Startup','AI'],\n ['Platform Engineer','Adidas','Germany','Large','Apparel']]\n```\n\nAnd a sorted version of the same (sorting on the first column):\n\n```\n[['Job Title','Company','Location','Company Size','Company Industry'],\n ['Data Architect','Airbus','France','Large','Aerospace'],\n ['Founder','Ellie Tech','Sweden','Startup','AI'],\n ['Platform Engineer','Adidas','Germany','Large','Apparel'],\n ['Sr. Mgt.','Boeing','USA','Large','Aerospace']]\n```\n\nWe have the following patch resulting from the diff:\n\n```\n{'@op':\"ModifyTable\",\n dimensions:{'@after':[5,5],'@before':[5,5]},\n deletes:[],\n inserts:[],\n copies:[{'@at':{'@height':1,'@width':5,'@x':0,'@y':0},'@value':[['Job Title','Company','Location','Company Size','Company Industry']]}],\n moves:[{'@from':{'@height':1,'@width':5,'@x':0,'@y':1},\n '@to':{'@height':1,'@width':5,'@x':0,'@y':4},\n '@value':[['Sr. Mgt.','Boeing','USA','Large','Aerospace']]},\n {'@from':{'@height':1,'@width':5,'@x':0,'@y':2},\n '@to':{'@height':1,'@width':5,'@x':0,'@y':1},\n '@value':[['Data Architect','Airbus','France','Large','Aerospace']]},\n {'@from':{'@height':1,'@width':5,'@x':0,'@y':3},\n '@to':{'@height':1,'@width':5,'@x':0,'@y':2},\n '@value':[['Founder','Ellie Tech','Sweden','Startup','AI']]},\n {'@from':{'@height':1,'@width':5,'@x':0,'@y':4},\n '@to':{'@height':1,'@width':5,'@x':0,'@y':3},\n '@value':[['Platform Engineer','Adidas','Germany','Large','Apparel']]}]}\n```\n\n## Diff and Patch Endpoints\n\nThe Patch and Diff endpoints expose endpoints to obtain diffs or patches of data. Use our public endpoint for each operation:\n\n**JSON Diff**\n\n```\nhttps://cloud.terminusdb.com/jsondiff\n```\n\n**JSON Patch**\n\n```\nhttps://cloud.terminusdb.com/jsonpatch\n```\n\n### Diff\n\nThe diff endpoint takes a POST of two JSON documents, _before_, and _after_. This endpoint then returns a 200 and a patch which takes _before_ to _after_ if applied using the patch interface.\n\nThe payload is structured as a JSON document with one of the following forms:\n\n* With `\"before\"` and `\"after\"`, pointing to the documents you would like to diff.\n* With `\"before_data_version\"`, `\"after\"` and `\"document_id\"`, specifying the data version or commit ID with which to compare the given _after_ document.\n* With `\"before_data_version\"`, `\"after_data_version\"` and `\"document_id\"` specifying the data version or commit ID with which to compare the document given by `\"document_id\"`\n* With `\"before_data_version\"`, `\"after_data_version\"`, meaning that we would like to get a diff for _all_ documents between the two specified data versions.\n\nThere are also two options:\n\n* `keep`: A dictionary which has keys which need to be copied\n* `copy_value`: Which specifies that we should make _explicit_ which values existed during a list copy.\n\nAn example of the payload:\n\n```\n{ \"before\" : { \"@id\" : \"Person/Jane\", \"@type\" : \"Person\", \"name\" : \"Jane\"},\n \"after\" : { \"@id\" : \"Person/Jane\", \"@type\" : \"Person\", \"name\" : \"Janine\"}}\n```\n\nWhich would result in the following patch:\n\n```\n{ \"name\" : { \"@op\" : \"SwapValue\", \"@before\" : \"Jane\", \"@after\": \"Janine\" }}\n```\n\nAn example of a payload comparing commits or dataversions:\n\n```\n{ \"before_data_version\" : \"branch:s7dde27gyj8ezat3itw5nr3peu1lymh\"\n \"document_id\" : \"terminusdb:///data/test/665df8a9c3a58be6db622be4b37a76bea46c3e5e3cd2db923e708e574d1566be\",\n \"after\" : { \"@id\" : \"Person/Jane\", \"@type\" : \"Person\", \"name\" : \"Janine\"}}\n```\n\nAn example of a payload comparing only dataversions:\n\n```\n{ \"before_data_version\" : \"branch:s7dde27gyj8ezat3itw5nr3peu1lymh\"\n \"after_data_version\" : \"branch:jb81rgx9lzow35r3pkrsvdf5l75kaq\"\n \"document_id\" : \"terminusdb:///data/test/665df8a9c3a58be6db622be4b37a76bea46c3e5e3cd2db923e708e574d1566be\"}\n```\n\n#### Diff examples using curl\n\n```\n$ curl -X POST -H \"Content-Type: application/json\" 'https://cloud.terminusdb.com/jsondiff' -d \\\n '{ \"before\" : { \"asdf\" : \"foo\", \"fdsa\" : \"bar\"}, \"after\" : { \"asdf\" : \"bar\", \"fdsa\" : \"bar\"}, \"keep\" : { \"fdsa\" : true}}'\n# Output: {\n \"asdf\": {\"@after\":\"bar\", \"@before\":\"foo\", \"@op\":\"SwapValue\"},\n \"fdsa\":\"bar\"\n}\n```\n\n```\n$ curl -X POST -H \"Content-Type: application/json\" 'https://cloud.terminusdb.com/jsondiff' -d \\\n '{ \"before\" : [{ \"asdf\" : \"foo\"}], \"after\" : [{ \"asdf\" : \"bar\"}]}'\n# Output: [ {\"asdf\": {\"@after\":\"bar\", \"@before\":\"foo\", \"@op\":\"SwapValue\"}} ]\n```\n\n```\n$ curl -X POST -H \"Content-Type: application/json\" 'https://cloud.terminusdb.com/jsondiff' -d \\\n '{ \"before\" : [0,1,2], \"after\" : [0,1,2,3]}'\n\n# Output:\n{\n \"@op\":\"CopyList\",\n \"@rest\": {\n \"@after\": [3 ],\n \"@before\": [],\n \"@op\":\"SwapList\",\n \"@rest\": {\"@op\":\"KeepList\"}\n },\n \"@to\":3\n}\n```\n\n```\n$ curl -X POST -H \"Content-Type: application/json\" 'https://cloud.terminusdb.com/jsondiff' -d \\\n '{ \"before\" : [0,1,2], \"after\" : [0,1,2,3], \"copy_value\" : true}'\n\n# Output:\n{\n \"@op\":\"CopyList\",\n \"@rest\": {\n \"@after\": [3 ],\n \"@before\": [],\n \"@op\":\"SwapList\",\n \"@rest\": {\"@op\":\"KeepList\", \"@value\": []}\n },\n \"@to\":3,\n \"@value\": [0, 1, 2 ]\n}\n```\n\n```\n$ curl -X POST -H \"Content-Type: application/json\" 'https://cloud.terminusdb.com/jsondiff' -d \\\n '{ \"before\" : { \"asdf\" : { \"fdsa\" : \"quux\"}}, \"after\" : { \"asdf\" : { \"fdsa\" : \"quuz\" }}}'\n\n# Output:\n{\n \"asdf\": {\"fdsa\": {\"@after\":\"quuz\", \"@before\":\"quux\", \"@op\":\"SwapValue\"}}\n}\n```\n\n### Patch\n\nPatch takes a POST with a _before_ document and a _patch_ and produces an _after_ document.\n\n```\n{ \"before\" : { \"@id\" : \"Person/Jane\", \"@type\" : \"Person\", \"name\" : \"Jane\"}\n \"patch\" : {\"name\" : { \"@op\" : \"ValueSwap\", \"@before\" : \"Jane\", \"@after\": \"Janine\" }}}\n```\n\nResulting in the following document:\n\n```\n{ \"@id\" : \"Person/Jane\", \"@type\" : \"Person\", \"name\" : \"Janine\"}\n```\n\n#### Patch examples using curl\n\n```\n$ curl -X POST -H \"Content-Type: application/json\" 'https://cloud.terminusdb.com/jsonpatch' -d \\\n '{ \"before\" : { \"alpha\" : 1, \"asdf\" : { \"fdsa\" : \"quux\"}}, \"patch\" : {\n \"asdf\": {\"fdsa\": {\"@after\":\"quuz\", \"@before\":\"quux\", \"@op\":\"SwapValue\"}}\n}}'\n# Output: {\"alpha\":1, \"asdf\": {\"fdsa\":\"quuz\"}}\n```\n\n```\n$ curl -X POST -H \"Content-Type: application/json\" 'https://cloud.terminusdb.com/jsonpatch' -d '\n{ \"before\" : [0,1,2], \"patch\" : {\n \"@op\":\"CopyList\",\n \"@rest\": {\n \"@after\": [3 ],\n \"@before\": [],\n \"@op\":\"SwapList\",\n \"@rest\": {\"@op\":\"KeepList\"}\n },\n \"@to\":3\n}}'\n#Output: [0, 1, 2, 3 ]\n```\n\n## Further Reading\n\nJavaScript client [diff](/docs/javascript/#getjsondiffbeforeafteroptions) and [patch](/docs/javascript/#patchbeforepatch).\n\nPython client [diff](/docs/python/#diff) and [patch](/docs/python/#patchbeforepatch)." + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "JSON Diff and Patch with TerminusCMS and TerminusDB", + "description": "JSON Diff and Patch reference guide to compare JSON documents.", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "TerminusCMS Path Query Reference Guide" + }, + "slug": "path-query-reference-guide", + "body": { + "@type": "Body", + "value": "TerminusDB & TerminusCMS allows _path regular expressions_ as a way to describe multi-hop searches in a concise fashion. When you need to follow a link repeatedly for shortest path queries or to find all linked documents meeting some specification you can often use a _path query_.\n\n> For guidance on back-links and path queries using GraphQL visit the [GraphQL reference guide](/docs/graphql-query-reference/#backlinks)\n\nThe syntax of path expressions, for expressions `A`, `B` and fields `F` is as follows:\n\nExpression\n\nExample\n\nName\n\nDescription\n\n`A,B`\n\n`friend,name`\n\nSequence\n\nFirst follow expression `A`, then from that node expression `B`\n\n`A|B`\n\n`friend|foe`\n\nChoice\n\nFollow expression `A` or expression `B`\n\n`F+`\n\n`friend+`\n\nPlus\n\nFollow the field `F` any number of times, but at least once\n\n`F*`\n\n`friend*`\n\nStar\n\nFollow the field `F` any number of times, including zero\n\n`.`\n\n`.`\n\nAny\n\nFollow any field `F` regardless of name\n\n`F`\n\n`friend`\n\nField\n\nFollow the field `F`\n\n`F{n,m}`\n\n`friend{1,3}`\n\nTimes\n\nFollow the field `F` between `n` and `m` times\n\n`(A)`\n\n`(friend|foe)`\n\nGroup\n\nGroup the expression for inclusion in a larger expression\n\n`F>`\n\n`friend>`\n\nForward\n\nFollow the field `F` forward. This is the same as `F`.\n\n` }\n```\n\nAn example of the operation would be:\n\n```\n{ \"@type\" : \"DeleteClass\",\n \"class\" : \"Person\" }\n```\n\nWhich would take the schema:\n\n```\n{ \"@id\" : \"Dog\",\n \"@type\" : \"Class\",\n \"name\" : \"xsd:string\"}\n{ \"@id\" : \"Person\",\n \"@type\" : \"Class\",\n \"name\" : \"xsd:string\" }\n```\n\nto:\n\n```\n{ \"@id\" : \"Dog\",\n \"@type\" : \"Class\",\n \"name\" : \"xsd:string\"}\n```\n\n## CreateClass\n\nThe `CreateClass` operation specifies the entire class to be created. This operation is always a _weakening_ operation.\n\n```\n{ \"@type\" : \"CreateClass\",\n \"class_document\" : }\n```\n\n### Example\n\nThe migration:\n\n```\n{ \"@type\" : \"CreateClass\",\n \"class_document\" :\n { \"@id\" : \"Person\",\n \"@type\" : \"Class\",\n \"name\" : \"xsd:string\" } }\n```\n\nWould take the schema:\n\n```\n{ \"@id\" : \"Dog\",\n \"@type\" : \"Class\",\n \"name\" : \"xsd:string\" }\n```\n\nto:\n\n```\n{ \"@id\" : \"Dog\",\n \"@type\" : \"Class\",\n \"name\" : \"xsd:string\"}\n{ \"@id\" : \"Person\",\n \"@type\" : \"Class\",\n \"name\" : \"xsd:string\" }\n```\n\n## MoveClass\n\nThe `MoveClass` operation renames a class and all of the URIs of instance data associated with that class. Due to the side-effects on instance data, this is not a _weakening_ operation.\n\n```\n{ \"@type\" : \"MoveClass\",\n \"from\" : ,\n \"to\" : }\n```\n\n### Example\n\n```\n{ \"@type\" : \"MoveClass\",\n \"from\" : \"Person\",\n \"to\" : \"Dog\" }\n```\n\nWould take the schema:\n\n```\n{ \"@id\" : \"Person\",\n \"@type\" : \"Class\",\n \"name\" : \"xsd:string\"}\n```\n\nto:\n\n```\n{ \"@id\" : \"Dog\",\n \"@type\" : \"Class\",\n \"name\" : \"xsd:string\"}\n```\n\n## ReplaceClassMetadata\n\nThe `ReplaceClassMetadata` operation replaces the metadata on a class (if it exists). This operation is always a _weakening_ operation and has no effect on instance data.\n\n```\n{ \"@type\" : \"ReplaceClassMetadata\",\n \"class\" : \n \"metadata\" : }\n```\n\n### Example\n\nThe operation:\n\n```\n{ \"@type\" : \"ReplaceClassMetadata\",\n \"class\" : \"Person\",\n \"metadata\" : { \"ui_preferences\" : { \"colour\" : \"blue\" } } }\n```\n\nWould take the schema:\n\n```\n{ \"@id\" : \"Person\",\n \"@type\" : \"Class\",\n \"@metadata\" : { \"ui_preferences\" : { \"colour\" : \"red\" } },\n \"name\" : \"xsd:string\"}\n```\n\nto:\n\n```\n{ \"@id\" : \"Dog\",\n \"@type\" : \"Class\",\n \"@metadata\" : { \"ui_preferences\" : { \"colour\" : \"blue\" } },\n \"name\" : \"xsd:string\" }\n```\n\n## ReplaceClassDocumentation\n\nThe `ReplaceClassDocumentation` operation replaces the documentation on a class (if it exists). This operation is always a _weakening_ operation and has no effect on instance data.\n\n```\n{ \"@type\" : \"ReplaceClassDocumentation\",\n \"class\" : \n \"documentation\" : }\n```\n\n### Example\n\nThe operation:\n\n```\n{ \"@type\" : \"ReplaceClassDocumentation\",\n \"class\" : \"Person\",\n \"documentation\" : { \"@comment\" : \"This is a person class\",\n \"@properties\" : { \"name\" : { \"@comment\" : \"The name of a person\",\n \"@label\" : \"name\" } },\n \"@label\" : \"Person\" } }\n```\n\nWould take the schema:\n\n```\n{ \"@id\" : \"Person\",\n \"@type\" : \"Class\",\n \"@documentation\" : { \"@comment\" : \"A Person\",\n \"@properties\" : { \"name\" : { \"@comment\" : \"Name of a person\",\n \"@label\" : \"name\" } },\n \"@label\" : \"Person\" },\n \"name\" : \"xsd:string\"}\n```\n\nto:\n\n```\n{ \"@id\" : \"Person\",\n \"@type\" : \"Class\",\n \"@documentation\" : { \"@comment\" : \"This is a person class\",\n \"@properties\" : { \"name\" : { \"@comment\" : \"The name of a person\",\n \"@label\" : \"name\" } },\n \"@label\" : \"Person\" },\n \"name\" : \"xsd:string\"}\n```\n\n## ReplaceContext\n\nThe `ReplaceContext` operation will update the context object, which will change how URIs are compressed when returning data.\n\nThis operation is a _weakening_ operation only when prefixes other than `@base` and `@schema` are changed. Otherwise, all data in the database will be moved to the new `@base` and `@schema` designations.\n\n```\n{ \"@type\" : \"ReplaceContext\",\n \"context\" : }\n```\n\n## ExpandEnum\n\nThe `ExpandEnum` operation will allow new fields to be added to an `Enum`. This operation is always a weakening operation.\n\n```\n{ \"@type\" : \"ExpandEnum\",\n \"enum\" : ,\n \"values\" : [, ... ] }\n```\n\n### Example\n\nThe command\n\n```\n{ \"@type\" : \"ReplaceContext\",\n \"context\" : { \"@type\" : \"@context\",\n \"@base\" : \"iri://terminusdb.com/data\",\n \"@schema\" : \"iri://terminusdb.com/schema#\" } }\n```\n\nWill take a schema:\n\n```\n{ \"@type\" : \"@context\",\n \"@base\" : \"http://example.com/data\",\n \"@schema\" : \"http://example.com/schema#\" }\n{ \"@id\" : \"Person\",\n \"@type\" : \"Class\",\n \"name\" : \"xsd:string\"}\n```\n\nTo the schema:\n\n```\n{ \"@type\" : \"@context\",\n \"@base\" : \"iri://terminusdb.com/data\",\n \"@schema\" : \"iri://terminusdb.com/schema#\" }\n{ \"@id\" : \"Person\",\n \"@type\" : \"Class\",\n \"name\" : \"xsd:string\"}\n```\n\n## DeleteClassProperty\n\nThe `DeleteClassProperty` command removes a property from the schema and deletes all associated data points in the instance graph. This is not a _weakening_ operation.\n\n```\n{ \"@type\" : \"DeleteClassProperty\",\n \"class\" : \n \"property\" : }\n```\n\n## CreateClassProperty\n\nThe `CreateClassProperty` command creates a new property of a given name and type. It is a weakening operation only if the type is within a type family which includes:\n\n* Cardinality including zero\n* A Set\n* An Optional\n* An Array\n\nNotably this excludes lists and required properties. With lists it will require the addition of the empty list resulting in a _strengthening_. The operation is impossible with a required property unless a default is specified.\n\n```\n{ \"@type\" : \"CreateClassProperty\",\n \"class\" : ,\n \"property\" : ,\n \"type\" : }\n```\n\nOr\n\n```\n{ \"@type\" : \"CreateClassProperty\",\n \"class\" : ,\n \"property\" : ,\n \"type\" : ,\n \"default\" : }\n```\n\n## MoveClassProperty\n\nThe `MoveClassProperty` command will move the name of a property from one name to another.\n\n```\n{ \"@type\" : \"MoveClassProperty\",\n \"class\" : ,\n \"from\" : ,\n \"to\" : }\n```\n\nThis operation is never a weakening.\n\n## UpcastClassProperty\n\nThe `UpcastClassProperty` command will weaken a type to another type which is a supertype or inclusive type family (such as moving a required or Optional to Set).\n\nThis operation is always a weakening.\n\n```\n{ \"@type\" : \"UpcastClassProperty\",\n \"class\" : \n \"property\" : ,\n \"type\" : }\n```\n\n## CastClassProperty\n\nThe `CastClassProperty` command will attempt to cast a property type to another type (such as a string to a date). This operation is never a weakening operation as it requires changing the type layout of data.\n\n```\n{ \"@type\" : \"CastClassProperty\",\n \"class\" : \n \"property\" : ,\n \"type\" : ,\n \"default\" : }\n```\n\nThe \\`DefaultOrError document is of the form:\n\n```\n{ \"@type\" : \"Error\" }\n```\n\nWhich will result in an error if casting is impossible, or:\n\n```\n{ \"@type\" : \"Default\",\n \"value\" : }\n```\n\nWhere `Value` is the value within type `TypeSpecification` which will be used if casting is impossible.\n\n## ChangeKey (unimplemented)\n\n## ChangeParents (unimplemented)\n\n## ChangeCollection (unimplemented)" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Schema Migration Reference Guide", + "description": "A reference guide explaining the schema migration capabilities of TerminusCMS and TerminusDB", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "WOQL Class Reference Guide" + }, + "slug": "woql-class-reference-guide", + "body": { + "@type": "Body", + "value": "## WOQL Schema\n\nThis is the WOQL schema. It gives a complete specification of the syntax of the WOQL query language. This allows WOQL queries to be checked for syntactic correctness, helps to prevent errors and detect conflicts in merge of queries, and allows the storage and retrieval of queries so that queries can be associated with data products.\n\n**Authored by:** Gavin Mendel-Gleason\n\n> Syntax is listed in alphabetical order.\n\n#### AddData\n\nAdd a (terminal) edge with a data value.\n\n**Class:** `AddData`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`subject`\n\n`NodeValue`\n\nA URI or variable which is the source or subject of the graph edge.\n\n`predicate`\n\n`NodeValue`\n\nA URI or variable which is the edge-label or predicate of the graph edge.\n\n`object`\n\n`DataValue`\n\nA datatype or variable which is the target or object of the graph edge.\n\n`graph`\n\n`xsd:string`\n\nAn optional graph (either 'instance' or 'schema')\n\n* * *\n\n#### AddLink\n\nAdd an edge which links between nodes in the graph.\n\n**Class:** `AddLink`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`subject`\n\n`NodeValue`\n\nA URI or variable which is the source or subject of the graph edge.\n\n`predicate`\n\n`NodeValue`\n\nA URI or variable which is the edge-label or predicate of the graph edge.\n\n`object`\n\n`NodeValue`\n\nA URI or variable which is the target or object of the graph edge.\n\n`graph`\n\n`xsd:string`\n\nAn optional graph (either 'instance' or 'schema')\n\n* * *\n\n#### AddTriple\n\nSpecify an edge to add to the graph.\n\n**Class:** `AddTriple`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`subject`\n\n`NodeValue`\n\nA URI or variable which is the source or subject of the graph edge.\n\n`predicate`\n\n`NodeValue`\n\nA URI or variable which is the edge-label or predicate of the graph edge.\n\n`object`\n\n`Value`\n\nA URI, datatype or variable which is the target or object of the graph edge.\n\n`graph`\n\n`xsd:string`\n\nAn optional graph (either 'instance' or 'schema')\n\n* * *\n\n#### AddedData\n\nSpecify an edge pattern with data value which was added in \\*this\\* commit\\*.\n\n**Class:** `AddedData`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`subject`\n\n`NodeValue`\n\nA URI or variable which is the source or subject of the graph edge.\n\n`predicate`\n\n`NodeValue`\n\nA URI or variable which is the edge-label or predicate of the graph edge.\n\n`object`\n\n`DataValue`\n\nA datatype or variable which is the target or object of the graph edge.\n\n`graph`\n\n`xsd:string`\n\nAn optional graph (either 'instance' or 'schema')\n\n* * *\n\n#### AddedLink\n\nSpecify an edge pattern which links between nodes at \\*this\\* commit.\n\n**Class:** `AddedLink`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`subject`\n\n`NodeValue`\n\nA URI or variable which is the source or subject of the graph edge.\n\n`predicate`\n\n`NodeValue`\n\nA URI or variable which is the edge-label or predicate of the graph edge.\n\n`object`\n\n`NodeValue`\n\nA URI or variable which is the target or object of the graph edge.\n\n`graph`\n\n`xsd:string`\n\nAn optional graph (either 'instance' or 'schema')\n\n* * *\n\n#### AddedTriple\n\nSpecify an edge pattern which was \\*added\\* at \\*this commit\\*.\n\n**Class:** `AddedTriple`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`subject`\n\n`NodeValue`\n\nA URI or variable which is the source or subject of the graph edge.\n\n`predicate`\n\n`NodeValue`\n\nA URI or variable which is the edge-label or predicate of the graph edge.\n\n`object`\n\n`Value`\n\nA URI, datatype or variable which is the target or object of the graph edge.\n\n`graph`\n\n`xsd:string`\n\nAn optional graph (either 'instance' or 'schema')\n\n* * *\n\n#### And\n\nA conjunction of queries which must all have a solution.\n\n**Class:** `And`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`and`\n\n`Query`\n\nList of queries which must hold.\n\n* * *\n\n#### ArithmeticExpression\n\nAn abstract class specifying the AST super-class of all arithemtic expressions. It is a subdocument\n\n**Class:** `ArithmeticExpression`\n\n* * *\n\n#### ArithmeticValue\n\nA variable or node. It is a subdocument\n\n**Class:** `ArithmeticValue`\n\n**Super class:** `ArithmeticExpression`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`data`\n\n`xsd:anySimpleType`\n\nAn xsd data type value.\n\n`variable`\n\n`xsd:string`\n\nA variable.\n\n* * *\n\n#### Column\n\nDescription pending.\n\n**Class:** `Column`\n\n* * *\n\n#### Concatenate\n\nConcatenate a list of strings.\n\n**Class:** `Concatenate`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`list`\n\n`DataValue`\n\nThe list to concatenate.\n\n`result`\n\n`DataValue`\n\nThe result string.\n\n* * *\n\n#### Count\n\nCounts the number of solutions of a query.\n\n**Class:** `Count`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`query`\n\n`Query`\n\nThe query from which to obtain the count.\n\n`count`\n\n`DataValue`\n\nThe count of the number of solutions.\n\n* * *\n\n#### Data\n\nSpecify an edge pattern which is terminal, and provides a data value association.\n\n**Class:** `Data`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`subject`\n\n`NodeValue`\n\nA URI or variable which is the source or subject of the graph edge.\n\n`predicate`\n\n`NodeValue`\n\nA URI or variable which is the edge-label or predicate of the graph edge.\n\n`object`\n\n`DataValue`\n\nA data type or variable which is the target or object of the graph edge.\n\n`graph`\n\n`xsd:string`\n\nAn optional graph (either 'instance' or 'schema')\n\n* * *\n\n#### DataValue\n\nA variable or node. It is a subdocument\n\n**Class:** `DataValue`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`data`\n\n`xsd:anySimpleType`\n\nAn xsd data type value.\n\n`variable`\n\n`xsd:string`\n\nA variable.\n\n`list`\n\n`DataValue`\n\nA list of datavalues\n\n* * *\n\n#### DeleteDocument\n\nDelete a document from the graph.\n\n**Class:** `DeleteDocument`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`identifier`\n\n`NodeValue`\n\nAn identifier specifying the documentation location to delete.\n\n* * *\n\n#### DeleteLink\n\nDelete an edge linking nodes.\n\n**Class:** `DeleteLink`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`subject`\n\n`NodeValue`\n\nA URI or variable which is the source or subject of the graph edge. The variable must be bound.\n\n`predicate`\n\n`NodeValue`\n\nA URI or variable which is the edge-label or predicate of the graph edge. The variable must be bound.\n\n`object`\n\n`NodeValue`\n\nA URI or variable which is the target or object of the graph edge. The variable must be bound.\n\n`graph`\n\n`xsd:string`\n\nAn optional graph (either 'instance' or 'schema')\n\n* * *\n\n#### DeleteTriple\n\nSpecify an edge pattern to remove from the graph.\n\n**Class:** `DeleteTriple`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`subject`\n\n`NodeValue`\n\nA URI or variable which is the source or subject of the graph edge.\n\n`predicate`\n\n`NodeValue`\n\nA URI or variable which is the edge-label or predicate of the graph edge.\n\n`object`\n\n`Value`\n\nA URI, datatype or variable which is the target or object of the graph edge.\n\n`graph`\n\n`xsd:string`\n\nAn optional graph (either 'instance' or 'schema')\n\n* * *\n\n#### DeletedLink\n\nAn edge pattern specifying a link beween nodes deleted \\*at this commit\\*.\n\n**Class:** `DeletedLink`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`subject`\n\n`NodeValue`\n\nA URI or variable which is the source or subject of the graph edge.\n\n`predicate`\n\n`NodeValue`\n\nA URI or variable which is the edge-label or predicate of the graph edge.\n\n`object`\n\n`NodeValue`\n\nA URI or variable which is the target or object of the graph edge.\n\n`graph`\n\n`xsd:string`\n\nAn optional graph (either 'instance' or 'schema')\n\n* * *\n\n#### DeletedTriple\n\nSpecify an edge pattern which was \\*deleted\\* at \\*this commit\\*.\n\n**Class:** `DeletedTriple`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`subject`\n\n`NodeValue`\n\nA URI or variable which is the source or subject of the graph edge.\n\n`predicate`\n\n`NodeValue`\n\nA URI or variable which is the edge-label or predicate of the graph edge.\n\n`object`\n\n`Value`\n\nA URI, datatype or variable which is the target or object of the graph edge.\n\n`graph`\n\n`xsd:string`\n\nAn optional graph (either 'instance' or 'schema')\n\n* * *\n\n#### Distinct\n\nEnsure variables listed result in distinct solutions.\n\n**Class:** `Distinct`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`variables`\n\n`xsd:string`\n\nThe variables which must be distinct from the query.\n\n`query`\n\n`Query`\n\nThe query which will be run prior to selection.\n\n* * *\n\n#### Div\n\nInteger divide two numbers.\n\n**Class:** `Div`\n\n**Super class:** `ArithmeticExpression`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`left`\n\n`ArithmeticExpression`\n\nFirst operand of div.\n\n`right`\n\n`ArithmeticExpression`\n\nSecond operand of div.\n\n* * *\n\n#### Divide\n\nDivide two numbers.\n\n**Class:** `Divide`\n\n**Super class:** `ArithmeticExpression`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`left`\n\n`ArithmeticExpression`\n\nFirst operand of divide.\n\n`right`\n\n`ArithmeticExpression`\n\nSecond operand of divide.\n\n* * *\n\n#### Dot\n\nExtract the value of a key in a bound document.\n\n**Class:** `Dot`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`star`\n\n`undefined`\n\nA path patterns.\n\n* * *\n\n#### Equals\n\nTrue whenever 'left' is the same as 'right'. Performs unification.\n\n**Class:** `Equals`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`child`\n\n`undefined`\n\nA URI, data value or variable.\n\n`parent`\n\n`undefined`\n\nA URI, data value or variable.\n\n* * *\n\n#### Eval\n\nEvaluate an arithmetic expression to obtain a result.\n\n**Class:** `Eval`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`expression`\n\n`ArithmeticExpression`\n\nThe expression to be evaluated.\n\n`result`\n\n`ArithmeticValue`\n\nThe numeric result.\n\n* * *\n\n#### Exp\n\nExponentiate a number.\n\n**Class:** `Exp`\n\n**Super class:** `ArithmeticExpression`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`left`\n\n`ArithmeticExpression`\n\nThe base.\n\n`right`\n\n`ArithmeticExpression`\n\nThe exponent.\n\n* * *\n\n#### Floor\n\nFind the integral part of a number.\n\n**Class:** `Floor`\n\n**Super class:** `ArithmeticExpression`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`argument`\n\n`ArithmeticExpression`\n\nThe number to floor.\n\n* * *\n\n#### FormatType\n\nDescription pending.\n\n**Class:** `FormatType`\n\n* * *\n\n#### From\n\nChange the default read graph (between instance/schema).\n\n**Class:** `From`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`query`\n\n`Query`\n\nThe subquery with a new default graph.\n\n`graph_filter`\n\n`xsd:string`\n\nThe graph filter: 'schema' or 'instance' or '\\*'.\n\n* * *\n\n#### Get\n\nDescription pending.\n\n**Class:** `Get`\n\n**Super class:** `Query`\n\n* * *\n\n#### Greater\n\nPredicate determining if one thing is greater than another according to natural ordering.\n\n**Class:** `Greater`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`left`\n\n`DataValue`\n\nThe greater element.\n\n`right`\n\n`DataValue`\n\nThe lesser element.\n\n* * *\n\n#### GroupBy\n\nGroup a query into a list with each element of the list specified by 'template' using a given variable set for the group.\n\n**Class:** `GroupBy`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`template`\n\n`xsd:string`\n\nThe template of elements in the result list.\n\n`group_by`\n\n`xsd:string`\n\nThe variables which should be grouped into like solutions.\n\n`query`\n\n`Query`\n\nThe subquery providing the solutions for the grouping.\n\n`grouped`\n\n`Value`\n\nThe final list of templated solutions.\n\n* * *\n\n#### HashKey\n\nGenerates a key identical to those generated automatically by 'HashKey' specifications.\n\n**Class:** `HashKey`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`base`\n\n`DataValue`\n\nThe URI base to the left of the key.\n\n`key_list`\n\n`DataValue`\n\nList of data elements required to generate the key.\n\n`uri`\n\n`NodeValue`\n\nThe resulting URI.\n\n* * *\n\n#### If\n\nA conditional which runs the then clause for every success from the test clause, otherwise runs the else clause.\n\n**Class:** `If`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`test`\n\n`Query`\n\nA query which will provide bindings for the then clause.\n\n`then`\n\n`Query`\n\nA query which will run for every solution of test with associated bindings.\n\n`else`\n\n`Query`\n\nA query which runs whenever test fails.\n\n* * *\n\n#### Immediately\n\nAttempts to perform all side-effecting operations immediately. Can have strange non-backtracking effects but can also increase performance. Use at your own risk.\n\n**Class:** `Immediately`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`query`\n\n`Query`\n\nThe query from which to obtain the side-effects.\n\n* * *\n\n#### Indicator\n\nDescription pending.\n\n**Class:** `Indicator`\n\n* * *\n\n#### Into\n\nChange the default write graph (between instance/schema).\n\n**Class:** `Into`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`query`\n\n`Query`\n\nThe subquery with a new default write graph.\n\n`graph`\n\n`xsd:string`\n\nThe graph filter: schema or instance.\n\n* * *\n\n#### InversePathPredicate\n\nA predicate to traverse \\*backwards\\*.\n\n**Class:** `InversePathPredicate`\n\n**Super class:** `PathPattern`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`predicate`\n\n`xsd:string`\n\nThe predicate to use in reverse direction in the pattern traversal.\n\n* * *\n\n#### IsA\n\nTest (or generate) the type of an element.\n\n**Class:** `IsA`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`element`\n\n`NodeValue`\n\nThe element to test.\n\n`type`\n\n`NodeValue`\n\nThe type of the element.\n\n* * *\n\n#### Join\n\nJoin a list of strings using 'separator'.\n\n**Class:** `Join`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`list`\n\n`DataValue`\n\nThe list to concatenate.\n\n`separator`\n\n`DataValue`\n\nThe separator between each joined string\n\n`result`\n\n`DataValue`\n\nThe result string.\n\n* * *\n\n#### Length\n\nThe length of a list.\n\n**Class:** `Length`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`list`\n\n`DataValue`\n\nThe list of which to find the length.\n\n`length`\n\n`DataValue`\n\nThe length of the list.\n\n* * *\n\n#### Less\n\nPredicate determining if one thing is less than another according to natural ordering.\n\n**Class:** `Less`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`left`\n\n`DataValue`\n\nThe lesser element.\n\n`right`\n\n`DataValue`\n\nThe greater element.\n\n* * *\n\n#### LexicalKey\n\nGenerates a key identical to those generated automatically by 'LexicalKey' specifications.\n\n**Class:** `LexicalKey`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`base`\n\n`DataValue`\n\nThe URI base to the left of the key.\n\n`key_list`\n\n`DataValue`\n\nList of data elements required to generate the key.\n\n`uri`\n\n`NodeValue`\n\nThe resulting URI.\n\n* * *\n\n#### Like\n\nDistance between strings, similar to a Levenstein distance.\n\n**Class:** `Like`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`left`\n\n`DataValue`\n\nThe first string.\n\n`right`\n\n`DataValue`\n\nThe second string.\n\n`similarity`\n\n`DataValue`\n\nNumber between -1 and 1 which gives a scale for similarity.\n\n* * *\n\n#### Limit\n\nLimit a query to a particular maximum number of solutions specified by 'limit'. Can be used with start to perform paging.\n\n**Class:** `Limit`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`query`\n\n`Query`\n\nThe query to perform.\n\n`limit`\n\n`xsd:nonNegativeInteger`\n\nMaximum number of solutions.\n\n* * *\n\n#### Link\n\nSpecify an edge pattern which is not terminal, but a link between objects.\n\n**Class:** `Link`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`subject`\n\n`NodeValue`\n\nA URI or variable which is the source or subject of the graph edge.\n\n`predicate`\n\n`NodeValue`\n\nA URI or variable which is the edge-label or predicate of the graph edge.\n\n`object`\n\n`NodeValue`\n\nA URI or variable which is the target or object of the graph edge.\n\n`graph`\n\n`xsd:string`\n\nAn optional graph (either 'instance' or 'schema')\n\n* * *\n\n#### Lower\n\nLowercase a string.\n\n**Class:** `Lower`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`mixed`\n\n`DataValue`\n\nThe mixed case string.\n\n`uppser`\n\n`undefined`\n\nThe lower case string.\n\n* * *\n\n#### Member\n\nGenerate or test every element of a list.\n\n**Class:** `Member`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`member`\n\n`DataValue`\n\nThe element to test for membership or to supply as generated.\n\n`list`\n\n`DataValue`\n\nThe list of elements against which to generate or test.\n\n* * *\n\n#### Minus\n\nSubtract two numbers.\n\n**Class:** `Minus`\n\n**Super class:** `ArithmeticExpression`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`left`\n\n`ArithmeticExpression`\n\nFirst operand of minus.\n\n`right`\n\n`ArithmeticExpression`\n\nSecond operand of minus.\n\n* * *\n\n#### NamedParametricQuery\n\nA named parametric query which names a specific query for later retrieval and re-use and allows the specification of bindings for a specific set of variables in the query.\n\n**Class:** `NamedParametricQuery`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`name`\n\n`xsd:string`\n\nThe name of the NamedParametricQuery to be retrieved.\n\n`parameters`\n\n`xsd:string`\n\nVariable name list for auxilliary bindings.\n\n`query`\n\n`Query`\n\nThe query AST as WOQL JSON.\n\n* * *\n\n#### NamedQuery\n\nA named query names a specific query for later retrieval and re-use.\n\n**Class:** `NamedQuery`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`name`\n\n`xsd:string`\n\nThe name of the NamedQuery to be retrieved\n\n`query`\n\n`Query`\n\nThe query AST as WOQL JSON\n\n* * *\n\n#### NodeValue\n\nA variable or node. It is a subdocument\n\n**Class:** `NodeValue`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`node`\n\n`xsd:string`\n\nA URI representing a resource.\n\n`variable`\n\n`xsd:string`\n\nA variable.\n\n* * *\n\n#### Not\n\nThe negation of a query. Provides no solution bindings, but will succeed if its sub-query fails.\n\n**Class:** `Not`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`query`\n\n`Query`\n\nThe query which must not hold.\n\n* * *\n\n#### Once\n\nObtains exactly one solution from a query. Simliar to a limit of 1.\n\n**Class:** `Once`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`query`\n\n`Query`\n\nThe query from which to obtain a solution.\n\n* * *\n\n#### Optional\n\nA query which will succeed (without bindings) even in the case of failure.\n\n**Class:** `Optional`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`query`\n\n`Query`\n\nThe query to run.\n\n* * *\n\n#### Or\n\nA disjunction of queries any of which can provide a solution.\n\n**Class:** `Or`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`or`\n\n`Query`\n\nList of queries which may hold.\n\n* * *\n\n#### Order\n\nDescription pending.\n\n**Class:** `Order`\n\n* * *\n\n#### OrderBy\n\nOrders query results according to an ordering specification.\n\n**Class:** `OrderBy`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`query`\n\n`Query`\n\nThe base query giving the solutions to order.\n\n`ordering`\n\n`OrderTemplate`\n\nA specification of the ordering of solutions.\n\n* * *\n\n#### OrderTemplate\n\nThe order template, consisting of the variable and ordering direction. It is a subdocument\n\n**Class:** `OrderTemplate`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`order`\n\n`Order`\n\nAn enum either 'asc' or 'desc'.\n\n`variable`\n\n`xsd:string`\n\nThe variable to order.\n\n* * *\n\n#### Pad\n\nPad a string.\n\n**Class:** `Pad`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`string`\n\n`DataValue`\n\nThe starting string.\n\n`char`\n\n`DataValue`\n\nThe padding character.\n\n`times`\n\n`DataValue`\n\nThe number of times to repeat the padding character.\n\n`result`\n\n`DataValue`\n\nThe result of the padding as a string.\n\n* * *\n\n#### Path\n\nFind a path through the graph according to 'pattern'. This 'pattern' is a regular graph expression which avoids cycles.\n\n**Class:** `Path`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`subject`\n\n`Value`\n\nThe starting node.\n\n`pattern`\n\n`PathPattern`\n\nThe pattern which describes how to traverse edges.\n\n`object`\n\n`Value`\n\nThe ending node.\n\n`path`\n\n`Value`\n\nAn optional list of edges traversed.\n\n* * *\n\n#### PathOr\n\nA set of patterns in which each of the patterns can result in objects starting from our current subject set.\n\n**Class:** `PathOr`\n\n**Super class:** `PathPattern`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`or`\n\n`PathPattern`\n\nA disjunction of path patterns.\n\n* * *\n\n#### PathPattern\n\nDescription pending.\n\n**Class:** `PathPattern`\n\n* * *\n\n#### PathPlus\n\nThe path pattern specified by 'plus' must hold one or more times in succession.\n\n**Class:** `PathPlus`\n\n**Super class:** `PathPattern`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`plus`\n\n`PathPattern`\n\nA path patterns.\n\n* * *\n\n#### PathPredicate\n\nA predicate to traverse.\n\n**Class:** `PathPredicate`\n\n**Super class:** `PathPattern`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`predicate`\n\n`xsd:string`\n\nThe predicate to use in the pattern traversal.\n\n* * *\n\n#### PathSequence\n\nA sequence of patterns in which each of the patterns in the list must result in objects which are subjects of the next pattern in the list.\n\n**Class:** `PathSequence`\n\n**Super class:** `PathPattern`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`sequence`\n\n`PathPattern`\n\nA sequence of path patterns.\n\n* * *\n\n#### PathStar\n\nThe path pattern specified by 'star' may hold zero or more times in succession.\n\n**Class:** `PathStar`\n\n**Super class:** `PathPattern`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`star`\n\n`PathPattern`\n\nA path patterns.\n\n* * *\n\n#### PathTimes\n\nThe path pattern specified by 'times' may hold 'from' to 'to' times in succession.\n\n**Class:** `PathTimes`\n\n**Super class:** `PathPattern`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`star`\n\n`undefined`\n\nA path patterns.\n\n* * *\n\n#### Plus\n\nAdd two numbers.\n\n**Class:** `Plus`\n\n**Super class:** `ArithmeticExpression`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`left`\n\n`ArithmeticExpression`\n\nFirst operand of add.\n\n`right`\n\n`ArithmeticExpression`\n\nSecond operand of add.\n\n* * *\n\n#### Put\n\nDescription pending.\n\n**Class:** `Put`\n\n**Super class:** `Query`\n\n* * *\n\n#### Query\n\nAn abstract class which represents an arbitrary query AST. It is a subdocument\n\n**Class:** `Query`\n\n* * *\n\n#### QueryResource\n\nDescription pending.\n\n**Class:** `QueryResource`\n\n* * *\n\n#### RandomKey\n\nGenerates a key identical to those generated automatically by 'RandomKey' specifications.\n\n**Class:** `RandomKey`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`base`\n\n`DataValue`\n\nThe URI base to the left of the key.\n\n`uri`\n\n`NodeValue`\n\nThe resulting URI.\n\n* * *\n\n#### ReadDocument\n\nRead a full document from an identifier.\n\n**Class:** `ReadDocument`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`document`\n\n`DataValue`\n\nVariable which will be bound to the document.\n\n`identifier`\n\n`NodeValue`\n\nThe URI of the document to load.\n\n* * *\n\n#### Regexp\n\nTest a string against a PCRE style regex pattern.\n\n**Class:** `Regexp`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`pattern`\n\n`DataValue`\n\nThe PCRE style pattern.\n\n`string`\n\n`DataValue`\n\nThe string to test.\n\n`result`\n\n`DataValue`\n\nAn optional result list of matches.\n\n* * *\n\n#### Select\n\nSelect specific variables from a query to return.\n\n**Class:** `Select`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`variables`\n\n`xsd:string`\n\nThe variables to select from the query.\n\n`query`\n\n`Query`\n\nThe query which will be run prior to selection.\n\n* * *\n\n#### Size\n\nSize of a database in magic units (bytes?).\n\n**Class:** `Size`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`resource`\n\n`xsd:string`\n\nThe resource to obtain the size of.\n\n`size`\n\n`DataValue`\n\nThe size.\n\n* * *\n\n#### Source\n\nDescription pending.\n\n**Class:** `Source`\n\n* * *\n\n#### Split\n\nSplit a string.\n\n**Class:** `Split`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`string`\n\n`DataValue`\n\nThe starting string.\n\n`pattern`\n\n`DataValue`\n\nThe splitting pattern.\n\n`list`\n\n`DataValue`\n\nThe result list of strings.\n\n* * *\n\n#### Start\n\nStart a query at the nth solution specified by 'start'. Allows resumption and paging of queries.\n\n**Class:** `Start`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`query`\n\n`Query`\n\nThe query to perform.\n\n`start`\n\n`xsd:nonNegativeInteger`\n\nThe numbered solution to start at.\n\n* * *\n\n#### Substring\n\nFinds the boundaries of a substring in a string.\n\n**Class:** `Substring`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`string`\n\n`DataValue`\n\nThe super-string as data or variable.\n\n`substring`\n\n`DataValue`\n\nThe super-string as data or variable.\n\n`length`\n\n`DataValue`\n\nThe length of the string as an integer or variable.\n\n`before`\n\n`DataValue`\n\nThe count of characters before substring as an integer or variable.\n\n`after`\n\n`DataValue`\n\nThe count of characters after substring as an integer or variable.\n\n* * *\n\n#### Subsumption\n\nProvides class subsumption (the inheritance model) according to the schema design. True whenver 'child' is a child of 'parent'. Can be used as a generator or a check.\n\n**Class:** `Subsumption`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`child`\n\n`NodeValue`\n\nThe child class as a URI or variable.\n\n`parent`\n\n`NodeValue`\n\nThe parent class as a URI or variable\n\n* * *\n\n#### Sum\n\nSum a list of strings.\n\n**Class:** `Sum`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`list`\n\n`DataValue`\n\nThe list of numbers to sum.\n\n`result`\n\n`DataValue`\n\nThe result of the sum as a number.\n\n* * *\n\n#### Trim\n\nTrims whitespace from 'untrimmed'.\n\n**Class:** `Trim`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`untrimmed`\n\n`DataValue`\n\nThe untrimmed string.\n\n`trimmed`\n\n`DataValue`\n\nThe string to be trimmed.\n\n* * *\n\n#### Triple\n\nSpecify an edge pattern in the graph.\n\n**Class:** `Triple`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`subject`\n\n`NodeValue`\n\nA URI or variable which is the source or subject of the graph edge.\n\n`predicate`\n\n`NodeValue`\n\nA URI or variable which is the edge-label or predicate of the graph edge.\n\n`object`\n\n`Value`\n\nA URI, datatype or variable which is the target or object of the graph edge.\n\n`graph`\n\n`xsd:string`\n\nAn optional graph (either 'instance' or 'schema')\n\n* * *\n\n#### TripleCount\n\nThe number of edges in a database.\n\n**Class:** `TripleCount`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`resource`\n\n`xsd:string`\n\nThe resource to obtain the edges from.\n\n`count`\n\n`DataValue`\n\nThe count of edges.\n\n* * *\n\n#### True\n\nThe query which is always true.\n\n**Class:** `True`\n\n**Super class:** `Query`\n\n* * *\n\n#### Typecast\n\nCasts one type as another if possible.\n\n**Class:** `Typecast`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`value`\n\n`Value`\n\nThe value to cast.\n\n`type`\n\n`NodeValue`\n\nThe type to which to cast.\n\n`result`\n\n`Value`\n\nThe resulting value after cast.\n\n* * *\n\n#### UpdateDocument\n\nUpdate a document in the graph.\n\n**Class:** `UpdateDocument`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`document`\n\n`DataValue`\n\nThe document to update. Must either have an '@id' or have a class specified key.\n\n`identifier`\n\n`NodeValue`\n\nAn optional returned identifier specifying the documentation location.\n\n* * *\n\n#### Upper\n\nUppercase a string.\n\n**Class:** `Upper`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`mixed`\n\n`DataValue`\n\nThe mixed case string.\n\n`uppser`\n\n`undefined`\n\nThe upper case string.\n\n* * *\n\n#### Using\n\nSelect a specific collection for query.\n\n**Class:** `Using`\n\n**Super class:** `Query`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`collection`\n\n`xsd:string`\n\nThe resource over which to run the query.\n\n`query`\n\n`Query`\n\nThe query which will be run on the selected collection.\n\n* * *\n\n#### Value\n\nA variable, node or data point. It is a subdocument\n\n**Class:** `Value`\n\n**Properties:**\n\nProperty\n\nRange\n\nDesc\n\n`node`\n\n`xsd:string`\n\nA URI representing a resource.\n\n`variable`\n\n`xsd:string`\n\nA variable.\n\n`list`\n\n`Value`\n\nA list of datavalues\n\n`data`\n\n`xsd:anySimpleType`\n\nAn xsd data type value." + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "WOQL Class Reference Guide", + "description": "The JSON-LD definition of the WOQL language", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "How to Use the Document UI SDK" + }, + "slug": "document-ui-sdk", + "body": { + "@type": "Body", + "value": "Use the TerminusDB documents User Interface (UI) utility `terminusdb-documents-ui` to automatically generate user interfaces for the document definitions in your TerminusDB schema. The utility takes frames as input and outputs forms in HTML format. A frame is the JSON structure of a JSON document, including the document's inherited properties and IRIs.\n\n### Install and import\n\nInstall the utility from `npm`:\n\n```\nnpm install @terminusdb/terminusdb-documents-ui --save\n```\n\nImport the `FrameViewer` component into your code:\n\n```python\nimport {FrameViewer} from '@terminusdb/terminusdb-documents-ui'\n```\n\nImport the `FrameViewer` css into your code:\n\nFor dark mode include the below css\n\n```python\nimport '@terminusdb/terminusdb-documents-ui/dist/css/terminusdb__darkly.css'\n```\n\nlight mode\n\n```python\nimport '@terminusdb/terminusdb-documents-ui/dist/css/terminusdb__light.css'\n```\n\n### The FrameViewer object\n\nUse the `FrameViewer` object of `terminusdb-documents-ui` to configure and display your forms. `FrameViewer` supports several parameters and functions.\n\n#### FrameViewer parameters\n\n**Parameter**\n\n**Description**\n\n`frame`\n\nThe JSON frame structure of a TerminusDB schema.\n\n`mode`\n\nForm modes - `Create`, `Edit`, or `View`.\n\n`formData`\n\nThe data entered into or provided for a form. Specify `formData` in `Edit` and `View` modes to display data.\n\n`type`\n\ndocument type of interest to be displayed in form.\n\n`language`\n\nlanguage code parameters to support a wide variety of languages in UI as defined in schema\n\n#### FrameViewer functions\n\n**Function**\n\n**Description**\n\n`onSubmit`\n\nA customizable JavaScrpt (JS) callback function to process data submitted via a form.\n\n`onSelect`\n\nJS callback function to retrieve the selected values from a `Select` component.\n\n`onTraverse`\n\nReturn the ID of a document on a click event. Useful for binding an `onClick` event with a document.\n\n#### FrameViewer Mandatory props\n\nprops\n\nMandatory\n\nframe\n\ntrue\n\ntype\n\ntrue\n\nmode\n\ntrue\n\nformData\n\nformData has to be mandatory in Edit or View mode. If nothing to display then pass empty json {}\n\n### FrameViewer common usage\n\nA common use of `terminusdb-documents-ui` is as follows:\n\n1. Set up a Webpack.\n2. Use the [TerminusDB JavaScript client](/docs/javascript/).\n3. Use the client function `getSchemaFrame` to retrieve frame data from a TerminusDB database.\n4. Set custom values and behaviour for `FrameViewer` parameters and functions as required.\n5. Call `FrameViewer` to display frame data in the specified form.\n\n### Get schema frame data from a database\n\nA basic example below to get started with a TerminusDB JavaScript client.\n\n```python\nconst TerminusDBClient = require(\"@terminusdb/terminusdb-client\");\nimport '@terminusdb/terminusdb-documents-ui/dist/css/terminusdb__darkly.css'\nimport {FrameViewer} from '@terminusdb/terminusdb-documents-ui'\n\ntry {\n let type = \"Person\" // type is the a document class of interest\n let frames = await woqlClient.getSchemaFrame(type, woqlClient.db())\n console.log(`Frames generated from ${woqlClient.db()}`, frames)\n} catch(err) {\n console.log(\"Error fetching frames\", err)\n}\n```\n\n### FrameViewer usage step-by-step\n\nUse three simple steps - input, configure, and output:\n\n[Step 1. Create frame data](#step1createframedata)\n\n[Step 2. Configure properties and functions](#step2configurepropertiesandfunctions)\n\n[Step 3. Generate the form](#step3generatetheform)\n\n#### Step 1. Create frame data\n\nFor simplicity, all examples use the `frames` definition below consisting of one document `Person`.\n\n```javascript\nlet frames = {\n \"@context\": {\n \"@base\": \"terminusdb:///data/\",\n \"@schema\": \"terminusdb:///schema#\",\n \"@type\": \"@context\"\n },\n \"Person\": {\n \"@key\": {\n \"@type\": \"Random\"\n },\n \"@type\": \"Class\",\n \"DOB\": \"xsd:dateTime\",\n \"active\": \"xsd:boolean\",\n \"age\": \"xsd:decimal\",\n \"name\": \"xsd:string\"\n }\n}\n\n// The document to display the frame for. \n\nlet type = \"Person\"\n```\n\n#### Step 2. Configure properties and functions\n\nThe example below generates an empty frame for the attributes of the `Person` document. The callback function `handleSubmit` displays any user-entered form data. Add functionality to `handleSubmit` to suit your requirements.\n\n```javascript\n// Mode \"Create\" displays an empty frame.\n\nlet mode = \"Create\"\n\n// Callback to display form data.\n\nfunction handleSubmit(data) {\n console.log(\"Form data: \", data)\n}\n```\n\n#### Step 3. Generate the form\n\nGenerate the form using the properties and functions defined in the previous step.\n\n```\n// Generate the form.\n\nreturn \n```\n\n### FrameViewer modes\n\nThe `FrameViewer` object supports three modes:\n\n* [Create](#createmode)\n* [Edit](#editmode)\n* [View](#viewmode)\n\n#### Create mode\n\nThe `Create` mode displays an empty frame as demonstrated in the previous example.\n\n#### Edit mode\n\nThe `Edit` mode displays populated and empty frames. This mode requires the `formData` parameter.\n\n```javascript\n// Mode \"Edit\" displays a frame with editable data.\n\nlet mode = \"Edit\"\n\n// Add form data to populate the frame.\n\nlet formData = {\n \"@id\": \"Person/John%20Doe\",\n \"@type\": \"Person\",\n first_name: \"John\",\n last_name: \"Doe\",\n age: \"17\",\n active: true,\n DOB: \"2022-03-31T10:01:11.000Z\"\n}\n\n// Callback to display form data.\n\nfunction handleSubmit(data) {\n console.log(\"Form data: \", data)\n}\n\n// Generate the form with formData paramter.\n\nreturn \n```\n\n#### View Mode\n\nThe `View` mode displays populated frames for view-only - the **Submit** button is automatically hidden. If the `formData` parameter is omitted, an empty form is displayed.\n\n```javascript\n// Mode \"View\" displays populated frames.\n\nlet mode = \"View\"\n\n// Add form data to populate the frame.\n\nlet formData = {\n \"@id\": \"Person/John%20Doe\",\n \"@type\": \"Person\",\n first_name: \"John\",\n last_name: \"Doe\",\n age: \"17\",\n active: true,\n DOB: \"2022-03-31T10:01:11.000Z\"\n}\n\n// Callback to display form data.\n\nfunction handleSubmit(data) {\n console.log(\"Form data: \", data)\n}\n\n// Generate the form with formData paramter.\n\nreturn \n```\n\n## Document UI SDK Examples\n\n[Document UI SDK Playground](https://documents-ui-playground.terminusdb.com/) - An interactive example of document properties in add, edit, and view modes with example schema and code.\n\n[Lego Data Product UI CodeSandbox Example](https://codesandbox.io/s/github/terminusdb/dashboard-examples-sandbox/tree/main/terminusdb-documents-ui-examples/lego-dataproduct-npm)" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "How to use the TerminusCMS Document UI SDK", + "description": "How to use the TerminusCMS Document UI SDK", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Documents UI SDK Data Types" + }, + "slug": "document-ui-sdk-data-types", + "body": { + "@type": "Body", + "value": "The TerminusDB documents user interface generates forms representing the properties or fields of document/s in your schema. For data entry, each field is one of several data types and is mandatory by default. Schema definitions enable the linking of documents and the specification of sets.\n\n[**Click here to find out how to get started with the Document UI SDK**](/docs/document-ui-sdk/)\n\n## Demo\n\nTake a look at the [**Document UI SDK Playground**](https://documents-ui-playground.terminusdb.com) to view the `` demo in Create, edit or view mode.\n\n## Data types\n\n### Basic data types\n\nThe table below lists the basic data types supported and their specifications.\n\n**Data type**\n\n**Declaration**\n\n**Example**\n\nBoolean\n\n`\"xsd:boolean\"`\n\n`\"active\": \"xsd:boolean\"`\n\nDecimal\n\n`\"xsd:decimal\"`\n\n`\"age\": \"xsd:decimal\"`\n\nEnum\n\n`\"@type: \"Enum\"`\n\n`\"@values\": [\"red\", \"blue\", \"yellow\", \"green\"]`\n\nInteger\n\n`\"xsd:integer\"`\n\n`\"age\": \"xsd:integer\"`\n\nDecimal\n\n`\"xsd:decimal\"`\n\n`\"age\": \"xsd:decimal\"`\n\nString\n\n`\"xsd:string\"`\n\n`\"name\": \"xsd:string\"`\n\nTemporal\n\n`\"xsd:dateTime\"`\n\n`\"DOB\": \"xsd:dateTime\"`\n\n### Data value optionality\n\nIf a property in the Form is displayed with a (Required) tab, that means the property is mandatory & has to be filled in order to submit the form. To define a property as optional, use the `\"@type\": \"Optional\"` declaration meaning the property is optional.\n\nA property can also be defined as an array in the following ways -\n\n`\"@type\": \"Set\"` - property can hold multiple values in an unordered fashion & can be optional\n\n`\"@type\": \"List\"` - property can hold multiple values in an ordered fashion & requires at least one entry\n\n### An example of all basic types\n\n**Enum**\n\nThe `\"Enum\"` data type in the example below specifies the colors a person likes - `\"@id\": \"Colors`, `\"Person\"`, `\"likes\"`. This is rendered as a dropdown menu with the colors specified in the `\"@values\"` list.\n\n**Optional**\n\nThe `\"age\"` of a `\"Person\"` is declared `\"Optional\"`\n\n```javascript\nlet frames = {\n \"@context\": {\n \"@base\": \"terminusdb:///data/\",\n \"@schema\": \"terminusdb:///schema#\",\n \"@type\": \"@context\"\n },\n \"Person\": {\n \"@key\": {\n \"@type\": \"Random\"\n },\n \"@type\": \"Class\",\n \"DOB\": \"xsd:dateTime\",\n \"active\": \"xsd:boolean\",\n \"age\": {\n \"@class\": \"xsd:decimal\",\n \"@type\": \"Optional\"\n },\n \"name\": \"xsd:string\",\n \"likes\": {\n \"@id\": \"Colors\",\n \"@type\": \"Enum\",\n \"@values\": [\n \"red\",\n \"blue\",\n \"yellow\",\n \"green\"\n ]\n }\n }\n}\n\nlet type = \"Person\"\nlet mode = \"Create\"\n\nreturn \n```\n\n## Link Properties\n\nLink properties enable links to other document or subdocument classes and are displayed as `Select` components.\n\n### Link Properties Example\n\nThe example below demonstrates:\n\n* The property `work_as` linked to document class `Job`\n* The property `lives_in` linked to a subdocument class `Address`\n\n```javascript\nlet frames = {\n \"@context\": {\n \"@base\": \"terminusdb:///data/\",\n \"@schema\": \"terminusdb:///schema#\",\n \"@type\": \"@context\"\n },\n \"Person\": {\n \"@key\": {\n \"@type\": \"Random\"\n },\n \"@type\": \"Class\",\n \"works_as\": \"Job\", // Link to subdocument Job\n \"lives_in\": \"Address\" // Link to subdocument Address\n },\n \"Job\": {\n \"@key\": {\n \"@type\": \"Random\"\n },\n \"@type\": \"Class\",\n \"title\": \"xsd:string\"\n },\n \"Address\": {\n \"@key\": {\n \"@type\": \"Random\"\n },\n \"@subdocument\": [],\n \"@type\": \"Class\",\n \"Address Line 1\": \"xsd:string\",\n \"Code\": \"xsd:decimal\",\n \"Country\": \"xsd:string\"\n }\n}\n\nlet type = \"Person\"\nlet mode = \"Create\"\n\nreturn \n```\n\n## Set properties\n\nA set specifies an **unordered set** of values of a class or data type.\n\n### Set property example\n\nIn the example below, the document `Person` consists of several nicknames - property `\"nickName\"` of `\"@type\": \"Set\"`. A set consists of zero, one or multiple items.\n\n```javascript\nlet frames = {\n \"@context\": {\n \"@base\": \"terminusdb:///data/\",\n \"@schema\": \"terminusdb:///schema#\",\n \"@type\": \"@context\"\n },\n \"Person\": {\n \"@key\": {\n \"@type\": \"Random\"\n },\n \"@type\": \"Class\",\n \"name\": \"xsd:string\",\n \"nickName\": {\n \"@class\": \"xsd:string\",\n \"@type\": \"Set\"\n }\n }\n}\n\nlet type = \"Person\"\nlet mode = \"Create\"\n\nreturn \n```\n\n### Document Class Set Example\n\nIn the example below, a `Person` has a property `works_as` defined as a set that links to the document `Job`, representing a person with multiple jobs.\n\n```javascript\nlet frames = {\n \"@context\": {\n \"@base\": \"terminusdb:///data/\",\n \"@schema\": \"terminusdb:///schema#\",\n \"@type\": \"@context\"\n },\n \"Person\": {\n \"@key\": {\n \"@type\": \"Random\"\n },\n \"@type\": \"Class\",\n \"name\": \"xsd:string\",\n \"works_as\": {\n \"@class\": \"Job\",\n \"@type\": \"Set\"\n }\n },\n \"Job\": {\n \"@key\": {\n \"@type\": \"Random\"\n },\n \"@type\": \"Class\",\n \"title\": \"xsd:string\"\n }\n}\n\nlet type = \"Person\"\nlet mode = \"Create\"\n\nreturn \n```\n\n### Subdocument Class Set Example\n\nIn the example below, a `Person` has a property `lived` defined as a set that links to the subdocument `Address`, representing a person's address history.\n\n```javascript\nlet frames = {\n \"@context\": {\n \"@base\": \"terminusdb:///data/\",\n \"@schema\": \"terminusdb:///schema#\",\n \"@type\": \"@context\"\n },\n \"Person\": {\n \"@key\": {\n \"@type\": \"Random\"\n },\n \"@type\": \"Class\",\n \"name\": \"xsd:string\",\n \"lived\": {\n \"@class\": {\n \"@class\": \"Address\",\n \"@subdocument\": []\n },\n \"@type\": \"Set\"\n }\n },\n \"Address\": {\n \"@key\": {\n \"@type\": \"Random\"\n },\n \"@subdocument\": [],\n \"@type\": \"Class\",\n \"Address Line 1\": \"xsd:string\",\n \"Code\": \"xsd:decimal\",\n \"Country\": \"xsd:string\"\n }\n}\n\nlet type = \"Person\"\nlet mode = \"Create\"\n\nreturn \n```\n\n## List Properties\n\nA list specifies an **ordered collection** of values of a class or data type. An ordered collection means values are displayed in the order they are entered in the form.\n\n### List property example\n\nIn the example below, a `Person` has two properties, `ordered_property` (a string data type) and `has_task` (a subdocument of type `\"List\"`.)\n\n```javascript\nlet frames = {\n \"@context\": {\n \"@base\": \"terminusdb:///data/\",\n \"@schema\": \"terminusdb:///schema#\",\n \"@type\": \"@context\"\n },\n \"Person\": {\n \"@key\": {\n \"@type\": \"Random\"\n },\n \"@type\": \"Class\",\n \"ordered_property\": {\n \"@class\": \"xsd:string\",\n \"@type\": \"List\"\n },\n \"has_task\": {\n \"@class\": \"Tasks\",\n \"@type\": \"List\"\n }\n },\n \"Tasks\": {\n \"@key\": {\n \"@type\": \"Random\"\n },\n \"@subdocument\": [],\n \"@type\": \"Class\",\n \"Address Line 1\": \"xsd:string\",\n \"Code\": \"xsd:decimal\",\n \"Country\": \"xsd:string\"\n }\n}\n\nlet type = \"Person\"\nlet mode = \"Create\"\n\n// call FrameViewer\nreturn \n```\n\nFor more information on data types, take a look at the individual types in more details:\n\n* [Array](/docs/array/)\n* [Choice Document](/docs/choice-document/)\n* [Choice Sub Document](/docs/choice-subdocuments/)\n* [List](/docs/list/)\n* [Mandatory](/docs/mandatory/)\n* [One Of](/docs/oneof/)\n* [Optional](/docs/optional/)\n* [Order By](/docs/orderby/)\n* [Render As](/docs/render-as/)\n* [Set](/docs/set/)\n* [sysJSON](/docs/sysjson/)\n\n## Document UI SDK Examples\n\n[Document UI SDK Playground](https://documents-ui-playground.terminusdb.com/) - An interactive example of document properties in add, edit, and view modes with example schema and code.\n\n[Lego Data Product UI CodeSandbox Example](https://codesandbox.io/s/github/terminusdb/dashboard-examples-sandbox/tree/main/terminusdb-documents-ui-examples/lego-dataproduct-npm)" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Documents UI SDK Data Types", + "description": "Understand the different data types to build data driven user interfaces", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Array" + }, + "slug": "array", + "body": { + "@type": "Body", + "value": "This example shows how `` appears for a document `ArrayExamplePerson` with array fields in Create/ Edit or View mode. If a field is described as array it means the field can have more than one value to it in an ordered fashion. The field can also be considered as an optional field meaning it can be empty or filled.\n\n## Demo\n\nTake a look at the **[](https://documents-ui-playground.terminusdb.com/Array)**[Demo](https://documents-ui-playground.terminusdb.com/Array) to view `` with Array properties in Create, edit or view mode.\n\n## Frame\n\nThe below frame consists of an ArrayExamplePerson document\n\n```javascript\n let frame = {\n \"@context\": {\n \"@base\": \"terminusdb:///data/\",\n \"@schema\": \"terminusdb:///schema#\",\n \"@type\": \"Context\",\n \"xsd\": \"http://www.w3.org/2001/XMLSchema#\"\n },\n \"Address\": {\n \"@documentation\": [\n {\n \"@comment\": \"An Address\",\n \"@label\": \"Address\",\n \"@language\": \"en\",\n \"@properties\": {\n \"AddressLine1\": {\n \"@comment\": \"Address Line one\",\n \"@label\": \"Address Line 1\"\n },\n \"Country\": {\n \"@comment\": \"A Country \",\n \"@label\": \"Country\"\n },\n \"postalCode\": {\n \"@comment\": \"A valid Postal Code\",\n \"@label\": \"Zip Code\"\n }\n }\n },\n {\n \"@comment\": \"მისამართი\",\n \"@label\": \"მისამართი\",\n \"@language\": \"ka\",\n \"@properties\": {\n \"AddressLine1\": {\n \"@comment\": \"მისამართის ხაზი პირველი\",\n \"@label\": \"მისამართის ხაზი 1\"\n },\n \"Country\": {\n \"@comment\": \"Ქვეყანა\",\n \"@label\": \"ქვეყანა\"\n },\n \"postalCode\": {\n \"@comment\": \"მოქმედი საფოსტო კოდი\",\n \"@label\": \"Ზიპ კოდი\"\n }\n }\n }\n ],\n \"@key\": {\n \"@type\": \"Random\"\n },\n \"@subdocument\": [],\n \"@type\": \"Class\",\n \"AddressLine1\": \"xsd:string\",\n \"City\": {\n \"@class\": \"xsd:string\",\n \"@type\": \"Optional\"\n },\n \"Country\": \"xsd:string\",\n \"postalCode\": \"xsd:string\"\n },\n \"ArrayExamplePerson\": {\n \"@key\": {\n \"@type\": \"Random\"\n },\n \"@type\": \"Class\",\n \"hangs_out_at\": {\n \"@class\": {\n \"@class\": \"Address\",\n \"@subdocument\": []\n },\n \"@type\": \"List\"\n },\n \"likes_color\": {\n \"@class\": {\n \"@id\": \"Colors\",\n \"@type\": \"Enum\",\n \"@values\": [\n \"Red\",\n \"Blue\",\n \"Yellow\",\n \"Green\"\n ]\n },\n \"@type\": \"List\"\n },\n \"to_do\": {\n \"@class\": \"xsd:string\",\n \"@type\": \"List\"\n }\n }\n }\n```\n\n### Create\n\n```python\nimport { FrameViewer } from '@terminusdb/terminusdb-documents-ui'\n\n return // type of document \n```\n\n### Edit & View\n\nNote - make sure to provide document values for View mode. The form will be in read only mode for View.\n\n```javascript\nlet data = {\n \"@id\": \"ArrayExamplePerson/c92d269b0dce719299bf86fc19f2065937ec4ef82d8a2a53702867a326d6144b\",\n \"@type\": \"OrderedPerson\",\n \"hangs_out_at\" : [\n {\n \"@id\": \"ArrayExamplePerson/3ca7d7a9c64ca2bc8319d83bca14b71697528ebb8536024e3e1795cbd049acdf/lived_at/Address/4f4fdae34ab4fa3b6297750917503a7137f75dc11589792de707e7a6d3502db3\",\n \"@type\": \"Address\",\n \"AddressLine1\": \"anywhere\",\n \"City\": \"Nice\", \n \"Country\": \"France\",\n \"postalCode\": \"FR27836\"\n },\n {\n \"@id\": \"ArrayExamplePerson/3ca7d7a9c64ca2bc8319d83bca14b71697528ebb8536024e3e1795cbd049acdf/lived_at/Address/7aaeeb6b983710a0adbc75de8f7d8104278df427124beadc6644b35b9d6c30af\",\n \"@type\": \"Address\",\n \"AddressLine1\": \"somewhere\",\n \"City\": \"Berlin\", \n \"Country\": \"Germany\",\n \"postalCode\": \"GER02398\"\n }\n ],\n \"likes_color\": [\n \"Blue\",\n \"Green\",\n \"Red\"\n ],\n \"to_do\": [\n \"First Thing\",\n \"Second Thing\",\n \"Third Thing\"\n ]\n}\n\nreturn \n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Array fields in the document UI", + "description": "Examples of how array fields in the document UI ", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Choice Document" + }, + "slug": "choice-document", + "body": { + "@type": "Body", + "value": "This example shows how `` appears for a document `Guy` with choice document fields in Create/ Edit or View mode.\n\nIn this example `Guy` has a mandatory property called `favorite_group` with the choice of documents called Art, Dance or Music, an optional `\"second_favorite_group\"` property also with the choice Art, Dance or Music, a set `member_of` property with the same choices, and a list `attends_group_in_order` property with the above same choices, in an ordered fashion.\n\n## Demo\n\nTake a look at the **[](https://documents-ui-playground.terminusdb.com/Choice%20Documents)**[Demo Playground](https://documents-ui-playground.terminusdb.com/Choice%20Documents) to view `` with Choice properties in Create, edit or view mode.\n\nThe below Frames show the definition of Art, Dance or Music which are other document classes.\n\n## Frame\n\nThe below Frame consists of the `Guy` document\n\n```javascript\n let frame = {\n \"@context\": {\n \"@base\": \"terminusdb:///data/\",\n \"@schema\": \"terminusdb:///schema#\",\n \"@type\": \"Context\",\n \"xsd\": \"http://www.w3.org/2001/XMLSchema#\"\n },\n \"Guy\": {\n \"@key\": {\n \"@type\": \"Random\"\n },\n \"@type\": \"Class\", \n \"attends_group_in_order\": {\n \"@class\": \"Group\",\n \"@type\": \"Set\"\n },\n \"favorite_group\": \"Group\",\n \"member_of\": {\n \"@class\": \"Group\",\n \"@type\": \"Set\"\n },\n \"second_favorite_group\": {\n \"@class\": \"Group\",\n \"@type\": \"Optional\"\n }\n },\n \"Dance\": {\n \"@documentation\": [\n {\n \"@language\": \"en\",\n \"@properties\": {\n \"capacity\": {\n \"@comment\": \"Max number of people in group\",\n \"@label\": \"Capacity\"\n },\n \"name\": {\n \"@comment\": \"Title of the group\",\n \"@label\": \"Name\"\n }\n }\n },\n {\n \"@language\": \"ka\",\n \"@properties\": {\n \"capacity\": {\n \"@comment\": \"ადამიანების მაქსიმალური რაოდენობა ჯგუფში\",\n \"@label\": \"ტევადობა\"\n },\n \"name\": {\n \"@comment\": \"ჯგუფის სათაური\",\n \"@label\": \"სახელი\"\n }\n }\n }\n ],\n \"@key\": {\n \"@fields\": [\n \"name\"\n ],\n \"@type\": \"Lexical\"\n },\n \"@type\": \"Class\",\n \"capacity\": \"xsd:decimal\",\n \"name\": \"xsd:string\"\n },\n \"Art\": {\n \"@documentation\": [\n {\n \"@language\": \"en\",\n \"@properties\": {\n \"capacity\": {\n \"@comment\": \"Max number of people in group\",\n \"@label\": \"Capacity\"\n },\n \"name\": {\n \"@comment\": \"Title of the group\",\n \"@label\": \"Name\"\n }\n }\n },\n {\n \"@language\": \"ka\",\n \"@properties\": {\n \"capacity\": {\n \"@comment\": \"ადამიანების მაქსიმალური რაოდენობა ჯგუფში\",\n \"@label\": \"ტევადობა\"\n },\n \"name\": {\n \"@comment\": \"ჯგუფის სათაური\",\n \"@label\": \"სახელი\"\n }\n }\n }\n ],\n \"@key\": {\n \"@fields\": [\n \"name\"\n ],\n \"@type\": \"Lexical\"\n },\n \"@type\": \"Class\",\n \"capacity\": \"xsd:decimal\",\n \"name\": \"xsd:string\"\n },\n \"Music\": {\n \"@documentation\": [\n {\n \"@language\": \"en\",\n \"@properties\": {\n \"capacity\": {\n \"@comment\": \"Max number of people in group\",\n \"@label\": \"Capacity\"\n },\n \"name\": {\n \"@comment\": \"Title of the group\",\n \"@label\": \"Name\"\n }\n }\n },\n {\n \"@language\": \"ka\",\n \"@properties\": {\n \"capacity\": {\n \"@comment\": \"ადამიანების მაქსიმალური რაოდენობა ჯგუფში\",\n \"@label\": \"ტევადობა\"\n },\n \"name\": {\n \"@comment\": \"ჯგუფის სათაური\",\n \"@label\": \"სახელი\"\n }\n }\n }\n ],\n \"@key\": {\n \"@fields\": [\n \"name\"\n ],\n \"@type\": \"Lexical\"\n },\n \"@type\": \"Class\",\n \"capacity\": \"xsd:decimal\",\n \"name\": \"xsd:string\"\n }\n }\n```\n\n### Create\n\n```python\nimport { FrameViewer } from '@terminusdb/terminusdb-documents-ui'\n\n return // type of document \n```\n\n### Edit & View\n\nNote - make sure to provide document values for View mode. The form will be in read only mode for View.\n\n```javascript\nlet data = {\n \"@id\": \"Guy/4489199036b83dbf79a6e7527a1594fbd416d11b9dde2f8a67fe6fa495dae433\",\n \"@type\": \"Guy\",\n \"favorite_group\": \"Art/Charcoal%20Art%20Group\",\n \"attends_group_in_order\": [\n \"Dance/Dance%20Everyday\",\n \"Art/Pastel%20Art%20Group\",\n \"Music/Music%2220Pop\"\n ],\n \"member_of\": [\n \"Art/Pastel%20Art%20Group\",\n \"Dance/Dance%20Everyday\"\n ],\n \"second_favorite_group\": \"Dance/Dance%20Everyday\",\n}\n\nreturn \n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Choice Document in the Document UI", + "description": "How document choice works in the document UI", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Choice Sub-Documents" + }, + "slug": "choice-subdocuments", + "body": { + "@type": "Body", + "value": "This example shows how `` appears for a document called `Student` with choice subdocument fields in Create/ Edit or View mode.\n\n`Student` has a mandatory `favorite_subject` property with the choices of Zoology, Botony or Maths, an optional `\"second_favorite_subject\"` property with the same document choices, a set `studied` property with the above choices, and a list `study_time_table` property with the same choices in an ordered fashion.\n\n## Demo\n\nTake a look at the **[](https://documents-ui-playground.terminusdb.com/Choice%20SubDocuments)**[Demo](https://documents-ui-playground.terminusdb.com/Choice%20SubDocuments) to view `` with Choice subdocuments in Create, edit or view mode.\n\nThe below Frames show the definition of Zoology, Botony or Maths which are subdocuments.\n\n## Frame\n\nThe frame below consists of a `Student` document -\n\n```javascript\n let frame = {\n \"@context\": {\n \"@base\": \"terminusdb:///data/\",\n \"@schema\": \"terminusdb:///schema#\",\n \"@type\": \"Context\",\n \"xsd\": \"http://www.w3.org/2001/XMLSchema#\"\n },\n \"Student\": {\n \"@key\": {\n \"@type\": \"Random\"\n },\n \"@type\": \"Class\",\n \"favorite_subject\": [\n {\n \"@class\": \"Zoology\",\n \"@subdocument\": []\n },\n {\n \"@class\": \"Botony\",\n \"@subdocument\": []\n },\n {\n \"@class\": \"Maths\",\n \"@subdocument\": []\n }\n ],\n \"second_favorite_subject\": {\n \"@class\": [\n {\n \"@class\": \"Zoology\",\n \"@subdocument\": []\n },\n {\n \"@class\": \"Botony\",\n \"@subdocument\": []\n },\n {\n \"@class\": \"Maths\",\n \"@subdocument\": []\n }\n ],\n \"@type\": \"Optional\"\n },\n \"studied\": {\n \"@class\": [\n {\n \"@class\": \"Zoology\",\n \"@subdocument\": []\n },\n {\n \"@class\": \"Botony\",\n \"@subdocument\": []\n },\n {\n \"@class\": \"Maths\",\n \"@subdocument\": []\n }\n ],\n \"@type\": \"Set\"\n },\n \"study_time_table\": {\n \"@class\": [\n {\n \"@class\": \"Zoology\",\n \"@subdocument\": []\n },\n {\n \"@class\": \"Botony\",\n \"@subdocument\": []\n },\n {\n \"@class\": \"Maths\",\n \"@subdocument\": []\n }\n ],\n \"@type\": \"List\"\n }\n },\n \"Zoology\": {\n \"@documentation\": [\n {\n \"@language\": \"en\",\n \"@properties\": {\n \"Number_of_classes_attended\": {\n \"@comment\": \"Number of Classes Attended\",\n \"@label\": \"Classes Attended\"\n },\n \"course_start_date\": {\n \"@comment\": \"Course Start Date\",\n \"@label\": \"Start Date\"\n }\n }\n },\n {\n \"@language\": \"ka\",\n \"@properties\": {\n \"Number_of_classes_attended\": {\n \"@comment\": \"კლასების რაოდენობა\",\n \"@label\": \"კლასები დაესწრო\"\n },\n \"course_start_date\": {\n \"@comment\": \"კურსის დაწყების თარიღი\",\n \"@label\": \"Დაწყების თარიღი\"\n }\n }\n }\n ],\n \"@key\": {\n \"@type\": \"Random\"\n },\n \"@subdocument\": [],\n \"@type\": \"Class\",\n \"Grade\": {\n \"@class\": \"xsd:string\",\n \"@type\": \"Optional\"\n },\n \"Notes\": {\n \"@class\": \"xsd:string\",\n \"@type\": \"Optional\"\n },\n \"Number_of_classes_attended\": {\n \"@class\": \"xsd:integer\",\n \"@type\": \"Optional\"\n },\n \"course_start_date\": {\n \"@class\": \"xsd:dateTime\",\n \"@type\": \"Optional\"\n }\n }\n \"Botony\": {\n \"@documentation\": [\n {\n \"@language\": \"en\",\n \"@properties\": {\n \"Number_of_classes_attended\": {\n \"@comment\": \"Number of Classes Attended\",\n \"@label\": \"Classes Attended\"\n },\n \"course_start_date\": {\n \"@comment\": \"Course Start Date\",\n \"@label\": \"Start Date\"\n }\n }\n },\n {\n \"@language\": \"ka\",\n \"@properties\": {\n \"Number_of_classes_attended\": {\n \"@comment\": \"კლასების რაოდენობა\",\n \"@label\": \"კლასები დაესწრო\"\n },\n \"course_start_date\": {\n \"@comment\": \"კურსის დაწყების თარიღი\",\n \"@label\": \"Დაწყების თარიღი\"\n }\n }\n }\n ],\n \"@key\": {\n \"@type\": \"Random\"\n },\n \"@subdocument\": [],\n \"@type\": \"Class\",\n \"Grade\": {\n \"@class\": \"xsd:string\",\n \"@type\": \"Optional\"\n },\n \"Number_of_classes_attended\": {\n \"@class\": \"xsd:integer\",\n \"@type\": \"Optional\"\n },\n \"course_start_date\": {\n \"@class\": \"xsd:dateTime\",\n \"@type\": \"Optional\"\n },\n \"number_of_assignments\": {\n \"@class\": \"xsd:integer\",\n \"@type\": \"Optional\"\n }\n },\n \"Maths\": {\n \"@documentation\": [\n {\n \"@comment\": \"Maths\",\n \"@label\": \"Maths\",\n \"@language\": \"en\",\n \"@properties\": {\n \"Number_of_classes_attended\": {\n \"@comment\": \"Number of Classes Attended\",\n \"@label\": \"Classes Attended\"\n },\n \"course_start_date\": {\n \"@comment\": \"Course Start Date\",\n \"@label\": \"Start Date\"\n },\n \"level\": {\n \"@comment\": \"Math level\",\n \"@label\": \"Level\"\n },\n \"love_maths\": {\n \"@comment\": \"a choice to love maths\",\n \"@label\": \"Do you like Maths?\"\n }\n }\n },\n {\n \"@comment\": \"მათემატიკა\",\n \"@label\": \"მათემატიკა\",\n \"@language\": \"ka\",\n \"@properties\": {\n \"Number_of_classes_attended\": {\n \"@comment\": \"კლასების რაოდენობა\",\n \"@label\": \"კლასები დაესწრო\"\n },\n \"course_start_date\": {\n \"@comment\": \"კურსის დაწყების თარიღი\",\n \"@label\": \"Დაწყების თარიღი\"\n },\n \"level\": {\n \"@comment\": \"მათემატიკის დონე\",\n \"@label\": \"დონე\"\n },\n \"love_maths\": {\n \"@comment\": \"არჩევანი გიყვარდეს მათემატიკა\",\n \"@label\": \"მოგწონთ მათემატიკა?\"\n }\n }\n }\n ],\n \"@key\": {\n \"@type\": \"Random\"\n },\n \"@subdocument\": [],\n \"@type\": \"Class\",\n \"Number_of_classes_attended\": {\n \"@class\": \"xsd:integer\",\n \"@type\": \"Optional\"\n },\n \"course_start_date\": {\n \"@class\": \"xsd:dateTime\",\n \"@type\": \"Optional\"\n },\n \"level\": {\n \"@class\": \"xsd:string\",\n \"@type\": \"Optional\"\n },\n \"love_maths\": {\n \"@class\": \"xsd:boolean\",\n \"@type\": \"Optional\"\n }\n }\n }\n```\n\n## Create\n\n```python\nimport { FrameViewer } from '@terminusdb/terminusdb-documents-ui'\n\n return // type of document \n```\n\n## Edit & View\n\nNote - make sure the document is filled in View mode. The form will be in read only mode for View.\n\n```javascript\nlet data = {\n \"@id\": \"Student/6bf39891b3aaab89771cecdd88a7771dad8c613cfc0530d07bb79bdde6d55d51\",\n \"@type\": \"Student\",\n \"favorite_subject\": {\n \"@id\": \"Student/6bf39891b3aaab89771cecdd88a7771dad8c613cfc0530d07bb79bdde6d55d51/favorite_subject/Botony/aef9f22fe04ece720d19f6630edcad27f85e546810a907e4724ee0b57aba4b52\",\n \"@type\": \"Botony\",\n \"Grade\": \"A\",\n \"Number_of_classes_attended\": 4,\n \"course_start_date\": \"2022-08-17T09:21:09Z\", \n \"number_of_assignments\": 5\n },\n \"second_favorite_subject\": {\n \"@id\": \"Student/6bf39891b3aaab89771cecdd88a7771dad8c613cfc0530d07bb79bdde6d55d51/second_favorite_subject/Zoology/2f0ab12e837a6d1bdbb15b41e556940b288167e7909061e1b32e56d91005431b\",\n \"@type\": \"Zoology\",\n \"Grade\": \"A\",\n \"Notes\": \"loves zoology\",\n \"Number_of_classes_attended\": 5,\n \"course_start_date\": \"2022-08-17T09:21:20Z\"\n },\n \"studied\": [\n {\n \"@id\": \"Student/6bf39891b3aaab89771cecdd88a7771dad8c613cfc0530d07bb79bdde6d55d51/studied/Botony/cc7e311138c8244f9ba043ad5f96e846c6a0961d9190210ee3f297f96976fd00\",\n \"@type\": \"Botony\",\n \"Grade\": \"A\",\n \"Number_of_classes_attended\": 67,\n \"course_start_date\": \"2022-08-17T09:21:53Z\",\n \"number_of_assignments\": 23\n },\n {\n \"@id\": \"Student/6bf39891b3aaab89771cecdd88a7771dad8c613cfc0530d07bb79bdde6d55d51/studied/Maths/666ce31233a834b895f4c42e72b0b5250188ea4dcf2f2bb8bc0dc32e710ceb26\",\n \"@type\": \"Maths\",\n \"Number_of_classes_attended\": 45,\n \"course_start_date\": \"2022-08-17T09:21:37Z\",\n \"level\": \"Medium\",\n \"love_maths\": true\n }\n ],\n \"study_time_table\": [\n {\n \"@id\": \"Student/6bf39891b3aaab89771cecdd88a7771dad8c613cfc0530d07bb79bdde6d55d51/study_time_table/0/Zoology/d0cade9042e0baee8e0b91a8ed0e85ec09db40084d0ff56532d92a454ff67c57\",\n \"@type\": \"Zoology\",\n \"Grade\": \"A\",\n \"Notes\": \"Best student\",\n \"Number_of_classes_attended\": 5,\n \"course_start_date\": \"2022-08-17T09:22:06Z\"\n },\n {\n \"@id\": \"Student/6bf39891b3aaab89771cecdd88a7771dad8c613cfc0530d07bb79bdde6d55d51/study_time_table/1/Botony/be10b1f3c70c1fe28eb52ad3113352356ae53d3375436ae6719abe019dc28f76\",\n \"@type\": \"Botony\",\n \"Grade\": \"B\",\n \"Number_of_classes_attended\": 54,\n \"course_start_date\": \"2022-08-17T09:22:32Z\",\n \"number_of_assignments\": 34\n }\n ]\n}\n\nreturn \n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "TerminusDB Document UI SDK - Using Choice Subdocuments", + "description": "A guide showing how to use multiple choice subdocuments with the TerminusDB document UI SDK", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "List" + }, + "slug": "list", + "body": { + "@type": "Body", + "value": "This example shows how `` appears for a document called `OrderedPerson` with list fields in Create/ Edit and View mode. If a field is described as a List it means the field can have one or more values and is ordered. The field must have at least one entry.\n\n## Demo\n\nTake a look at the [**Demo Playground**](https://documents-ui-playground.terminusdb.com/List) to view the `` with list properties in Create, Edit and View mode.\n\n## Frame\n\nThe below frame consists of an `OrderedPerson` document\n\n```javascript\n let frame = {\n \"@context\": {\n \"@base\": \"terminusdb:///data/\",\n \"@schema\": \"terminusdb:///schema#\",\n \"@type\": \"Context\",\n \"xsd\": \"http://www.w3.org/2001/XMLSchema#\"\n },\n \"Address\": {\n \"@documentation\": [\n {\n \"@comment\": \"An Address\",\n \"@label\": \"Address\",\n \"@language\": \"en\",\n \"@properties\": {\n \"AddressLine1\": {\n \"@comment\": \"Address Line one\",\n \"@label\": \"Address Line 1\"\n },\n \"Country\": {\n \"@comment\": \"A Country \",\n \"@label\": \"Country\"\n },\n \"postalCode\": {\n \"@comment\": \"A valid Postal Code\",\n \"@label\": \"Zip Code\"\n }\n }\n },\n {\n \"@comment\": \"მისამართი\",\n \"@label\": \"მისამართი\",\n \"@language\": \"ka\",\n \"@properties\": {\n \"AddressLine1\": {\n \"@comment\": \"მისამართის ხაზი პირველი\",\n \"@label\": \"მისამართის ხაზი 1\"\n },\n \"Country\": {\n \"@comment\": \"Ქვეყანა\",\n \"@label\": \"ქვეყანა\"\n },\n \"postalCode\": {\n \"@comment\": \"მოქმედი საფოსტო კოდი\",\n \"@label\": \"Ზიპ კოდი\"\n }\n }\n }\n ],\n \"@key\": {\n \"@type\": \"Random\"\n },\n \"@subdocument\": [],\n \"@type\": \"Class\",\n \"AddressLine1\": \"xsd:string\",\n \"City\": {\n \"@class\": \"xsd:string\",\n \"@type\": \"Optional\"\n },\n \"Country\": \"xsd:string\",\n \"postalCode\": \"xsd:string\"\n },\n \"OrderedPerson\": {\n \"@key\": {\n \"@type\": \"Random\"\n },\n \"@type\": \"Class\",\n \"hangs_out_at\": {\n \"@class\": {\n \"@class\": \"Address\",\n \"@subdocument\": []\n },\n \"@type\": \"List\"\n },\n \"likes_color\": {\n \"@class\": {\n \"@id\": \"Colors\",\n \"@type\": \"Enum\",\n \"@values\": [\n \"Red\",\n \"Blue\",\n \"Yellow\",\n \"Green\"\n ]\n },\n \"@type\": \"List\"\n },\n \"to_do\": {\n \"@class\": \"xsd:string\",\n \"@type\": \"List\"\n }\n }\n }\n```\n\n### Create\n\n```python\nimport { FrameViewer } from '@terminusdb/terminusdb-documents-ui'\n\n return // type of document \n```\n\n### Edit & View\n\nNote - make sure to provide document values for View mode. The form will be in read only mode for View.\n\n```javascript\nlet data = {\n \"@id\": \"OrderedPerson/c92d269b0dce719299bf86fc19f2065937ec4ef82d8a2a53702867a326d6144b\",\n \"@type\": \"OrderedPerson\",\n \"hangs_out_at\" : [\n {\n \"@id\": \"OrderedPerson/3ca7d7a9c64ca2bc8319d83bca14b71697528ebb8536024e3e1795cbd049acdf/lived_at/Address/4f4fdae34ab4fa3b6297750917503a7137f75dc11589792de707e7a6d3502db3\",\n \"@type\": \"Address\",\n \"AddressLine1\": \"anywhere\",\n \"City\": \"Nice\", \n \"Country\": \"France\",\n \"postalCode\": \"FR27836\"\n },\n {\n \"@id\": \"OrderedPerson/3ca7d7a9c64ca2bc8319d83bca14b71697528ebb8536024e3e1795cbd049acdf/lived_at/Address/7aaeeb6b983710a0adbc75de8f7d8104278df427124beadc6644b35b9d6c30af\",\n \"@type\": \"Address\",\n \"AddressLine1\": \"somewhere\",\n \"City\": \"Berlin\", \n \"Country\": \"Germany\",\n \"postalCode\": \"GER02398\"\n }\n ],\n \"likes_color\": [\n \"Blue\",\n \"Green\",\n \"Red\"\n ],\n \"to_do\": [\n \"First Thing\",\n \"Second Thing\",\n \"Third Thing\"\n ]\n}\n\nreturn \n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "List Properties in the Document UI", + "description": "How list properties work in the document UI software development kit.", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Mandatory" + }, + "slug": "mandatory", + "body": { + "@type": "Body", + "value": "This example shows how `` appears for a document called `Person` with mandatory fields in Create/ Edit and View mode. A required tag will appear against every mandatory field.\n\n## Demo\n\nTake a look at the [**Demo Playground**](https://documents-ui-playground.terminusdb.com/Mandatory) to view the `` with mandatory properties in Create, Edit and View mode.\n\n## Frame\n\nThe below frame consists of a `Person` document with mandatory fields -\n\n```javascript\n let frame = {\n \"@context\": {\n \"@base\": \"terminusdb:///data/\",\n \"@schema\": \"terminusdb:///schema#\",\n \"@type\": \"Context\",\n \"xsd\": \"http://www.w3.org/2001/XMLSchema#\"\n },\n \"Address\": {\n \"@documentation\": [\n {\n \"@comment\": \"An Address\",\n \"@label\": \"Address\",\n \"@language\": \"en\",\n \"@properties\": {\n \"AddressLine1\": {\n \"@comment\": \"Address Line one\",\n \"@label\": \"Address Line 1\"\n },\n \"Country\": {\n \"@comment\": \"A Country \",\n \"@label\": \"Country\"\n },\n \"postalCode\": {\n \"@comment\": \"A valid Postal Code\",\n \"@label\": \"Zip Code\"\n }\n }\n },\n {\n \"@comment\": \"მისამართი\",\n \"@label\": \"მისამართი\",\n \"@language\": \"ka\",\n \"@properties\": {\n \"AddressLine1\": {\n \"@comment\": \"მისამართის ხაზი პირველი\",\n \"@label\": \"მისამართის ხაზი 1\"\n },\n \"Country\": {\n \"@comment\": \"Ქვეყანა\",\n \"@label\": \"ქვეყანა\"\n },\n \"postalCode\": {\n \"@comment\": \"მოქმედი საფოსტო კოდი\",\n \"@label\": \"Ზიპ კოდი\"\n }\n }\n }\n ],\n \"@key\": {\n \"@type\": \"Random\"\n },\n \"@subdocument\": [],\n \"@type\": \"Class\",\n \"AddressLine1\": \"xsd:string\",\n \"City\": {\n \"@class\": \"xsd:string\",\n \"@type\": \"Optional\"\n },\n \"Country\": \"xsd:string\",\n \"postalCode\": \"xsd:string\"\n },\n \"Person\": {\n \"@documentation\": {\n \"@comment\": \"\",\n \"@properties\": {\n \"above18\": \"18 plus\",\n \"permanentAddress\": \"Permanent Address\"\n }\n },\n \"@key\": {\n \"@type\": \"Random\"\n },\n \"@type\": \"Class\",\n \"Birthday\": \"xsd:dateTime\",\n \"PhoneNumber\": \"xsd:decimal\",\n \"Today\": \"xsd:dateTime\",\n \"above18\": \"xsd:boolean\",\n \"age\": \"xsd:decimal\",\n \"email\": \"xsd:string\",\n \"name\": \"xsd:string\",\n \"permanentAddress\": {\n \"@class\": \"Address\",\n \"@subdocument\": []\n },\n \"website\": \"xsd:string\"\n }\n }\n```\n\n### Create\n\n```python\nimport { FrameViewer } from '@terminusdb/terminusdb-documents-ui'\n\n return // type of document \n```\n\n### Edit & View\n\nNote - make sure to provide document values for View mode. The form will be in read only mode for View.\n\n```javascript\n let data = {\n \"@id\": \"Person/72a8a2778bafbc4290f59ca851e0307c6918f7205207d93ac1b2a1f796a94587\",\n \"@type\": \"Person\",\n \"Birthday\": \"2022-08-15T12:59:46Z\",\n \"PhoneNumber\": 353912839283123140,\n \"Today\": \"2022-08-15T12:59:50Z\",\n \"above18\": true,\n \"age\": 22,\n \"email\": \"rack@gmail.com\",\n \"name\": \"John Rock\",\n \"permanentAddress\": {\n \"@id\": \"Person/72a8a2778bafbc4290f59ca851e0307c6918f7205207d93ac1b2a1f796a94587/permanentAddress/Address/5879ec85b65bb0caaa03f48e99073a9d4302c31ec3c3a382889a12980899e95f\",\n \"@type\": \"Address\",\n \"AddressLine1\": \"somewhere in Europe\",\n \"Country\": \"New Zeeland\",\n \"City\": \"City\",\n \"postalCode\": \"NZ29038\"\n },\n \"website\": \"rack@rocking.com\"\n }\n\n return \n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Mandatory Properties in the Document UI", + "description": "How mandatory properties work in the document user interface.", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "One Of" + }, + "slug": "oneof", + "body": { + "@type": "Body", + "value": "This example shows how `` appears for a document called `Graduate` with a one of field in Create/ Edit and View mode. The value of the @oneOf field is a set, so can be any number of documents all of which have mutually disjointed properties, but which can coexist.\n\nIn this example `Graduate` has a property `scored` that points to `Grades`. `Grades` is defined as @oneOf that is an array of documents which can take any choice within. In this example, `Grades` can take any choice from `grade`, `marks` or `report`.\n\n## Demo\n\nTake a look at the [**Demo Playground**](https://documents-ui-playground.terminusdb.com/OneOfs) to view the `` with the OneOfs properties in Create, Edit and View mode.\n\n## Frame\n\nThis frame consists of a Graduate document -\n\n```javascript\n let frame = {\n \"@context\": {\n \"@base\": \"terminusdb:///data/\",\n \"@schema\": \"terminusdb:///schema#\",\n \"@type\": \"Context\",\n \"xsd\": \"http://www.w3.org/2001/XMLSchema#\"\n },\n \"Grades\": {\n \"@documentation\": [\n {\n \"@comment\": \"Grades of a person\",\n \"@label\": \"Grades\",\n \"@language\": \"en\",\n \"@properties\": {\n \"grade\": {\n \"@comment\": \"Grades achieved\",\n \"@label\": \"Grade\"\n },\n \"marks\": {\n \"@comment\": \"Marks achieved\",\n \"@label\": \"Marks\"\n },\n \"report\": {\n \"@comment\": \"Report Card\",\n \"@label\": \"Report\"\n }\n }\n },\n {\n \"@comment\": \"პიროვნების კლასები\",\n \"@label\": \"შეფასებები\",\n \"@language\": \"ka\",\n \"@properties\": {\n \"grade\": {\n \"@comment\": \"მიღწეული ქულები\",\n \"@label\": \"შეფასება\"\n },\n \"marks\": {\n \"@comment\": \"მიღწეული ნიშნები\",\n \"@label\": \"ნიშნები\"\n },\n \"report\": {\n \"@comment\": \"მოსწრების ფურცელი\",\n \"@label\": \"ანგარიში\"\n }\n }\n }\n ],\n \"@key\": {\n \"@type\": \"Random\"\n },\n \"@oneOf\": [\n {\n \"grade\": \"xsd:string\",\n \"marks\": \"xsd:decimal\",\n \"report\": {\n \"@class\": \"GradeReport\",\n \"@subdocument\": []\n }\n }\n ],\n \"@subdocument\": [],\n \"@type\": \"Class\"\n },\n \"Graduate\": {\n \"@key\": {\n \"@type\": \"Random\"\n },\n \"@type\": \"Class\",\n \"scored\": {\n \"@class\": {\n \"@class\": \"Grades\",\n \"@subdocument\": []\n },\n \"@type\": \"Optional\"\n }\n }\n }\n```\n\n### Create\n\n```python\nimport { FrameViewer } from '@terminusdb/terminusdb-documents-ui'\n\n return // type of document \n```\n\n### Edit & View\n\nNote - make sure to provide document values for View mode. The form will be in read only mode for View.\n\n```javascript\nlet data = {\n \"@id\": \"Graduate/efb4f89c825dd2c6404b5998b0d170b1df9a250103d7556833c3017e2107da23\",\n \"@type\": \"Graduate\",\n \"scored\": {\n \"@id\": \"Graduate/efb4f89c825dd2c6404b5998b0d170b1df9a250103d7556833c3017e2107da23/scored/Grades/8079b8089b18a97dab9d4af3bffd496f744841bf7b72caaa4a2a2f189fc496b7\",\n \"@type\": \"Grades\",\n \"report\": {\n \"@id\": \"Graduate/efb4f89c825dd2c6404b5998b0d170b1df9a250103d7556833c3017e2107da23/scored/Graduate/efb4f89c825dd2c6404b5998b0d170b1df9a250103d7556833c3017e2107da23/scored/Grades/8079b8089b18a97dab9d4af3bffd496f744841bf7b72caaa4a2a2f189fc496b7/report/GradeReport/d947ef4e4a261ef6e469b9e24c944c58405e49952fe45b8f50852b650481aec1\",\n \"@type\": \"GradeReport\",\n \"comments\": \"Outstanding \",\n \"score\": \"Outstanding\"\n }\n }\n}\n\nreturn \n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "One Of Documents in the Document UI", + "description": "An example of how one of properties work in the document UI", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Optional Properties" + }, + "slug": "optional", + "body": { + "@type": "Body", + "value": "This example shows how `` appears for a document `Person_Optional` with optional fields in Create/ Edit and View mode.\n\n## Demo\n\nTake a look at the [**Demo Playground**](https://documents-ui-playground.terminusdb.com/Optional)\\*\\* to view `` with Optional properties in Create, Edit and View mode.\n\n## Frame\n\nThis frame consists of a `Person` document\n\n```javascript\n let frame = {\n \"@context\": {\n \"@base\": \"terminusdb:///data/\",\n \"@schema\": \"terminusdb:///schema#\",\n \"@type\": \"Context\",\n \"xsd\": \"http://www.w3.org/2001/XMLSchema#\"\n },\n \"Address\": {\n \"@documentation\": [\n {\n \"@comment\": \"An Address\",\n \"@label\": \"Address\",\n \"@language\": \"en\",\n \"@properties\": {\n \"AddressLine1\": {\n \"@comment\": \"Address Line one\",\n \"@label\": \"Address Line 1\"\n },\n \"Country\": {\n \"@comment\": \"A Country \",\n \"@label\": \"Country\"\n },\n \"postalCode\": {\n \"@comment\": \"A valid Postal Code\",\n \"@label\": \"Zip Code\"\n }\n }\n },\n {\n \"@comment\": \"მისამართი\",\n \"@label\": \"მისამართი\",\n \"@language\": \"ka\",\n \"@properties\": {\n \"AddressLine1\": {\n \"@comment\": \"მისამართის ხაზი პირველი\",\n \"@label\": \"მისამართის ხაზი 1\"\n },\n \"Country\": {\n \"@comment\": \"Ქვეყანა\",\n \"@label\": \"ქვეყანა\"\n },\n \"postalCode\": {\n \"@comment\": \"მოქმედი საფოსტო კოდი\",\n \"@label\": \"Ზიპ კოდი\"\n }\n }\n }\n ],\n \"@key\": {\n \"@type\": \"Random\"\n },\n \"@subdocument\": [],\n \"@type\": \"Class\",\n \"AddressLine1\": \"xsd:string\",\n \"City\": {\n \"@class\": \"xsd:string\",\n \"@type\": \"Optional\"\n },\n \"Country\": \"xsd:string\",\n \"postalCode\": \"xsd:string\"\n },\n \"Person_Optional\": {\n \"@documentation\": {\n \"@comment\": \"\",\n \"@properties\": {\n \"above18\": \"18 plus\",\n \"permanentAddress\": \"Permanent Address\"\n }\n },\n \"@key\": {\n \"@type\": \"Random\"\n },\n \"@type\": \"Class\",\n \"Birthday\": {\n \"@class\": \"xsd:dateTime\",\n \"@type\": \"Optional\"\n },\n \"PhoneNumber\": {\n \"@class\": \"xsd:decimal\",\n \"@type\": \"Optional\"\n },\n \"Today\": {\n \"@class\": \"xsd:dateTime\",\n \"@type\": \"Optional\"\n },\n \"above18\": {\n \"@class\": \"xsd:boolean\",\n \"@type\": \"Optional\"\n },\n \"age\": {\n \"@class\": \"xsd:decimal\",\n \"@type\": \"Optional\"\n },\n \"email\": {\n \"@class\": \"xsd:string\",\n \"@type\": \"Optional\"\n },\n \"name\": {\n \"@class\": \"xsd:string\",\n \"@type\": \"Optional\"\n },\n \"permanentAddress\": {\n \"@class\": {\n \"@class\": \"Address\",\n \"@subdocument\": []\n },\n \"@type\": \"Optional\"\n },\n \"website\": {\n \"@class\": \"xsd:string\",\n \"@type\": \"Optional\"\n }\n }\n }\n```\n\n#### Create\n\n```python\nimport { FrameViewer } from '@terminusdb/terminusdb-documents-ui'\n\n return // type of document \n```\n\n#### Edit & View\n\nNote - make sure to provide document values for View mode. The form will be in read only mode for View.\n\n```javascript\n let data = {\n \"@id\": \"Person_Optional/72a8a2778bafbc4290f59ca851e0307c6918f7205207d93ac1b2a1f796a94587\",\n \"@type\": \"Person_Optional\",\n \"Birthday\": \"2022-08-15T12:59:46Z\",\n \"PhoneNumber\": 353912839283123140,\n \"Today\": \"2022-08-15T12:59:50Z\",\n \"above18\": true,\n \"age\": 22,\n \"email\": \"rack@gmail.com\",\n \"name\": \"John Rock\",\n \"permanentAddress\": {\n \"@id\": \"Person_Optional/72a8a2778bafbc4290f59ca851e0307c6918f7205207d93ac1b2a1f796a94587/permanentAddress/Address/5879ec85b65bb0caaa03f48e99073a9d4302c31ec3c3a382889a12980899e95f\",\n \"@type\": \"Address\",\n \"AddressLine1\": \"somewhere in Europe\",\n \"Country\": \"New Zeeland\",\n \"City\": \"City\",\n \"postalCode\": \"NZ29038\"\n },\n \"website\": \"rack@rocking.com\"\n }\n\n return \n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Optional Properties - Document UI TerminusDB", + "description": "How optional properties work in the document UI", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Order By Using @metadata" + }, + "slug": "orderby", + "body": { + "@type": "Body", + "value": "This example shows how `` appears for a document `OrderByExample` in Create/ Edit and View mode.\n\nThe Frame below to shows `@metadata` with an `order_by` tag which tells `` to order fields according to the `order_by` array. Note there is a `@metadata` tag in the `SubBody` class definition which also tells `` to order the subdocument's internal fields in the order included in the `@metadata` `order_by` array.\n\n## Demo\n\nTake a look at the [**Demo Playground**](https://documents-ui-playground.terminusdb.com/Order%20By) to view `` with properties where order\\_by is defined in the `@metadata` tag - in Create, Edit and view mode.\n\n## Frame\n\nThis frame consists of an `OrderByExample` document\n\n```javascript\n let frame = {\n \"@context\": {\n \"@base\": \"terminusdb:///data/\",\n \"@schema\": \"terminusdb:///schema#\",\n \"@type\": \"Context\",\n \"xsd\": \"http://www.w3.org/2001/XMLSchema#\"\n },\n \"OrderByExample\": {\n \"@key\": {\n \"@fields\": [\n \"title\"\n ],\n \"@type\": \"Lexical\",\n },\n \"@type\": \"Class\",\n \"@metadata\": {\n \"order_by\": [ \"num_lines\", \"paragh\", \"body\", \"title\" ] \n },\n \"paragh\": \"xsd:string\",\n \"title\": \"xsd:string\",\n \"num_lines\": \"xsd:decimal\",\n \"body\": {\n \"@class\": \"SubBody\",\n \"@subdocument\": []\n }\n },\n \"SubBody\": {\n \"@key\": {\n \"@type\": \"Random\"\n },\n \"@metadata\": {\n \"order_by\": [ \"section\", \"url\", \"text\" ]\n },\n \"@subdocument\": [],\n \"@type\": \"Class\",\n \"text\": \"xsd:string\",\n \"section\": \"xsd:string\",\n \"url\": \"xsd:url\"\n }\n } \n```\n\n### Create\n\n```python\nimport { FrameViewer } from '@terminusdb/terminusdb-documents-ui'\n\n return // type of document \n```\n\n### Edit & View\n\nNote - make sure to provide document values for View mode. The form will be in read only mode for View.\n\n```javascript\nlet data = {\n \"@id\": \"OrderByExample/431b3406a64d99714b57133019408a16a6a514755fb229aff01419b4b423cb62\",\n \"@type\": \"OrderByExample\",\n \"paragh\": \"An example showing field ordered\",\n \"title\": \"ordering example\",\n \"num_lines\": \"23\",\n \"body\": {\n \"@id\": \"SubBody/72a8a2778bafbc4290f59ca851e0307c6918f7205207d93ac1b2a1f796a94587/body/SubBody/5879ec85b65bb0caaa03f48e99073a9d4302c31ec3c3a382889a12980899e95f\",\n \"@type\": \"SubBody\",\n \"text\": \"sample text\",\n \"section\": \"a section\",\n \"url\": \"https://terminusdb.com/\"\n },\n}\n\n\nreturn \n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Order By Using @metadata", + "description": "How to order properties in the document UI", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Render As Markdown Using @metadata" + }, + "slug": "render-as", + "body": { + "@type": "Body", + "value": "This example shows how `` appears for a document `metaDataExample` with the fields `body` & `title` in Create/ Edit or View mode. The Frame below shows `@metadata` with the `render_as` tag included that tells `` to render field `body` as Markdown.\n\n## Demo\n\nTake a look at the [**Demo Playground**](https://documents-ui-playground.terminusdb.com/Render%20As) to view `` with properties where render\\_as is defined in @metadata tag - in Create, Edit or View mode.\n\n## Frame\n\nThis frame consists of an `metaDataExample` document\n\n```javascript\n let frame = {\n \"@context\": {\n \"@base\": \"terminusdb:///data/\",\n \"@schema\": \"terminusdb:///schema#\",\n \"@type\": \"Context\",\n \"xsd\": \"http://www.w3.org/2001/XMLSchema#\"\n },\n \"metaDataExample\": {\n \"@key\": {\n \"@fields\": [\n \"title\"\n ],\n \"@type\": \"Lexical\",\n },\n \"@type\": \"Class\",\n \"@metadata\": {\n \"render_as\": {\n \"body\": \"markdown\"\n }\n },\n \"body\": \"xsd:string\",\n \"title\": \"xsd:string\"\n }\n } \n```\n\n### Create\n\n```python\nimport { FrameViewer } from '@terminusdb/terminusdb-documents-ui'\n\n return // type of document \n```\n\n### Edit & View\n\nNote - make sure to provide document values for View mode. The form will be in read only mode for View.\n\n```javascript\nlet data = {\n \"@id\": \"metaDataExample/431b3406a64d99714b57133019408a16a6a514755fb229aff01419b4b423cb62\",\n \"@type\": \"metaDataExample\",\n \"title\": \"Example\",\n \"body\": \"---\\ndescription: >-\\n This page provides an overview of the TerminusCMS dashboard to help you\\n navigate its features.\\n---\\n\\n# Product Tour\\n\\nTerminusCMS includes many features to build content infrastructures for complex environments. This product tour aims to provide you with an understanding of how to navigate the product and get started on your projects. \\n\\n* [Creating projects, managing them, and designing your schema](projects-data-products.md)\\n* [Content and data curation](content-and-data-curation.md)\\n* [Change request workflows for collaborative content management](change-request-workflows.md)\\n* [Managing teams and users](manage-teams-and-users.md)\\n* [GraphQL and WOQL playgrounds to build and test queries](graphql-and-woql-playgrounds.md)\\n\\n### Sign Up and Try Out a Demo Project \\n\\nSign up for TerminusCMS for free at: [https://dashboard.terminusdb.com](https://dashboard.terminusdb.com).\\n\\nVerify your email address by clicking on the link emailed to you and logging in.\\n\\nClick get started on the Community Package and then select the automatically generated team. \\n\\nFrom here, clone one of the demo projects to play around with -\\n\\n
\\\"\\\"
\"\n}\n\n\nreturn \n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Render As Markdown Using @metadata", + "description": "How to render properties as markdown in the document UI", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Set Properties in the Document UI" + }, + "slug": "set", + "body": { + "@type": "Body", + "value": "This example shows how `` appears for a document `UnorderedPerson` with set fields in Create/ Edit or View mode. If a field is described as a Set it means the field can have more than one value to it in any unordered fashion. The field can also be considered optional, meaning it can be empty.\n\n## Demo\n\nTake a look at the [**Demo Playground**](https://documents-ui-playground.terminusdb.com/Set) to view `` with set properties in Create, Edit or View mode.\n\n## Frame\n\nThis frame consists of an `UnorderedPerson` document\n\n```javascript\n let frame = {\n \"@context\": {\n \"@base\": \"terminusdb:///data/\",\n \"@schema\": \"terminusdb:///schema#\",\n \"@type\": \"Context\",\n \"xsd\": \"http://www.w3.org/2001/XMLSchema#\"\n },\n \"Address\": {\n \"@documentation\": [\n {\n \"@comment\": \"An Address\",\n \"@label\": \"Address\",\n \"@language\": \"en\",\n \"@properties\": {\n \"AddressLine1\": {\n \"@comment\": \"Address Line one\",\n \"@label\": \"Address Line 1\"\n },\n \"Country\": {\n \"@comment\": \"A Country \",\n \"@label\": \"Country\"\n },\n \"postalCode\": {\n \"@comment\": \"A valid Postal Code\",\n \"@label\": \"Zip Code\"\n }\n }\n },\n {\n \"@comment\": \"მისამართი\",\n \"@label\": \"მისამართი\",\n \"@language\": \"ka\",\n \"@properties\": {\n \"AddressLine1\": {\n \"@comment\": \"მისამართის ხაზი პირველი\",\n \"@label\": \"მისამართის ხაზი 1\"\n },\n \"Country\": {\n \"@comment\": \"Ქვეყანა\",\n \"@label\": \"ქვეყანა\"\n },\n \"postalCode\": {\n \"@comment\": \"მოქმედი საფოსტო კოდი\",\n \"@label\": \"Ზიპ კოდი\"\n }\n }\n }\n ],\n \"@key\": {\n \"@type\": \"Random\"\n },\n \"@subdocument\": [],\n \"@type\": \"Class\",\n \"AddressLine1\": \"xsd:string\",\n \"City\": {\n \"@class\": \"xsd:string\",\n \"@type\": \"Optional\"\n },\n \"Country\": \"xsd:string\",\n \"postalCode\": \"xsd:string\"\n },\n \"UnorderedPerson\": {\n \"@key\": {\n \"@type\": \"Random\"\n },\n \"@type\": \"Class\",\n \"likes_color\": {\n \"@class\": {\n \"@id\": \"Colors\",\n \"@type\": \"Enum\",\n \"@values\": [\n \"Red\",\n \"Blue\",\n \"Yellow\",\n \"Green\"\n ]\n },\n \"@type\": \"Set\"\n },\n \"lived_at\": {\n \"@class\": {\n \"@class\": \"Address\",\n \"@subdocument\": []\n },\n \"@type\": \"Set\"\n },\n \"nicknames\": {\n \"@class\": \"xsd:string\",\n \"@type\": \"Set\"\n },\n \"worked_as\": {\n \"@class\": \"Jobs\",\n \"@type\": \"Set\"\n }\n }\n }\n```\n\n### Create\n\n```python\nimport { FrameViewer } from '@terminusdb/terminusdb-documents-ui'\n\n return // type of document \n```\n\n### Edit & View\n\nNote - make sure to provide document values for View mode. The form will be in read only mode for View.\n\n```javascript\nlet data = {\n \"@id\": \"UnorderedPerson/3ca7d7a9c64ca2bc8319d83bca14b71697528ebb8536024e3e1795cbd049acdf\",\n \"@type\": \"UnorderedPerson\",\n \"likes_color\": [\n \"Green\",\n \"Red\",\n \"Yellow\"\n ],\n \"lived_at\": [\n {\n \"@id\": \"UnorderedPerson/3ca7d7a9c64ca2bc8319d83bca14b71697528ebb8536024e3e1795cbd049acdf/lived_at/Address/4f4fdae34ab4fa3b6297750917503a7137f75dc11589792de707e7a6d3502db3\",\n \"@type\": \"Address\",\n \"AddressLine1\": \"anywhere\",\n \"City\": \"Nice\", \n \"Country\": \"France\",\n \"postalCode\": \"FR27836\"\n },\n {\n \"@id\": \"UnorderedPerson/3ca7d7a9c64ca2bc8319d83bca14b71697528ebb8536024e3e1795cbd049acdf/lived_at/Address/7aaeeb6b983710a0adbc75de8f7d8104278df427124beadc6644b35b9d6c30af\",\n \"@type\": \"Address\",\n \"AddressLine1\": \"somewhere\",\n \"City\": \"Berlin\", \n \"Country\": \"Germany\",\n \"postalCode\": \"GER02398\"\n }\n ],\n \"nicknames\": [\n \"Adam\",\n \"Chane\",\n \"Luca\"\n ],\n \"worked_as\": [\n \"Jobs/33e3013112e6e76381ee6aba23a15f686b98fc2c300b3608e6fb25f585d93d24\",\n \"Jobs/c8114bddb166325e704e368da237ed87e1c2de1dd23ae103431f974eaeefbbda\"\n ]\n}\n\nreturn \n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Set Properties in the Document UI", + "description": "How to use set properties in the document UI", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "sys:JSON Properties in the Document UI" + }, + "slug": "sysjson", + "body": { + "@type": "Body", + "value": "This example shows how `` appears for a document `ComputerStudent` with sys:JSON field in Create/ Edit or View mode.\n\n`ComputerStudent` has a required mandatory field `likes` and a set field `stores_as`.\n\n## Demo\n\nTake a look at the [**Demo Playground**](https://documents-ui-playground.terminusdb.com/JSON) to view `` with sys:JSON properties in Create, Edit or View mode.\n\n## Frame\n\nThis frame consists of an ComputerStudent document\n\n```javascript\n let frame = {\n \"@context\": {\n \"@base\": \"terminusdb:///data/\",\n \"@schema\": \"terminusdb:///schema#\",\n \"@type\": \"Context\",\n \"xsd\": \"http://www.w3.org/2001/XMLSchema#\"\n },\n \"ComputerStudent\": {\n \"@key\": {\n \"@type\": \"Random\"\n },\n \"@type\": \"Class\",\n \"likes\": \"sys:JSON\",\n \"stores_as\": {\n \"@class\": \"sys:JSON\",\n \"@type\": \"Set\"\n }\n }\n}\n```\n\n### Create\n\n```python\nimport { FrameViewer } from '@terminusdb/terminusdb-documents-ui'\n\n return // type of document \n```\n\n### Edit & View\n\nNote - make sure to provide document values for View mode. The form will be in read only mode for View.\n\n```javascript\nlet data = {\n \"@id\": \"ComputerStudent/431b3406a64d99714b57133019408a16a6a514755fb229aff01419b4b423cb62\",\n \"@type\": \"ComputerStudent\",\n \"likes\": {\n \"age\": 39,\n \"name\": \"Madame Uppercut\",\n \"powers\": [\"Million tonne punch\", \"Damage resistance\", \"Superhuman reflexes\"],\n \"secretIdentity\": \"Jane Wilson\"\n },\n \"stores_as\": [\n {\n \"name\": \"Molecule Man\",\n \"age\": 29,\n \"secretIdentity\": \"Dan Jukes\",\n \"powers\": [\n \"Radiation resistance\",\n \"Turning tiny\",\n \"Radiation blast\"\n ]\n },\n {\n \"name\": \"Eternal Flame\",\n \"age\": 1000000,\n \"secretIdentity\": \"Unknown\",\n \"powers\": [\n \"Immortality\",\n \"Heat Immunity\",\n \"Inferno\",\n \"Teleportation\",\n \"Interdimensional travel\"\n ]\n }\n ]\n}\n\n\nreturn \n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "sys:JSON Properties in the Document UI ", + "description": "How to use sys:JSON properties in the document UI", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "UI SDK GeoJSON" + }, + "slug": "ui-sdk-geojson", + "body": { + "@type": "Body", + "value": "#### Demo\n\nTake a look at the [**GeoJSON Playground**](https://documents-ui-playground-geojson.terminusdb.com/Feature) to view the `` demo in create, edit or view mode.\n\n### GeoJSON Schema\n\nBelow is the schema for loading geoJSON into a TerminusDB data product.\n\n```\n[\n {\n \"@base\": \"terminusdb:///data/\",\n \"@schema\": \"terminusdb:///schema#\",\n \"@type\": \"@context\"\n },\n { \"@type\" : \"Class\",\n \"@id\" : \"GeoJSON\",\n \"@abstract\" : [],\n \"bbox\" : { \"@class\" : \"xsd:decimal\",\n \"@dimensions\" : 1,\n \"@type\" : \"Array\" }\n },\n { \"@type\" : \"Class\",\n \"@id\" : \"FeatureCollection\",\n \"@inherits\": \"GeoJSON\",\n \"@key\" : { \"@type\" : \"Random\" },\n \"@unfoldable\" : [],\n \"name\" : { \"@type\" : \"Optional\",\n \"@class\" : \"xsd:string\" },\n \"type\": \"FeatureCollection_Type\",\n \"crs\" : { \"@type\" : \"Optional\",\n \"@class\" : \"sys:JSON\" },\n \"properties\" : { \"@type\" : \"Optional\",\n \"@class\" : \"sys:JSON\" },\n \"features\" : { \"@type\" : \"Set\",\n \"@class\": \"Feature\"}\n },\n {\n \"@id\": \"Polygon\",\n \"@inherits\": \"Geometry\",\n \"@type\": \"Class\",\n \"coordinates\": {\n \"@class\": \"xsd:decimal\",\n \"@dimensions\": 3,\n \"@type\": \"Array\"\n },\n \"type\": \"Polygon_Type\"\n },\n { \"@type\" : \"Class\",\n \"@id\" : \"Geometry\",\n \"@inherits\": \"GeoJSON\",\n \"@abstract\" : [],\n \"@unfoldable\" : []\n },\n {\n \"@id\": \"GeometryCollection_Type\",\n \"@type\": \"Enum\",\n \"@value\": [\n \"GeometryCollection\"\n ]\n },\n {\n \"@id\": \"GeometryCollection\",\n \"@inherits\": \"Geometry\",\n \"@type\": \"Class\",\n \"geometries\": {\n \"@class\": \"Geometry\",\n \"@type\": \"Set\"\n },\n \"type\": \"GeometryCollection_Type\"\n },\n {\n \"@id\": \"MultiPolygon\",\n \"@inherits\": \"Geometry\",\n \"@type\": \"Class\",\n \"coordinates\": {\n \"@class\": \"xsd:double\",\n \"@dimensions\": 4,\n \"@type\": \"Array\"\n },\n \"type\": \"MultiPolygon_Type\"\n },\n {\n \"@id\": \"LineString\",\n \"@inherits\": \"Geometry\",\n \"@type\": \"Class\",\n \"coordinates\": {\n \"@class\": \"xsd:double\",\n \"@dimensions\": 2,\n \"@type\": \"Array\"\n },\n \"type\": \"LineString_Type\"\n },\n {\n \"@id\": \"Point\",\n \"@inherits\": \"Geometry\",\n \"@type\": \"Class\",\n \"coordinates\": {\n \"@class\": \"xsd:double\",\n \"@dimensions\": 1,\n \"@type\": \"Array\"\n },\n \"type\": \"Point_Type\"\n },\n {\n \"@id\": \"Polygon_Type\",\n \"@type\": \"Enum\",\n \"@value\": [\n \"Polygon\"\n ]\n },\n {\n \"@id\": \"Point_Type\",\n \"@type\": \"Enum\",\n \"@value\": [\n \"Point\"\n ]\n },\n {\n \"@id\": \"MultiPolygon_Type\",\n \"@type\": \"Enum\",\n \"@value\": [\n \"MultiPolygon\"\n ]\n },\n {\n \"@id\": \"Name_Type\",\n \"@type\": \"Enum\",\n \"@value\": [\n \"name\"\n ]\n },\n {\n \"@id\": \"LineString_Type\",\n \"@type\": \"Enum\",\n \"@value\": [\n \"LineString\"\n ]\n },\n {\n \"@id\": \"Feature_Type\",\n \"@type\": \"Enum\",\n \"@value\": [\n \"Feature\"\n ]\n },\n {\n \"@id\": \"FeatureCollection_Type\",\n \"@type\": \"Enum\",\n \"@value\": [\n \"FeatureCollection\"\n ]\n },\n {\n \"@id\": \"Feature\",\n \"@type\": \"Class\",\n \"@inherits\": \"GeoJSON\",\n \"@unfoldable\": [],\n \"centerline\": {\n \"@class\": \"Geometry\",\n \"@type\": \"Optional\"\n },\n \"geometry\": \"Geometry\",\n \"id\": {\n \"@class\": \"xsd:string\",\n \"@type\": \"Optional\"\n },\n \"properties\": { \"@type\" : \"Optional\",\n \"@class\" : \"sys:JSON\" },\n \"title\": {\n \"@class\": \"xsd:string\",\n \"@type\": \"Optional\"\n },\n \"type\": \"Feature_Type\"\n }\n]\n```\n\n### GeoJSON Frames\n\nThe equivalent geoJSON frame that can be retrieved from `getSchemaFrame()` call\n\n```\n{\n \"@context\": {\n \"@base\": \"terminusdb:///data/\",\n \"@schema\": \"terminusdb:///schema#\",\n \"@type\": \"Context\"\n },\n \"Feature\": {\n \"@inherits\": [\n \"GeoJSON\"\n ],\n \"@type\": \"Class\",\n \"@unfoldable\": [],\n \"bbox\": {\n \"@class\": \"xsd:decimal\",\n \"@dimensions\": 1,\n \"@type\": \"Array\"\n },\n \"centerline\": {\n \"@class\": [\n \"GeometryCollection\",\n \"LineString\",\n \"MultiPolygon\",\n \"Point\",\n \"Polygon\"\n ],\n \"@type\": \"Optional\"\n },\n \"geometry\": [\n \"GeometryCollection\",\n \"LineString\",\n \"MultiPolygon\",\n \"Point\",\n \"Polygon\"\n ],\n \"id\": {\n \"@class\": \"xsd:string\",\n \"@type\": \"Optional\"\n },\n \"properties\": {\n \"@class\": \"sys:JSON\",\n \"@type\": \"Optional\"\n },\n \"title\": {\n \"@class\": \"xsd:string\",\n \"@type\": \"Optional\"\n },\n \"type\": {\n \"@id\": \"Feature_Type\",\n \"@type\": \"Enum\",\n \"@values\": [\n \"Feature\"\n ]\n }\n },\n \"FeatureCollection\": {\n \"@inherits\": [\n \"GeoJSON\"\n ],\n \"@key\": {\n \"@type\": \"Random\"\n },\n \"@type\": \"Class\",\n \"@unfoldable\": [],\n \"bbox\": {\n \"@class\": \"xsd:decimal\",\n \"@dimensions\": 1,\n \"@type\": \"Array\"\n },\n \"crs\": {\n \"@class\": \"sys:JSON\",\n \"@type\": \"Optional\"\n },\n \"features\": {\n \"@class\": \"Feature\",\n \"@type\": \"Set\"\n },\n \"name\": {\n \"@class\": \"xsd:string\",\n \"@type\": \"Optional\"\n },\n \"properties\": {\n \"@class\": \"sys:JSON\",\n \"@type\": \"Optional\"\n },\n \"type\": {\n \"@id\": \"FeatureCollection_Type\",\n \"@type\": \"Enum\",\n \"@values\": [\n \"FeatureCollection\"\n ]\n }\n },\n \"FeatureCollection_Type\": {\n \"@type\": \"Enum\",\n \"@values\": [\n \"FeatureCollection\"\n ]\n },\n \"Feature_Type\": {\n \"@type\": \"Enum\",\n \"@values\": [\n \"Feature\"\n ]\n },\n \"GeoJSON\": {\n \"@abstract\": [],\n \"@type\": \"Class\",\n \"bbox\": {\n \"@class\": \"xsd:decimal\",\n \"@dimensions\": 1,\n \"@type\": \"Array\"\n }\n },\n \"Geometry\": {\n \"@abstract\": [],\n \"@inherits\": [\n \"GeoJSON\"\n ],\n \"@type\": \"Class\",\n \"@unfoldable\": [],\n \"bbox\": {\n \"@class\": \"xsd:decimal\",\n \"@dimensions\": 1,\n \"@type\": \"Array\"\n }\n },\n \"GeometryCollection\": {\n \"@inherits\": [\n \"GeoJSON\",\n \"Geometry\"\n ],\n \"@type\": \"Class\",\n \"@unfoldable\": [],\n \"bbox\": {\n \"@class\": \"xsd:decimal\",\n \"@dimensions\": 1,\n \"@type\": \"Array\"\n },\n \"geometries\": {\n \"@class\": [\n \"GeometryCollection\",\n \"LineString\",\n \"MultiPolygon\",\n \"Point\",\n \"Polygon\"\n ],\n \"@type\": \"Set\"\n },\n \"type\": {\n \"@id\": \"GeometryCollection_Type\",\n \"@type\": \"Enum\",\n \"@values\": [\n \"GeometryCollection\"\n ]\n }\n },\n \"GeometryCollection_Type\": {\n \"@type\": \"Enum\",\n \"@values\": [\n \"GeometryCollection\"\n ]\n },\n \"LineString\": {\n \"@inherits\": [\n \"GeoJSON\",\n \"Geometry\"\n ],\n \"@type\": \"Class\",\n \"@unfoldable\": [],\n \"bbox\": {\n \"@class\": \"xsd:decimal\",\n \"@dimensions\": 1,\n \"@type\": \"Array\"\n },\n \"coordinates\": {\n \"@class\": \"xsd:double\",\n \"@dimensions\": 2,\n \"@type\": \"Array\"\n },\n \"type\": {\n \"@id\": \"LineString_Type\",\n \"@type\": \"Enum\",\n \"@values\": [\n \"LineString\"\n ]\n }\n },\n \"LineString_Type\": {\n \"@type\": \"Enum\",\n \"@values\": [\n \"LineString\"\n ]\n },\n \"MultiPolygon\": {\n \"@inherits\": [\n \"GeoJSON\",\n \"Geometry\"\n ],\n \"@type\": \"Class\",\n \"@unfoldable\": [],\n \"bbox\": {\n \"@class\": \"xsd:decimal\",\n \"@dimensions\": 1,\n \"@type\": \"Array\"\n },\n \"coordinates\": {\n \"@class\": \"xsd:double\",\n \"@dimensions\": 4,\n \"@type\": \"Array\"\n },\n \"type\": {\n \"@id\": \"MultiPolygon_Type\",\n \"@type\": \"Enum\",\n \"@values\": [\n \"MultiPolygon\"\n ]\n }\n },\n \"MultiPolygon_Type\": {\n \"@type\": \"Enum\",\n \"@values\": [\n \"MultiPolygon\"\n ]\n },\n \"Name_Type\": {\n \"@type\": \"Enum\",\n \"@values\": [\n \"name\"\n ]\n },\n \"Point\": {\n \"@inherits\": [\n \"GeoJSON\",\n \"Geometry\"\n ],\n \"@type\": \"Class\",\n \"@unfoldable\": [],\n \"bbox\": {\n \"@class\": \"xsd:decimal\",\n \"@dimensions\": 1,\n \"@type\": \"Array\"\n },\n \"coordinates\": {\n \"@class\": \"xsd:double\",\n \"@dimensions\": 1,\n \"@type\": \"Array\"\n },\n \"type\": {\n \"@id\": \"Point_Type\",\n \"@type\": \"Enum\",\n \"@values\": [\n \"Point\"\n ]\n }\n },\n \"Point_Type\": {\n \"@type\": \"Enum\",\n \"@values\": [\n \"Point\"\n ]\n },\n \"Polygon\": {\n \"@inherits\": [\n \"GeoJSON\",\n \"Geometry\"\n ],\n \"@type\": \"Class\",\n \"@unfoldable\": [],\n \"bbox\": {\n \"@class\": \"xsd:decimal\",\n \"@dimensions\": 1,\n \"@type\": \"Array\"\n },\n \"coordinates\": {\n \"@class\": \"xsd:decimal\",\n \"@dimensions\": 3,\n \"@type\": \"Array\"\n },\n \"type\": {\n \"@id\": \"Polygon_Type\",\n \"@type\": \"Enum\",\n \"@values\": [\n \"Polygon\"\n ]\n }\n },\n \"Polygon_Type\": {\n \"@type\": \"Enum\",\n \"@values\": [\n \"Polygon\"\n ]\n }\n}\n```\n\n### **Demo**\n\nTake a look at the [**Demo Playground**](https://documents-ui-playground-geojson.terminusdb.com/) to view `` with geoJSON data.\n\n### Example\n\nThis example shows how to load a `FeartureCollection` into ``.\n\n> Note: In View mode we display the map view of geoJSONs using react-leaflets under the hood.\n\n```python\nimport { FrameViewer } from '@terminusdb/terminusdb-documents-ui'\n\n return // type of document \n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "UI SDK GeoJSON", + "description": "Understand how can load geoJSON to display geographic data structures in Create, Edit or View Mode", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Document UI Template" + }, + "slug": "document-ui-template", + "body": { + "@type": "Body", + "value": "A Software Development Kit (SDK) to build a UI from @terminusdb/terminusdb-documents-ui and the @terminusdb/terminusdb-react-table.\n\nThis template has components to assemble a dashboard quickly. You also have the option to use our base components like the FramesViewer and TDBReactTable.\n\n## Installation\n\nInstall the dependencies from npm\n\n```\nnpm install @terminusdb/terminusdb-documents-ui\nnpm install @terminusdb/terminusdb-react-table\nnpm install @terminusdb/terminusdb-documents-ui-templates\n```\n\n## Run a Dashboard Example in Code Sandbox\n\n`terminusdb-documents-ui-templates` are a collection of hooks to connect with the TerminusCMS server and a number of templates (components) for building a dashboard.\n\nThe sandbox features an example and how to use the components and hooks to assemble your pages.\n\n[Source Code](https://github.com/terminusdb/dashboard-examples-sandbox/tree/main/terminusdb-documents-ui-template-example/dashboard-demo)\n\n[Code Sandbox](https://codesandbox.io/s/github/terminusdb/dashboard-examples-sandbox/tree/main/terminusdb-documents-ui-template-example/dashboard-demo)" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Document UI Template", + "description": "The document ui template has components to assemble a dashboard quickly. ", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "TerminusDB React Table" + }, + "slug": "tdb-react-table", + "body": { + "@type": "Body", + "value": "Learn how to include TerminusDB React Table components in your projects to display documents in an interactive table.\n\n## Installation\n\nThe best way to use @terminusdb/terminusdb-react-table is via the npm package that you can install with npm (or yarn if you prefer).\n\n`npm install @terminusdb/terminusdb-react-table`\n\nThe library has two main components [`TDBReactTable`](#tdbreacttable) and [`AdvancedSearch`](#advancedsearch)\n\n## TDBReactTable\n\n### Properties\n\nProperties\n\nDescription\n\n`start:Number`\n\nThe pagination start value, we view the row from start to start+limit\n\n`limit:Number`\n\nDetermines the amount of rows on any given page, the default value is 10\n\n`totalRows:Number`\n\nThe total number of rows\n\n`result:Array`\n\nThe data array to display in the table\n\n`config`\n\nTable configuration. The main options are `columns:Array` required - The core columns configuration object for the entire table. `rowClick : Function` A function that acts as a callback when the table row is clicked\n\n`orderBy:Array`\n\n\\- An array of sorting objects. The sorting object should contain an `id` key with the corresponding column ID to sort by. An optional `desc` key (defaults to `false`) - this information is stored in state\n\n`filterBy:Array`\n\n\\- An array of objects, each having a column `id` and a corresponding filter `value`. This information is stored in state\n\n`downloadConfig:Object`\n\n\\- The download config object should contain an filename for the file output, a headersLabel array with the list of columns to add to the files, and a className to style the download button component\n\n`setFilters:Function`\n\n\\- A function that acts as a callback when the columns input filter is filled and the Enter key if pressed, row filters need to be implemented outside of the table\n\n`setOrder:Function`\n\n\\- A function that acts as a callback when the columns sort arrow is clicked. Implement your own sorting outside of the table\n\n`setLimits:Function(currentlimit:Number,currentstart:Number)`\n\n\\- A function that acts as a callback when the pageSize or the pageIndex changes in the table. You should implement your own sorting outside of the table\n\n`setHiddenColumns:Function(id:String, checked:Bool)`\n\n\\- A function that acts as a callback when the hide/show check box if clicked\n\n### Column Options\n\nThe following options are supported on any column object you can pass to columns.\n\nProperties\n\nDescription\n\n`accessor:String`\n\n\\- Function(originalRow, rowIndex) => any - Required - This string/function is used to build the data model for your column.\n\n`id: String`\n\n\\- Required - This is the unique ID for the column. It is used as a reference in things like sorting, grouping, filtering etc.\n\n`Header: String`\n\n\\- Optional, the column title, the id will used if this property is not provided\n\n`width:Number`\n\n\\- Optional\n\n`minWidth: Number`\n\n\\- Optional\n\n`maxWidth: Number`\n\n\\- Optional\n\n`disableSortBy : Bool`\n\n\\- Disables sorting of a column.\n\n`disableFilters:Bool`\n\n\\- Disables filtering of the column.\n\n`renderer: String or Function`\n\n\\- Optional, - The available values for the string value are `json` - `number` - `string` - `image`. If you pass a function instead, this will receive the table instance and cell model as properties and return a JSX object or a string\n\n`filter:Object`\n\n\\- This object should have a `type` property, the available values for type are : `list` , `number`, `string` or `boolean`. Use an `options` object to set the operator for the filter to override the defaults\n\n### Usage\n\n```python\nimport React, {useState,useEffect} from 'react';\nimport {TDBReactTable} from '@terminusdb/terminusdb-react-table'\nimport {columnsConfiguration} from './columnsConfiguration'\nimport data from './data.json'\nimport './terminusdb-react-table-main.css'\nimport {Container,Alert,Row} from \"react-bootstrap\"\n\nconst App = (props) =>{\n const [rowSelected, setRowSelected] = useState(false)\n const [limit, setLimit] = useState(5)\n const [start, setStart] = useState(0)\n const [filter, setFilter] = useState([])\n const [order, setOrder] = useState([])\n const hiddenColumnsArr = ['_id','desc','MGLT','length', 'cost_in_credits','max_atmosphering_speed','_speed','crew',\n'passengers','cargo_capacity','consumables','hyperdrive_rating',\n'starship_class','created,edited','url']\n\nconst [dataWithPagination, setData] = useState(data)\nconst onRowClick = (row) =>{\n setRowSelected(row.original['fullID'])\n}\n\nconst tableConfigObj = {}\ntableConfigObj.columns = columnsConfiguration\ntableConfigObj.rowClick = onRowClick\n\nconst setHiddenColumns = (id, selected)=>{\n //implement a setHiddenColumns function to store the status\n}\n\nconst changeFilters = (filterArr)=>{setFilter(filterArr)}\nconst changeLimits = (currentlimit,currentpage)=>\n setLimit(currentlimit)\n setStart(currentpage)\n }\n\nconst changeOrders = (orderArr)=>{setOrder(orderArr)}\n\nuseEffect(() => {\n const tmpData = data.slice(start,(limit+start))\n setData(tmpData)\n},[limit,start])\n\nreturn \n
{`Row selected id ${rowSelected}`}\n    You need to Implement a logic to change the Hidden status
\n\n
{`YOU NEED TO IMPLEMENT A FILTER LOGIC, Table filter ${JSON.stringify(filter)}`}
\n\n
{`YOU NEED TO IMPLEMENT AN ORDER LOGIC, Table order ${JSON.stringify(order)}`}
\n\n\n\n\n
\n}\n\nexport default App;\n```\n\n### Example `TdbReactTable` Code\n\n[TdbReactTable Code](https://github.com/terminusdb/terminusdb-dashboard/tree/main/packages/tdb-react-table/src)\n\n[Code sandbox](https://codesandbox.io/s/github/terminusdb/dashboard-examples-sandbox/tree/main/terminusdb-react-table-examples/table-basic-conf)\n\n## AdvancedSearch\n\n### Properties\n\nProperties\n\nDescription\n\n`setFilter:Function(advFilter:Object)`\n\nA function that acts as a callback when the advanced filter `Filter Data` button is clicked\n\n`fields:Object`\n\nThe Advanced Search fields description\n\n### Fields Options\n\nThe following options are supported on any files object that you can pass to field, the keys in fields are the ID of the field itself.\n\nProperties\n\nDescription\n\n`label:String`\n\n\\- Required - the field label\n\n`type:string`\n\n\\- Required - is the field widget match type for GraphQL\n\n`valueSources:Array`\n\n\\- Required - for the default widget this is always \\[\"value\"\\]\n\n`typeValue:String`\n\n\\- Required - the GraphQL value type (String,BigInt )\n\n`operators:Array`\n\n\\- Optional - an Array of available operators\n\n`defaultOperator:String`\n\n\\- Optional - the default operator for the type\n\n`fieldSettings`\n\n\\- Optional - an Array of options for the valuetype ENUM\n\n`subfields`\n\n\\- Optional - a list of subfields for the type `!group` valuetype Object\n\n```\n{\"myfield\":{\n \"label\":\"myfiledLabel\",\n \"type\":\"text\",\n \"valueSources\":[\"value\"],\n \"typevalue\":\"String\"\n }\n}\n```\n\n[advancedSearchMatchType code](https://github.com/terminusdb/terminusdb-dashboard/blob/main/packages/tdb-react-table/src/advancedSearchUtils.js)\n\n**You can use the following method to format the advanced search fields**\n\n```python\nimport {advancedSearchMatchType} from \"@terminusdb/terminusdb-react-table/advancedSearchUtils\"\n\nconst stringFormat = advancedSearchMatchType(\"String\")\nstringFormat.label= \"myPropertyName\"\nconst fields = {\"myPropertyName\" : stringFormat}\n```\n\n### Code Examples of Advanced Search\n\n[AdvancedSearch Code](https://github.com/terminusdb/terminusdb-dashboard/tree/main/packages/tdb-react-table/src)\n\n[Code sandbox](https://codesandbox.io/s/github/terminusdb/dashboard-examples-sandbox/tree/main/terminusdb-react-table-examples/advanced-search)" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "TerminusDB React Table", + "description": "Learn how to include TerminusDB React Table components in your projects to display documents in an interactive table", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "useTDBDocuments hook" + }, + "slug": "usetdbdocuments", + "body": { + "@type": "Body", + "value": "`useTDBDocuments` is the main hook to connect @terminusdb/terminusdb-documents-ui with the TerminusCMS server. To use it, pass it with an instance of [@terminusdb/terminusdb-client](https://github.com/terminusdb/terminusdb-client-js)\n\n## useTDBDocuments parameters\n\n`useTDBDocuments(woqlClient:WOQLClient)`\n\n* `woqlClient : WOQLClient`\n* Required\n* An WOQLClient instance with your connections settings\n\n## Instance Properties\n\n* `state.loading : Bool`\n * This is the current `loading` value, located on the state, if true the hook is doing a server call\n* `state.error: Object|Bool`\n * This is the current error reporting object from the server, located on the state, the starting value\n* `state.perDocumentCount:Object|Bool`\n * This is the current information about the number of documents, of every type, present in the database in a specific branch. The starting value is null, we need to call the `getDocumentsNumber` function to fill this property status\n* `state.totalDocumentCount:Number|Bool`\n * This is the current information about the total number of documents present in the database in a specific branch, the starting value is null, we need to call the `getDocumentsNumber` function to fill this property status\n* `state.documentClasses:Array|Bool`\n * This is the current information about the documents classes, the starting value is null, you need to call the `getDocumentNumbers` or the `getDocumentClasses` function to fill this property status\n* `state.selectedDocument:Object|Bool`\n * This is the current selected document object, the starting value is null, you need to call the `getSelectedDocument` function to fill this property status\n* `state.frame:Object|Bool`\n * This is the current documents frames object, the starting value is false, you need to call the `getDocumentFrames`function to fill this property status\n* `state.documentTablesConfig:Object|Bool`\n * This is the current document tables template, this property status stores the graphQL query for every document, the configuration for the tables, and the advanced search components. The starting value is null, you need to call the `getGraphqlTablesConfig`function to fill this property status, after the call the status will either be the table config Object, or false if the call failed\n* `setError: Function(value:Object|Bool)`\n * This function sets the error property status.\n* `getDocumentClasses: Function()`\n * This function calls the TerminusDB server to get the database classes list and sets the `documentClasses` property with the server response.\n* `getDocumentNumbers: Function()`\n * This function calls the TerminusDB server to get the database classes list and sets the `documentClasses` property with the server response. It runs a query to get the total number of documents and the number of documents for type and fills the `perDocumentCount` and the `totalDocumentCount`\n* `getDocumentFrames: Function()`\n * This function gets the current database frames and sets the `frames` status property\n* `getGraphqlTablesConfig: Function()`\n * This function calls the TerminusDB server to get the GraphQL tables configuration and sets the `getGraphqlTablesConfig` property status with the server response or `error` if there was an error in the call.\n* `createDocument: Function(jsonDocument:Object)`\n * This function calls the server to create a new document in the current database\n* `getSelectedDocument: Function(documentId:String)` \n * Calls the server to get a document object and sets the `selectedDocument` status property with the response\n* `deleteDocument: Function(documentId:String)`\n * Calls the server to delete a document\n* `updateDocument: Function(jsonDocument:Object)`\n * Calls the server to update a document\n* `getDocumentById: Function(documentId:String)`\n * Calls the server to get a document object and return it\n\nView the useTDBDocuments component integrated inside a dashboard here\n\n[useTDBDocuments example JS code to create a new document](https://github.com/terminusdb/dashboard-examples-sandbox/blob/main/terminusdb-documents-ui-template-example/dashboard-demo/src/pages/DocumentNew.js)\n\n[Code Sandbox](https://codesandbox.io/s/github/terminusdb/dashboard-examples-sandbox/tree/main/terminusdb-documents-ui-template-example/dashboard-demo)\n\n* * *\n\nFor more detailed information take a look at the UI component pages - [Document Classes Summary](/docs/documentclassessummary/), [Document GraphQL Table](/docs/documentsgraphqltable/), [Edit Documents](/docs/edit-document-component/), [List Documents](/docs/list-documents-component/), [New Documents](/docs/newdocumentcomponent/), and [View Documents](/docs/viewdocumentcomponent/)." + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "useTDBDocuments hook", + "description": "useTDBDocuments is the main hook to connect @terminusdb/terminusdb-documents-ui with the TerminusCMS server", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "useTDBGraphqlQuery" + }, + "slug": "usetdbgraphqlquery", + "body": { + "@type": "Body", + "value": "`useTDBGraphqlQuery` is the main hook to connect @terminusdb/terminusdb-react-table with TerminusCMS server. To use it, pass it with an instance of [ApolloClient](https://www.apollographql.com/docs/react/).\n\n## useTDBGraphqlQuery parameters\n\n`useTDBGraphqlQuery(apolloClient:ApolloClient, graphqlQuery:gql, documentType:String, options:Object)`\n\n* `apolloClient : ApolloClient`\n* Required\n* An Apollo Client instance with your connections settings\n* `graphqlQuery : gql`\n* Required\n* A GraphQL query\n* `documentType : string`\n* Required\n* The document type\n* `options : object`\n\nThe following options are supported via the main options object passed to useTDBGraphqlQuery\n\n* `limit : number`\n \n * Optional\n * The initial state value for `limit`\n* `start : number`\n \n * Optional\n * The initial state value for `start`\n* `tableConfigObj: Object`\n \n * Optional\n * The table configuration object\n* `hiddenColumns : Array`\n \n * Optional\n * The initial state object for `hiddenColumnsArr`\n \n ## Instance Properties\n \n The following properties are available on the table instance returned from useTDBGraphqlQuery\n \n* `state.loading : Bool`\n \n * This is the current `loading` value, located on the state, if true the hook is doing a server call\n* `state.error: Object|Bool`\n \n * This is the current error reporting object from the server, located on the state, the starting value is false\n* `state.limit: Number`\n \n * This is set the limit clause to select a limited number of records, The starting value is 10. Using the `changeLimits` function will change the status of this property\n* `state.start:Number`\n \n * This is the pagination start value, pagination allows returning only a portion, rather than the whole, result set. The start value is 0. Use the `changeLimits` function to change the status of this property\n* `state.queryFilters:Object`\n \n * This is the query filter status, this value is used to fill the filter value in the GraphQL query variables. Use the `setAdvancedFilters` or `changeFilters` functions to change the status of this property\n* `state.queryOrders:Object`\n \n * This is the query orderBy status. Use this value to fill the orderBy value in the graphql query variables. Use the `changeOrders` function to change the status of this property\n* `state.orderBy:Array` - This is the table orderBy status, transform this value to create the queryOrders object. Use the `changeOrders` function to change the status of this property\n \n* `state.filterBy:Array`\n \n * This is the table filter status, transform this value to create the queryFilters object. Use the `changeFilters` function to change the status of this property\n* `state.rowCount:Number`\n \n * This is the current number of records loaded\n* `state.documentResults:Array`\n \n * The successful GraphQL query fetch result data\n* `state.extractedData:Array`\n \n * The successful GraphQL query fetch result data formatted for the table\n* `state.hiddenColumnsArr:Array`\n \n * Store the table hiddenColumns list. If a column's ID is contained in this array, it will be hidden using the `setHiddenColumns` function\n* `callGraphqlServer: Function(currentlimit:Number,currentstart:Number,queryOrders:Object,queryFilters:Object)`\n \n * This function changes the `limit`, the `start` status, the `queryOrders`, and the `queryFilters` properties and calls the server with pagination, returning only a portion, rather than the whole, result.\n* `changeLimits: Function(currentlimit:Number,currentstart:Number)`\n \n * This function changes the `limit` and `start` status properties and calls the server with pagination, returning only a portion, rather than the whole, result.\n* `changeOrders: Function(orderByArr:Array)`\n \n * This function gets the graphqlTable orderByArr variable and transforms it in the GraphQL orderBy variables format.\n * Set the `queryOrders` and `orderBy` properties status to call the server with the current `queryOrders` and `queryFilters` status\n* `changeFilters: Function(filtersArr:Array)`\n \n * This function gets the graphqlTable filtersArr variable and transforms it in the GraphQL filters variables format.\n * Set the `queryFilters` and `filterBy` properties status to call the server with the current `queryFilters` and `queryOrders` status\n* `setAdvancedFilters: Function(advfilter:Object)`\n \n * This gets the advfilter in the GraphQL filters variables format\n * Set the `queryFilters` reset the `filterBy` properties status to call the server with the current `queryFilters` and `queryOrders` status\n* `setHiddenColumns: Function(id:string, checked:bool)`\n \n * This function is called to add or remove a columns ID to the `hiddenColumns` status property\n\nView the useTDBGraphqlQuery component integrated inside a dashboard here\n\n[useTDBGraphqlQuery source code](https://github.com/terminusdb/terminusdb-dashboard/blob/main/packages/tdb-documents-ui-template/src/hook/useTDBGraphqlQuery.js)\n\n[useTDBGraphqlQuery usage in the DocumentsGraphqlTable component](https://github.com/terminusdb/terminusdb-dashboard/blob/main/packages/tdb-documents-ui-template/src/components/DocumentsGraphqlTable.js)" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "useTDBGraphqlQuery Hook", + "description": "useTDBGraphqlQuery` is the main hook to connect @terminusdb/terminusdb-react-table with TerminusCMS server", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Document UI Components" + }, + "slug": "ui-components", + "body": { + "@type": "Body", + "value": "[Document Classes Summary](/docs/documentclassessummary/)[Documents GraphQL Table](/docs/documentsgraphqltable/)[Edit Documents](/docs/edit-document-component/)[List Documents](/docs/list-documents-component/)[New Documents](/docs/newdocumentcomponent/)[View Documents](/docs/viewdocumentcomponent/)" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Document UI Components", + "description": "A list of components and links to further information for the document UI components to build dashboards quickly.", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "DocumentClassesSummary Component" + }, + "slug": "documentclassessummary", + "body": { + "@type": "Body", + "value": "The `DocumentClassesSummary` component allows you to visualize document classes using interactive cards.\n\n## Installation\n\nInstall the dependencies from npm\n\n```\n npm install @terminusdb/terminusdb-documents-ui\n npm install @terminusdb/terminusdb-react-table\n npm install @terminusdb/terminusdb-documents-ui-templates\n```\n\n## Properties\n\nProperties\n\nDescription\n\ntotalDocumentCount\n\nThe total number of documents\n\nperDocumentCount\n\nThe number of documents for a type\n\nonDocumentClick\n\nA function that acts as a callback when the document class card is clicked\n\n## Example\n\n```python\nimport React, {useEffect} from \"react\"\nimport {DocumentClassesSummary,useTDBDocuments} from \"@terminusdb/terminusdb-documents-ui-template\"\n\nexport const Documents = ({tdbClient}) => { \n const {perDocumentCount,\n totalDocumentCount, \n getDocumentNumbers,\n setError,\n loading,\n error}=useTDBDocuments(tdbClient)\n\n\n useEffect(() => {\n if(tdbClient)getDocumentNumbers()\n }, [tdbClient])\n\n function handleCardClick (doc) {\n // do something after click the card, \n // maybe navigate in the document list page\n }\n\n if(!frames) return
{`Fetching frames for document type ${type} ...`}
\n const errorMessage = typeof error === \"object\" ? JSON.stringify(error,null,4) : error\n\n return
\n {error && {error &&
Server Error: {errorMessage}
}\n \n
\n}\n```\n\nView the DocumentClassesSummary integrated inside a dashboard here\n\n[DocumentClassesSummary full example JS code](https://github.com/terminusdb/dashboard-examples-sandbox/blob/main/terminusdb-documents-ui-template-example/dashboard-demo/src/pages/Documents.js)\n\n[Code Sandbox](https://codesandbox.io/s/github/terminusdb/dashboard-examples-sandbox/tree/main/terminusdb-documents-ui-template-example/dashboard-demo)" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "DocumentClassesSummary Component", + "description": "The DocumentClassesSummary component allows you to visualize document classes using interactive cards.", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "DocumentsGraphqlTable Component" + }, + "slug": "documentsgraphqltable", + "body": { + "@type": "Body", + "value": "The `DocumentsGraphqlTable` component allows you to use GraphQL queries and visualize the results in a the [TDBReactTable](/docs/tdb-react-table/), you need to pass your instace of ApolloClient, the GraphQL query and the table and advanced search configuration. [Read here for the configuration documentation](/docs/tdb-react-table/).\n\n## Installation\n\nInstall the dependencies from npm\n\n```\nnpm install @terminusdb/terminusdb-documents-ui\nnpm install @terminusdb/terminusdb-react-table\nnpm install @terminusdb/terminusdb-documents-ui-templates\n```\n\n## Properties\n\nProperties\n\nDescription\n\ntype\n\nThe document type\n\ngqlQuery\n\nThe GraphQL query\n\napolloClient\n\nAn apollo client instance - [Apollo Client documentation](https://www.apollographql.com/docs/react/)\n\ntableConfig\n\nAn object with the table configuration to pass to the [TDBReactTable Component](/docs/tdb-react-table/)\n\nadvancedSearchConfig\n\nAn object with the advancedSearch configuration to pass to the [AdvancedSearch Component](/docs/tdb-react-table/#advancedsearch)\n\nonRowClick\n\nA function that acts as a callback when the table row is clicked\n\nonViewButtonClick\n\nA function that acts as a callback when the table row view button is clicked\n\nonEditButtonClick\n\nA function that acts as a callback when the table row edit button is clicked\n\nonDeleteButtonClick\n\nA function that acts as a callback when the table row delete button is clicked\n\nshowGraphqlTab\n\nA boolean property to enable the GraphQL query view tab\n\n## Example\n\n```python\nimport React,{useEffect} from \"react\"\nimport {DocumentsGraphqlTable,useTDBDocuments} from \"@terminusdb/terminusdb-documents-ui-template\"\nimport {gql} from \"@apollo/client\"\n/**\n * \n * @param {*} setSelected function to get selected document link by user \n * @param {*} doctype document type selected\n * @returns \n */\nexport const DocumentSearchComponent = ({setSelected, doctype,apolloClient,tdbClient}) => {\n const {documentTablesConfig,getGraphqlTablesConfig} = useTDBDocuments(tdbClient)\n\n useEffect(() => {\n if(doctype){ \n getGraphqlTablesConfig() \n }\n },[doctype]);\n\n const querystr = documentTablesConfig && documentTablesConfig.objQuery ? documentTablesConfig.objQuery[doctype].query : null\n const gqlQuery = querystr ? gql`${querystr}` : null\n const tableConfig = documentTablesConfig && documentTablesConfig.tablesColumnsConfig ? documentTablesConfig.tablesColumnsConfig[type] : []\n const advancedSearchConfig = documentTablesConfig && documentTablesConfig.advancedSearchObj ? documentTablesConfig.advancedSearchObj[type] : null\n if(!gqlQuery || !tableConfig) return
\n\n return \n\n}\n```\n\nView the DocumentsGraphqlTable component integrated inside a dashboard here\n\n[DocumentSearchComponent full example JS code](https://github.com/terminusdb/dashboard-examples-sandbox/blob/main/terminusdb-documents-ui-template-example/dashboard-demo/src/components/DocumentSearchComponent.js)\n\n[Code Sandbox](https://codesandbox.io/s/github/terminusdb/dashboard-examples-sandbox/tree/main/terminusdb-documents-ui-template-example/dashboard-demo)" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "DocumentsGraphqlTable Component", + "description": "The DocumentsGraphqlTable component allows you to use GraphQL queries and visualize the results in a the TDBReactTable", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "EditDocumentComponent" + }, + "slug": "edit-document-component", + "body": { + "@type": "Body", + "value": "The `EditDocumentComponent` allows you to edit an existing document using the [FrameViewer](/docs/document-ui-sdk/) component.\n\n## Installation\n\nInstall the dependencies from npm\n\n```\n npm install @terminusdb/terminusdb-documents-ui\n npm install @terminusdb/terminusdb-react-table\n npm install @terminusdb/terminusdb-documents-ui-templates\n```\n\n## Properties\n\nProperties\n\nDescription\n\ntype\n\nThe document type\n\ndocumentJson\n\nThe document object\n\ndocumentID\n\nThe document ID\n\nframes\n\nThe database Class Frame, or object of all class frames\n\ncloseButtonClick\n\nA function that acts as a callback when the panel exit `x` button is clicked\n\nupdateDocument\n\nA function that acts as a callback when the `submit` button is clicked\n\nSearchComponent\n\nA react component used as search component\n\n## Example\n\n```python\nimport React, {useEffect} from \"react\";\nimport {EditDocumentComponent,useTDBDocuments} from \"@terminusdb/terminusdb-documents-ui-template\"\n\nexport const DocumentEdit = ({type, documentID, tdbClient}) => { \n const {\n updateDocument,\n getDocument,\n selectedDocument,\n getDocumentFrames,\n frames,\n error,\n setError\n } = useTDBDocuments(tdbClient)\n\n const updateDocumentHandler = async (jsonDoc) =>{\n const docUp = await updateDocument(jsonDoc)\n if(docUp){\n getDocument(documentID)\n // do somethig after update document\n }\n }\n // implement the chage method\n useEffect(() => {\n getDocumentFrames()\n getDocument(documentID)\n },[])\n\n const closeButtonClick = () =>{\n // do something after click the close panel button the interface\n }\n\n const DocumentSearchComponent = () =>{\n //make you document search component\n return
\n }\n\n if(!frames) return
{`Fetching frames for document type ${type} ...`}
\n const errorMessage = typeof error === \"object\" ? JSON.stringify(error,null,4) : error\n\n return \n {error &&
Server Error: {errorMessage}
}\n \n
\n}\n```\n\nView the EditDocumentComponent component integrated inside a dashboard here\n\n[EditDocumentComponent full example JS code](https://github.com/terminusdb/dashboard-examples-sandbox/blob/main/terminusdb-documents-ui-template-example/dashboard-demo/src/pages/DocumentEdit.js)\n\n[Code Sandbox](https://codesandbox.io/s/github/terminusdb/dashboard-examples-sandbox/tree/main/terminusdb-documents-ui-template-example/dashboard-demo)" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "EditDocumentComponent", + "description": "The EditDocumentComponent allows you to edit an existing document using the FrameViewer component", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "ListDocumentsComponent" + }, + "slug": "list-documents-component", + "body": { + "@type": "Body", + "value": "The `ListDocumentsComponent` element allows you to visualize the documents inside the [TDBReactTable](/docs/tdb-react-table/) and query the documents using the advanced search component.\n\n### Installation\n\nInstall the dependencies from npm\n\n```\n npm install @terminusdb/terminusdb-documents-ui\n npm install @terminusdb/terminusdb-react-table\n npm install @terminusdb/terminusdb-documents-ui-templates\n```\n\n### Properties\n\nProperties\n\nDescription\n\ntype\n\nThe document type\n\ngqlQuery\n\nThe graphql query\n\napolloClient\n\nAn apollo client instance - [documentation](https://www.apollographql.com/docs/react/)\n\ntableConfig\n\nAn object with the table configuration to pass to the [TDBReactTable Component](/docs/tdb-react-table/)\n\nadvancedSearchConfig\n\nAn object with the advancedSearch configuration to pass to the [Advanced Search Component](/docs/tdb-react-table/#advancedsearch)\n\nonRowClick\n\nA function that acts as a callback when the table row is clicked\n\nonViewButtonClick\n\nA function that acts as a callback when the table row view button is clicked\n\nonEditButtonClick\n\nA function that acts as a callback when the table row edit button is clicked\n\nonDeleteButtonClick\n\nA function that acts as a callback when the table row delete button is clicked\n\nonCreateButtonClick\n\nA function that acts as a callback when the create button is clicked\n\nshowGraphqlTab\n\nA boolean property that enables the GraphQL query view tab\n\n### Example\n\n```python\nimport React, {useEffect} from \"react\";\nimport {gql} from \"@apollo/client\";\nimport { ListDocumentsComponent,useTDBDocuments } from \"@terminusdb/terminusdb-documents-ui-template\";\n\n// I pass this so I'm sure it exists before loading the component\nexport const ListDocuments = ({type,apolloClient,tdbClient}) => { \n const {deleteDocument,\n loading,\n error,\n getGraphqlTablesConfig,\n documentTablesConfig,\n setError} = useTDBDocuments(tdbClient)\n\n const navigate = useNavigate()\n\n useEffect(() => {\n getGraphqlTablesConfig()\n },[tdbClient])\n\n async function callDeleteDocument(row){\n var answer = window.confirm(\"Are you sure you want to delete this document\");\n if (answer) {\n let fullId = row['id']\n const delCall = await deleteDocument(fullId)\n if(delCall){\n //do something after delete\n }\n } \n }\n\n const onViewClick = (row) =>{\n let fullId = row['id']\n let fullIdEncode = btoa(fullId)\n //do something after row view button click\n }\n\n const onEditClick = (row) =>{\n let fullId = row['id']\n let fullIdEncode = btoa(fullId)\n //do something after row edit button click\n }\n\n function handleCreate(e) {\n //do something after create button click\n }\n\n if(loading) return
{`Fetching ${type} ...`}>
\n\n const querystr = documentTablesConfig ? documentTablesConfig.objQuery[type].query : null\n const query = querystr ? gql`${querystr}` : false\n const tableConfig = documentTablesConfig && documentTablesConfig.tablesColumnsConfig ? documentTablesConfig.tablesColumnsConfig[type] : []\n const advancedSearchConfig = documentTablesConfig && documentTablesConfig.advancedSearchObj ? documentTablesConfig.advancedSearchObj[type] : null\n\n const errorMessage = typeof error === \"object\" ? JSON.stringify(error,null,4) : error\n\n return \n {errorMessage &&
Server Error: {errorMessage}
}}\n {query && tableConfig &&\n }\n
\n}\n```\n\nView the ListDocumentsComponent integrated inside a dashboard here\n\n[ListDocumentsComponent full example JS code](https://github.com/terminusdb/dashboard-examples-sandbox/blob/main/terminusdb-documents-ui-template-example/dashboard-demo/src/pages/ListDocuments.js)\n\n[Code Sandbox](https://codesandbox.io/s/github/terminusdb/dashboard-examples-sandbox/tree/main/terminusdb-documents-ui-template-example/dashboard-demo)" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "ListDocumentsComponent", + "description": "The ListDocumentsComponent element allows you to visualize the documents inside the TDBReactTable and query the documents using the advanced search component", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "NewDocumentComponent" + }, + "slug": "newdocumentcomponent", + "body": { + "@type": "Body", + "value": "The `NewDocumentComponent` allows you to create new documents using the [FrameViewer](/docs/document-ui-sdk/).\n\n### Installation\n\nInstall the dependencies from npm\n\n```\n npm install @terminusdb/terminusdb-documents-ui\n npm install @terminusdb/terminusdb-react-table\n npm install @terminusdb/terminusdb-documents-ui-templates\n```\n\n### Properties\n\nProperties\n\nDescription\n\ntype\n\nThe document type\n\ndocumentJson\n\nThe document object, it is empty ({}) for new\n\ncreateDocument\n\nA function that acts as a callback when the `submit` button is clicked\n\nframes\n\nThe database Class Frame, or object of all class frames\n\ncloseButtonClick\n\nA function that acts as a callback when the panel exit `x` button is clicked\n\nSearchComponent\n\nA react component used as search component\n\n### Example\n\n```python\n//This is use the NewDocumentComponent template to create a new document type\nimport React, {useEffect} from \"react\";\n//we import the NewDocumentComponent and the useTDBDocuments from the terminusdb-documents-ui-template\n//you need to pass your terminusdb-client instance and the document type \nimport {NewDocumentComponent,useTDBDocuments} from \"@terminusdb/terminusdb-documents-ui-template\"\n\nexport const DocumentNew = ({type,tdbClient}) => { \n const {\n frames,\n error,\n getDocumentFrames,\n createDocument,\n setError\n } = useTDBDocuments(tdbClient)\n\n useEffect(() => {\n getDocumentFrames()\n },[])\n\n const callCreateDocument = async (jsonDocument) =>{\n const created = await createDocument(jsonDocument)\n if(created){\n //do something after create a new element\n }\n }\n\n const closeButtonClick = () =>{\n // do something after click the close panel button the interface\n }\n\n const DocumentSearchComponent = () =>{\n //make you document search component\n return \n }\n\n if(!frames) return
{`Fetching frames for document type ${type} ...`}
\n const errorMessage = typeof error === \"object\" ? JSON.stringify(error,null,4) : error\n\n return \n {error &&
Server Error: {errorMessage}
}\n \n
\n}\n```\n\nView the NewDocumentComponent integrated inside a dashboard here\n\n[NewDocumentComponent full example JS code](https://github.com/terminusdb/dashboard-examples-sandbox/blob/main/terminusdb-documents-ui-template-example/dashboard-demo/src/pages/DocumentNew.js)\n\n[Code Sandbox](https://codesandbox.io/s/github/terminusdb/dashboard-examples-sandbox/tree/main/terminusdb-documents-ui-template-example/dashboard-demo)" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "NewDocumentComponent", + "description": "The NewDocumentComponent allows you to create new documents using the FrameViewer", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "ViewDocumentComponent" + }, + "slug": "viewdocumentcomponent", + "body": { + "@type": "Body", + "value": "The `ViewDocumentComponent` allows you to view existing documents using the [FrameViewer](/docs/document-ui-sdk/) component.\n\n### Installation\n\nInstall the dependencies from npm\n\n```\n npm install @terminusdb/terminusdb-documents-ui\n npm install @terminusdb/terminusdb-react-table\n npm install @terminusdb/terminusdb-documents-ui-templates\n```\n\n### Properties\n\nProperties\n\nDescription\n\ntype\n\nThe document type\n\ndocumentID\n\nThe document ID\n\ndocumentJson\n\nThe document object\n\nframes\n\nThe database Class Frame, or object of all class frames\n\ncloseButtonClick\n\nA function that acts as a callback when the panel exit `x` button is clicked\n\ndeleteDocument\n\nA function that acts as a callback when the delete button is clicked\n\neditDocument\n\nA function that acts as a callback when the edit button is clicked\n\ngetDocumentById\n\nA function that acts as a callback when the a link property (a link to another document) is clicked inside the document interface\n\n### Example\n\n```python\nimport React, {useEffect} from \"react\";\nimport {ViewDocumentComponent,useTDBDocuments} from \"@terminusdb/terminusdb-documents-ui-template\"\n\nexport const DocumentView = ({tdbClient,type, documentID}) => { \n const {\n frames,\n selectedDocument,\n error,\n deleteDocument,\n getSelectedDocument,\n getDocumentById,\n getDocumentFrames,\n setError\n } = useTDBDocuments(tdbClient)\n\n useEffect(() => {\n getDocumentFrames()\n getSelectedDocument(documentID)\n }, [] )\n\n async function callDeleteDocument(){\n var answer = window.confirm(\"Are you sure you want to delete this document\");\n if (answer) {\n const delCall = await deleteDocument(documentID)\n if(delCall){\n //do something after delete document\n }\n } \n }\n\n const closeButtonClick = () =>{\n // do something after click the close panel button the interface\n // like navigate to the list of documents\n }\n\n const gotToEditDocument = () =>{\n // do something after click the edit button like navigate to the \n // edit page\n }\n\n\n if(!frames) return
{`Fetching frames for document type ${type} ...`}
\n const errorMessage = typeof error === \"object\" ? JSON.stringify(error,null,4) : error\n\n return \n {error &&
Server Error: {errorMessage}
}\n \n
\n}\n```\n\nView the ViewDocumentComponent integrated inside a dashboard here\n\n[ViewDocumentComponent full example JS code](https://github.com/terminusdb/dashboard-examples-sandbox/blob/main/terminusdb-documents-ui-template-example/dashboard-demo/src/pages/DocumentView.js)\n\n[Code Sandbox](https://codesandbox.io/s/github/terminusdb/dashboard-examples-sandbox/tree/main/terminusdb-documents-ui-template-example/dashboard-demo)" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "ViewDocumentComponent", + "description": "The ViewDocumentComponent allows you to view existing documents using the FrameViewer component", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Acid Transaction Explanation" + }, + "slug": "acid-transactions-explanation", + "body": { + "@type": "Body", + "value": "### What is ACID?\n\nACID ([Atomicity](#atomicity), [Consistency](#consistency), [Isolation](#isolation), [Durability](#durability)) are properties of database transactions that are generally considered desirable for many applications.\n\n### Atomicity\n\nAtomicity is an all-or-nothing approach to database transactions. If a transaction starts but does not complete, then all data manipulation or modification operations carried out by that transaction are undone, and any affected data or objects remain unchanged. The database is returned to the state it was in before the transaction started. Atomicity, or atomic transactions, guarantee the consistency and integrity of data and objects, ensuring the database is not left in an inconsistent or partially changed state.\n\n#### Atomicity and immutability\n\nTerminusDB combines atomicity with [immutability](/docs/immutability-explanation/) to provide atomic transactions.\n\n### Consistency\n\nConsistency has multiple forms and can be interpreted in different ways. TerminusDB implements two forms of consistency - full and partial consistency.\n\n#### Full consistency\n\nWhere a schema exists for a TerminusDB database, a transaction will not be completed unless all schema conditions are satisfied. The consistency of the schema is maintained under all conditions.\n\n#### Partial consistency\n\nWhen rebasing, transactions that complete under certain **read-conditions** can be _replayed_ by reordering their commits. Schema consistency is maintained but not under all conditions.\n\n### Isolation\n\nThe isolation property gives a user the impression of being the sole user of a database. The user experiences no currency or conflicts with other users of the database.\n\n#### Read isolation\n\nTerminusDB uses inherent database [immutability](/docs/immutability-explanation/) to ensure each read query exists at a given layer providing each user with an isolated snapshot of the database.\n\n#### Write isolation\n\nSimilar to read isolation, completing write transactions ensures isolation with optimistic concurrency, simply restarting any transactions failing mid-run.\n\n### Durability\n\nTerminusDB is durable. Transactions failing mid-run do not corrupt data. Data is protected from external sources of potential corruption such as operating system bugs. In the unlikely event of a partial commit, previous layers remain unchanged and recoverable. Backups are significantly simplified, requiring copy storage only to ensure a safely recoverable state.\n\n### Further Reading\n\n[**Documents in a knowledge graph and how to use them**](/docs/documents-explanation/)." + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Acid Transactions Explanation", + "description": "An explanation about Acid Transactions and how TerminusDB and TerminusCMS ensures acid compliance", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Datalog Explanation" + }, + "slug": "datalog-explanation", + "body": { + "@type": "Body", + "value": "### What is Datalog?\n\nDatalog, a declarative subset of Prolog, is a flexible and powerful declarative query language proficient at dealing with the complex and multi-hop relationships that occur in graphs. Graph query languages not based on Datalog lack the level of clarity, simplicity, and logical framework that Datalog provides.\n\n### Predicates\n\nSimilar to its super-set Prolog, Datalog is based on **predicates**. Predicates are similar to relations in relational languages such as SQL. Queries can use predicates with _logical variables_ to represent unknowns to which meaning is assigned based on a logical formula. Meaning is assigned by joining predicates with logical connectives or operators such as `and` and `or` and [unifying](#unificationandquery) logical variables. Repeated occurrences of the same variable require the query has identical solutions at given points.\n\n### Advantages of Datalog in queries\n\nVariables in Datalog are restricted to finite **atomic** values. The use of atomic values simplifies query optimization and guarantees the termination of queries even in the event of recursion. The finite atomic values restriction is relaxed in [WOQL](/docs/woql-explanation/) (the Web Object Query Language used in TerminusDB) to enable lists that are useful in aggregation and dis-aggregation queries such as `group by` and `member` respectively. However, TerminusDB retains the pure declarative quality of Datalog.\n\n#### Datalog compared with SQL\n\nCompared with relational databases, Datalog provides a more flexible logical framework that is easier to extend consistently with recursive and path-centric operations. Datalog also enables complex joins to be expressed more elegantly with a less verbose syntax. Datalog represents a stepping-stone from relational languages such as SQL to more fully-featured programming languages while retaining the declarative, robust, pervasive, and resilient properties of query languages.\n\n### Unification and query\n\nUnification in Datalog is the process of finding values of logical variables which are consistent for a given logical sentence or query.\n\nA logical variable for a query can only take on one value in a given solution. If the variable is used in two places then these two values must be the same. We can get the concrete value of solutions for a logical value either from an equation or from the definition of a predicate.\n\nWhen we search using datalog in WOQL, we implicitly ask for _all_ solutions (this can be restricted by using additional words such as `limit(n,Q)`). This gives us back something that looks quite similar to a table, but it is a list of solutions with bindings for all logical variables that took on a value during the course of searching for the solutions to the query.\n\n#### An Example\n\nPerhaps the most important predicate in WOQL is `triple` which gives results about edges in the current graph.\n\nOur logical variables are represented as strings with the prefix `\"v:\"`. Our edges are represented by having a position for the _subject_, _predicate_ and _object_ of the edge in the graph. The _predicate_ is the labeled name of the edge, and the _subject_ and _object_ nodes the source, and target respectively.\n\n```\ntriple(\"v:Subject\", \"v:Predicate\", \"v:Object\")\n```\n\nWith this query, we simply get back the solutions for every possible assignment of subjects, predicates, and objects that our graph currently has, that is, all edges in the graph. The concrete referents for the subject, predicate and object are data points represented by a URI (a universal resource indicator).\n\n```\ntriple(\"v:Subject\", \"v:Predicate\", \"v:Intermediate\")\ntriple(\"v:Intermediate\", \"v:Predicate\", \"v:Object\")\n```\n\nIn this second query, we have _joined_ two predicates together by requiring that the target of the first edge is the source of the second. This gives us back all two-hop paths possible in the graph.\n\n```\ntriple(\"My_Object\", \"v:Predicate\", \"v:Intermediate\")\ntriple(\"v:Intermediate\", \"v:Predicate\", \"v:Object\")\n```\n\nAnd here we refer to a specific starting node and search for every two-hop path starting from _this_ object.\n\n### Further Reading\n\n[**Documents in a knowledge graph and how to use them**](/docs/documents-explanation/)." + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Datalog Explanation | TerminusCMS & TerminusDB", + "description": "A brief explanation of Datalog and its benefits in database queries.", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Documents Explanation" + }, + "slug": "documents-explanation", + "body": { + "@type": "Body", + "value": "### The TerminusDB document store\n\nTerminusDB is a document store as well as a knowledge graph database. TerminusDB [schemata](/docs/schema-reference-guide/) describe how to interpret segments of graphs as self-contained documents.\n\n### TerminusDB storage structure\n\nThe underlying storage structure of TerminusDB is a **labeled**, **directed**, and **edge-labeled** graph. Each source and target node has a distinct name, and every edge has a name and a direction.\n\n#### Graph segments as documents\n\nSegments of the graph are **documents**. Documents can be extracted as JSON objects, providing a convenient data package for applications. JSON objects can be updated by submitting modified versions. The graph's entire document segment can be deleted by deleting the document. However, the full graph structure is retained, allowing sophisticated search and traversal.\n\n#### Subdocuments overview\n\nDocuments can contain **subdocuments**. A subdocument:\n\n* Is owned by its containing document.\n* Is a segment of the graph which is solely pointed to by the containing document.\n* Can have any number of outgoing links to other documents or subdocuments.\n\nSee the [Subdocuments](#subdocuments) section for more information.\n\n### Simple documents\n\nDocuments are described by creating a class definition in the [schema](/docs/schema-reference-guide/). The simplest document definition contains properties with data elements only.\n\n#### A simple document example\n\nThe [Football roster CSV file](#datafootballrostercsvfile) is loaded using the [Football roster class definition](#codefootballrosterclassdefinition) below. This class definition describes the JSON document that can be submitted or retrieved from the graph.\n\nA valid [Football roster JSON document definition](#codefootballrosterjsondocumentdefinition), which corresponds to a row in the CSV file, is also shown below.\n\n#### Data: Football roster CSV file\n\n```\nname, position\nGeorge, Centre Back\nDoug, Full Back\nKaren, Centre Forward\n```\n\n#### Code: Football roster class definition\n\n```\n{ \"@type\" : \"@context\",\n \"@schema\" : \"terminusdb://Roster/schema#\",\n \"@base\" : \"terminusdb://Roster/document\" }\n\n{ \"@type\" : \"Class\",\n \"@id\" : \"Player\",\n \"name\" : \"xsd:string\",\n \"position\": \"xsd:string\" }\n```\n\n#### Code: Football roster JSON document definition\n\n```\n{ \"@type\" : \"Player\",\n \"@id\" : \"Player/George\",\n \"@base\" : \"terminusdb://Roster/document\",\n \"name\" : \"George\",\n \"position\": \"Centre Back\" }\n```\n\n#### The JSON document definition\n\nThe following table describes the properties of the JSON document definition above.\n\n#### Table: Properties of the JSON document definition\n\nProperty\n\nValue\n\nDescription\n\n`@type`\n\n`Player`\n\nThe type of data held - a football player\n\n`@id`\n\n`Player/George`\n\nThe address of the document used for retrieval, update, or deletion, or as a reference used in other documents. If the address in `@id` is **unambiguous**, for example, when used in the same collection, then `@id` can be used as-is, i.e., as `Player/George`. Otherwise, the `@base` property is required.\n\n`@base`\n\n`terminusdb://Roster/schema#`\n\nThe **fully qualified** address for `Player/George` expanding to `terminusdb://Roster/document/Player/George`.\n\n#### Unique document @id\n\nIt is important to ensure a unique document `@id`. The parameters `@key` and `@base` are available in the class definition, enabling you to use a calculated `@id`. Refer to the [Schema reference](/docs/schema-reference-guide/) for more information.\n\n### Documents with references\n\nTerminusDB enables references to other documents, forming a **graph of documents**.\n\n#### Create objects from data\n\nThe [simple document example](#asimpledocumentexample) introduced above is convertible to an object that refers to each player, as demonstrated in the code-snippet [Player and roster classes](#codeplayerandrosterclasses). In this snippet, the `Roster` class points to a `Set` of `Player`s (or `Player` classes.)\n\n#### The Set property\n\nThe `Set` property in the code-snippet is a _type family_ allowing us to state that the `player` property can have any number of `Player`s attached. `Set` does not provide ordering or multiplicity; a `Player` is either connected or not connected. For ordering and multiplicity, use `@type` `List` or `Array`.\n\n#### Code: Player and roster classes\n\n```\n{ \"@type\" : \"@context\",\n \"@schema\": \"terminusdb://Roster/schema#\",\n \"@base\" : \"terminusdb://Roster/document\" }\n\n{ \"@type\" : \"Class\",\n \"@id\" : \"Player\",\n \"name\" : \"xsd:string\",\n \"position\": \"xsd:string\" }\n\n{ \"@type\" : \"Class\",\n \"@id\" : \"Roster\",\n \"player\" : { \n \"@type\" : \"Set\",\n \"@class\": \"Player\" } }\n```\n\n#### Create documents from class specifications\n\nA set of documents that meets the above specification and that represents the data in the [Football roster CSV file](#datafootballrostercsvfile) can be defined as:\n\n#### Code: CSV roster data in document form\n\n```\n{ \"@type\" : \"Roster\",\n \"@id\" : \"Roster/Wolves\",\n \"player\": [ \"Player/George\", \"Player/Karen\", \"Player/Doug\" ] }\n\n{ \"@type\" : \"Player\",\n \"@id\" : \"Player/George\",\n \"name\" : \"George\",\n \"position\": \"Centre Back\" }\n\n{ \"@type\" : \"Player\",\n \"@id\" : \"Player/Doug\",\n \"name\" : \"Doug\",\n \"position\": \"Full Back\" }\n\n{ \"@type\" : \"Player\",\n \"@id\" : \"Player/Karen\",\n \"name\" : \"Karen\",\n \"position\": \"Centre Forward\" }\n```\n\nThe `Roster` points to the various `Player` documents. When requesting the document `Roster/Wolves`, each player in the `player` array is retrieved. Each identifier can be queried in a similar way to retrieve all associated documents.\n\n### Subdocuments\n\nA subdocument can only be pointed to by its containing document. It is information internal to the identity of a document and not intended to be shared. This designation enables deeply nested JSON documents that are self-contained and retrievable using the TerminusDB [document interface](/docs/document-insertion/).\n\n#### A subdocument example\n\nIn the subdocument example below, the schema specification defines players with a subdocument of `stats`. `Stats` is declared a subdocument using the `@subdocument` property and the special value `[]`. Also, it has a `Random` key, meaning the key is automatically generated if not provided.\n\n#### Code: An example of a player stats subdocument\n\n```\n{ \"@type\" : \"@context\",\n \"@schema\": \"terminusdb://Roster/schema#\",\n \"@base\" : \"terminusdb://Roster/document\" }\n\n{ \"@type\" : \"Class\",\n \"@id\" : \"Stats\",\n \"@subdocument\": [],\n \"@key\" : { \"@type\" : \"Random\" },\n \"strength\" : \"xsd:integer\",\n \"intelligence\": \"xsd:integer\",\n \"dexterity\" : \"xsd:integer\",\n \"charisma\" : \"xsd:integer\",\n \"wisdom\" : \"xsd:integer\",\n \"constitution\": \"xsd:integer\" }\n\n{ \"@type\": \"Class\",\n \"@id\" : \"Player\",\n \"name\" : \"xsd:string\",\n \"stats\": \"Stats\" }\n```\n\nIn the example below, the subdocument enables sending and retrieving `Stats` with the `Player` object. It is also possible for subdocuments to point recursively to other subdocuments or documents.\n\n#### Code: Stats with the player object\n\n```\n{ \"@type\" : \"Player\",\n \"@id\" : \"Player/Hieronymous\",\n \"stats\" : \n { \n \"@type\" : \"Stats\",\n \"strength\" : 14,\n \"intelligence\": 10,\n \"dexterity\" : 14,\n \"charisma\" : 8,\n \"wisdom\" : 12,\n \"constitution\": 9 \n } \n}\n```\n\n### Visualizing the Graph\n\nDocuments and subdocuments, and references to other documents, provide the best of both worlds: document storage and knowledge graphs. However, visualizing what this means requires a bit of experience.\n\n#### A graph visualization example\n\nThe following Contact graph diagram illustrates the boundaries around what constitutes a document and a subdocument.\n\nAn example schema representing this scenario is provided in the code-snippet [Contact graph schema](#codecontactgraphschema) further below with an example of a corresponding [Contact graph document](#codecontactgraph-document) definition.\n\nWith a bit of practice, designing your knowledge graphs in TerminusDB will become second nature.\n\n#### Diagram: Contact graph\n\n![](https://assets.terminusdb.com/docs/terminusdb-contact-graph-diagram.png)\n\n#### Code: Contact graph schema\n\n```\n{ \"@type\" : \"@context\",\n \"@schema\": \"terminusdb://Roster/schema#\",\n \"@base\" : \"terminusdb://Roster/document\" }\n\n{ \"@type\" : \"Class\",\n \"@id\" : \"Coordinate\",\n \"@subdocument\": [],\n \"@key\" : { \"@type\" : \"Random\" },\n \"lat\" : \"xsd:decimal\",\n \"long\" : \"xsd:decimal\" }\n\n{ \"@type\" : \"Class\",\n \"@id\" : \"Map\",\n \"coordinates\": { \"@type\" : \"Array\",\n \"@class\": \"Coordinate\" } }\n\n{ \"@type\": \"Class\",\n \"@id\" : \"Country\",\n \"name\" : \"xsd:string\",\n \"map\" : \"Map\" }\n\n{ \"@type\" : \"Class\",\n \"@id\" : \"Address\",\n \"@subdocument\": [],\n \"@key\" : { \"@type\" : \"Random\" },\n \"country\" : \"Country\",\n \"street\" : \"xsd:string\" }\n\n{ \"@type\" : \"Class\",\n \"@id\" : \"Person\",\n \"name\" : \"xsd:string\",\n \"address\": \"Address\",\n \"friend\" : \"Person\" }\n```\n\n#### Code: Contact graph document\n\n```\n{ \"@type\" : \"Person\",\n \"@id\" : \"Person/Joe\",\n \"name\" : \"Joe Bloggs\",\n \"address\": { \"@type\" : \"Address\",\n \"@id\" : \"Adress/aa1264e404a5b34381abc37cad83fabd\",\n \"street\" : \"Elm St.\",\n \"country\": \"Country/USA\" },\n \"friend\" : [ \"Person/Jill\" ] }\n\n{ \"@type\" : \"Person\",\n \"@id\" : \"Person/Jill\",\n \"name\" : \"Jill Smith\",\n \"address\": { \"@type\" : \"Address\",\n \"@id\" : \"Adress/5fba7438dc2b23258d304bb8cd1222bd\",\n \"street\" : \"Main St.\",\n \"country\": \"Country/Ireland\" },\n \"friend\" : [ \"Person/Joe\" ] }\n\n{ \"@type\" : \"Country\",\n \"@id\" : \"Country/USA\",\n \"name\" : \"USA\",\n \"coordinates\": [ ... ] }\n\n{ \"@type\" : \"Country\",\n \"@id\" : \"Country/Ireland\",\n \"name\" : \"Ireland\",\n \"coordinates\": [ ... ] }\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "TerminusCMS Documents Explanation", + "description": "The types of documents available in TerminusDB and TerminusCMS with examples of their definitions and interactions.", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + }, + "media": [ + { + "@type": "Media", + "alt": "", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "Image 1" + }, + "value": "https://assets.terminusdb.com/docs/terminusdb-contact-graph-diagram.png" + } + ] + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Glossary of Terms" + }, + "slug": "glossary", + "body": { + "@type": "Body", + "value": "> **Context:** Unless otherwise stated, the context for all definitions is computer, data, or information science.\n> \n> **Source:** Unless otherwise stated, the source of all definitions is [Wikipedia](https://en.wikipedia.org/wiki/Main_Page)\n\n## Graph concepts\n\n### Knowledge Graph\n\nThere are numerous definitions of knowledge graphs. One one the simpler definitions is: A digital structure that represents knowledge as concepts and the relationships between them (facts.) A knowledge graph can include an [ontology](#ontology) that allows both humans and machines to understand and reason about its contents.\n\n[Read more](https://en.wikipedia.org/wiki/Knowledge_graph#Definitions)\n\n### Graph database\n\nA database that uses [graph structures](#graphstructure) for [semantic queries](#semanticquery) with [nodes](#node), [edges](#edge), and [properties](#property) to represent and store data. The edges form the graph. The graph relates the data items in the store to a collection of nodes and edges, the edges representing the relationships between the nodes. The relationships allow data in the store to be linked together directly and, in many cases, retrieved with one operation. Graph databases hold the relationships between data as a priority. Querying relationships is fast because they are perpetually stored in the database. Relationships can be intuitively visualized using graph databases, making them useful for heavily inter-connected data\n\n[Read more](https://en.wikipedia.org/wiki/Graph_database)\n\n### Graph Structure\n\nAn abstract data type for implementing the graph theory concepts of [Undirected](#undirectedgraph) and [Directed](#directedgraph) graphs. The former concept consists of **unordered pairs** of vertices (also called [nodes](#node) or points.) The latter consists of **ordered pairs** of vertices.\n\nA graph data structure consists of a finite set of vertices, together with a set of unordered or ordered pairs of these vertices as defined above. These pairs are known as [edges](#edge) (also called links or lines, and sometimes called arrows or arcs for a directed graph.) The vertices may be part of the graph structure, or may be external [entities](#entity) represented by integer indices or references.\n\nA graph data structure may also associate an edge value to each edge, such as a symbolic label or a numeric attribute (cost, capacity, length, etc.)\n\n[Read more](https://en.wikipedia.org/wiki/Graph_\\(abstract_data_type\\))\n\n### Directed Graph\n\nA directed graph (or **digraph**) is a graph made up of vertices connected by directed [edges](#edge) often called **arcs**.\n\n[Read more](https://en.wikipedia.org/wiki/Directed_graph)\n\n### Ontology\n\nA way of showing the properties of a subject area and how they are related, by defining a set of concepts and categories that represent the subject. An ontology encompasses a representation, formal naming and definition of the categories, properties and relations between the concepts, data and entities that substantiate one, many, or all [domains](#domain) of discourse.\n\n[Read more](https://en.wikipedia.org/wiki/Ontology_\\(information_science\\))\n\n### Semantic Query\n\nSemantic queries allow for queries and analytics of an associative and contextual nature. Semantic queries enable the retrieval of both explicitly and implicitly derived information based on syntactic, semantic and structural information contained in data. They are designed to deliver precise results (possibly the distinctive selection of one single piece of information) or to answer more fuzzy and wide-open questions through pattern matching and digital reasoning.\n\n[Read more](https://en.wikipedia.org/wiki/Semantic_query)\n\n### Node\n\nA **vertex** (plural vertices) or **node** is the fundamental unit of which graphs are formed: an undirected graph consists of a set of vertices and a set of [edges](#edge) (unordered pairs of vertices), while a directed graph consists of a set of vertices and a set of **arcs** (ordered pairs of vertices). In a diagram of a graph, a vertex is usually represented by a circle with a label, and an edge is represented by a line or arrow extending from one vertex to another.\n\n[Read more](https://en.wikipedia.org/wiki/Vertex_\\(graph_theory\\))\n\n### Edge\n\nAn edge (together with [vertices](#node)) is one of the two basic units out of which graphs are constructed. Each edge has two (or in hypergraphs, more) vertices to which it is attached, called its **endpoints**. Edges may be [directed](#directedgraph) or undirected; undirected edges are also called **lines** and directed edges are also called **arcs** or **arrows**. In an undirected simple graph, an edge may be represented as the set of its [vertices](#node), and in a directed simple graph it may be represented as an ordered pair of its vertices. An edge that connects vertices x and y is sometimes written xy.\n\n[Read more](https://en.wikipedia.org/wiki/Glossary_of_graph_theory#edge)\n\n## Data\n\n### Delta Encoding\n\nA way of storing and transmitting data in the form of **deltas** (differences) between sequential data rather than complete files; sometimes referred to as data differencing. Delta encoding is sometimes called delta compression, particularly where archival histories of changes are required, for example, in revision control systems such as [GitHub](https://github.com) and the **TerminusDB** version-controlled graph databases.\n\n[Read more](https://en.wikipedia.org/wiki/Delta_encoding)\n\n### Metadata\n\nMetadata is data that provides information about other data, but not the content of the data, such as the text of a message or an image. There are many distinct types of metadata.\n\n[Read more](https://en.wikipedia.org/wiki/Metadata)\n\n### RDF\n\nThe **Resource Description Framework** (RDF) is a family of **W3C** specifications used as a general method for conceptual description or modeling of information that is implemented in web resources, using a variety of syntax notations and data [serialization](#serialization) formats.\n\n### Triple\n\nA **semantic triple**, or **RDF triple** or simply **triple**, is the atomic data entity in the [RDF](#rdf) data model. A triple is a set of three entities that codifies a statement about [semantic data](#semantic-data) in the form of [subject](#subject)–[predicate](#predicate)–[object](#object) expressions. Examples:\n\n#### Table: Subject-Predicate-Object examples\n\nSubject\n\nPredicate\n\nObject\n\nBob\n\nknows\n\nJohn\n\nBob\n\nis\n\n35\n\nThis format enables knowledge to be represented in a machine-readable way. Every part of an RDF triple is individually addressable via unique URIs. For example, the statement \"Bob knows John\" might be represented in RDF as:\n\n```\nhttp://example.name#Bob12 http://xmlns.com/foaf/0.1/knows http://example.name#John34\n```\n\n[Read more](https://en.wikipedia.org/wiki/Semantic_triple)\n\n### Semantic Data\n\nSemantic data or **Semantic Data Model** (SDM) is a high-level semantics-based database description or model. This database model is designed to capture more of the meaning of an application environment than is possible with contemporary database models.\n\n[Read more](https://en.wikipedia.org/wiki/Semantic_data_model)\n\n### Serialization\n\nThe process of translating a data structure or object state into a format that can be stored (for example, in a file or memory) or transmitted (for example, over a computer network) and reconstructed later (possibly in a different computer environment.)\n\n[Read more](https://en.wikipedia.org/wiki/Serialization)\n\n### Schema\n\nThe organization of data as a blueprint of how the database is constructed.\n\n[Read more](https://en.wikipedia.org/wiki/Database_schema)\n\n### Attribute\n\nThe columns of a table in relational databases. Similar to properties in graph databases.\n\n### Entity\n\nTables in relational databases. Similar to nodes in graph databases.\n\n### Relationship\n\nThe relationships between two tables in relational databases. In graph databases, relationships are directed and named connections between two nodes.\n\n## TerminusDB specific\n\n### WOQL\n\nWOQL (**Web Object Query Language**) is TerminusDB's query language for querying complex data patterns and structures. WOQL is based on three fundamental concepts: WOQL [triples](#triples), WOQL **variables** and WOQL **operators**. WOQL also provides [PCRE](#pcre).\n\n> WOQL does not use the [SPARQL](https://en.wikipedia.org/wiki/SPARQL) protocol.\n\n### Immutable\n\nIn programming, the state of an immutable object is unchangeable, i.e., its state cannot be modified after it is created. In TerminusDB, **immutable data** means an instance of data that cannot be changed after it is created. Newer instances or versions of that data can be created, but the tat version is immutable.\n\n[Read more](https://en.wikipedia.org/wiki/Immutable_object)\n\n### Mutable\n\nIn contrast to an [immutable](#immutable) object, a mutable object is changeable.\n\n[Read more](https://en.wikipedia.org/wiki/Immutable_object)\n\n### PCRE\n\n**Perl Compatible Regular Expressions** (PCRE) is a library that implements a regular expression engine, inspired by the capabilities of the Perl programming language. PCRE's syntax is more powerful and flexible than many other regular-expression libraries.\n\n[Read more](https://en.wikipedia.org/wiki/Perl_Compatible_Regular_Expressions)\n\n### IRI\n\nThe **Internationalized Resource Identifier** (IRI) is an internet protocol standard that builds on the Uniform Resource Identifier (URI) protocol by greatly expanding the set of permitted characters. IRIs extend URIs by using the Universal Character Set, where URIs were limited to ASCII, with far fewer characters. IRIs may be represented by a sequence of octets but by definition are defined as a sequence of characters, because IRIs may be spoken or written by hand.\n\n[Read more](https://en.wikipedia.org/wiki/Internationalized_Resource_Identifier)" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "TerminusCMS/DB Glossary of Terms", + "description": "A glossary of terms for TerminusDB and TerminusCMS", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Graphs Explanation" + }, + "slug": "graphs-explanation", + "body": { + "@type": "Body", + "value": "### Graph hierarchy\n\nA TerminusDB database is a hierarchical collection of [data graphs](#datagraphs) and [control graphs](#controlgraphs). These graphs are key to providing a graph database system with **collaboration** and **revision control**.\n\n#### Data graphs\n\nData graphs keep track of data and information about data. Each level of the database hierarchy is a combination of the following data graphs.\n\n* **Instance graphs** contain data for a given level in a hierarchy.\n* **Schema graphs** contain information about what data is allowed and how to interpret it.\n* **Inference graphs** enable facts to be inferred about the data.\n\n#### Control graphs\n\nControl graphs govern data graphs and database functionality. Each level of the control graph hierarchy, listed below, consists of one or more data graphs. The remainder of this article explains each control graph and the lowest level of the hierarchy - layers.\n\n* **Repository graphs** for collaboration.\n* **Commit graphs** for revision control.\n* **Branch graphs** for data storage and correctness.\n* **Layers** for storing data changes.\n\n### Repository graphs\n\nRepository graphs provide collaboration and communication with other TerminusDB instances and keep track of other TerminusDB repositories.\n\n#### Referencing repository graphs\n\nRepository graphs are referenced using the name `_meta` which contains links with various repositories.\n\n#### Repository naming\n\nA repository is addressed by specifying its organization and name. For example, organization `admin`, database name `foo` expressed as `admin/foo`.\n\n#### Local repositories\n\nThe identifier `local` is used for specifying local repositories, for example, `admin/foo/local`.\n\nA local repository in the repository instance data has **layer identifiers** that point to associated commit graphs.\n\n#### Remote repositories\n\nAn identifier other than `local` is used for specifying remote repositories (or remotes.) For example `admin/foo/origin`.\n\nA remote in the repository instance data has layer identifiers **and** the URL of the remote. The URL enables communication with the remote and enables push and pull from various remotes to update and synchronize with the local repository.\n\n### Commit graphs\n\nCommit graphs provide revision control. They contain the information required for time-travel, branch, squash, reset and rebase operations. Commit graphs hold information about branches and all commits on them.\n\n#### Referencing commit graphs\n\nCommit graphs are referenced by appending the name `_commits` to the database identifier, for example: `admin/foo/local/_commits`. Commits are trackable on local and remote TerminusDB instances enabling synchronization with different instances.\n\n#### Branch objects in commit graphs\n\nBranch objects in a commit-graph point to a commit object. A commit object is associated with layers representing the branch of interest. A commit object also has parent commits if the commit has a history.\n\n### Branch graphs\n\nBranch graphs store data in a queryable format and ensure the correctness of data by maintaining a schema.\n\n#### Referencing branch graphs\n\nBranch graphs are referenced with the name `branch` followed by the branch of interest. The default is `main`. For example `admin/foo/local/branch/main`.\n\n### Layers\n\nThe lowest level of the hierarchy is a single graph composed of a sequence of layers. Layers specify each change to data such as additions and deletions.\n\n### Transactions in graphs\n\nA transaction in a graph is also a hierarchical operation, ensuring [ACID transactions](/docs/acid-transactions-explanation/). An update transaction has the following stages:\n\n* The layers of a branch graph are updated, resulting in the addition of new layers.\n* A schema check is performed. If the check succeeds, the layer names of the updated graphs are obtained (an update can affect several graphs simultaneously.)\n* New layers are written as commit objects in the commit instance graph, and the head of the branch is moved, resulting in a new instance graph for the commit-graph.\n* The layer name of the new instance graph is written to the repository graph, enabling the identification of the current, most recent state of the repository.\n* The layer name of the repository graph is labeled as the newest version and kept in the layer store as a named pointer to a layer.\n\n### Further Reading\n\n#### [Documents in a knowledge graph and how to use them](/docs/documents-explanation/)" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Graphs Explanation", + "description": "An introduction to the hierarchy and system of graphs used by TerminusDB and TerminusCMS for collaboration and revision control.", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Immutability Explanation" + }, + "slug": "immutability-explanation", + "body": { + "@type": "Body", + "value": "TerminusDB is an immutable data store. When data is written to a store, it does not change or mutate existing data. Any deleted data is masked, any new data resulting from a transaction is added on top of the mask.\n\n### Advantages of immutability\n\nImmutability has several advantages, including:\n\n* [Transaction safety](#transactionsafety)\n* [Lock-free concurrency](#lockfreeconcurrency)\n* [Commit and branch time travel](#commitandbranchtimetravel)\n* [Change audit](#changeaudit)\n* [Collaboration and synchronization](#collaborationandsynchronization)\n\n### Transaction safety\n\nTransactions are safer and more reliable in an immutable store and any issues during transactions are easier to handle. In most cases, even in system crashes, TerminusDB resumes operation with data integrity intact and any incomplete transactions are undone.\n\n### Lock-free concurrency\n\nTerminusDB uses immutable data structures making it lock-free in most cases. The query engine uses optimistic concurrency allowing transactions to retry if their state changed while executing. The lack of locking simplifies the engine and makes deadlocks very unlikely while providing [ACID](/docs/acid-transactions-explanation/) guarantees.\n\n### Commit and branch time travel\n\nThe transaction history of TerminusDB databases is preserved. It is easy to travel back in time to a commit or branch and create a new database starting at any commit. All data and information at a commit point are immediately available, eliminating the requirement to rebuild the state of a past commit.\n\n### Change audit\n\nTime travel is supplemented with information about what was committed, at what date and time, and by whom. Data provenance is reliably tracked adding significant value to data in regulated environments.\n\n### Collaboration and synchronization\n\nHistorical commit information is also required for TerminusDB collaboration functionality. The state of two databases that share a common lineage can be compared. Commits made by different authors can be rerun on the current database using a rebase operation, enabling the synchronization of both databases." + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "TerminusCMS Immutability Explanation", + "description": "An explanation of how TerminusDB & TerminusCMS implements immutability, and handles deleted and new data.", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "TerminusDB Explanation" + }, + "slug": "terminusdb-explanation", + "body": { + "@type": "Body", + "value": "### What is TerminusDB?\n\nTerminusDB is a powerful, in-memory graph database enabling you to maximize your productivity and the value of your data. TerminusDB has numerous features and several interfaces enabling you to create data-intensive, immutable, and synchronized databases with built-in version control and other [Git-like](#gitlikemodel) operations.\n\n#### Diagram: Some key features of TerminusDB\n\n![](https://assets.terminusdb.com/docs/terminusdb-what-is-it.png)\n\n### Why choose TerminusDB?\n\nA few of the many reasons to choose TerminusDB as your graph database solution:\n\n#### An enterprise-level graph database\n\nEnterprise-level availability, functionality, performance, scalability, and stability. TerminusDB is a data-intensive, in-memory, high-speed and scalable platform suitable for both small and enterprise-level applications.\n\n#### Quick and easy to use\n\nMaximize your productivity and start realizing the value of your data by having your databases up and running in a few minutes. Easily create, query, and maintain your databases using graphical and programmatic interfaces.\n\n#### Feature-rich and Git-like\n\nNumerous unique features and [Git-like](#gitlikemodel) operations including clone, branch, merge, control and time-travel. TerminusDB databases are immutable, fully preserving data lineage and change history with built-in revision control, similar to distributed version control systems.\n\n#### Advanced query language\n\nA powerful query language enabling fast and recursive searches across complex data patterns.\n\n#### Forms and data validation\n\nGenerate forms for viewing and entering data with automatic data validation.\n\n#### Visual model builder\n\nUse a lightweight Graphical User Interface to easily build, maintain and enforce complex data models.\n\n#### Multiple interfaces\n\nCreate and maintain your databases using programmatic interfaces such as JavaScript and Python APIs.\n\n#### Data-centric collaboration\n\nTerminusDB is highly configurable with powerful features for rapidly and collaboratively creating synchronized, application-centric and data-centric databases. Maximize productivity through application and data-centric distributed development and collaboration.\n\n#### Diagram: Reasons to choose TerminusDB\n\n![](https://assets.terminusdb.com/docs/terminusdb-why-choose.png)\n\n### Git-like model\n\nTerminusDB has many Git-like features including revision-control and distributed collaboration. Similar to Git, TerminusDB is open source, model-driven, and uses the **Resource Description Framework** ([RDF](/docs/glossary/#rdf)) specification for collaboration.\n\n#### Delta-encoding\n\nTerminusDB implements an advanced Git-like model, using [delta encoding](/docs/glossary/#deltaencoding) to store append or delta-only changes to graphs. These deltas are stored in succinct [terminusdb-store](https://github.com/terminusdb/terminusdb-store) data structures. The delta encoding approach enables branch, merge, push, pull, clone, time-travel, and other Git-like operations.\n\n#### Diagram: TerminusDB Git-like operations\n\n![](https://assets.terminusdb.com/docs/terminusdb-git-model.png)\n\n### Further Reading\n\n#### TerminusDB whitepaper\n\nRead our [white paper on succinct data structures and delta encoding in modern databases](https://terminusdb.com/blog/succinct-data-structures-for-modern-databases/).\n\n#### Get started\n\n[Get Started](/docs/get-started-with-terminusdb/) with an overview of the available [Installation Options](/docs/terminusdb-install-options/) and then check out the [how-to guides](/docs/use-the-clients/) for step-by-step help.\n\n#### TerminusCMS\n\nTake a look at the [product tour of TerminusCMS](/docs/product-tour/) for information about the headless content management system.\n\n#### Documents\n\n[Documents](/docs/documents-explanation/) in a knowledge graph and how to use them." + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "TerminusDB Explanation", + "description": "A high-level description of what TerminusDB is, reasons for using TerminusDB, and its Git-like features.", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + }, + "media": [ + { + "@type": "Media", + "alt": "", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "Image 1" + }, + "value": "https://assets.terminusdb.com/docs/terminusdb-what-is-it.png" + }, + { + "@type": "Media", + "alt": "", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "Image 2" + }, + "value": "https://assets.terminusdb.com/docs/terminusdb-why-choose.png" + }, + { + "@type": "Media", + "alt": "", + "caption": "", + "media_type": "Image", + "title": { + "@type": "Title", + "value": "Image 3" + }, + "value": "https://assets.terminusdb.com/docs/terminusdb-git-model.png" + } + ] + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "What is Schema Weakening" + }, + "slug": "what-is-schema-weakening", + "body": { + "@type": "Body", + "value": "A schema describes the shape of data in a data product. It provides constraints and assurances about what kind of data will be retrieved.\n\nHowever, often you need to _change_ the schema in the process of developing a data product.\n\n## What is a weak versus a strong schema change?\n\nA schema change is a _weakening_ of the schema if the change can not possibly invalidate any data which was present in the original schema.\n\nSome examples of weakening include:\n\n* Adding a new class that is not the parent of any existing class is always valid since there are no elements of this class.\n* Adding a new _optional_ property to a class is also permitted.\n* Changing a required field to _optional_ or _set_.\n\nSchema weakening is often a desirable approach to schema change as we do not require alterations to any of our data. This can ensure a form of backward compatibility which can avoid problems in long term maintenance.\n\n## Using weakened schemas safely\n\nThe _weakening_ approach also suggests an appropriate style for the consumption of data that is received by clients. The exact shape of a document should not be relied on, as new optional properties could be added, and required properties could be weakened to become optional.\n\nWe should instead test for the existence of a field, before attempting to consume it, and we should avoid clients requiring fields that are not part of a _key_.\n\n## Why do schemas evolve?\n\nSchema evolution can happen at various phases in data product development.\n\nAt the beginning of schema development, it is often the case that the schema evolves very rapidly as we try to capture the important information for consideration or change the way it should be represented.\n\nIn this phase it is common for schema changes to be _strong_, that is they require that the data, if it exists, to be modified.\n\nIf there is very little data it can sometimes be more convenient to delete the data and then alter the schema, to avoid schema violations. Alternatively, one can try to use [schema migration](/docs/schema-migration-reference-guide/) to achieve the desired changes.\n\nLater in schema evolution, there will be clients that rely on the shape of data, and any strong change will require filling data, deleting data, or modifying data which is associated with the existing schema. This strong change will _require_ [schema migration](/docs/schema-migration-reference-guide/).\n\nThis also means that we need to pay special attention to keeping the two in sync. This can best be done by focusing on schema weakening, coupled with a defensive client style as described above." + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "What is Schema Weakening | TerminusCMS", + "description": "An explanation about schema weakening and why you need it to change a schema.", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "WOQL Explanation" + }, + "slug": "woql-explanation", + "body": { + "@type": "Body", + "value": "### WOQL fluent vs. functional style\n\nWOQL supports both **fluent** and **functional** styles for writing queries. The fluent style is recommended for simplifying complex compound query expressions.\n\n#### The fluent style\n\nMany WOQL expressions accept a sub-query as an argument. WOQL enables appending sub-queries to the initial function as a new function. Queries in this style are easier to read and write. Visual parameter matching is easier to perform when checking for query correctness. A simple example below.\n\n#### Code: Fluent style WOQL\n\n```\nselect(a, b).triple(c, d, e)\n```\n\n#### The functional style\n\nSub-queries are contained within the initial function. The example below is the functional style equivalent of the fluent style example.\n\n#### Code: Functional style WOQL\n\n```\nselect(a, b, triple(c, d, e))\n```\n\n#### Conjunctions\n\nFluent queries are parsed left to right. Functions to the right of another function are considered sub-queries of the first function, with one important exception - **conjunction**.\n\n#### Functional style conjunction\n\nThe functional style of expressing conjunction using the WOQL `and()` function is straightforward and is often more useful for clarity:\n\n#### Code: Functional style conjunction\n\n```\nand(triple(a, b, c), triple(d, e, f))\n```\n\n#### Fluid style conjunction\n\nConjunction expressed in fluent style enables the use of any of the three variations shown below.\n\n#### Code: Fluent style conjunction\n\n```\n// Fluent style 1\nand(triple(a, b, c)).triple(d, e, f)\n\n// Fluent style 2\ntriple(a, b, c).and().triple(d, e, f)\n\n// Fluent style 3\ntriple(a, b, c).triple(d, e, f)\n```\n\n#### Implicit and()\n\nIn the example above, fluent style 3 is more concise and unambiguous where WOQL functions that are chained together do not take sub-clauses (or commands.) As conjunction is frequently used, this concise form, where the `and()` is implicit, is more convenient in many situations.\n\n!> Use implicit `and()` with care.\n\n?> if in doubt, use the explicit `and()` functional style as this clarifies which functions are sub-clauses of other functions.\n\nThe conjunction is always applied to the function immediately to the left of the period `.` in the chain, and not to any functions further up the chain. If used improperly with clauses that take sub-clauses, it will produce improperly specified queries, especially with negation (`not`) and optional functions (`opt`).\n\nFor example, consider the following three queries. The first two are equivalent. However, the first query is incorrect and easy to misinterpret when the intended expression is that shown in the third query.\n\n#### Code: Fluent style implicit conjunction\n\n```\ntriple(a, b, c).opt().triple(d, e, f).triple(g, h, i)\n```\n\n#### Code: Functional style explicit conjunction\n\n```\nand(\n triple(a, b, c),\n opt(\n and(\n triple(d, e, f),\n triple(g, h, i)\n )\n )\n)\n```\n\n#### Code: Fluent style explicit conjunction\n\n```\nand(\n triple(a, b, c),\n opt().triple(d, e, f),\n triple(g, h, i)\n)\n```\n\n### WOQL and JSON-LD\n\nWOQL uses JSON-LD and a formally specified [ontology](/docs/glossary/#ontology) to define the language and transmit queries.\n\nJSON-LD is sometimes tedious for us to read and write. Therefore, WOQL.js is designed to be as easy as possible for developers to write. All WOQL.js queries are translated into the equivalent JSON-LD format for transmission over networks.\n\n#### The WOQLQuery object\n\nThe WOQL.js `json()` function translates any WOQL query to its JSON-LD format, and JSON-LD to its WOQL.js equivalent - a `WOQLQuery()` object.\n\nAs shown in the example below, if passed a JSON-LD (`json_ld`) argument, WOQL.js (`wjs`) will generate the equivalent `WOQLQuery()` object. If an argument is not provided, WOQL.js will return the JSON-LD equivalent of the `WOQLQuery()` object.\n\n#### Code: Using WOQLQuery() and json()\n\n```javascript\nlet wjs = new WOQLQuery().json(json_ld)\njson_ld == wjs.json()\n```\n\n#### Embedding JSON-LD in WOQL.js\n\nIt is possible to use JSON-LD interchangeably within WOQL.js. Wherever a WOQL function or argument can be accepted directly in WOQL.js, the JSON-LD equivalent can also be supplied. For example, the following two WOQL statements are identical.\n\nThere should never be a situation that necessitates using JSON-LD directly. WOQL.js expresses all queries that are expressible in the underlying JSON-LD. However, it can be convenient to embed JSON-LD in queries in some cases.\n\n#### Code: Interchangeable WOQL and JSON-LD\n\n```\ntriple(a, b, 1) == triple(a, b, {\"@type\": \"xsd:integer\", \"@value\": 1})\n```\n\n### WOQL variables\n\nWOQL allows variables or constants to be substituted for any argument to all its functions, except for the resource identifier functions: `using`, `with`, `into`, `from`. These functions are used for specifying the graphs against which operations such as queries are carried out.\n\n#### Unification\n\nWOQL uses the formal-logical approach to variables known as unification borrowed from the Prolog engine that implements WOQL within TerminusDB.\n\n#### Unification in variables\n\nUnification in variables means each valid value for a variable, as constrained by the totality of the query, will produce a new row in the results. For multiple variables, the rows returned are the cartesian product of all the possible combinations of variable values in the query.\n\n#### Unification in functions\n\nUnification in functions enables most WOQL functions to serve as both pattern matchers and pattern generators, depending on whether a variable or constant is provided as an argument. If a variable is provided, WOQL will generate all possible valid solutions which fill the variable value. If a constant is provided, WOQL will match only those solutions with exactly that value. Except for resource identifiers, WOQL functions accept either variables or constants in virtually all of their arguments.\n\n#### Expressing variables\n\nIn WOQL.js, there are two distinct ways of expressing variables within queries. All are semantically equivalent. The first is generally preferred as it is easier to type and easier to distinguish variables from constants at a glance due to the lack of quotation marks around the variables\n\n#### Code: WOQL variables using let\n\n```javascript\nlet [a, b, c] = vars('a', 'b', 'c')\ntriple(a, b, c)\n```\n\n#### Code: WOQL variables using prefix v:\n\n```\ntriple('v:a', 'v:b', 'v:c')\n```\n\n### WOQL prefixes\n\nInternally, TerminusDB uses strict [RDF](/docs/glossary/#rdf) rules to represent all data. This means all identifiers and properties are represented by [IRIs](/docs/glossary/#iri) (a superset of URLs.)\n\n#### Shorthand prefixes\n\nHowever, IRIs are difficult to remember and tedious to type. RDF generally solves this problem by allowing prefixed shorthand forms. For example, `\"http://obscure.w3c.url/with/embedded/dates#type\"` is shortened to `\"rdf:type\"`.\n\n#### Prefixes @base and @schema\n\nTerminusDB also defines the two **optional** prefixes listed below. These enable users to write expressions such as `\"@base:X\"` or `\"@schema:X\"` and ensure expressions always resolve to valid IRIs in all databases.\n\n* The `\"@base\"` prefix for instance-data IRIs.\n* The `\"@schema\"` prefix for schema IRIs.\n\n#### Automatic prefixes\n\nWOQL goes a step beyond supporting prefixes by automatically applying prefixes where possible, enabling users to specify prefixes only when necessary. The default prefixes are applied as follows:\n\n* `\"@base\"` applies to **woql:subject** (first argument to triple) where **instance data IRIs** are normally required.\n* `\"@schema\"` applies to **woql:predicate** and other arguments (`sub`, `type`) where **schema elements** are normally required.\n* When standard predicates are used without a prefix, the standard correct prefixes are applied.\n* `label`\n* `type`\n* `comment`\n* `subClassOf`\n* `domain`\n* `range`\n* Otherwise, if no prefix is applied a string is assumed.\n\n### Further Reading\n\n#### WOQL Reference\n\n[JavaScript](/docs/javascript/) and [Python](/docs/python/) WOQL Reference guides\n\n#### How-to guides\n\nSee the [How-to Guides](/docs/use-the-clients/) for further examples of using WOQL.\n\n#### Documents\n\n[Documents](/docs/documents-explanation/) in a knowledge graph and how to use them." + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "WOQL Explanation", + "description": "A brief explanation of the TerminusDB Web Object Query Langauge (WOQL)", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } + }, + { + "@type": "Page", + "title": { + "@type": "Title", + "value": "Access Control with the JavaScript Client Reference Guide" + }, + "slug": "js-client-access-control-reference", + "body": { + "@type": "Body", + "value": "**License**: Apache Version 2\n\n## new AccessControl()\n\nThe AccessControl is a driver to work with TerminusDB and TerminusX access control api for the credential you can use the JWT token, the API token or the basic authentication with username and password\n\n**Example**\n\n```javascript\n//connect with the API token\n//(to request a token create an account in https://terminusdb.com/)\nconst accessContol = new AccessControl(\"https://servername.com\",\n{organization:\"my_team_name\",\ntoken:\"dGVybWludXNkYjovLy9kYXRhL2tleXNfYXB........\"})\naccessControl.getOrgUsers().then(result=>{\n console.log(result)\n})\n//connect with the jwt token this type of connection is only for the dashboard\n//or for application integrate with our login workflow\nconst accessContol = new AccessControl(\"https://servername.com\",\n{organization:\"my_team_name\",\njwt:\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IkpXUjBIOXYyeTFORUd........\"})\naccessControl.getOrgUsers().then(result=>{\n console.log(result)\n})\n//if the jwt is expired you can change it with\naccessControl.setJwtToken(\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IkpXUjBIOXYy\neTFORUd.......\")\n//connect with the base authentication this type of connection is only for the local installation\nconst accessContol = new AccessControl(\"http://localhost:6363\",\n{organization:\"my_team_name\", user:\"admin\"\nkey:\"mykey\"})\naccessControl.getOrgUsers().then(result=>{\n console.log(result)\n})\n```\n\n## getDefaultOrganization\n\n##### accessControl.getDefaultOrganization(params) ⇒ `string` | `undefined`\n\nGet a organization from parameters.\n\n**Returns**: `string` | `undefined` - - organization\n\nParam\n\nType\n\nDescription\n\nparams\n\n`object`\n\nThe parameters\n\n## setJwtToken\n\n##### accessControl.setJwtToken(jwt)\n\nSets the Jwt token for the object\n\nParam\n\nType\n\nDescription\n\njwt\n\n`string`\n\nThe jwt api token to use\n\n## setApiToken\n\n##### accessControl.setApiToken(atokenpi)\n\nSets the API token for the object, to request a token create an account in https://terminusdb.com/\n\nParam\n\nType\n\nDescription\n\natokenpi\n\n`string`\n\nThe API token to use to connect with TerminusX\n\n## setApiKey\n\n##### accessControl.setApiKey(atokenpi)\n\nSets the API token for the object, to request a token create an account in https://terminusdb.com/\n\nParam\n\nType\n\nDescription\n\natokenpi\n\n`string`\n\nThe API token to use to connect with TerminusX\n\n## getAPIUrl\n\n##### accessControl.getAPIUrl(cloudAPIUrl) ⇒ `string`\n\nGet a API url from cloudAPIUrl\n\n**Returns**: `string` - apiUrl\n\nParam\n\nType\n\nDescription\n\ncloudAPIUrl\n\n`string`\n\nThe base url for cloud\n\n## customHeaders\n\n##### accessControl.customHeaders(customHeaders) ⇒ `object`\n\nadd extra headers to your request\n\nParam\n\nType\n\ncustomHeaders\n\n`object`\n\n## getOrganization\n\n##### accessControl.getOrganization(organization) ⇒ `object`\n\n\\-- TerminusDB API --- Get an organization from the TerminusDB API.\n\n**Returns**: `object` - - organization\n\nParam\n\nType\n\nDescription\n\norganization\n\n`string`\n\nThe organization\n\n## getAllOrganizations\n\n##### accessControl.getAllOrganizations() ⇒ `Promise`\n\n\\-- TerminusDB API --- This end point works in basic authentication, admin user Get list of organizations\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\n## createOrganization\n\n##### accessControl.createOrganization(orgName) ⇒ `Promise`\n\n\\-- TerminusDB API --- This end point works in basic authentication, admin user Create an organization\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\norgName\n\n`string`\n\nThe organization name to create\n\n**Example**\n\n```\naccessControl.createOrganization(\"my_org_name\").then(result=>{\n console.log(result)\n})\n```\n\n## deleteOrganization\n\n##### accessControl.deleteOrganization(orgName) ⇒ `Promise`\n\n\\-- TerminusDB API --- Delete an Organization\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\norgName\n\n`string`\n\nThe organization name to delete\n\n**Example**\n\n```\naccessControl.createOrganization(\"my_org_name\").then(result=>{\n console.log(result)\n})\n```\n\n## createRole\n\n##### accessControl.createRole(\\[name\\], \\[actions\\]) ⇒ `Promise`\n\n\\--TerminusDB API --- basic authentication, admin user. Create a new role in the system database.\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\n\\[name\\]\n\n`string`\n\nThe role name.\n\n\\[actions\\]\n\n`typedef.RolesActions`\n\nA list of actions\n\n**Example**\n\n```\naccessControl.createRole(\"Reader\",[ACTIONS.INSTANCE_READ_ACCESS]).then(result=>{\n console.log(result)\n})\n```\n\n## deleteRole\n\n##### accessControl.deleteRole(\\[name\\]) ⇒ `Promise`\n\n\\-- TerminusdDB API --- basic Authentication, admin user. Delete role in the system database, (this api is enabled only in the local installation)\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\n\\[name\\]\n\n`string`\n\nThe role name.\n\n**Example**\n\n```\naccessControl.deleteRole(\"Reader\").then(result=>{\n console.log(result)\n})\n```\n\n## getAllUsers\n\n##### accessControl.getAllUsers() ⇒ `Promise`\n\n\\-- TerminusdDB API --- basic Authentication, admin user. Return the list of all the users (this api is enabled only in the local installation)\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected. \n**Example**\n\n```\naccessControl.getAllUsers().then(result=>{\n console.log(result)\n})\n```\n\n## createUser\n\n##### accessControl.createUser(name, \\[password\\]) ⇒ `Promise`\n\n\\-- TerminusdDB API --- basic Authentication, admin user. Add the user into the system database\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\nname\n\n`string`\n\nthe user name\n\n\\[password\\]\n\n`string`\n\nyou need the password for basic authentication\n\n**Example**\n\n```\naccessControl.deleteUser(userId).then(result=>{\n console.log(result)\n})\n```\n\n## deleteUser\n\n##### accessControl.deleteUser(userId) ⇒ `Promise`\n\n\\-- TerminusdDB API --- basic Authentication, admin user. Remove the user from the system database.\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\nuserId\n\n`string`\n\nthe document user id\n\n**Example**\n\n```\naccessControl.deleteUser(userId).then(result=>{\n console.log(result)\n})\n```\n\n## manageCapability\n\n##### accessControl.manageCapability(userName, resourceName, rolesArr, operation, scopeType) ⇒ `Promise`\n\n\\-- TerminusdDB API --- Grant/Revoke Capability\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\nuserName\n\n`string`\n\nthe document user id\n\nresourceName\n\n`string`\n\nthe name of a (database or team)\n\nrolesArr\n\n`array`\n\nthe roles name list\n\noperation\n\n`typedef.CapabilityCommand`\n\ngrant/revoke operation\n\nscopeType\n\n`typedef.ScopeType`\n\nthe resource type (database or organization)\n\n**Example**\n\n```\n//we add an user to an organization and manage users' access\n//the user myUser can access the Organization and all the database under the organization with \"reader\" Role\nclient.manageCapability(myUser,myteam,[reader],\"grant\",\"organization\").then(result=>{\n consol.log(result)\n})\n//the user myUser can access the database db__001 under the organization myteam\n//with \"writer\" Role\nclient.manageCapability(myUser,myteam/db__001,[writer],\"grant\",\"database\").then(result=>{\n consol.log(result)\n})\n```\n\n## getAccessRoles\n\n##### accessControl.getAccessRoles() ⇒ `Promise`\n\n\\--TerminusX and TerminusDB API --- Get all the system database roles types.\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\n## getOrgUsers\n\n##### accessControl.getOrgUsers(\\[orgName\\]) ⇒ `Promise`\n\n\\-- TerminusX and TerminusDB API -- Get all the organization's users and roles,\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\n\\[orgName\\]\n\n`string`\n\nThe organization name.\n\n**Example**\n\n```javascript\naccessControl.getOrgUsers().then(result=>{\n console.log(result)\n})\n//this function will return an array of capabilities with users and roles\n//-- TerminusX -- response array example\n//[{capability: \"Capability/3ea26e1d698821c570afe9cb4fe81a3......\"\n// email: {@type: \"xsd:string\", @value: \"user@terminusdb.com\"}\n// picture: {@type: \"xsd:string\",…}\n// role: \"Role/dataReader\"\n// scope: \"Organization/my_org_name\"\n// user: \"User/auth0%7C613f5dnndjdjkTTT\"}]\n//\n//\n// -- Local Installation -- response array example\n//[{ \"@id\":\"User/auth0%7C615462f8ab33f4006a6bee0c\",\n// \"capability\": [{\n// \"@id\":\"Capability/c52af34b71f6f8916ac0115ecb5fe0e31248ead8b1e3d100852015...\",\n// \"@type\":\"Capability\",\n// \"role\": [{\n// \"@id\":\"Role/admin\",\n// \"@type\":\"Role\",\n// \"action\": [\"instance_read_access\"],\n// \"name\":\"Admin Role\"\n// }],\n// \"scope\":\"Organization/@team\"}]]\n```\n\n## getTeamUserRoles\n\n##### accessControl.getTeamUserRoles(\\[userName\\], \\[orgName\\]) ⇒ `Promise`\n\n\\-- TerminusX and TerminusDB API -- Get the user roles for a given organization or the default organization,\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\n\\[userName\\]\n\n`string`\n\nThe organization name.\n\n\\[orgName\\]\n\n`string`\n\nThe organization name.\n\n**Example**\n\n```\naccessControl.getTeamUserRole(\"myUser\").then(result=>{\n console.log(result)\n})\n//response object example\n{\n \"@id\": \"User/myUser\",\n \"capability\": [\n {\n \"@id\":\"Capability/server_access\",\n \"@type\":\"Capability\",\n \"role\": [{\n \"@id\":\"Role/reader\",\n \"@type\":\"Role\",\n \"action\": [\n \"instance_read_access\",\n ],\n \"name\":\"reader\"\n }],\n \"scope\":\"Organization/myteam\"\n }\n ],\n \"name\": \"myUser\"\n}\n```\n\n## ifOrganizationExists\n\n##### accessControl.ifOrganizationExists(orgName) ⇒ `Promise`\n\n\\-- TerminusX API --- Check if the organization exists. it is a Head call . IMPORTANT This does not work with the API-TOKEN.\n\n**Returns**: `Promise` - A promise that returns the call status object, 200: if the organization exists and 404: if the organization does not exist\n\nParam\n\nType\n\nDescription\n\norgName\n\n`string`\n\nThe organization name to check if exists.\n\n## createOrganizationRemote\n\n##### accessControl.createOrganizationRemote(orgName) ⇒ `Promise`\n\n\\-- TerminusX API --- IMPORTANT This does not work with the API-TOKEN. Create an organization\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\norgName\n\n`string`\n\nThe organization name to create\n\n**Example**\n\n```\naccessControl.createOrganization(\"my_org_name\").then(result=>{\n console.log(result)\n})\n```\n\n## getPendingOrgInvites\n\n##### accessControl.getPendingOrgInvites(\\[orgName\\]) ⇒ `Promise`\n\n\\-- TerminusX API --- Get the pending invitations list.\n\n**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\n\\[orgName\\]\n\n`string`\n\nThe organization name.\n\n**Example**\n\n```javascript\nconst invitationList = accessControl.getPendingOrgInvites().then(result=>{\n console.log(invitationList)\n})\n//this will return an array of invitations object like this\n//[{@id: \"Organization/my_team_name/invitations/Invitation/7ad0c9eb82b6175bcda9c0dfc2ac51161ef5ba\ncb0988d992c4bce82b3fa5d25\"\n// @type: \"Invitation\"\n// creation_date: \"2021-10-22T11:13:28.762Z\"\n// email_to: \"new_user@terminusdb.com\"\n// invited_by: \"User/auth0%7C6162f8ab33567406a6bee0c\"\n// role: \"Role/dataReader\"\n// status: \"needs_invite\"}]\n```\n\n## sendOrgInvite\n\n##### accessControl.sendOrgInvite(userEmail, role, \\[note\\], \\[orgName\\]) ⇒ `Promise`\n\n\\-- TerminusX API --- Send a new invitation **Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\nuserEmail\n\n`string`\n\nThe email of user.\n\nrole\n\n`string`\n\nThe role for user. (the document @id role like Role/collaborator)\n\n\\[note\\]\n\n`string`\n\nThe note to send with the invitation.\n\n\\[orgName\\]\n\n`string`\n\nThe organization name.\n\n**Example**\n\n```\naccessControl.sendOrgInvite(\"new_user@terminusdb.com\",\"Role/admin\",\n\"please join myteam\").then(result=>{\n console.log(result)\n})\n```\n\n## getOrgInvite\n\n##### accessControl.getOrgInvite(inviteId, \\[orgName\\]) ⇒ `Promise`\n\n\\-- TerminusX API --- Get the invitation info **Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\ninviteId\n\n`string`\n\nThe invite id to retrieve.\n\n\\[orgName\\]\n\n`string`\n\nThe organization name.\n\n**Example**\n\n```javascript\nconst fullInviteId=\"Organization/my_team_name/invitations/Invitation/7ad0c9eb82b6175bcda9c0dfc\n2ac51161ef5ba7cb0988d992c4bce82b3fa5d25\"\naccessControl.getOrgInvite(fullInviteId).then(result=>{\n console.log(result)\n})\n```\n\n## deleteOrgInvite\n\n##### accessControl.deleteOrgInvite(inviteId, \\[orgName\\]) ⇒ `Promise`\n\n\\-- TerminusX API --- Delete an invitation **Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\ninviteId\n\n`string`\n\nThe invite id to delete.\n\n\\[orgName\\]\n\n`string`\n\nThe organization name.\n\n**Example**\n\n```javascript\nconst fullInviteId=\"Organization/my_team_name/invitations/Invitation/7ad0c9eb82b6175bcda9\nc0dfc2ac51161ef5ba7cb0988d992c4bce82b3fa5d25\"\naccessControl.deleteOrgInvite(fullInviteId).then(result=>{\n console.log(result)\n})\n```\n\n## updateOrgInviteStatus\n\n##### accessControl.updateOrgInviteStatus(inviteId, accepted, \\[orgName\\]) ⇒ `Promise`\n\n\\-- TerminusX API --- Accept /Reject invitation. if the invitation has been accepted we add the current user to the organization. the only user that can accept this invitation is the user registered with the invitation email, we indentify the user with the jwt token **Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\ninviteId\n\n`string`\n\nThe invite id to updated.\n\naccepted\n\n`boolean`\n\nThe status of the invitation.\n\n\\[orgName\\]\n\n`string`\n\nThe organization name.\n\n**Example**\n\n```javascript\nconst fullInviteId=\"Organization/my_team_name/invitations/Invitation/7ad0c9eb82b6175bcda9\nc0dfc2ac51161ef5ba7cb0988d992c4bce82b3fa5d25\"\naccessControl.updateOrgInviteStatus(fullInviteId,true).then(result=>{\n console.log(result)\n})\n```\n\n## getTeamUserRole\n\n##### accessControl.getTeamUserRole(\\[orgName\\]) ⇒ `Promise`\n\n\\-- TerminusX API --- Get the user role for a given organization or the default organization The user is identified by the jwt or the access token **Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\n\\[orgName\\]\n\n`string`\n\nThe organization name.\n\n**Example**\n\n```\naccessControl.getTeamUserRole().then(result=>{\n console.log(result)\n})\n//response object example\n{\"userRole\":\"Role/admin\"}\n```\n\n## removeUserFromOrg\n\n##### accessControl.removeUserFromOrg(userId, \\[orgName\\]) ⇒ `Promise`\n\n\\-- TerminusX API -- Remove an user from an organization, only an admin user can remove an user from an organization **Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\nuserId\n\n`string`\n\nThe id of the user to be removed. (this is the document user's @id)\n\n\\[orgName\\]\n\n`string`\n\nThe organization name in which the user is to be removed.\n\n**Example**\n\n```\naccessControl.removeUserFromOrg(\"User/auth0%7C613f5dnndjdjkTTT\",\"my_org_name\").then(result=>{\n console.log(result)\n})\n```\n\n## getDatabaseRolesOfUser\n\n##### accessControl.getDatabaseRolesOfUser(userId, \\[orgName\\]) ⇒ `Promise`\n\n\\-- TerminusX API -- Get the user's role for every databases under the organization **Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\nuserId\n\n`string`\n\nThe user's id.\n\n\\[orgName\\]\n\n`string`\n\nThe organization name.\n\n**Example**\n\n```\naccessControl.getDatabaseRolesOfUser('User/auth0%7C61790e366377Yu6596a').then(result=>{\n console.log(result)\n})\n//this is a capabilities list of databases and roles\n//[ {capability: \"Capability/b395e8523d509dec6b33aefc9baed3b2e2bfadbd4c79d4ff9b20dce2b14e2edc\"\n//if there is an id we have a user specific capabality for this database\n // name: {@type: \"xsd:string\", @value: \"profiles_test\"}\n // role: \"Role/dataUpdater\"\n // scope: \"UserDatabase/7ebdfae5a02bc7e8f6d79sjjjsa4e179b1df9d4576a3b1d2e5ff3b4859\"\n // user: \"User/auth0%7C61790e11a3966d006906596a\"},\n//{ capability: null\n// if the capability id is null the user level of access for this database is the\nsame of the team\n //name: {@type: \"xsd:string\", @value: \"Collab002\"}\n //role: \"Role/dataReader\"\n // scope: \"UserDatabase/acfcc2db02b83792sssb15239ccdf586fc5b176846ffe4878b1aea6a36c8f\"\n //user: \"User/auth0%7C61790e11a3966d006906596a\"}]\n```\n\n## createUserRole\n\n##### accessControl.createUserRole(userId, scope, role, \\[orgName\\]) ⇒ `Promise`\n\n\\-- TerminusX API -- Create a user's a role for a resource (organization/database) **Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\nuserId\n\n`string`\n\nThe user's id.\n\nscope\n\n`string`\n\nThe resource name/id.\n\nrole\n\n`string`\n\nThe user role to be assigned.\n\n\\[orgName\\]\n\n`string`\n\nThe organization name.\n\n**Example**\n\n```javascript\nconst dbId = \"UserDatabase/acfcc2db02b83792sssb15239ccdf586fc5b176846ffe4878b1aea6a36c8f\"\naccessControl.assignUserRole('User/auth0%7C61790e11a3966d006906596a',dbId,\n\"Role/collaborator\").then(result=>{\n console.log(result)\n})\n```\n\n## updateUserRole\n\n##### accessControl.updateUserRole(userId, capabilityId, scope, role, \\[orgName\\]) ⇒ `Promise`\n\n\\-- TerminusX API -- Update user's a role for a resource (organization/database), (this api works only in terminusX) **Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\nuserId\n\n`string`\n\nThe user's id.\n\ncapabilityId\n\n`string`\n\nThe capability id.\n\nscope\n\n`string`\n\nThe resource name/id.\n\nrole\n\n`string`\n\nThe user role to be updated.\n\n\\[orgName\\]\n\n`string`\n\nThe organization name.\n\n**Example**\n\n```javascript\nconst dbId = \"UserDatabase/acfcc2db02b83792sssb15239ccdf586fc5b176846ffe4878b1aea6a36c8f\"\nconst capId= \"Capability/b395e8523d509dec6b33aefc9baed3b2e2bfadbd4c79d4ff9b20dce2b14e2edc\"\naccessControl.updateUserRole('User/auth0%7C61790e11a3966d006906596a',capId,dbId,\n\"Role/dataUpdater\").then(result=>{\n console.log(result)\n})\n```\n\n## accessRequestsList\n\n##### accessControl.accessRequestsList(\\[orgName\\]) ⇒ `Promise`\n\n\\-- TerminusX API -- Get all the access request list for a specify organization **Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\n\\[orgName\\]\n\n`string`\n\nThe organization name.\n\n**Example**\n\n```\naccessControl.accessRequestsList().then(result=>{\n console.log(result)\n})\n```\n\n## sendAccessRequest\n\n##### accessControl.sendAccessRequest(\\[email\\], \\[affiliation\\], \\[note\\], \\[orgName\\]) ⇒ `Promise`\n\n\\-- TerminusX API -- Get all the access request list for a specify organization **Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\n\\[email\\]\n\n`string`\n\nthe user email.\n\n\\[affiliation\\]\n\n`string`\n\nthe user affiliation, company, university etc..\n\n\\[note\\]\n\n`string`\n\nthe message for the team admin\n\n\\[orgName\\]\n\n`string`\n\nThe organization name.\n\n**Example**\n\n```\naccessControl.sendAccessRequest(\"myemail@terminusdb.com\",\n \"my_company\",\n \"please add me to your team\"\n).then(result=>{\n console.log(result)\n})\n```\n\n## deleteAccessRequest\n\n##### accessControl.deleteAccessRequest(\\[orgName\\]) ⇒ `Promise`\n\n\\-- TerminusX API -- Delete an access request to join your team, only an admin user can delete it **Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected.\n\nParam\n\nType\n\nDescription\n\n\\[orgName\\]\n\n`string`\n\nThe organization name.\n\n**Example**\n\n```\naccessControl.deleteAccessRequest(\"djjdshhsuuwewueueuiHYHYYW.......\").then(result=>{\n console.log(result)\n})\n```" + }, + "seo_metadata": { + "@type": "SEOMetadata", + "title": "Access Control with the JavaScript Client Reference Guide", + "description": "A reference guide to help you understand access control using the JavaScript Client", + "og_image": "https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png" + } } ] diff --git a/schema/javascript.json b/schema/javascript.json new file mode 100644 index 0000000..23618c1 --- /dev/null +++ b/schema/javascript.json @@ -0,0 +1,9032 @@ +{ + "@type": "Application", + "language": "Javascript", + "version": "10.0.33", + "license": "Apache-2.0", + "name": "@terminusdb/terminusdb-client", + "summary": "TerminusDB client library", + "modules": [ + { + "@type": "Module", + "name": "lib", + "classes": [ + { + "@type": "Class", + "name": "AccessControl", + "summary": "The AccessControl is a driver to work with\nTerminusDB and TerminusX access control api\nfor the credential you can use the JWT token, the API token or\nthe basic authentication with username and password", + "memberFunctions": [ + { + "@type": "Definition", + "name": "getDefaultOrganization", + "summary": "Get a organization from parameters.", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "params", + "type": "object", + "summary": "The parameters" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "- organization", + "type": "string|undefined" + } + }, + { + "@type": "Definition", + "name": "setJwtToken", + "summary": "Sets the Jwt token for the object", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "jwt", + "type": "string", + "summary": "The jwt api token to use" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "setApiToken", + "summary": "Sets the API token for the object, to request a token create an account in https://terminusdb.com/", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "atokenpi", + "type": "string", + "summary": "The API token to use to connect with TerminusX" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "setApiKey", + "summary": "Sets the API token for the object, to request a token create an account in https://terminusdb.com/", + "examples": [], + "section": "Authorization", + "parameters": [ + { + "@type": "Parameter", + "name": "atokenpi", + "type": "string", + "summary": "The API token to use to connect with TerminusX" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "getAPIUrl", + "summary": "Get a API url from cloudAPIUrl", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "cloudAPIUrl", + "type": "string", + "summary": "The base url for cloud" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "apiUrl", + "type": "string" + } + }, + { + "@type": "Definition", + "name": "customHeaders", + "summary": "add extra headers to your request", + "examples": [], + "section": "Authorization", + "parameters": [ + { + "@type": "Parameter", + "name": "customHeaders", + "type": "object" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "object" + } + }, + { + "@type": "Definition", + "name": "getOrganization", + "summary": "-- TerminusDB API ---\nGet an organization from the TerminusDB API.", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "organization", + "type": "string", + "summary": "The organization" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "- organization", + "type": "object" + } + }, + { + "@type": "Definition", + "name": "getAllOrganizations", + "summary": "-- TerminusDB API ---\nThis end point works in basic authentication, admin user\nGet list of organizations", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "createOrganization", + "summary": "-- TerminusDB API ---\nThis end point works in basic authentication, admin user\nCreate an organization", + "examples": [ + "accessControl.createOrganization(\"my_org_name\").then(result=>{\n console.log(result)\n})" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "orgName", + "type": "string", + "summary": "The organization name to create" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "deleteOrganization", + "summary": "-- TerminusDB API ---\nDelete an Organization", + "examples": [ + "accessControl.deleteOrganization(\"my_org_name\").then(result=>{\n console.log(result)\n})" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "orgName", + "type": "string", + "summary": "The organization name to delete" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "createRole", + "summary": "--TerminusDB API ---\nbasic authentication, admin user.\nCreate a new role in the system database.", + "examples": [ + "accessControl.createRole(\"Reader\",[ACTIONS.INSTANCE_READ_ACCESS]).then(result=>{\n console.log(result)\n})" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "name", + "type": "string", + "summary": "The role name." + }, + { + "@type": "Parameter", + "name": "actions", + "type": "typedef.RolesActions", + "summary": "A list of actions" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "deleteRole", + "summary": "-- TerminusdDB API ---\nbasic Authentication, admin user.\nDelete role in the system database, (this api is enabled only in the local installation)", + "examples": [ + "accessControl.deleteRole(\"Reader\").then(result=>{\n console.log(result)\n})" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "name", + "type": "string", + "summary": "The role name." + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "getAllUsers", + "summary": "-- TerminusdDB API ---\nbasic Authentication, admin user.\nReturn the list of all the users (this api is enabled only in the local installation)", + "examples": [ + "accessControl.getAllUsers().then(result=>{\n console.log(result)\n})" + ], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "createUser", + "summary": "-- TerminusdDB API ---\nbasic Authentication, admin user.\nAdd the user into the system database", + "examples": [ + "accessControl.deleteUser(userId).then(result=>{\n console.log(result)\n})" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "name", + "type": "string", + "summary": "the user name" + }, + { + "@type": "Parameter", + "name": "password", + "type": "string", + "summary": "you need the password for basic authentication" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "deleteUser", + "summary": "-- TerminusdDB API ---\nbasic Authentication, admin user.\nRemove the user from the system database.", + "examples": [ + "accessControl.deleteUser(userId).then(result=>{\n console.log(result)\n})" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "userId", + "type": "string", + "summary": "the document user id" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "manageCapability", + "summary": "-- TerminusdDB API ---\nGrant/Revoke Capability", + "examples": [ + "//we add an user to an organization and manage users' access\n//the user myUser can access the Organization and all the database under the organization with \"reader\" Role\nclient.manageCapability(myUser,myteam,[reader],\"grant\",\"organization\").then(result=>{\n consol.log(result)\n})\n\n//the user myUser can access the database db__001 under the organization myteam\n//with \"writer\" Role\nclient.manageCapability(myUser,myteam/db__001,[writer],\"grant\",\"database\").then(result=>{\n consol.log(result)\n})" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "userName", + "type": "string", + "summary": "the document user id" + }, + { + "@type": "Parameter", + "name": "resourceName", + "type": "string", + "summary": "the name of a (database or team)" + }, + { + "@type": "Parameter", + "name": "rolesArr", + "type": "array", + "summary": "the roles name list" + }, + { + "@type": "Parameter", + "name": "operation", + "type": "typedef.CapabilityCommand", + "summary": "grant/revoke operation" + }, + { + "@type": "Parameter", + "name": "scopeType", + "type": "typedef.ScopeType", + "summary": "the resource type (database or organization)" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "getAccessRoles", + "summary": "--TerminusX and TerminusDB API ---\nGet all the system database roles types.", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "getOrgUsers", + "summary": "-- TerminusX and TerminusDB API --\nGet all the organization's users and roles,", + "examples": [ + "accessControl.getOrgUsers().then(result=>{\n console.log(result)\n})\n\n//this function will return an array of capabilities with users and roles\n//-- TerminusX -- response array example\n//[{capability: \"Capability/3ea26e1d698821c570afe9cb4fe81a3......\"\n// email: {@type: \"xsd:string\", @value: \"user@terminusdb.com\"}\n// picture: {@type: \"xsd:string\",…}\n// role: \"Role/dataReader\"\n// scope: \"Organization/my_org_name\"\n// user: \"User/auth0%7C613f5dnndjdjkTTT\"}]\n//\n//\n// -- Local Installation -- response array example\n//[{ \"@id\":\"User/auth0%7C615462f8ab33f4006a6bee0c\",\n// \"capability\": [{\n// \"@id\":\"Capability/c52af34b71f6f8916ac0115ecb5fe0e31248ead8b1e3d100852015...\",\n// \"@type\":\"Capability\",\n// \"role\": [{\n// \"@id\":\"Role/admin\",\n// \"@type\":\"Role\",\n// \"action\": [\"instance_read_access\"],\n// \"name\":\"Admin Role\"\n// }],\n// \"scope\":\"Organization/@team\"}]]" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "orgName", + "type": "string", + "summary": "The organization name." + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "getTeamUserRoles", + "summary": "-- TerminusX and TerminusDB API --\nGet the user roles for a given organization or the default organization,", + "examples": [ + "accessControl.getTeamUserRole(\"myUser\").then(result=>{\n console.log(result)\n})\n\n//response object example\n{\n \"@id\": \"User/myUser\",\n \"capability\": [\n {\n \"@id\":\"Capability/server_access\",\n \"@type\":\"Capability\",\n \"role\": [{\n \"@id\":\"Role/reader\",\n \"@type\":\"Role\",\n \"action\": [\n \"instance_read_access\",\n ],\n \"name\":\"reader\"\n }],\n \"scope\":\"Organization/myteam\"\n }\n ],\n \"name\": \"myUser\"\n}" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "userName", + "type": "string", + "summary": "The organization name." + }, + { + "@type": "Parameter", + "name": "orgName", + "type": "string", + "summary": "The organization name." + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "ifOrganizationExists", + "summary": "-- TerminusX API ---\nCheck if the organization exists. it is a Head call .\nIMPORTANT This does not work with the API-TOKEN.", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "orgName", + "type": "string", + "summary": "The organization name to check if exists." + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call status object, 200: if the organization\nexists and 404: if the organization does not exist", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "createOrganizationRemote", + "summary": "-- TerminusX API ---\nIMPORTANT This does not work with the API-TOKEN.\nCreate an organization", + "examples": [ + "accessControl.createOrganization(\"my_org_name\").then(result=>{\n console.log(result)\n})" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "orgName", + "type": "string", + "summary": "The organization name to create" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "getPendingOrgInvites", + "summary": "-- TerminusX API ---\nGet the pending invitations list.", + "examples": [ + "const invitationList = accessControl.getPendingOrgInvites().then(result=>{\n console.log(invitationList)\n\n})\n//this will return an array of invitations object like this\n//[{@id: \"Organization/my_team_name/invitations/Invitation/7ad0c9eb82b6175bcda9c0dfc2ac51161ef5ba\ncb0988d992c4bce82b3fa5d25\"\n// @type: \"Invitation\"\n// creation_date: \"2021-10-22T11:13:28.762Z\"\n// email_to: \"new_user@terminusdb.com\"\n// invited_by: \"User/auth0%7C6162f8ab33567406a6bee0c\"\n// role: \"Role/dataReader\"\n// status: \"needs_invite\"}]" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "orgName", + "type": "string", + "summary": "The organization name." + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "sendOrgInvite", + "summary": "-- TerminusX API ---\nSend a new invitation", + "examples": [ + "accessControl.sendOrgInvite(\"new_user@terminusdb.com\",\"Role/admin\",\n\"please join myteam\").then(result=>{\n console.log(result)\n})" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "userEmail", + "type": "string", + "summary": "The email of user." + }, + { + "@type": "Parameter", + "name": "role", + "type": "string", + "summary": "The role for user. (the document @id role like Role/collaborator)" + }, + { + "@type": "Parameter", + "name": "note", + "type": "string", + "summary": "The note to send with the invitation." + }, + { + "@type": "Parameter", + "name": "orgName", + "type": "string", + "summary": "The organization name." + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "getOrgInvite", + "summary": "-- TerminusX API ---\nGet the invitation info", + "examples": [ + "const fullInviteId=\"Organization/my_team_name/invitations/Invitation/7ad0c9eb82b6175bcda9c0dfc\n2ac51161ef5ba7cb0988d992c4bce82b3fa5d25\"\naccessControl.getOrgInvite(fullInviteId).then(result=>{\n console.log(result)\n})" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "inviteId", + "type": "string", + "summary": "The invite id to retrieve." + }, + { + "@type": "Parameter", + "name": "orgName", + "type": "string", + "summary": "The organization name." + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "deleteOrgInvite", + "summary": "-- TerminusX API ---\nDelete an invitation", + "examples": [ + "const fullInviteId=\"Organization/my_team_name/invitations/Invitation/7ad0c9eb82b6175bcda9\nc0dfc2ac51161ef5ba7cb0988d992c4bce82b3fa5d25\"\naccessControl.deleteOrgInvite(fullInviteId).then(result=>{\n console.log(result)\n})" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "inviteId", + "type": "string", + "summary": "The invite id to delete." + }, + { + "@type": "Parameter", + "name": "orgName", + "type": "string", + "summary": "The organization name." + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "updateOrgInviteStatus", + "summary": "-- TerminusX API ---\nAccept /Reject invitation. if the invitation has been accepted we add the current user\nto the organization.\n\nthe only user that can accept this invitation is the user registered with the invitation email,\nwe indentify the user with the jwt token", + "examples": [ + "const fullInviteId=\"Organization/my_team_name/invitations/Invitation/7ad0c9eb82b6175bcda9\nc0dfc2ac51161ef5ba7cb0988d992c4bce82b3fa5d25\"\naccessControl.updateOrgInviteStatus(fullInviteId,true).then(result=>{\n console.log(result)\n})" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "inviteId", + "type": "string", + "summary": "The invite id to updated." + }, + { + "@type": "Parameter", + "name": "accepted", + "type": "boolean", + "summary": "The status of the invitation." + }, + { + "@type": "Parameter", + "name": "orgName", + "type": "string", + "summary": "The organization name." + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "getTeamUserRole", + "summary": "-- TerminusX API ---\nGet the user role for a given organization or the default organization\nThe user is identified by the jwt or the access token", + "examples": [ + "accessControl.getTeamUserRole().then(result=>{\n console.log(result)\n})\n\n//response object example\n{\"userRole\":\"Role/admin\"}" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "orgName", + "type": "string", + "summary": "The organization name." + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "removeUserFromOrg", + "summary": "-- TerminusX API --\nRemove an user from an organization, only an admin user can remove an user from an organization", + "examples": [ + "accessControl.removeUserFromOrg(\"User/auth0%7C613f5dnndjdjkTTT\",\"my_org_name\").then(result=>{\n console.log(result)\n})" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "userId", + "type": "string", + "summary": "The id of the user to be removed. (this is the document user's @id)" + }, + { + "@type": "Parameter", + "name": "orgName", + "type": "string", + "summary": "The organization name in which the user is to be removed." + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "getDatabaseRolesOfUser", + "summary": "-- TerminusX API --\nGet the user's role for every databases under the organization", + "examples": [ + "accessControl.getDatabaseRolesOfUser('User/auth0%7C61790e366377Yu6596a').then(result=>{\n console.log(result)\n})\n\n//this is a capabilities list of databases and roles\n//[ {capability: \"Capability/b395e8523d509dec6b33aefc9baed3b2e2bfadbd4c79d4ff9b20dce2b14e2edc\"\n//if there is an id we have a user specific capabality for this database\n // name: {@type: \"xsd:string\", @value: \"profiles_test\"}\n // role: \"Role/dataUpdater\"\n // scope: \"UserDatabase/7ebdfae5a02bc7e8f6d79sjjjsa4e179b1df9d4576a3b1d2e5ff3b4859\"\n // user: \"User/auth0%7C61790e11a3966d006906596a\"},\n\n//{ capability: null\n// if the capability id is null the user level of access for this database is the\nsame of the team\n //name: {@type: \"xsd:string\", @value: \"Collab002\"}\n //role: \"Role/dataReader\"\n // scope: \"UserDatabase/acfcc2db02b83792sssb15239ccdf586fc5b176846ffe4878b1aea6a36c8f\"\n //user: \"User/auth0%7C61790e11a3966d006906596a\"}]" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "userId", + "type": "string", + "summary": "The user's id." + }, + { + "@type": "Parameter", + "name": "orgName", + "type": "string", + "summary": "The organization name." + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "createUserRole", + "summary": "-- TerminusX API --\nCreate a user's a role for a resource (organization/database)", + "examples": [ + "const dbId = \"UserDatabase/acfcc2db02b83792sssb15239ccdf586fc5b176846ffe4878b1aea6a36c8f\"\naccessControl.assignUserRole('User/auth0%7C61790e11a3966d006906596a',dbId,\n\"Role/collaborator\").then(result=>{\n console.log(result)\n\n})" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "userId", + "type": "string", + "summary": "The user's id." + }, + { + "@type": "Parameter", + "name": "scope", + "type": "string", + "summary": "The resource name/id." + }, + { + "@type": "Parameter", + "name": "role", + "type": "string", + "summary": "The user role to be assigned." + }, + { + "@type": "Parameter", + "name": "orgName", + "type": "string", + "summary": "The organization name." + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "updateUserRole", + "summary": "-- TerminusX API --\nUpdate user's a role for a resource (organization/database), (this api works only in terminusX)", + "examples": [ + "const dbId = \"UserDatabase/acfcc2db02b83792sssb15239ccdf586fc5b176846ffe4878b1aea6a36c8f\"\nconst capId= \"Capability/b395e8523d509dec6b33aefc9baed3b2e2bfadbd4c79d4ff9b20dce2b14e2edc\"\naccessControl.updateUserRole('User/auth0%7C61790e11a3966d006906596a',capId,dbId,\n\"Role/dataUpdater\").then(result=>{\n console.log(result)\n\n})" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "userId", + "type": "string", + "summary": "The user's id." + }, + { + "@type": "Parameter", + "name": "capabilityId", + "type": "string", + "summary": "The capability id." + }, + { + "@type": "Parameter", + "name": "scope", + "type": "string", + "summary": "The resource name/id." + }, + { + "@type": "Parameter", + "name": "role", + "type": "string", + "summary": "The user role to be updated." + }, + { + "@type": "Parameter", + "name": "orgName", + "type": "string", + "summary": "The organization name." + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "accessRequestsList", + "summary": "-- TerminusX API --\nGet all the access request list for a specify organization", + "examples": [ + "accessControl.accessRequestsList().then(result=>{\n console.log(result)\n})" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "orgName", + "type": "string", + "summary": "The organization name." + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "sendAccessRequest", + "summary": "-- TerminusX API --\nGet all the access request list for a specify organization", + "examples": [ + "accessControl.sendAccessRequest(\"myemail@terminusdb.com\",\n \"my_company\",\n \"please add me to your team\"\n).then(result=>{\n console.log(result)\n})" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "email", + "type": "string", + "summary": "the user email." + }, + { + "@type": "Parameter", + "name": "affiliation", + "type": "string", + "summary": "the user affiliation, company, university etc.." + }, + { + "@type": "Parameter", + "name": "note", + "type": "string", + "summary": "the message for the team admin" + }, + { + "@type": "Parameter", + "name": "orgName", + "type": "string", + "summary": "The organization name." + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "deleteAccessRequest", + "summary": "-- TerminusX API --\nDelete an access request to join your team, only an admin user can delete it", + "examples": [ + "accessControl.deleteAccessRequest(\"djjdshhsuuwewueueuiHYHYYW.......\").then(result=>{\n console.log(result)\n})" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "orgName", + "type": "string", + "summary": "The organization name." + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "getUserInfo", + "summary": "-- TerminusX API --\nGet the userinfo teams ownership and subscription", + "examples": [ + "accessControl.getUserInfo().then(result=>{\n console.log(result)\n})" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "orgName", + "type": "string", + "summary": "The organization name." + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + } + ] + }, + { + "@type": "Class", + "name": "connectionConfig.js", + "summary": "Object representing the state of a connection to a terminus db - these are:\nprovides methods for getting and setting connection parameters", + "memberFunctions": [] + }, + { + "@type": "Class", + "name": "WOQLQuery", + "summary": "defines the internal functions of the woql query object - the\nlanguage API is defined in WOQLQuery", + "memberFunctions": [ + { + "@type": "Definition", + "name": "star", + "summary": "Simple composite functions which produce WOQL queries", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "all", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "Subj", + "type": "string|Var", + "summary": "The IRI of a triple’s subject or a variable" + }, + { + "@type": "Parameter", + "name": "Pred", + "type": "string|Var", + "summary": "The IRI of a property or a variable" + }, + { + "@type": "Parameter", + "name": "Obj", + "type": "string|Var", + "summary": "The IRI of a node or a variable, or a literal" + }, + { + "@type": "Parameter", + "name": "Graph", + "type": "typedef.GraphRef", + "summary": "the resource identifier of a graph possible" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "- A WOQLQuery which contains the pattern matching expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "string", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "s", + "type": "string" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "object" + } + }, + { + "@type": "Definition", + "name": "boolean", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "tf", + "type": "boolean" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "object" + } + }, + { + "@type": "Definition", + "name": "literal", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "s", + "type": "any" + }, + { + "@type": "Parameter", + "name": "t", + "type": "string" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "object" + } + }, + { + "@type": "Definition", + "name": "iri", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "s", + "type": "string" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "object" + } + }, + { + "@type": "Definition", + "name": "update_triple", + "summary": "Update a pattern matching rule for the triple (Subject, Predicate, oldObjValue) with the\nnew one (Subject, Predicate, newObjValue)", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subject", + "type": "string|Var", + "summary": "The IRI of a triple’s subject or a variable" + }, + { + "@type": "Parameter", + "name": "predicate", + "type": "string|Var", + "summary": "The IRI of a property or a variable" + }, + { + "@type": "Parameter", + "name": "newObjValue", + "type": "string|Var", + "summary": "The value to update or a literal" + }, + { + "@type": "Parameter", + "name": "oldObjValue", + "type": "string|Var", + "summary": "The old value of the object" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the a Update Triple Statement", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "update_quad", + "summary": "Update a pattern matching rule for the quad [S, P, O, G]\n(Subject, Predicate, Object, Graph)", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subject", + "type": "string", + "summary": "The IRI of a triple’s subject or a variable" + }, + { + "@type": "Parameter", + "name": "predicate", + "type": "string", + "summary": "The IRI of a property or a variable" + }, + { + "@type": "Parameter", + "name": "newObject", + "type": "string", + "summary": "The value to update or a literal" + }, + { + "@type": "Parameter", + "name": "graph", + "type": "string", + "summary": "the resource identifier of a graph possible value are\nschema/{main - myschema - *} | instance/{main - myschema - *} | inference/{main - myschema - *}" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the a Update Quad Statement", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "nuke", + "summary": "Deletes all triples in the passed graph (defaults to instance/main)", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "graphRef", + "type": "typedef.GraphRef", + "summary": "Resource String identifying the graph from\nwhich all triples will be removed" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "- A WOQLQuery which contains the deletion expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "node", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "node", + "type": "string|Var", + "summary": "The IRI of a node or a variable containing an IRI which will\nbe the subject of the builder functions" + }, + { + "@type": "Parameter", + "name": "type", + "type": "typedef.FuntionType", + "summary": "Optional type of builder function to build\n(default is triple)" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "- A WOQLQuery which contains the partial Node pattern matching expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "graph", + "summary": "Sets the graph resource ID that will be used for subsequent chained function calls", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "graphRef", + "type": "typedef.GraphRef", + "summary": "Resource String identifying the graph which will\nbe used for subsequent chained schema calls" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the partial Graph pattern matching expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "insert", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "id", + "type": "string|Var", + "summary": "IRI string or variable containing" + }, + { + "@type": "Parameter", + "name": "type", + "type": "string|Var", + "summary": "IRI string or variable containing the IRI of the" + }, + { + "@type": "Parameter", + "name": "refGraph", + "type": "typedef.GraphRef", + "summary": "Optional Graph resource identifier" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the insert expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "parameterError", + "summary": "Basic Error handling", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "addSubQuery", + "summary": "Internal library function which adds a subquery and sets the cursor", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "containsUpdate", + "summary": "Does this query contain an update", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "updated", + "summary": "Called to inidicate that this query will cause an update to the DB", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "jlt", + "summary": "Wraps the passed value in a json-ld literal carriage", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "jobj", + "summary": "Transforms a javascript representation of a query into a json object if needs be", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "asv", + "summary": "Wraps the elements of an AS variable in the appropriate json-ld", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "wform", + "summary": "JSON LD Format Descriptor", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "opts", + "type": "object" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "arop", + "summary": "Wraps arithmetic operators in the appropriate json-ld", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "dataList", + "summary": "takes input that can be either a string (variable name)\nor an array - each element of the array is a member of the list", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "valueList", + "summary": "takes a list of input that can be any value", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "vlist", + "summary": "creates an unadorned variable name list", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "dataValueList", + "summary": "Wraps data values", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "cleanSubject", + "summary": "Transforms whatever is passed in as the subject into the appropriate json-ld for variable or id", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "cleanPredicate", + "summary": "Transforms whatever is passed in as the predicate (id or variable) into the\nappropriate json-ld form", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "cleanObject", + "summary": "Transforms whatever is passed in as the object of\na triple into the appropriate json-ld form (variable, literal or id)", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "cleanGraph", + "summary": "Transforms a graph filter or graph id into the proper json-ld form", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "expandVariable", + "summary": "Transforms strings that start with v: into variable json-ld structures", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "varname", + "type": "unknown", + "summary": "will be transformed if it starts with v:" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "getContext", + "summary": "Retrieves the value of the current json-ld context", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "context", + "summary": "sets the value of the current json-ld context on a full query scope", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "loadDefaultVocabulary", + "summary": "vocabulary elements that can be used without prefixes in woql.js queries", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "setVocabulary", + "summary": "Provides the query with a 'vocabulary' a list of well known predicates that can be used without\nprefixes mapping: id: prefix:id ...", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "execute", + "summary": "Use instead woqlclient.query('myWOQLQuery')", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "json", + "summary": "converts back and forward from json\nif the argument is present, the current query is set to it,\nif the argument is not present, the current json version of this query is returned", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "json", + "type": "object", + "summary": "a query in json format" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "object" + } + }, + { + "@type": "Definition", + "name": "prettyPrint", + "summary": "Returns a script version of the query", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "clang", + "type": "string", + "summary": "either \"js\" or \"python\"" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "findLastSubject", + "summary": "Finds the last woql element that has a subject in it and returns the json for that\nused for triplebuilder to chain further calls - when they may be inside ands or ors or subqueries", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "json", + "type": "object" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "findLastProperty", + "summary": "Finds the last woql element that has a subject in that is a property id\nused for triplebuilder to chain further calls - when they may be inside ands or ors or subqueries", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "json", + "type": "object" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "compilePathPattern", + "summary": "Turns a textual path pattern into a JSON-LD description", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "update_triple", + "summary": "Update a pattern matching rule for the triple (Subject, Predicate, oldObjValue) with the\nnew one (Subject, Predicate, newObjValue)", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subject", + "type": "string|Var", + "summary": "The IRI of a triple’s subject or a variable" + }, + { + "@type": "Parameter", + "name": "predicate", + "type": "string|Var", + "summary": "The IRI of a property or a variable" + }, + { + "@type": "Parameter", + "name": "newObjValue", + "type": "string|Var", + "summary": "The value to update or a literal" + }, + { + "@type": "Parameter", + "name": "oldObjValue", + "type": "string|Var", + "summary": "The old value of the object" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the a Update Triple Statement", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "star", + "summary": "Generates a query that by default matches all triples in a graph identified by \"graph\"\nor in all the current terminusDB's graph", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "graph", + "type": "string|boolean", + "summary": "false or the resource identifier of a graph possible\nvalue are schema/{main - myschema - *} | instance/{main - myschema - *} |\ninference/{main - myschema - *}" + }, + { + "@type": "Parameter", + "name": "subject", + "type": "string|Var", + "summary": "The IRI of a triple’s subject or a variable,\ndefault value \"v:Subject\"" + }, + { + "@type": "Parameter", + "name": "predicate", + "type": "string|Var", + "summary": "The IRI of a property or a variable,\n default value \"v:Predicate\"" + }, + { + "@type": "Parameter", + "name": "object", + "type": "string|Var", + "summary": "The IRI of a node or a variable, or a literal,\ndefault value \"v:Object\"" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the pattern matching expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "update_quad", + "summary": "Update a pattern matching rule for the quad [S, P, O, G] (Subject, Predicate, Object, Graph)", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subject", + "type": "string|Var", + "summary": "The IRI of a triple’s subject or a variable" + }, + { + "@type": "Parameter", + "name": "predicate", + "type": "string|Var", + "summary": "The IRI of a property or a variable" + }, + { + "@type": "Parameter", + "name": "newObject", + "type": "string|Var", + "summary": "The value to update or a literal" + }, + { + "@type": "Parameter", + "name": "graphRef", + "type": "typedef.GraphRef", + "summary": "A valid graph resource identifier string" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the a Update Quad Statement", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "insert", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "id", + "type": "string|Var", + "summary": "IRI string or variable containing" + }, + { + "@type": "Parameter", + "name": "type", + "type": "string|Var", + "summary": "IRI string or variable containing the IRI of the" + }, + { + "@type": "Parameter", + "name": "refGraph", + "type": "typedef.GraphRef", + "summary": "Optional Graph resource identifier" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the insert expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "graph", + "summary": "Sets the graph resource ID that will be used for subsequent chained function calls", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "graphRef", + "type": "typedef.GraphRef", + "summary": "Resource String identifying the graph which will\nbe used for subsequent chained schema calls" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the partial Graph pattern matching expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "node", + "summary": "Specifies the identity of a node that can then be used in subsequent builder functions.\nNote that node() requires subsequent chained functions to complete the triples / quads\nthat it produces - by itself it only generates the subject.", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "nodeid", + "type": "string|Var", + "summary": "The IRI of a node or a variable containing an IRI which will\nbe the subject of the builder functions" + }, + { + "@type": "Parameter", + "name": "chainType", + "type": "typedef.FuntionType", + "summary": "Optional type of builder function to build\n(default is triple)" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "- A WOQLQuery which contains the partial Node pattern matching expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "nuke", + "summary": "Deletes all triples in the passed graph (defaults to instance/main)", + "examples": [ + "nuke(\"schema/main\")\n//will delete everything from the schema/main graph" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "graphRef", + "type": "typedef.GraphRef", + "summary": "Resource String identifying the graph from\nwhich all triples will be removed" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "- A WOQLQuery which contains the deletion expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "all", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "Subj", + "type": "string|Var", + "summary": "The IRI of a triple’s subject or a variable" + }, + { + "@type": "Parameter", + "name": "Pred", + "type": "string|Var", + "summary": "The IRI of a property or a variable" + }, + { + "@type": "Parameter", + "name": "Obj", + "type": "string|Var", + "summary": "The IRI of a node or a variable, or a literal" + }, + { + "@type": "Parameter", + "name": "Graph", + "type": "typedef.GraphRef", + "summary": "the resource identifier of a graph possible" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "- A WOQLQuery which contains the pattern matching expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "boolean", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "tf", + "type": "boolean" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "object" + } + }, + { + "@type": "Definition", + "name": "string", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "s", + "type": "string" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "object" + } + }, + { + "@type": "Definition", + "name": "literal", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "s", + "type": "any" + }, + { + "@type": "Parameter", + "name": "t", + "type": "string" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "object" + } + }, + { + "@type": "Definition", + "name": "iri", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "s", + "type": "string" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "object" + } + }, + { + "@type": "Definition", + "name": "addSubQuery", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "Subq", + "type": "WOQLQuery" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "parameterError", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "msg", + "type": "string" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "updated", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "read_document", + "summary": "Read a node identified by an IRI as a JSON-LD document", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "IRI", + "type": "string", + "summary": "The document id or a variable to read" + }, + { + "@type": "Parameter", + "name": "output", + "type": "string", + "summary": "Variable which will be bound to the document." + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "WOQLQuery", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "insert_document", + "summary": "Insert a document in the graph.", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "docjson", + "type": "object", + "summary": "The document to insert. Must either have an '@id' or\nhave a class specified key." + }, + { + "@type": "Parameter", + "name": "IRI", + "type": "string", + "summary": "An optional identifier specifying the document location." + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "WOQLQuery", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "update_document", + "summary": "Update a document identified by an IRI", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "docjson", + "type": "object", + "summary": "The document to update. Must either have an '@id' or\nhave a class specified key." + }, + { + "@type": "Parameter", + "name": "IRI", + "type": "string", + "summary": "An optional identifier specifying the document location." + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "WOQLQuery", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "delete_document", + "summary": "Delete a document from the graph.", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "IRI", + "type": "string", + "summary": "The document id or a variable" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "WOQLQuery", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "wrapCursorWithAnd", + "summary": "Contains definitions of the WOQL functions which map directly to JSON-LD types\nAll other calls and queries can be composed from these", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "using", + "summary": "Query running against any specific commit Id", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "refPath", + "type": "string", + "summary": "path to specific reference Id or commit Id" + }, + { + "@type": "Parameter", + "name": "subquery", + "type": "WOQLQuery", + "summary": "subquery for the specific commit point" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "comment", + "summary": "Adds a text comment to a query - can also be used to wrap any part of a query to turn it off", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "comment", + "type": "string", + "summary": "text comment" + }, + { + "@type": "Parameter", + "name": "subquery", + "type": "WOQLQuery", + "summary": "query that is \"commented out\"" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "select", + "summary": "Filters the query so that only the variables included in [V1...Vn] are returned in the bindings", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "varNames", + "type": "string|Var", + "summary": "only these variables are returned" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "distinct", + "summary": "Filter the query to return only results that are distinct in the given variables", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "varNames", + "type": "string|Var", + "summary": "these variables are guaranteed to be unique as a tuple" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "and", + "summary": "Logical conjunction of the contained queries - all queries must match or the entire clause fails", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subqueries", + "type": "WOQLQuery", + "summary": "A list of one or more woql queries to execute as a conjunction" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "- A WOQLQuery object containing the conjunction of queries", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "or", + "summary": "Creates a logical OR of the arguments", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subqueries", + "type": "WOQLQuery", + "summary": "A list of one or more woql queries\nto execute as alternatives" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "- A WOQLQuery object containing the logical Or of the subqueries", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "from", + "summary": "Specifies the database URL that will be the default database for the enclosed query", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "graphRef-", + "type": "typedef.GraphRef", + "summary": "A valid graph resource identifier string" + }, + { + "@type": "Parameter", + "name": "query", + "type": "WOQLQuery", + "summary": "The query" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery object containing the from expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "into", + "summary": "Specifies the graph resource to write the contained query into", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "graphRef-", + "type": "typedef.GraphRef", + "summary": "A valid graph resource identifier string" + }, + { + "@type": "Parameter", + "name": "subquery", + "type": "WOQLQuery", + "summary": "The query which will be written into the graph" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which will be written into the graph in question", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "triple", + "summary": "Creates a triple pattern matching rule for the triple [S, P, O] (Subject, Predicate, Object)", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subject", + "type": "string|Var", + "summary": "The IRI of a triple’s subject or a variable" + }, + { + "@type": "Parameter", + "name": "predicate", + "type": "string|Var", + "summary": "The IRI of a property or a variable" + }, + { + "@type": "Parameter", + "name": "object", + "type": "string|Var", + "summary": "The IRI of a node or a variable, or a literal" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "added_triple", + "summary": "Creates a triple pattern matching rule for the triple [S, P, O] (Subject, Predicate,\nObject) added in the current layer", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subject", + "type": "string|Var", + "summary": "The IRI of a triple’s subject or a variable" + }, + { + "@type": "Parameter", + "name": "predicate", + "type": "string|Var", + "summary": "The IRI of a property or a variable" + }, + { + "@type": "Parameter", + "name": "object", + "type": "string|Var", + "summary": "The IRI of a node or a variable, or a literal" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "removed_triple", + "summary": "Creates a triple pattern matching rule for the triple [S, P, O] (Subject, Predicate,\nObject) added in the current commit", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subject", + "type": "string|Var", + "summary": "The IRI of a triple’s subject or a variable" + }, + { + "@type": "Parameter", + "name": "predicate", + "type": "string|Var", + "summary": "The IRI of a property or a variable" + }, + { + "@type": "Parameter", + "name": "object", + "type": "string|Var", + "summary": "The IRI of a node or a variable, or a literal" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "link", + "summary": "Creates a pattern matching rule for triple [Subject, Predicate, Object]", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subject", + "type": "string|Var", + "summary": "The IRI of a triple’s subject or a variable" + }, + { + "@type": "Parameter", + "name": "predicate", + "type": "string|Var", + "summary": "The IRI of a property or a variable" + }, + { + "@type": "Parameter", + "name": "object", + "type": "string|Var", + "summary": "The IRI of a node or a variable, or a literal" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the a quad or a triple Statement", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "value", + "summary": "Creates a pattern matching rule for triple [Subject, Predicate, Object]\nadd extra information about the type of the value object", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subject", + "type": "string|Var", + "summary": "The IRI of a triple’s subject or a variable" + }, + { + "@type": "Parameter", + "name": "predicate", + "type": "string|Var", + "summary": "The IRI of a property or a variable" + }, + { + "@type": "Parameter", + "name": "objValue", + "type": "string|number|boolean|Var", + "summary": "an specific value" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the a quad or a triple Statement", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "quad", + "summary": "Creates a pattern matching rule for the quad [S, P, O, G] (Subject, Predicate, Object, Graph)", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subject", + "type": "string|Var", + "summary": "The IRI of a triple’s subject or a variable" + }, + { + "@type": "Parameter", + "name": "predicate", + "type": "string|Var", + "summary": "The IRI of a property or a variable" + }, + { + "@type": "Parameter", + "name": "object", + "type": "string|Var", + "summary": "The IRI of a node or a variable, or a literal" + }, + { + "@type": "Parameter", + "name": "graphRef", + "type": "typedef.GraphRef", + "summary": "A valid graph resource identifier string" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "added_quad", + "summary": "Creates a pattern matching rule for the quad [S, P, O, G] (Subject, Predicate,\nObject, Graph) removed from the current commit", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subject", + "type": "string|Var", + "summary": "The IRI of a triple’s subject or a variable" + }, + { + "@type": "Parameter", + "name": "predicate", + "type": "string|Var", + "summary": "The IRI of a property or a variable" + }, + { + "@type": "Parameter", + "name": "object", + "type": "string|Var", + "summary": "The IRI of a node or a variable, or a literal" + }, + { + "@type": "Parameter", + "name": "graphRef-", + "type": "typedef.GraphRef", + "summary": "A valid graph resource identifier string" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "removed_quad", + "summary": "Creates a pattern matching rule for the quad [S, P, O, G] (Subject, Predicate,\nObject, Graph) removed from the current commit", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subject", + "type": "string|Var", + "summary": "The IRI of a triple’s subject or a variable" + }, + { + "@type": "Parameter", + "name": "predicate", + "type": "string|Var", + "summary": "The IRI of a property or a variable" + }, + { + "@type": "Parameter", + "name": "object", + "type": "string|Var", + "summary": "The IRI of a node or a variable, or a literal" + }, + { + "@type": "Parameter", + "name": "graphRef-", + "type": "typedef.GraphRef", + "summary": "A valid graph resource identifier string" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "sub", + "summary": "Returns true if ClassA subsumes ClassB, according to the current DB schema", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "classA", + "type": "string", + "summary": "ClassA" + }, + { + "@type": "Parameter", + "name": "classB", + "type": "string", + "summary": "ClassB" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "WOQLQuery", + "type": "boolean" + } + }, + { + "@type": "Definition", + "name": "eq", + "summary": "Matches if a is equal to b", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "varName", + "type": "string|Var", + "summary": "literal, variable or id" + }, + { + "@type": "Parameter", + "name": "varValue", + "type": "string|Var", + "summary": "literal, variable or id" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "substr", + "summary": "Substring", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "string", + "type": "string|Var", + "summary": "String or variable" + }, + { + "@type": "Parameter", + "name": "before", + "type": "number|Var", + "summary": "integer or variable (characters from start to begin)" + }, + { + "@type": "Parameter", + "name": "length", + "type": "number|Var", + "summary": "integer or variable (length of substring)" + }, + { + "@type": "Parameter", + "name": "after", + "type": "number|Var", + "summary": "integer or variable (number of characters after substring)" + }, + { + "@type": "Parameter", + "name": "subString", + "type": "string|Var", + "summary": "String or variable" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "get", + "summary": "Use the document inteface to import documents", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "asvars", + "type": "Vars|array.", + "summary": "an array of AsVar variable mappings (see as for format below)" + }, + { + "@type": "Parameter", + "name": "queryResource", + "type": "WOQLQuery", + "summary": "an external resource (remote, file, post) to query" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the get expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "put", + "summary": "Use the document inteface to import documents", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "varsToExp", + "type": "Vars|array.", + "summary": "an array of AsVar variable\nmappings (see as for format below)" + }, + { + "@type": "Parameter", + "name": "query", + "type": "WOQLQuery", + "summary": "The query which will be executed to produce the results" + }, + { + "@type": "Parameter", + "name": "fileResource", + "type": "string", + "summary": "an file resource local to the server" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the put expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "as", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "varList", + "type": "array|string|Var", + "summary": "variable number of arguments" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "WOQLQuery", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "remote", + "summary": "Identifies a remote resource by URL and specifies the format of the resource through the options", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "remoteObj", + "type": "object", + "summary": "The URL at which the remote resource can be accessed" + }, + { + "@type": "Parameter", + "name": "formatObj", + "type": "typedef.DataFormatObj", + "summary": "The format of the resource data {}" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the remote resource identifier", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "post", + "summary": "Identifies a resource as a local path on the client, to be sent to the server through a\nHTTP POST request, with the format defined through the options", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "url", + "type": "string", + "summary": "The Path on the server at which the file resource can be accessed" + }, + { + "@type": "Parameter", + "name": "formatObj", + "type": "typedef.DataFormatObj", + "summary": "imput options, optional" + }, + { + "@type": "Parameter", + "name": "source", + "type": "string", + "summary": "It defines the source of the file, it can be 'url','post'" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the Post resource identifier", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "delete_triple", + "summary": "Deletes a single triple from the default graph of the database", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subject", + "type": "string|Var", + "summary": "The IRI of a triple’s subject or a variable" + }, + { + "@type": "Parameter", + "name": "predicate", + "type": "string|Var", + "summary": "The IRI of a property or a variable" + }, + { + "@type": "Parameter", + "name": "object", + "type": "string|Var", + "summary": "The IRI of a node or a variable, or a literal" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "- A WOQLQuery which contains the Triple Deletion statement", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "add_triple", + "summary": "Adds triples according to the the pattern [subject,predicate,object]", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subject", + "type": "string|Var", + "summary": "The IRI of a triple’s subject or a variable" + }, + { + "@type": "Parameter", + "name": "predicate", + "type": "string|Var", + "summary": "The IRI of a property or a variable" + }, + { + "@type": "Parameter", + "name": "object", + "type": "string|Var", + "summary": "The IRI of a node or a variable, or a literal" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "delete_quad", + "summary": "Deletes a single triple from the graph [Subject, Predicate, Object, Graph]", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subject", + "type": "string|Var", + "summary": "The IRI of a triple’s subject or a variable" + }, + { + "@type": "Parameter", + "name": "predicate", + "type": "string|Var", + "summary": "The IRI of a property or a variable" + }, + { + "@type": "Parameter", + "name": "object", + "type": "string|Var", + "summary": "The IRI of a node or a variable, or a literal" + }, + { + "@type": "Parameter", + "name": "graphRef", + "type": "typedef.GraphRef", + "summary": "A valid graph resource identifier string" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "- A WOQLQuery which contains the Delete Quad Statement", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "add_quad", + "summary": "Adds quads according to the pattern [S,P,O,G]", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subject", + "type": "string|Var", + "summary": "The IRI of a triple’s subject or a variable" + }, + { + "@type": "Parameter", + "name": "predicate", + "type": "string|Var", + "summary": "The IRI of a property or a variable" + }, + { + "@type": "Parameter", + "name": "object", + "type": "string|Var", + "summary": "The IRI of a node or a variable, or a literal" + }, + { + "@type": "Parameter", + "name": "graphRef", + "type": "typedef.GraphRef", + "summary": "A valid graph resource identifier string" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "trim", + "summary": "Remove whitespace from both sides of a string:", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "inputStr", + "type": "string|Var", + "summary": "A string or variable containing\nthe untrimmed version of the string" + }, + { + "@type": "Parameter", + "name": "resultVarName", + "type": "string|Var", + "summary": "A string or variable\ncontaining the trimmed version of the string" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the Trim pattern matching expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "eval", + "summary": "Evaluates the passed arithmetic expression and generates or matches the result value", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "arithExp", + "type": "object|WOQLQuery|string", + "summary": "query or JSON-LD representing the query" + }, + { + "@type": "Parameter", + "name": "resultVarName", + "type": "string|Var", + "summary": "output variable" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "plus", + "summary": "Adds the numbers together", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "args", + "type": "string|number|Var", + "summary": "a variable or numeric containing the values to add" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the addition expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "minus", + "summary": "Subtracts Numbers N1..Nn", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "args", + "type": "string|number|Var", + "summary": "variable or numeric containing the value that will be\nsubtracted from" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the subtraction expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "times", + "summary": "Multiplies numbers N1...Nn together", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "args", + "type": "string|number|Var", + "summary": "a variable or numeric containing the value" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the multiplication expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "divide", + "summary": "Divides numbers N1...Nn by each other left, to right precedence", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "args", + "type": "string|number|Var", + "summary": "numbers to tbe divided" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the division expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "div", + "summary": "Division - integer division - args are divided left to right", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "args", + "type": "string|number|Var", + "summary": "numbers for division" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the division expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "exp", + "summary": "Exponent - raises varNum01 to the power of varNum02", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "varNum", + "type": "string|number|Var", + "summary": "a variable or numeric containing the number to be\nraised to the power of the second number" + }, + { + "@type": "Parameter", + "name": "expNum", + "type": "number", + "summary": "a variable or numeric containing the exponent" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the exponent expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "floor", + "summary": "Generates the nearest lower integer to the passed number", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "varNum", + "type": "string|number|Var", + "summary": "Variable or numeric containing the number to be floored" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the floor expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "isa", + "summary": "Tests whether a given instance IRI has type Class, according to the current state of the DB", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "instanceIRI", + "type": "string|Var", + "summary": "A string IRI or a variable that identify the class instance" + }, + { + "@type": "Parameter", + "name": "classId", + "type": "string|Var", + "summary": "A Class IRI or a variable" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery object containing the type test", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "like", + "summary": "Generates a string Leverstein distance measure between stringA and stringB", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "stringA", + "type": "string|Var", + "summary": "string literal or variable representing a string to be compared" + }, + { + "@type": "Parameter", + "name": "stringB", + "type": "string|Var", + "summary": "string literal or variable\nrepresenting the other string to be compared" + }, + { + "@type": "Parameter", + "name": "distance", + "type": "number|string|Var", + "summary": "variable representing the distance between the variables" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the Like pattern matching expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "less", + "summary": "Compares the value of v1 against v2 and returns true if v1 is less than v2", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "varNum01", + "type": "string|number|Var", + "summary": "a variable or numeric containing\nthe number to be compared" + }, + { + "@type": "Parameter", + "name": "varNum02", + "type": "string|number|Var", + "summary": "a variable or numeric containing the second comporator" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the comparison expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "greater", + "summary": "Compares the value of v1 against v2 and returns true if v1 is greater than v2", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "varNum01", + "type": "string|number|Var", + "summary": "a variable or numeric containing the number to be compared" + }, + { + "@type": "Parameter", + "name": "varNum02", + "type": "string|number|Var", + "summary": "a variable or numeric containing the second comporator" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the comparison expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "opt", + "summary": "Specifies that the Subquery is optional - if it does not match the query will not fail", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subquery", + "type": "WOQLQuery", + "summary": "A subquery which will be optionally matched" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery object containing the optional sub Query", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "unique", + "summary": "Generate a new IRI from the prefix and a hash of the variables which will be unique for any\ngiven combination of variables", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "prefix", + "type": "string", + "summary": "A prefix for the IRI - typically formed of the doc prefix and the\nclasstype of the entity (“doc:Person”)" + }, + { + "@type": "Parameter", + "name": "inputVarList", + "type": "array|string|Var", + "summary": "An array of variables and / or strings from which the\nunique hash will be generated" + }, + { + "@type": "Parameter", + "name": "resultVarName", + "type": "string|Var", + "summary": "Variable in which the unique ID is stored" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery object containing the unique ID generating function", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "idgen", + "summary": "Generates the node's ID combined the variable list with a specific prefix (URL base).\nIf the input variables's values are the same, the output value will be the same.", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "prefix", + "type": "string" + }, + { + "@type": "Parameter", + "name": "inputVarList", + "type": "string|array", + "summary": "the variable input list for generate the id" + }, + { + "@type": "Parameter", + "name": "outputVar", + "type": "string", + "summary": "the output variable name" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "upper", + "summary": "Changes a string to upper-case", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "inputVarName", + "type": "string|Var", + "summary": "string or variable representing the uncapitalized string" + }, + { + "@type": "Parameter", + "name": "resultVarName", + "type": "string|Var", + "summary": "variable that stores the capitalized string output" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the Upper case pattern matching expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "lower", + "summary": "Changes a string to lower-case", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "inputVarName", + "type": "string|Var", + "summary": "string or variable representing the non-lowercased string" + }, + { + "@type": "Parameter", + "name": "resultVarName", + "type": "string|Var", + "summary": "variable that stores the lowercased string output" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the Lower case pattern matching expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "pad", + "summary": "Pads out the string input to be exactly len long by appending the pad character pad to\nform output", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "inputVarName", + "type": "string|Var", + "summary": "The input string or variable in unpadded state" + }, + { + "@type": "Parameter", + "name": "pad", + "type": "string|Var", + "summary": "The characters to use to pad the string or a variable representing them" + }, + { + "@type": "Parameter", + "name": "len", + "type": "number|string|Var", + "summary": "The variable or integer value representing the length of\nthe output string" + }, + { + "@type": "Parameter", + "name": "resultVarName", + "type": "string|Var", + "summary": "stores output" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the Pad pattern matching expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "split", + "summary": "Splits a string (Input) into a list strings (Output) by removing separator", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "inputVarName", + "type": "string|Var", + "summary": "A string or variable representing the unsplit string" + }, + { + "@type": "Parameter", + "name": "separator", + "type": "string|Var", + "summary": "A string or variable containing a sequence of charatcters\nto use as a separator" + }, + { + "@type": "Parameter", + "name": "resultVarName", + "type": "string|Var", + "summary": "variable that stores output list" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the Split pattern matching expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "member", + "summary": "Matches if List includes Element", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "element", + "type": "string|object|Var", + "summary": "Either a variable, IRI or any simple datatype" + }, + { + "@type": "Parameter", + "name": "list", + "type": "string|array|Var", + "summary": "List ([string, literal] or string*) Either a variable\nrepresenting a list or a list of variables or literals" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the List inclusion pattern matching expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "concat", + "summary": "takes a variable number of string arguments and concatenates them into a single string", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "varList", + "type": "array|string|Var", + "summary": "a variable representing a list or a list of variables or\nstrings - variables can be embedded in the string if they do not contain spaces" + }, + { + "@type": "Parameter", + "name": "resultVarName", + "type": "string|Var", + "summary": "A variable or string containing the output string" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the Concatenation pattern matching expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "join", + "summary": "Joins a list variable together (Input) into a string variable (Output) by glueing the strings\ntogether with Glue", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "varList", + "type": "string|array|Var", + "summary": "a variable representing a list or a list of strings\nand / or variables" + }, + { + "@type": "Parameter", + "name": "glue", + "type": "string|Var", + "summary": "A variable (v:glue) or (glue) string representing the characters\nto put in between the joined strings in input" + }, + { + "@type": "Parameter", + "name": "resultVarName", + "type": "string|Var", + "summary": "A variable or string containing the output string" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the Join pattern matching expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "sum", + "summary": "computes the sum of the List of values passed. In contrast to other arithmetic functions,\nsum self-evaluates - it does not have to be passed to evaluate()", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subquery", + "type": "WOQLQuery", + "summary": "a subquery or ([string or numeric]) - a list variable, or a\nlist of variables or numeric literals" + }, + { + "@type": "Parameter", + "name": "total", + "type": "string|Var", + "summary": "the variable name with the sum result of the values in List" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "- A WOQLQuery which contains the Sum expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "start", + "summary": "Specifies an offset position in the results to start listing results from", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "start", + "type": "number|string|Var", + "summary": "A variable that refers to an interger or an integer literal" + }, + { + "@type": "Parameter", + "name": "subquery", + "type": "WOQLQuery", + "summary": "WOQL Query object, you can pass a subquery as an argument\nor a chained query" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery whose results will be returned starting from\nthe specified offset", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "limit", + "summary": "Specifies a maximum number of results that will be returned from the subquery", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "limit", + "type": "number|string", + "summary": "A variable that refers to an non-negative integer or a\nnon-negative integer" + }, + { + "@type": "Parameter", + "name": "subquery", + "type": "WOQLQuery", + "summary": "A subquery whose results will be limited" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery whose results will be returned starting from\nthe specified offset", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "re", + "summary": "Matches the regular expression defined in Patern against the Test string, to produce\nthe matched patterns in Matches", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "pattern", + "type": "string", + "summary": "string or variable using normal PCRE regular expression syntax with\nthe exception that special characters have to be escaped twice (to enable transport in JSONLD)" + }, + { + "@type": "Parameter", + "name": "inputVarName", + "type": "string|Var", + "summary": "string or variable containing the string to be tested for\npatterns with the regex" + }, + { + "@type": "Parameter", + "name": "resultVarList", + "type": "string|array|object|Var", + "summary": "variable representing the list of matches\nor a list of strings or variables" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the Regular Expression pattern\nmatching expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "length", + "summary": "Calculates the length of the list in va and stores it in vb", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "inputVarList", + "type": "string|array", + "summary": "Either a variable representing a list or a list of\nvariables or literals" + }, + { + "@type": "Parameter", + "name": "resultVarName", + "type": "string|Var", + "summary": "A variable in which the length of the list is stored or\nthe length of the list as a non-negative integer" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the Length pattern matching expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "not", + "summary": "Logical negation of the contained subquery - if the subquery matches, the query\nwill fail to match", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subquery", + "type": "string|WOQLQuery", + "summary": "A subquery which will be negated" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery object containing the negated sub Query", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "once", + "summary": "Results in one solution of the subqueries", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subquery", + "type": "string|WOQLQuery", + "summary": "WOQL Query objects" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery object containing the once sub Query", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "immediately", + "summary": "Runs the query without backtracking on side-effects", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subquery", + "type": "string|WOQLQuery", + "summary": "WOQL Query objects" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery object containing the immediately sub Query", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "count", + "summary": "Creates a count of the results of the query", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "countVarName", + "type": "string|number|Var", + "summary": "variable or integer count" + }, + { + "@type": "Parameter", + "name": "subquery", + "type": "WOQLQuery" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery object containing the count sub Query", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "typecast", + "summary": "Casts the value of Input to a new value of type Type and stores the result in CastVar", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "varName", + "type": "string|number|object|Var", + "summary": "Either a single variable or a\nliteral of any basic type" + }, + { + "@type": "Parameter", + "name": "varType", + "type": "string|Var", + "summary": "Either a variable or a basic datatype (xsd / xdd)" + }, + { + "@type": "Parameter", + "name": "resultVarName", + "type": "string|Var", + "summary": "save the return variable" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the casting expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "order_by", + "summary": "Orders the results of the contained subquery by a precedence list of variables", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "orderedVarlist", + "type": "string|Var|array", + "summary": "A sequence of variables,\nby which to order the results,\neach optionally followed by either “asc” or “desc” to represent order as a list, by default\nit will sort the variable in ascending order" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the ordering expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "group_by", + "summary": "Groups the results of the contained subquery on the basis of identical values for Groupvars,\nextracts the patterns defined in PatternVars and stores the results in GroupedVar", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "gvarlist", + "type": "array|string|Var", + "summary": "Either a single variable or an array of variables" + }, + { + "@type": "Parameter", + "name": "groupedvar", + "type": "array|string|Var", + "summary": "Either a single variable or an array of variables" + }, + { + "@type": "Parameter", + "name": "output", + "type": "string|Var", + "summary": "output variable name" + }, + { + "@type": "Parameter", + "name": "groupquery", + "type": "WOQLQuery", + "summary": "The query whose results will be grouped" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the grouping expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "true", + "summary": "A function that always matches, always returns true", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery object containing the true value that will match any pattern", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "path", + "summary": "Performs a path regular expression match on the graph", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subject", + "type": "string|Var", + "summary": "An IRI or variable that refers to an IRI representing the subject,\ni.e. the starting point of the path" + }, + { + "@type": "Parameter", + "name": "pattern", + "type": "string", + "summary": "(string) - A path regular expression describing a pattern through\nmultiple edges of the graph (see: https://terminusdb.com/docs/path-query-reference-guide)" + }, + { + "@type": "Parameter", + "name": "object", + "type": "string|Var", + "summary": "An IRI or variable that refers to an IRI representing the object,\ni.e. ending point of the path" + }, + { + "@type": "Parameter", + "name": "resultVarName", + "type": "string|Var", + "summary": "A variable in which the actual paths\ntraversed will be stored" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "- A WOQLQuery which contains the path regular expression matching expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "dot", + "summary": "Extract the value of a key in a bound document.", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "document", + "type": "string|Var", + "summary": "Document which is being accessed." + }, + { + "@type": "Parameter", + "name": "field", + "type": "string|Var", + "summary": "The field from which the document which is being accessed." + }, + { + "@type": "Parameter", + "name": "value", + "type": "string|Var", + "summary": "The value for the document and field." + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the a dot Statement", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "size", + "summary": "Calculates the size in bytes of the contents of the resource identified in ResourceID", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "resourceId", + "type": "string|Var", + "summary": "A valid resource identifier string (can refer to any graph /\nbranch / commit / db)" + }, + { + "@type": "Parameter", + "name": "resultVarName", + "type": "string|Var", + "summary": "The variable name" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "triple_count", + "summary": "Calculates the number of triples of the contents of the resource identified in ResourceID", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "resourceId", + "type": "string|Var", + "summary": "A valid resource identifier string (can refer to any graph /\nbranch / commit / db)" + }, + { + "@type": "Parameter", + "name": "tripleCount", + "type": "string|number|Var", + "summary": "An integer literal with the size in bytes or a\nvariable containing that integer" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the size expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "type_of", + "summary": "Returns true if 'elementId' is of type 'elementType', according to the current DB schema", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "elementId", + "type": "string|Var", + "summary": "the id of a schema graph element" + }, + { + "@type": "Parameter", + "name": "elementType", + "type": "string|Var", + "summary": "the element type" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery object containing the type_of pattern matching rule", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "getLimit", + "summary": "Functions to manipulate and check the paging related properties of a query", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "getPagingProperty", + "summary": "Returns the value of one of the 'paging' related properties (limit, start,...)", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "setPagingProperty", + "summary": "Sets the value of one of the paging_transitive_properties properties", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + } + ] + }, + { + "@type": "Class", + "name": "WOQLLibrary", + "summary": "Library Functions to manage the commits graph", + "memberFunctions": [ + { + "@type": "Definition", + "name": "branches", + "summary": "General Pattern 4: Retrieves Branches, Their ID, Head Commit ID, Head Commit Time\n(if present, new branches have no commits)", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "commits", + "summary": "get all the commits of a specific branch\nif a timestamp is given, gets all the commits before the specified timestamp", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "branch", + "type": "string", + "summary": "the branch name" + }, + { + "@type": "Parameter", + "name": "limit", + "type": "number", + "summary": "the max number of result" + }, + { + "@type": "Parameter", + "name": "start", + "type": "number", + "summary": "the start of the pagination" + }, + { + "@type": "Parameter", + "name": "timestamp", + "type": "number", + "summary": "Unix timestamp in seconds" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "previousCommits", + "summary": "get commits older than the specified commit id", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "commit_id", + "type": "string", + "summary": "the commit id" + }, + { + "@type": "Parameter", + "name": "limit", + "type": "number", + "summary": "the max number of result" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "first_commit", + "summary": "Finds the id of the very first commit in a database's history\n\nThis is useful for finding information about when, by who and why the database was created\nThe first commit is the only commit in the database that does not have a parent commit", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + } + ] + }, + { + "@type": "Class", + "name": "ViewConfig", + "summary": "Generic functions / configs that are available to all config types", + "memberFunctions": [] + }, + { + "@type": "Class", + "name": "WOQLViewRule", + "memberFunctions": [] + }, + { + "@type": "Class", + "name": "View", + "summary": "We bundle the useful functions in a View object and just export that for ease of consumption", + "memberFunctions": [ + { + "@type": "Definition", + "name": "rule", + "summary": "Shorthand functions for accessing the pattern matching capabilities", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "matchRow", + "summary": "Called to match an entire row of results is matched by a set of rules\nreturns array of rules that matched", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "matchColumn", + "summary": "Called to test whether an entire column of results is matched by a set of rules\nreturns array of rules that matched", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "matchCell", + "summary": "Called to test whether a specific cell is matched by a set of rules\nreturns array of rules that matched", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "matchNode", + "summary": "Called to test whether a specific node is matched by a set of rules\nreturns array of rules that matched", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "matchEdge", + "summary": "Called to test whether a specific edge (source -> target) is matched by a set of rules\nreturns array of rules that matched", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "matchFrame", + "summary": "Called to test whether a specific frame is matched by a set of rules", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + } + ] + }, + { + "@type": "Class", + "name": "WOQL", + "summary": "The WOQL object is a wrapper around the WOQLQuery object\nSyntactic sugar to allow writing WOQL.triple()... instead of new WOQLQuery().triple()\nEvery function matches one of the public api functions of the woql query object", + "memberFunctions": [ + { + "@type": "Definition", + "name": "using", + "summary": "Query running against any specific commit Id", + "examples": [ + "let [a, b, c] = vars(\"a\", \"b\", \"c\")\nWOQL.using(\"userName/dbName/local/commit|branch/commitID\").triple(a, b, c)" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "refPath", + "type": "string", + "summary": "path to specific reference Id or commit Id" + }, + { + "@type": "Parameter", + "name": "subquery", + "type": "WOQLQuery", + "summary": "subquery for the specific commit point" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "comment", + "summary": "Adds a text comment to a query - can also be used to wrap any part of a query to turn it off", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "comment", + "type": "string", + "summary": "text comment" + }, + { + "@type": "Parameter", + "name": "subquery", + "type": "WOQLQuery", + "summary": "query that is \"commented out\"" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "select", + "examples": [ + "let [a, b, c] = vars(\"a\", \"b\", \"c\")\nWOQL.select(a, triple(a, b, c))\nFilters the query so that only the variables included in [V1...Vn] are returned in the bindings" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "varNames", + "type": "string|Var", + "summary": "only these variables are returned" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "distinct", + "summary": "Filter the query to return only results that are distinct in the given variables", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "varNames", + "type": "string|Var", + "summary": "these variables are guaranteed to be unique as a tuple" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "and", + "summary": "Logical conjunction of the contained queries - all queries must match or the entire clause fails", + "examples": [ + "//find triples that are of type scm:Journey, and have\n//a start_station Start, and that start_station is labeled Start_Label\nlet [Journey, Start, Start_Label] = vars(\"Journey\", \"Start\", \"Start_Label\")\nWOQL.and(\n WOQL.triple(Journey, \"rdf:type\", \"@schema:Journey\"),\n WOQL.triple(Journey, \"start_station\", Start),\n WOQL.triple(Start, \"label\", Start_Label))" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subqueries", + "type": "WOQLQuery", + "summary": "A list of one or more woql queries to execute as a conjunction" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "- A WOQLQuery object containing the conjunction of queries", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "read_object", + "summary": "Use {@link #read_document|read_document} instead.", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "read_document", + "summary": "Read a node identified by an IRI as a JSON-LD document", + "examples": [ + "let [person] = vars(\"Person\")\nconst query = WOQL.read_document(\n \"Person/0b4feda109d9d13c9da809090b342ad9e4d8185545ce05f7cd20b97fe458f547\",\n person\n);\nconst res = await client.query(query);" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "IRI", + "type": "string", + "summary": "The document id or a variable to read" + }, + { + "@type": "Parameter", + "name": "output", + "type": "string", + "summary": "Variable which will be bound to the document." + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "WOQLQuery", + "type": "object" + } + }, + { + "@type": "Definition", + "name": "insert_document", + "summary": "Insert a document in the graph.", + "examples": [ + "const res = await client.query(\n WOQL.insert_document(WOQL.doc({ \"@type\" : \"Person\", \"label\": \"John\" }))\n)" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "docjson", + "type": "object", + "summary": "The document to insert. Must either have an '@id' or\nhave a class specified key." + }, + { + "@type": "Parameter", + "name": "IRI", + "type": "string", + "summary": "An optional identifier specifying the document location." + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "WOQLQuery", + "type": "object" + } + }, + { + "@type": "Definition", + "name": "update_document", + "summary": "Update a document identified by an IRI", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "docjson", + "type": "object", + "summary": "The document to update. Must either have an '@id' or\nhave a class specified key." + }, + { + "@type": "Parameter", + "name": "IRI", + "type": "string", + "summary": "An optional identifier specifying the document location." + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "WOQLQuery", + "type": "object" + } + }, + { + "@type": "Definition", + "name": "delete_document", + "summary": "Delete a document from the graph.", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "IRI", + "type": "string", + "summary": "The document id or a variable" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "WOQLQuery", + "type": "object" + } + }, + { + "@type": "Definition", + "name": "or", + "summary": "Creates a logical OR of the arguments", + "examples": [ + "let [Subject] = vars(\"Subject\")\nor(\n triple(Subject, 'label', \"A\"),\n triple(Subject, \"label\", \"a\")\n )" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subqueries", + "type": "WOQLQuery", + "summary": "A list of one or more woql queries\nto execute as alternatives" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "- A WOQLQuery object containing the logical Or of the subqueries", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "from", + "summary": "Specifies the database URL that will be the default database for the enclosed query", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "graphRef-", + "type": "typedef.GraphRef", + "summary": "A valid graph resource identifier string" + }, + { + "@type": "Parameter", + "name": "query", + "type": "WOQLQuery", + "summary": "The query" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery object containing the from expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "into", + "summary": "Specifies the graph resource to write the contained query into", + "examples": [ + "//Subq is an argument or a chained query\nusing(\"admin/minecraft\").into(\"instance/main\").add_triple(\"a\", \"rdf:type\", \"@schema:X\")\n//writes a single tripe (doc:a, rdf:type, scm:X) into the main instance graph" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "graphRef-", + "type": "typedef.GraphRef", + "summary": "A valid graph resource identifier string" + }, + { + "@type": "Parameter", + "name": "subquery", + "type": "WOQLQuery", + "summary": "The query which will be written into the graph" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which will be written into the graph in question", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "triple", + "summary": "Creates a triple pattern matching rule for the triple [S, P, O] (Subject, Predicate, Object)", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subject", + "type": "string|Var", + "summary": "The IRI of a triple’s subject or a variable" + }, + { + "@type": "Parameter", + "name": "predicate", + "type": "string|Var", + "summary": "The IRI of a property or a variable" + }, + { + "@type": "Parameter", + "name": "object", + "type": "string|Var", + "summary": "The IRI of a node or a variable, or a literal" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "added_triple", + "summary": "Creates a triple pattern matching rule for the triple [S, P, O] (Subject, Predicate,\nObject) added in the current layer", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subject", + "type": "string|Var", + "summary": "The IRI of a triple’s subject or a variable" + }, + { + "@type": "Parameter", + "name": "predicate", + "type": "string|Var", + "summary": "The IRI of a property or a variable" + }, + { + "@type": "Parameter", + "name": "object", + "type": "string|Var", + "summary": "The IRI of a node or a variable, or a literal" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "removed_triple", + "summary": "Creates a triple pattern matching rule for the triple [S, P, O] (Subject, Predicate,\nObject) added in the current commit", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subject", + "type": "string|Var", + "summary": "The IRI of a triple’s subject or a variable" + }, + { + "@type": "Parameter", + "name": "predicate", + "type": "string|Var", + "summary": "The IRI of a property or a variable" + }, + { + "@type": "Parameter", + "name": "object", + "type": "string|Var", + "summary": "The IRI of a node or a variable, or a literal" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "quad", + "summary": "Creates a pattern matching rule for the quad [S, P, O, G] (Subject, Predicate, Object, Graph)", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subject", + "type": "string|Var", + "summary": "The IRI of a triple’s subject or a variable" + }, + { + "@type": "Parameter", + "name": "predicate", + "type": "string|Var", + "summary": "The IRI of a property or a variable" + }, + { + "@type": "Parameter", + "name": "object", + "type": "string|Var", + "summary": "The IRI of a node or a variable, or a literal" + }, + { + "@type": "Parameter", + "name": "graphRef", + "type": "typedef.GraphRef", + "summary": "A valid graph resource identifier string" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "added_quad", + "summary": "Creates a pattern matching rule for the quad [S, P, O, G] (Subject, Predicate,\nObject, Graph) removed from the current commit", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subject", + "type": "string|Var", + "summary": "The IRI of a triple’s subject or a variable" + }, + { + "@type": "Parameter", + "name": "predicate", + "type": "string|Var", + "summary": "The IRI of a property or a variable" + }, + { + "@type": "Parameter", + "name": "object", + "type": "string|Var", + "summary": "The IRI of a node or a variable, or a literal" + }, + { + "@type": "Parameter", + "name": "graphRef-", + "type": "typedef.GraphRef", + "summary": "A valid graph resource identifier string" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "removed_quad", + "summary": "Creates a pattern matching rule for the quad [S, P, O, G] (Subject, Predicate,\nObject, Graph) removed from the current commit", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subject", + "type": "string|Var", + "summary": "The IRI of a triple’s subject or a variable" + }, + { + "@type": "Parameter", + "name": "predicate", + "type": "string|Var", + "summary": "The IRI of a property or a variable" + }, + { + "@type": "Parameter", + "name": "object", + "type": "string|Var", + "summary": "The IRI of a node or a variable, or a literal" + }, + { + "@type": "Parameter", + "name": "graphRef-", + "type": "typedef.GraphRef", + "summary": "A valid graph resource identifier string" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "sub", + "summary": "Returns true if ClassA subsumes ClassB, according to the current DB schema", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "classA", + "type": "string", + "summary": "ClassA" + }, + { + "@type": "Parameter", + "name": "classB", + "type": "string", + "summary": "ClassB" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "WOQLQuery", + "type": "boolean" + } + }, + { + "@type": "Definition", + "name": "eq", + "summary": "Matches if a is equal to b", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "varName", + "type": "string|Var", + "summary": "literal, variable or id" + }, + { + "@type": "Parameter", + "name": "varValue", + "type": "string|Var", + "summary": "literal, variable or id" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "substr", + "summary": "Substring", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "string", + "type": "string|Var", + "summary": "String or variable" + }, + { + "@type": "Parameter", + "name": "before", + "type": "number|Var", + "summary": "integer or variable (characters from start to begin)" + }, + { + "@type": "Parameter", + "name": "length", + "type": "number|Var", + "summary": "integer or variable (length of substring)" + }, + { + "@type": "Parameter", + "name": "after", + "type": "number|Var", + "summary": "integer or variable (number of characters after substring)" + }, + { + "@type": "Parameter", + "name": "substring", + "type": "string|Var", + "summary": "String or variable" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "get", + "summary": "Use the document inteface to import documents", + "examples": [ + "let [a, b] = vars(\"a\", \"b\")\nget(as(\"a\", a).as(\"b\", b)).remote(\"http://my.url.com/x.csv\")\n//copies the values from column headed \"a\" into a variable a and from column\n//\"b\" into a variable b from remote CSV" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "asvars", + "type": "Vars|array.", + "summary": "an array of AsVar variable mappings (see as for format below)" + }, + { + "@type": "Parameter", + "name": "queryResource", + "type": "WOQLQuery", + "summary": "an external resource (remote, file, post) to query" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the get expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "put", + "summary": "Use the document inteface to import documents", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "varsToExp", + "type": "Vars|array.", + "summary": "an array of AsVar variable\nmappings (see as for format below)" + }, + { + "@type": "Parameter", + "name": "query", + "type": "WOQLQuery", + "summary": "The query which will be executed to produce the results" + }, + { + "@type": "Parameter", + "name": "fileResource", + "type": "string", + "summary": "an file resource local to the server" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the put expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "as", + "summary": "Imports the value identified by Source to a Target variable", + "examples": [ + "let [First_Var, Second_Var] = vars('First_Var', 'Second_Var')\nWOQL.as(\"first var\", First_Var, \"string\").as(\"second var\", Second_Var)\nWOQL.as([\"first var\", First_Var, \"string\"], [\"second var\", Second_Var])" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "source", + "type": "string|number|Var", + "summary": "Source" + }, + { + "@type": "Parameter", + "name": "target", + "type": "string|Var", + "summary": "Target" + }, + { + "@type": "Parameter", + "name": "type", + "type": "string", + "summary": "type to cast value to string|number etc..." + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "remote", + "summary": "Identifies a remote resource by URL and specifies the format of the resource through the options", + "examples": [ + "remote({url:\"http://url.of.resource\"}, {type: \"csv\"})" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "remoteObj", + "type": "object", + "summary": "The URL at which the remote resource can be accessed" + }, + { + "@type": "Parameter", + "name": "formatObj", + "type": "typedef.DataFormatObj", + "summary": "The format of the resource data {}" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the remote resource identifier", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "post", + "summary": "Identifies a resource as a local path on the client, to be sent to the server through a\nHTTP POST request, with the format defined through the options", + "examples": [ + "post(\"/.../.../\", {type:'csv'})" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "url", + "type": "string", + "summary": "The Path on the server at which the file resource can be accessed" + }, + { + "@type": "Parameter", + "name": "formatObj", + "type": "typedef.DataFormatObj", + "summary": "imput options, optional" + }, + { + "@type": "Parameter", + "name": "source", + "type": "string", + "summary": "It defines the source of the file, it can be 'url','post'" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the Post resource identifier", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "delete_triple", + "summary": "Deletes a single triple from the default graph of the database", + "examples": [ + "delete_triple(\"john\", \"age\", 42)" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subject", + "type": "string|Var", + "summary": "The IRI of a triple’s subject or a variable" + }, + { + "@type": "Parameter", + "name": "predicate", + "type": "string|Var", + "summary": "The IRI of a property or a variable" + }, + { + "@type": "Parameter", + "name": "object", + "type": "string|Var", + "summary": "The IRI of a node or a variable, or a literal" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "- A WOQLQuery which contains the Triple Deletion statement", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "delete_quad", + "summary": "Deletes a single triple from the graph [Subject, Predicate, Object, Graph]", + "examples": [ + "remove the class Person from the schema graph\nWOQL.delete_quad(\"Person\", \"rdf:type\", \"sys:Class\", \"schema\")" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subject", + "type": "string|Var", + "summary": "The IRI of a triple’s subject or a variable" + }, + { + "@type": "Parameter", + "name": "predicate", + "type": "string|Var", + "summary": "The IRI of a property or a variable" + }, + { + "@type": "Parameter", + "name": "object", + "type": "string|Var", + "summary": "The IRI of a node or a variable, or a literal" + }, + { + "@type": "Parameter", + "name": "graphRef", + "type": "typedef.GraphRef", + "summary": "A valid graph resource identifier string" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "- A WOQLQuery which contains the Delete Quad Statement", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "add_triple", + "summary": "Adds triples according to the the pattern [subject,predicate,object]", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subject", + "type": "string|Var", + "summary": "The IRI of a triple’s subject or a variable" + }, + { + "@type": "Parameter", + "name": "predicate", + "type": "string|Var", + "summary": "The IRI of a property or a variable" + }, + { + "@type": "Parameter", + "name": "object", + "type": "string|Var", + "summary": "The IRI of a node or a variable, or a literal" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "add_quad", + "summary": "Adds quads according to the pattern [S,P,O,G]", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subject", + "type": "string|Var", + "summary": "The IRI of a triple’s subject or a variable" + }, + { + "@type": "Parameter", + "name": "predicate", + "type": "string|Var", + "summary": "The IRI of a property or a variable" + }, + { + "@type": "Parameter", + "name": "object", + "type": "string|Var", + "summary": "The IRI of a node or a variable, or a literal" + }, + { + "@type": "Parameter", + "name": "graphRef-", + "type": "typedef.GraphRef", + "summary": "A valid graph resource identifier string" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "trim", + "summary": "Remove whitespace from both sides of a string:", + "examples": [ + "let [trimmed] = vars(\"trimmed\")\ntrim(\"hello \", trimmed)\n//trimmed contains \"hello\"" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "inputStr", + "type": "string|Var", + "summary": "A string or variable containing\nthe untrimmed version of the string" + }, + { + "@type": "Parameter", + "name": "resultVarName", + "type": "string|Var", + "summary": "A string or variable\ncontaining the trimmed version of the string" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the Trim pattern matching expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "evaluate", + "summary": "Evaluates the passed arithmetic expression and generates or matches the result value", + "examples": [ + "let [result] = vars(\"result\")\nevaluate(plus(2, minus(3, 1)), result)" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "arithExp", + "type": "object|WOQLQuery|string", + "summary": "A WOQL query containing a valid WOQL Arithmetic\nExpression, which is evaluated by the function" + }, + { + "@type": "Parameter", + "name": "resultVarName", + "type": "string|number|Var", + "summary": "Either a variable, in which the result of the\nexpression will be stored, or a numeric literal which will be used as a test of result of\nthe evaluated expression" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the Arithmetic function", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "eval", + "summary": "Evaluates the passed arithmetic expression and generates or matches the result value", + "examples": [ + "let [result] = vars(\"result\")\neval(plus(2, minus(3, 1)), result)" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "arithExp", + "type": "object|WOQLQuery|string", + "summary": "A WOQL query containing a valid WOQL Arithmetic\nExpression, which is evaluated by the function" + }, + { + "@type": "Parameter", + "name": "resultVarName", + "type": "string|number|Var", + "summary": "Either a variable, in which the result of the\nexpression will be stored, or a numeric literal which will be used as a test of result of\nthe evaluated expression" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the Arithmetic function", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "plus", + "summary": "Adds the numbers together", + "examples": [ + "let [result] = vars(\"result\")\nevaluate(plus(2, plus(3, 1)), result)" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "args", + "type": "string|number|Var", + "summary": "a variable or numeric containing the values to add" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the addition expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "minus", + "summary": "Subtracts Numbers N1..Nn", + "examples": [ + "let [result] = vars(\"result\")\nevaluate(minus(2.1, plus(0.2, 1)), result)" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "args", + "type": "string|number|Var", + "summary": "variable or numeric containing the value that will be\nsubtracted from" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the subtraction expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "times", + "summary": "Multiplies numbers N1...Nn together", + "examples": [ + "let [result] = vars(\"result\")\nevaluate(times(10, minus(2.1, plus(0.2, 1))), result)\n //result contains 9.000000000000002y" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "args", + "type": "string|number|Var", + "summary": "a variable or numeric containing the value" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the multiplication expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "divide", + "summary": "Divides numbers N1...Nn by each other left, to right precedence", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "args", + "type": "string|number|Var", + "summary": "numbers to tbe divided" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the division expression\nlet [result] = vars(\"result\")\nevaluate(divide(times(10, minus(2.1, plus(0.2, 1))), 10), result)\n //result contains 0.9000000000000001", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "div", + "summary": "Division - integer division - args are divided left to right", + "examples": [ + "let [result] = vars(\"result\")\nevaluate(div(10, 3), result)\n//result contains 3" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "args", + "type": "string|number|Var", + "summary": "numbers for division" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the division expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "exp", + "summary": "Exponent - raises varNum01 to the power of varNum02", + "examples": [ + "let [result] = vars(\"result\")\nevaluate(exp(3, 2), result)\n//result contains 9" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "varNum", + "type": "string|number|Var", + "summary": "a variable or numeric containing the number to be\nraised to the power of the second number" + }, + { + "@type": "Parameter", + "name": "expNum", + "type": "number", + "summary": "a variable or numeric containing the exponent" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the exponent expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "floor", + "summary": "Generates the nearest lower integer to the passed number", + "examples": [ + "let [result] = vars(\"result\")\nevaluate(divide(floor(times(10, minus(2.1, plus(0.2, 1)))), 10), result)\n//result contains 0.9 - floating point error removed" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "varNum", + "type": "string|number|Var", + "summary": "Variable or numeric containing the number to be floored" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the floor expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "isa", + "summary": "Tests whether a given instance IRI has type Class, according to the current state of the DB", + "examples": [ + "let [subject] = vars(\"subject\")\nisa(subject, \"Person\")" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "instanceIRI", + "type": "string|Var", + "summary": "A string IRI or a variable that identify the class instance" + }, + { + "@type": "Parameter", + "name": "classId", + "type": "string|Var", + "summary": "A Class IRI or a variable" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery object containing the type test", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "like", + "summary": "Generates a string Leverstein distance measure between stringA and stringB", + "examples": [ + "let [dist] = vars('dist')\nlike(\"hello\", \"hallo\", dist)\n//dist contains 0.7265420560747664" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "stringA", + "type": "string|Var", + "summary": "string literal or variable representing a string to be compared" + }, + { + "@type": "Parameter", + "name": "stringB", + "type": "string|Var", + "summary": "string literal or variable\nrepresenting the other string to be compared" + }, + { + "@type": "Parameter", + "name": "distance", + "type": "number|string|Var", + "summary": "variable representing the distance between the variables" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the Like pattern matching expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "less", + "summary": "Compares the value of v1 against v2 and returns true if v1 is less than v2", + "examples": [ + "let [result] = vars(\"result\")\nless(1, 1.1).eq(result, literal(true, \"boolean\"))\n//result contains true" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "varNum01", + "type": "string|number|Var", + "summary": "a variable or numeric containing\nthe number to be compared" + }, + { + "@type": "Parameter", + "name": "varNum02", + "type": "string|number|Var", + "summary": "a variable or numeric containing the second comporator" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the comparison expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "greater", + "summary": "Compares the value of v1 against v2 and returns true if v1 is greater than v2", + "examples": [ + "let [result] = vars(\"result\")\ngreater(1.2, 1.1).eq(result, literal(true, \"boolean\"))\n//result contains true" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "varNum01", + "type": "string|number|Var", + "summary": "a variable or numeric containing the number to be compared" + }, + { + "@type": "Parameter", + "name": "varNum02", + "type": "string|number|Var", + "summary": "a variable or numeric containing the second comporator" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the comparison expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "opt", + "summary": "Specifies that the Subquery is optional - if it does not match the query will not fail", + "examples": [ + "let [subject] = vars(\"subject\")\nopt(triple(subject, 'label', \"A\"))\n//Subq is an argument or a chained query\nopt().triple(subject, 'label', \"A\")" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subquery", + "type": "WOQLQuery", + "summary": "A subquery which will be optionally matched" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery object containing the optional sub Query", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "unique", + "summary": "Generate a new IRI from the prefix and a hash of the variables which will be unique for any\ngiven combination of variables", + "examples": [ + "let [newid] = vars(\"newid\")\nunique(\"doc:Person\", [\"John\", \"Smith\"], newid)" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "prefix", + "type": "string", + "summary": "A prefix for the IRI - typically formed of the doc prefix and the\nclasstype of the entity (“doc:Person”)" + }, + { + "@type": "Parameter", + "name": "inputVarList", + "type": "array|string|Var", + "summary": "An array of variables and / or strings from which the\nunique hash will be generated" + }, + { + "@type": "Parameter", + "name": "resultVarName", + "type": "string|Var", + "summary": "Variable in which the unique ID is stored" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery object containing the unique ID generating function", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "idgen", + "summary": "Generate a new IRI from the prefix and concatention of the variables", + "examples": [ + "let [newid] = vars(\"newid\")\nidgen(\"doc:Person\", [\"John\", \"Smith\"], newid)" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "prefix", + "type": "string", + "summary": "A prefix for the IRI - typically formed of the doc prefix and the\nclasstype of the entity (“doc:Person”)" + }, + { + "@type": "Parameter", + "name": "inputVarList", + "type": "array|string|Var", + "summary": "An array of variables and / or strings from which the\nunique hash will be generated" + }, + { + "@type": "Parameter", + "name": "resultVarName", + "type": "string|Var", + "summary": "Variable in which the unique ID is stored" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery object containing the ID generating function", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "upper", + "summary": "Changes a string to upper-case", + "examples": [ + "let [allcaps] = vars(\"allcaps\")\nupper(\"aBCe\", allcaps)\n//upper contains \"ABCE\"" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "inputVarName", + "type": "string|Var", + "summary": "string or variable representing the uncapitalized string" + }, + { + "@type": "Parameter", + "name": "resultVarName", + "type": "string|Var", + "summary": "variable that stores the capitalized string output" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the Upper case pattern matching expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "lower", + "summary": "Changes a string to lower-case", + "examples": [ + "let [lower] = var(\"l\")\nlower(\"aBCe\", lower)\n//lower contains \"abce\"" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "inputVarName", + "type": "string|Var", + "summary": "string or variable representing the non-lowercased string" + }, + { + "@type": "Parameter", + "name": "resultVarName", + "type": "string|Var", + "summary": "variable that stores the lowercased string output" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the Lower case pattern matching expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "pad", + "summary": "Pads out the string input to be exactly len long by appending the pad character pad to\nform output", + "examples": [ + "let [fixed] = vars(\"fixed length\")\npad(\"joe\", \" \", 8, fixed)\n//fixed contains \"joe \"" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "inputVarName", + "type": "string|Var", + "summary": "The input string or variable in unpadded state" + }, + { + "@type": "Parameter", + "name": "pad", + "type": "string|Var", + "summary": "The characters to use to pad the string or a variable representing them" + }, + { + "@type": "Parameter", + "name": "len", + "type": "number|string|Var", + "summary": "The variable or integer value representing the length of\nthe output string" + }, + { + "@type": "Parameter", + "name": "resultVarName", + "type": "string|Var", + "summary": "stores output" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the Pad pattern matching expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "split", + "summary": "Splits a string (Input) into a list strings (Output) by removing separator", + "examples": [ + "let [words] = vars(\"words\")\nsplit(\"joe has a hat\", \" \", words)" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "inputVarName", + "type": "string|Var", + "summary": "A string or variable representing the unsplit string" + }, + { + "@type": "Parameter", + "name": "separator", + "type": "string|Var", + "summary": "A string or variable containing a sequence of charatcters\nto use as a separator" + }, + { + "@type": "Parameter", + "name": "resultVarName", + "type": "string|Var", + "summary": "variable that stores output list" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the Split pattern matching expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "member", + "summary": "Matches if List includes Element", + "examples": [ + "let [name] = vars(\"name\")\nmember(name, [\"john\", \"joe\", \"frank\"])" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "element", + "type": "string|object|Var", + "summary": "Either a variable, IRI or any simple datatype" + }, + { + "@type": "Parameter", + "name": "list", + "type": "string|array|Var", + "summary": "List ([string, literal] or string*) Either a variable\nrepresenting a list or a list of variables or literals" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the List inclusion pattern matching expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "concat", + "summary": "takes a variable number of string arguments and concatenates them into a single string", + "examples": [ + "let [first_name, last_name, full_name] = vars(\"first_name\", \"last_name\", \"full_name\")\nconcat([first_name, \" \", last_name], full_name)" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "varList", + "type": "array|string|Var", + "summary": "a variable representing a list or a list of variables or\nstrings - variables can be embedded in the string if they do not contain spaces" + }, + { + "@type": "Parameter", + "name": "resultVarName", + "type": "string|Var", + "summary": "A variable or string containing the output string" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the Concatenation pattern matching expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "join", + "summary": "Joins a list variable together (Input) into a string variable (Output) by glueing the strings\ntogether with Glue", + "examples": [ + "let [sentence] = vars(\"sentence\")\njoin([\"joe\", \"has\", \"a\", \"hat\", \" \", sentence)" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "varList", + "type": "string|array|Var", + "summary": "a variable representing a list or a list of strings\nand / or variables" + }, + { + "@type": "Parameter", + "name": "glue", + "type": "string|Var", + "summary": "A variable (v:glue) or (glue) string representing the characters\nto put in between the joined strings in input" + }, + { + "@type": "Parameter", + "name": "resultVarName", + "type": "string|Var", + "summary": "A variable or string containing the output string" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the Join pattern matching expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "sum", + "summary": "computes the sum of the List of values passed. In contrast to other arithmetic functions,\nsum self-evaluates - it does not have to be passed to evaluate()", + "examples": [ + "let [total] = vars(\"total\")\nsum([2, 3, 4, 5], total)" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subquery", + "type": "WOQLQuery", + "summary": "a subquery or ([string or numeric]) - a list variable, or a\nlist of variables or numeric literals" + }, + { + "@type": "Parameter", + "name": "total", + "type": "string|Var", + "summary": "the variable name with the sum result of the values in List" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "- A WOQLQuery which contains the Sum expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "start", + "summary": "Specifies an offset position in the results to start listing results from", + "examples": [ + "let [a, b, c] = vars(\"a\", \"b\", \"c\")\nstart(100).triple(a, b, c)" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "start", + "type": "number|string|Var", + "summary": "A variable that refers to an interger or an integer literal" + }, + { + "@type": "Parameter", + "name": "subquery", + "type": "WOQLQuery", + "summary": "WOQL Query object, you can pass a subquery as an argument\nor a chained query" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery whose results will be returned starting from\nthe specified offset", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "limit", + "summary": "Specifies a maximum number of results that will be returned from the subquery", + "examples": [ + "let [a, b, c] = vars(\"a\", \"b\", \"c\")\nlimit(100).triple(a, b, c)\n//subquery is an argument or a chained query\nlimit(100,triple(a, b, c))" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "limit", + "type": "number|string", + "summary": "A variable that refers to an non-negative integer or a\nnon-negative integer" + }, + { + "@type": "Parameter", + "name": "subquery", + "type": "WOQLQuery", + "summary": "A subquery whose results will be limited" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery whose results will be returned starting from\nthe specified offset", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "re", + "summary": "Matches the regular expression defined in Patern against the Test string, to produce\nthe matched patterns in Matches", + "examples": [ + "let [All, Sub] = vars(\"All\", \"Sub\")\nWOQL.re(\"h(.).*\", \"hello\", [All, Sub])\n//e contains 'e', llo contains 'llo'\n//p is a regex pattern (.*) using normal regular expression syntax, the only unusual\nthing is that special characters have to be escaped twice, s is the string to be matched\nand m is a list of matches:" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "pattern", + "type": "string", + "summary": "string or variable using normal PCRE regular expression syntax with\nthe exception that special characters have to be escaped twice (to enable transport in JSONLD)" + }, + { + "@type": "Parameter", + "name": "inputVarName", + "type": "string|Var", + "summary": "string or variable containing the string to be tested for\npatterns with the regex" + }, + { + "@type": "Parameter", + "name": "resultVarList", + "type": "string|array|object|Var", + "summary": "variable representing the list of matches\nor a list of strings or variables" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the Regular Expression pattern\nmatching expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "length", + "summary": "Calculates the length of the list in va and stores it in vb", + "examples": [ + "let [count] = vars(\"count\")\nlength([\"john\", \"joe\", \"frank\"], count)" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "inputVarList", + "type": "string|array", + "summary": "Either a variable representing a list or a list of\nvariables or literals" + }, + { + "@type": "Parameter", + "name": "resultVarName", + "type": "string|Var", + "summary": "A variable in which the length of the list is stored or\nthe length of the list as a non-negative integer" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the Length pattern matching expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "not", + "summary": "Logical negation of the contained subquery - if the subquery matches, the query\nwill fail to match", + "examples": [ + "let [subject, label] = vars(\"subject\", \"label\")\nnot().triple(subject, 'label', label)" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subquery", + "type": "string|WOQLQuery", + "summary": "A subquery which will be negated" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery object containing the negated sub Query", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "once", + "summary": "Results in one solution of the subqueries", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subquery", + "type": "string|WOQLQuery", + "summary": "WOQL Query objects" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery object containing the once sub Query", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "immediately", + "summary": "Runs the query without backtracking on side-effects", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subquery", + "type": "string|WOQLQuery", + "summary": "WOQL Query objects" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery object containing the immediately sub Query", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "count", + "summary": "Creates a count of the results of the query", + "examples": [ + "let [count, Person] = vars(\"count\", \"Person\")\nWOQL.count(count).triple(Person, \"rdf:type\", \"@schema:Person\")" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "countVarName", + "type": "string|number|Var", + "summary": "variable or integer count" + }, + { + "@type": "Parameter", + "name": "subquery", + "type": "WOQLQuery" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery object containing the count sub Query", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "typecast", + "summary": "Casts the value of Input to a new value of type Type and stores the result in CastVar", + "examples": [ + "let [time] = vars(\"time\")\ncast(\"22/3/98\", \"xsd:dateTime\", time)" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "varName", + "type": "string|number|object|Var", + "summary": "Either a single variable or a\nliteral of any basic type" + }, + { + "@type": "Parameter", + "name": "varType", + "type": "string|Var", + "summary": "Either a variable or a basic datatype (xsd / xdd)" + }, + { + "@type": "Parameter", + "name": "resultVarName", + "type": "string|Var", + "summary": "save the return variable" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the casting expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "order_by", + "summary": "Orders the results of the contained subquery by a precedence list of variables", + "examples": [ + "let [A, B, C] = vars(\"A\", \"B\", \"C\")\nWOQL.order_by(A, [B, \"asc\"], [C, \"desc\"]).triple(A, B, C);" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "varNames", + "type": "string|Var|array", + "summary": "A sequence of variables,\nby which to order the results,\neach optionally followed by either “asc” or “desc” to represent order as a list, by default\nit will sort the variable in ascending order" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the ordering expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "group_by", + "summary": "Groups the results of the contained subquery on the basis of identical values for Groupvars,\nextracts the patterns defined in PatternVars and stores the results in GroupedVar", + "examples": [ + "//subquery is an argument or a chained query\nlet [age, last_name, first_name, age_group, person] = vars(\"age\", \"last name\", \"first name\",\n\"age group\", \"person\")\ngroup_by(age, [last_name, first_name], age_group)\n .triple(person, \"first_name\", first_name)\n .triple(person, \"last_name\", last_name)\n .triple(person, \"age\", age)" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "varList", + "type": "array|string|Var", + "summary": "Either a single variable or an array of variables" + }, + { + "@type": "Parameter", + "name": "patternVars", + "type": "array|string|Var", + "summary": "Either a single variable or an array of variables" + }, + { + "@type": "Parameter", + "name": "resultVarName", + "type": "string|Var", + "summary": "output variable name" + }, + { + "@type": "Parameter", + "name": "subquery", + "type": "WOQLQuery", + "summary": "The query whose results will be grouped" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the grouping expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "true", + "summary": "A function that always matches, always returns true", + "examples": [ + "when(true()).triple(\"a\", \"b\", \"c\")" + ], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery object containing the true value that will match any pattern", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "path", + "summary": "Performs a path regular expression match on the graph", + "examples": [ + "let [person, grand_uncle, lineage] = vars(\"person\", \"grand uncle\", \"lineage\")\npath(person, \"((father|mother) {2,2}), brother)\", grand_uncle, lineage)" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subject", + "type": "string|Var", + "summary": "An IRI or variable that refers to an IRI representing the subject,\ni.e. the starting point of the path" + }, + { + "@type": "Parameter", + "name": "pattern", + "type": "string", + "summary": "(string) - A path regular expression describing a pattern through\nmultiple edges of the graph (see: https://terminusdb.com/docs/path-query-reference-guide)" + }, + { + "@type": "Parameter", + "name": "object", + "type": "string|Var", + "summary": "An IRI or variable that refers to an IRI representing the object,\ni.e. ending point of the path" + }, + { + "@type": "Parameter", + "name": "resultVarName", + "type": "string|Var", + "summary": "A variable in which the actual paths\ntraversed will be stored" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "- A WOQLQuery which contains the path regular expression matching expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "size", + "summary": "Calculates the size in bytes of the contents of the resource identified in ResourceID", + "examples": [ + "let [varSize] = vars(\"varSize\")\nsize(\"admin/minecraft/local/branch/main/instance/main\", varSize)\n//returns the number of bytes in the main instance graph on the main branch" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "resourceId", + "type": "string|Var", + "summary": "A valid resource identifier string (can refer to any graph /\nbranch / commit / db)" + }, + { + "@type": "Parameter", + "name": "resultVarName", + "type": "string|Var", + "summary": "The variable name" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "triple_count", + "summary": "Calculates the number of triples of the contents of the resource identified in ResourceID", + "examples": [ + "let [count] = vars(\"count\")\ntriple_count(\"admin/minecraft/local/_commits\", count)\n//returns the number of bytes in the local commit graph" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "resourceId", + "type": "string|Var", + "summary": "A valid resource identifier string (can refer to any graph /\nbranch / commit / db)" + }, + { + "@type": "Parameter", + "name": "tripleCount", + "type": "string|number|Var", + "summary": "An integer literal with the size in bytes or a\nvariable containing that integer" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the size expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "type_of", + "summary": "Returns true if 'elementId' is of type 'elementType', according to the current DB schema", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "elementId", + "type": "string|Var", + "summary": "the id of a schema graph element" + }, + { + "@type": "Parameter", + "name": "elementType", + "type": "string|Var", + "summary": "the element type" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery object containing the type_of pattern matching rule", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "star", + "summary": "Generates a query that by default matches all triples in a graph identified by \"graph\"\nor in all the current terminusDB's graph", + "examples": [ + "star(\"schema/main\")\n//will return every triple in schema/main graph" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "graph", + "type": "string|boolean", + "summary": "false or the resource identifier of a graph possible\nvalue are schema/{main - myschema - *} | instance/{main - myschema - *} |\ninference/{main - myschema - *}" + }, + { + "@type": "Parameter", + "name": "subject", + "type": "string|Var", + "summary": "The IRI of a triple’s subject or a variable,\ndefault value \"v:Subject\"" + }, + { + "@type": "Parameter", + "name": "predicate", + "type": "string|Var", + "summary": "The IRI of a property or a variable,\n default value \"v:Predicate\"" + }, + { + "@type": "Parameter", + "name": "object", + "type": "string|Var", + "summary": "The IRI of a node or a variable, or a literal,\ndefault value \"v:Object\"" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the pattern matching expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "all", + "summary": "Generates a query that by default matches all triples in a graph - identical to\nstar() except for order of arguments", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subject", + "type": "string|Var", + "summary": "The IRI of a triple’s subject or a variable" + }, + { + "@type": "Parameter", + "name": "predicate", + "type": "string|Var", + "summary": "The IRI of a property or a variable" + }, + { + "@type": "Parameter", + "name": "object", + "type": "string|Var", + "summary": "The IRI of a node or a variable, or a literal" + }, + { + "@type": "Parameter", + "name": "graphRef", + "type": "typedef.GraphRef", + "summary": "the resource identifier of a graph possible\nvalue are schema/{main - myschema - *} | instance/{main - myschema - *} |\ninference/{main - myschema - *}" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "- A WOQLQuery which contains the pattern matching expression\nall(\"mydoc\")\n//will return every triple in the instance/main graph that has \"doc:mydoc\" as its subject", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "node", + "summary": "Specifies the identity of a node that can then be used in subsequent builder functions.\nNote that node() requires subsequent chained functions to complete the triples / quads\nthat it produces - by itself it only generates the subject.", + "examples": [ + "node(\"mydoc\").label(\"my label\")\n//equivalent to triple(\"mydoc\", \"label\", \"my label\")" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "nodeid", + "type": "string|Var", + "summary": "The IRI of a node or a variable containing an IRI which will\nbe the subject of the builder functions" + }, + { + "@type": "Parameter", + "name": "chainType", + "type": "typedef.FuntionType", + "summary": "Optional type of builder function to build\n(default is triple)" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "- A WOQLQuery which contains the partial Node pattern matching expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "insert", + "summary": "Inserts a single triple into the database declaring the Node to have type Type,\noptionally into the specified graph", + "examples": [ + "insert(\"mydoc\", \"MyType\")\n//equivalent to add_triple(\"mydoc\", \"rdf:type\", \"@schema:MyType\")" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "classId", + "type": "string|Var", + "summary": "IRI string or variable containing\nthe IRI of the node to be inserted" + }, + { + "@type": "Parameter", + "name": "classType", + "type": "string|Var", + "summary": "IRI string or variable containing the IRI of the\ntype of the node (class/document name)" + }, + { + "@type": "Parameter", + "name": "graphRef", + "type": "typedef.GraphRef", + "summary": "Optional Graph resource identifier" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the insert expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "graph", + "summary": "Sets the graph resource ID that will be used for subsequent chained function calls", + "examples": [ + "WOQL.graph(\"schema\")\n//equivalent to add_quad(\"MyClass\", \"label\", \"My Class Label\", \"schema/main\")" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "graphRef", + "type": "typedef.GraphRef", + "summary": "Resource String identifying the graph which will\nbe used for subsequent chained schema calls" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the partial Graph pattern matching expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "nuke", + "summary": "Deletes all triples in the passed graph (defaults to instance/main)", + "examples": [ + "nuke(\"schema/main\")\n//will delete everything from the schema/main graph" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "graphRef", + "type": "typedef.GraphRef", + "summary": "Resource String identifying the graph from\nwhich all triples will be removed" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "- A WOQLQuery which contains the deletion expression", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "query", + "summary": "Generates an empty WOQLQuery object", + "examples": [ + "let q = query()\n//then q.triple(1, 1) ..." + ], + "section": "Query the database", + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "json", + "summary": "Generates a WOQLQuery object from the passed WOQL JSON - if an argument is passed,\nthe query object is created from it, if none is passed, the current state is\nreturned as a JSON-LD", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "JSON_LD", + "type": "object", + "summary": "JSON-LD woql document encoding a query" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "either a JSON-LD or a WOQLQuery object\n\njson version of query for passing to api", + "type": "WOQLQuery|object" + } + }, + { + "@type": "Definition", + "name": "lib", + "summary": "get the predefined library query [WOQLLibrary](/api/woqlLibrary.js?id=WOQLLibrary)", + "examples": [ + "//get commits older than the specified commit id\nconst query = WOQL.lib().previousCommits('m8vpxewh2aovfauebfkbzwmj4qwr5lb')\n\n//return the commits of a specific branch starting from the head\n//you can add the limit (how many results to return.) and the start point\n//if a timestamp is given, gets the commits before the specified timestamp\n//WOQL.lib().commits(branch='main',limit=0,start=0,timestamp=0)\n\nconst query = WOQL.lib().commits('main',10,2,1630683082.9278786)\n\n//return the branches list with the timestamp and commits id\nconst query = WOQL.lib().branches()" + ], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "summary": "WOQLQuery object", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "string", + "summary": "Generates explicitly a JSON-LD string literal from the input", + "examples": [ + "string(1)\n//returns { \"@type\": \"xsd:string\", \"@value\": \"1\" }" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "val", + "type": "string|boolean|number", + "summary": "any primitive literal type" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "- A JSON-LD string literal", + "type": "object" + } + }, + { + "@type": "Definition", + "name": "literal", + "summary": "Generates explicitly a JSON-LD string literal from the input", + "examples": [ + "literal(1, \"nonNegativeInteger\")\n//returns { \"@type\": \"xsd:nonNegativeInteger\", \"@value\": 1 }" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "val", + "type": "string", + "summary": "any literal type" + }, + { + "@type": "Parameter", + "name": "type", + "type": "string", + "summary": "an xsd or xdd type" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "- A JSON-LD literal", + "type": "object" + } + }, + { + "@type": "Definition", + "name": "date", + "summary": "Generates explicitly a JSON-LD literal date from the imput", + "examples": [ + "date(\"2022-10-02\")\n//returns { \"@type\": \"xsd:date\", \"@value\": \"2022-10-02\" }" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "date", + "type": "string", + "summary": "any date format string (YYYY-MM-DD)" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "- A JSON-LD literal date", + "type": "object" + } + }, + { + "@type": "Definition", + "name": "datetime", + "summary": "Generates explicitly a JSON-LD literal datetime from the imput", + "examples": [ + "datetime(\"2022-10-19T14:17:12Z\")\n//returns { \"@type\": \"xsd:dateTime\", \"@value\": \"2022-10-19T14:17:12Z\" }" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "datetime", + "type": "string", + "summary": "any datetime format string (YYYY-MM-DDThh-mm-ssZ)" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "- A JSON-LD literal datetime", + "type": "object" + } + }, + { + "@type": "Definition", + "name": "boolean", + "summary": "Generates explicitly a JSON-LD literal boolean from the input", + "examples": [ + "boolean(true)\n//returns { \"@type\": \"xsd:boolean\", \"@value\": true }" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "bool", + "type": "boolean", + "summary": "true | false" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "- A JSON-LD literal boolean", + "type": "object" + } + }, + { + "@type": "Definition", + "name": "iri", + "summary": "Explicitly sets a value to be an IRI - avoiding automatic type marshalling", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "val", + "type": "string", + "summary": "string which will be treated as an IRI" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "- A JSON-LD IRI value", + "type": "object" + } + }, + { + "@type": "Definition", + "name": "vars", + "summary": "Generates javascript variables for use as WOQL variables within a query", + "examples": [ + "const [a, b, c] = WOQL.vars(\"a\", \"b\", \"c\")\n//a, b, c are javascript variables which can be used as WOQL variables in subsequent queries" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "varNames", + "type": "string" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "an array of javascript variables which can be dereferenced using the\narray destructuring operation", + "type": "array." + } + }, + { + "@type": "Definition", + "name": "doc", + "summary": "Produces an encoded form of a document that can be used by a WOQL operation\nsuch as `WOQL.insert_document`.", + "examples": [ + "const doc = WOQL.doc({ \"@type\": \"Person\", name: \"Newperson\" })" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "object", + "type": "object", + "summary": "Document to encode" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "The encoded document", + "type": "object" + } + }, + { + "@type": "Definition", + "name": "client", + "summary": "Use instead to run your query woqlclient.query('myWOQLQuery')", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "client", + "type": "WOQLClient" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "WOQLClient" + } + }, + { + "@type": "Definition", + "name": "Vars", + "examples": [ + "const v = WOQL.Vars('var01', 'var02', 'var03');\ntriple(v.var01, v.var02, v.var03)" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "varNames", + "type": "string" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "object." + } + }, + { + "@type": "Definition", + "name": "emerge", + "summary": "query module\nallow you to use WOQL words as top level functions", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "auto_eval", + "type": "*" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "update_triple", + "summary": "Update a pattern matching rule for the triple (Subject, Predicate, oldObjValue) with the\nnew one (Subject, Predicate, newObjValue)", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subject", + "type": "string|Var", + "summary": "The IRI of a triple’s subject or a variable" + }, + { + "@type": "Parameter", + "name": "predicate", + "type": "string|Var", + "summary": "The IRI of a property or a variable" + }, + { + "@type": "Parameter", + "name": "newObjValue", + "type": "string|Var", + "summary": "The value to update or a literal" + }, + { + "@type": "Parameter", + "name": "oldObjValue", + "type": "string|Var", + "summary": "The old value of the object" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the a Update Triple Statement", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "update_quad", + "summary": "Update a pattern matching rule for the quad [S, P, O, G] (Subject, Predicate, Object, Graph)", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subject", + "type": "string|Var", + "summary": "The IRI of a triple’s subject or a variable" + }, + { + "@type": "Parameter", + "name": "predicate", + "type": "string|Var", + "summary": "The IRI of a property or a variable" + }, + { + "@type": "Parameter", + "name": "newObject", + "type": "string|Var", + "summary": "The value to update or a literal" + }, + { + "@type": "Parameter", + "name": "graphRef", + "type": "typedef.GraphRef", + "summary": "A valid graph resource identifier string" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the a Update Quad Statement", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "value", + "summary": "Creates a pattern matching rule for a triple [Subject, Predicate, Object]\nadd extra information about the type of the value object", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subject", + "type": "string|Var", + "summary": "The IRI of a triple’s subject or a variable" + }, + { + "@type": "Parameter", + "name": "predicate", + "type": "string|Var", + "summary": "The IRI of a property or a variable" + }, + { + "@type": "Parameter", + "name": "objValue", + "type": "string|number|boolean|Var", + "summary": "an specific value" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the a quad or a triple Statement", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "link", + "summary": "Creates a pattern matching rule for a triple [Subject, Predicate, Object]", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "subject", + "type": "string|Var", + "summary": "The IRI of a triple’s subject or a variable" + }, + { + "@type": "Parameter", + "name": "predicate", + "type": "string|Var", + "summary": "The IRI of a property or a variable" + }, + { + "@type": "Parameter", + "name": "object", + "type": "string|Var", + "summary": "The IRI of a node or a variable, or a literal" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the a quad or a triple Statement", + "type": "WOQLQuery" + } + }, + { + "@type": "Definition", + "name": "dot", + "summary": "Extract the value of a key in a bound document.", + "examples": [], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "document", + "type": "string|Var", + "summary": "Document which is being accessed." + }, + { + "@type": "Parameter", + "name": "field", + "type": "string|Var", + "summary": "The field from which the document which is being accessed." + }, + { + "@type": "Parameter", + "name": "value", + "type": "string|Var", + "summary": "The value for the document and field." + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A WOQLQuery which contains the a dot Statement", + "type": "WOQLQuery" + } + } + ] + }, + { + "@type": "Class", + "name": "WOQLClient", + "memberFunctions": [ + { + "@type": "Definition", + "name": "setApiKey", + "summary": "set the api key to access the cloud resources", + "examples": [], + "section": "Authorization", + "parameters": [ + { + "@type": "Parameter", + "name": "accessToken", + "type": "string" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "customHeaders", + "summary": "add extra headers to your request", + "examples": [], + "section": "Authorization", + "parameters": [ + { + "@type": "Parameter", + "name": "customHeaders", + "type": "object" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "object" + } + }, + { + "@type": "Definition", + "name": "copy", + "summary": "creates a copy of the client with identical internal state and context\nuseful if we want to change context for a particular API call without changing\nthe current client context", + "examples": [ + "let newClient = client.copy()" + ], + "section": "Utility", + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "summary": "new client object with identical state to original but\nwhich can be manipulated independently", + "type": "WOQLClient" + } + }, + { + "@type": "Definition", + "name": "server", + "summary": "Gets the current connected server url\nit can only be set creating a new WOQLCLient instance", + "examples": [], + "section": "Get or Change the current Params", + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "string" + } + }, + { + "@type": "Definition", + "name": "api", + "summary": "Retrieve the URL of the server’s API base that we are currently connected to", + "examples": [ + "let api_url = client.api()" + ], + "section": "Get or Change the current Params", + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "summary": "the URL of the TerminusDB server api endpoint we are connected\nto (typically server() + “api/”)", + "type": "string" + } + }, + { + "@type": "Definition", + "name": "organization", + "summary": "Gets/Sets the client’s internal organization context value, if you change the organization\nname the databases list will be set to empty", + "examples": [ + "client.organization(\"admin\")" + ], + "section": "Manage Organization", + "parameters": [ + { + "@type": "Parameter", + "name": "orgId", + "type": "string|boolean", + "summary": "the organization id to set the context to" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "string|boolean" + } + }, + { + "@type": "Definition", + "name": "hasDatabase", + "summary": "Checks if a database exists\n\nReturns true if a DB exists and false if it doesn't. Other results\nthrow an exception.", + "examples": [ + "async function executeIfDatabaseExists(f){\n const hasDB = await client.hasDatabase(\"admin\", \"testdb\")\n if (hasDB) {\n f()\n }\n}" + ], + "section": "Manage Triples", + "parameters": [ + { + "@type": "Parameter", + "name": "orgName", + "type": "string", + "summary": "the organization id to set the context to" + }, + { + "@type": "Parameter", + "name": "dbName", + "type": "string", + "summary": "the db name to set the context to" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "getDatabases", + "summary": "Gets the organization's databases list.\n\nIf no organization has been set up, the function throws an exception", + "examples": [ + "async function callGetDatabases(){\n const dbList = await client.getDatabases()\n console.log(dbList)\n}" + ], + "section": "Manage Organization", + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "databases", + "summary": "Set/Get the organization's databases list (id, label, comment) that the current\nuser has access to on the server.", + "examples": [ + "//to get the list of all organization's databases\nasync function callGetDatabases(){\n await client.getDatabases()\n console.log(client.databases())\n}" + ], + "section": "Manage Organization", + "parameters": [ + { + "@type": "Parameter", + "name": "dbList", + "type": "array", + "summary": "a list of databases the user has access to on the server, each having:" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "the organization's databases list", + "type": "array" + } + }, + { + "@type": "Definition", + "name": "user", + "summary": "Gets the current user object as returned by the connect capabilities response\nuser has fields: [id, name, notes, author]", + "examples": [], + "section": "Get or Change the current Params", + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "Object" + } + }, + { + "@type": "Definition", + "name": "userOrganization", + "examples": [], + "section": null, + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "summary": "the user organization name", + "type": "string" + } + }, + { + "@type": "Definition", + "name": "databaseInfo", + "summary": "Gets the database's details", + "examples": [], + "section": "Manage Organization", + "parameters": [ + { + "@type": "Parameter", + "name": "dbName", + "type": "string", + "summary": "the datbase name" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "the database description object", + "type": "object" + } + }, + { + "@type": "Definition", + "name": "db", + "summary": "Sets / Gets the current database", + "examples": [ + "client.db(\"mydb\")" + ], + "section": "Manage Triples", + "parameters": [ + { + "@type": "Parameter", + "name": "dbId", + "type": "string", + "summary": "the database id to set the context to" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "- the current database or false", + "type": "string|boolean" + } + }, + { + "@type": "Definition", + "name": "setSystemDb", + "summary": "Sets the internal client context to allow it to talk to the server’s internal system database", + "examples": [], + "section": "Get or Change the current Params", + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "repo", + "summary": "Gets / Sets the client’s internal repository context value (defaults to ‘local’)", + "examples": [ + "client.repo(\"origin\")" + ], + "section": "Get or Change the current Params", + "parameters": [ + { + "@type": "Parameter", + "name": "repoId", + "type": "typedef.RepoType|string", + "summary": "default value is local" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "the current repository id within the client context", + "type": "string" + } + }, + { + "@type": "Definition", + "name": "checkout", + "summary": "Gets/Sets the client’s internal branch context value (defaults to ‘main’)", + "examples": [], + "section": "Manage Branch", + "parameters": [ + { + "@type": "Parameter", + "name": "branchId", + "type": "string", + "summary": "the branch id to set the context to" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "the current branch id within the client context", + "type": "string" + } + }, + { + "@type": "Definition", + "name": "ref", + "summary": "Sets / gets the current ref pointer (pointer to a commit within a branch)\nReference ID or Commit ID are unique hashes that are created whenever a new commit is recorded", + "examples": [ + "client.ref(\"mkz98k2h3j8cqjwi3wxxzuyn7cr6cw7\")" + ], + "section": "Manage Branch", + "parameters": [ + { + "@type": "Parameter", + "name": "commitId", + "type": "string", + "summary": "the reference ID or commit ID" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "the current commit id within the client context", + "type": "string|boolean" + } + }, + { + "@type": "Definition", + "name": "localAuth", + "summary": "Sets/Gets set the database basic connection credential", + "examples": [ + "client.localAuth({user:\"admin\",\"key\":\"mykey\",\"type\":\"basic\"})" + ], + "section": "Authorization", + "parameters": [ + { + "@type": "Parameter", + "name": "newCredential", + "type": "typedef.CredentialObj" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "typedef.CredentialObj|boolean" + } + }, + { + "@type": "Definition", + "name": "remoteAuth", + "summary": "Sets/Gets the jwt token for authentication\nwe need this to connect 2 terminusdb server to each other for push, pull, clone actions", + "examples": [ + "client.remoteAuth({\"key\":\"dhfmnmjglkrelgkptohkn\",\"type\":\"jwt\"})" + ], + "section": "Authorization", + "parameters": [ + { + "@type": "Parameter", + "name": "newCredential", + "type": "typedef.CredentialObj" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "typedef.CredentialObj|boolean" + } + }, + { + "@type": "Definition", + "name": "author", + "summary": "Gets the string that will be written into the commit log for the current user", + "examples": [ + "client.author()" + ], + "section": "Get or Change the current Params", + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "summary": "the current user", + "type": "string" + } + }, + { + "@type": "Definition", + "name": "set", + "examples": [ + "sets several of the internal state values in a single call\n(similar to connect, but only sets internal client state, does not communicate with server)\nclient.set({key: \"mypass\", branch: \"dev\", repo: \"origin\"})" + ], + "section": "Get or Change the current Params", + "parameters": [ + { + "@type": "Parameter", + "name": "params", + "type": "typedef.ParamsObj", + "summary": "a object with connection params" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "resource", + "summary": "Generates a resource string for the required context\nof the current context for \"commits\" \"meta\" \"branch\" and \"ref\" special resources", + "examples": [ + "const branch_resource = client.resource(\"branch\")" + ], + "section": "Utility", + "parameters": [ + { + "@type": "Parameter", + "name": "resourceType", + "type": "typedef.ResourceType", + "summary": "the type of resource string that is required - one\nof “db”, “meta”, “repo”, “commits”, “branch”, “ref”" + }, + { + "@type": "Parameter", + "name": "resourceId", + "type": "string", + "summary": "can be used to specify a specific branch / ref - if not supplied\nthe current context will be used" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "a resource string for the desired context", + "type": "string" + } + }, + { + "@type": "Definition", + "name": "connect", + "summary": "You can call this to get the server info or override the start params\nconfiguration, this.connectionConfig.server will be used if present,\nor the promise will be rejected.", + "examples": [ + "client.connect()" + ], + "section": "Api Deprecated", + "parameters": [ + { + "@type": "Parameter", + "name": "params", + "type": "typedef.ParamsObj", + "summary": "TerminusDB Server connection parameters" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "the connection capabilities response object or an error object", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "createDatabase", + "summary": "Creates a new database in TerminusDB server", + "examples": [ + "//remember set schema:true if you need to add a schema graph\nclient.createDatabase(\"mydb\", {label: \"My Database\", comment: \"Testing\", schema: true})" + ], + "section": "Manage Database", + "parameters": [ + { + "@type": "Parameter", + "name": "dbId", + "type": "string", + "summary": "The id of the new database to be created" + }, + { + "@type": "Parameter", + "name": "dbDetails", + "type": "typedef.DbDetails", + "summary": "object containing details about the database to be created" + }, + { + "@type": "Parameter", + "name": "orgId", + "type": "string", + "summary": "optional organization id - if absent default local organization\nid is used" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "updateDatabase", + "summary": "Update a database in TerminusDB server", + "examples": [ + "client.updateDatabase({id: \"mydb\", label: \"My Database\", comment: \"Testing\"})" + ], + "section": "Manage Database", + "parameters": [ + { + "@type": "Parameter", + "name": "dbDoc", + "type": "typedef.DbDoc", + "summary": "object containing details about the database to be updated" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "deleteDatabase", + "summary": "Deletes a database from a TerminusDB server", + "examples": [ + "client.deleteDatabase(\"mydb\")" + ], + "section": "Manage Database", + "parameters": [ + { + "@type": "Parameter", + "name": "dbId", + "type": "string", + "summary": "The id of the database to be deleted" + }, + { + "@type": "Parameter", + "name": "orgId", + "type": "string", + "summary": "the id of the organization to which the database belongs\n(in desktop use, this will always be “admin”)" + }, + { + "@type": "Parameter", + "name": "force", + "type": "boolean" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "getTriples", + "summary": "Retrieve the contents of a graph within a TerminusDB as triples, encoded in\nthe turtle (ttl) format", + "examples": [ + "const turtle = await client.getTriples(\"schema\", \"alt\")" + ], + "section": "Manage Triples", + "parameters": [ + { + "@type": "Parameter", + "name": "graphType", + "type": "typedef.GraphType", + "summary": "type of graph to get triples from,\neither “instance” or “schema”" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object (with\nthe contents being a string representing a set of triples in turtle (ttl) format),\nor an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "updateTriples", + "summary": "Replace the contents of the specified graph with the passed triples encoded\nin the turtle (ttl) format", + "examples": [ + "client.updateTriples(\"schema\", \"alt\", turtle_string, \"dumping triples to graph alt\")" + ], + "section": "Manage Triples", + "parameters": [ + { + "@type": "Parameter", + "name": "graphType", + "type": "string", + "summary": "type of graph |instance|schema|inference|" + }, + { + "@type": "Parameter", + "name": "turtle", + "type": "string", + "summary": "string encoding triples in turtle (ttl) format" + }, + { + "@type": "Parameter", + "name": "commitMsg", + "type": "string", + "summary": "Textual message describing the reason for the update" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "insertTriples", + "summary": "Appends the passed turtle to the contents of a graph", + "examples": [], + "section": "Manage Triples", + "parameters": [ + { + "@type": "Parameter", + "name": "graphType", + "type": "string", + "summary": "type of graph |instance|schema|inference|" + }, + { + "@type": "Parameter", + "name": "turtle", + "type": "string", + "summary": "is a valid set of triples in turtle format (OWL)" + }, + { + "@type": "Parameter", + "name": "commitMsg", + "type": "string", + "summary": "Textual message describing the reason for the update" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "message", + "summary": "Sends a message to the server", + "examples": [], + "section": "Utility", + "parameters": [ + { + "@type": "Parameter", + "name": "message", + "type": "string", + "summary": "textual string" + }, + { + "@type": "Parameter", + "name": "pathname", + "type": "string", + "summary": "a server path to send the message to" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "action", + "summary": "Sends an action to the server", + "examples": [], + "section": "Utility", + "parameters": [ + { + "@type": "Parameter", + "name": "actionName", + "type": "string", + "summary": "structure of the action" + }, + { + "@type": "Parameter", + "name": "payload", + "type": "object", + "summary": "a request body call" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "info", + "summary": "Gets TerminusDB Server Information", + "examples": [ + "client.info()" + ], + "section": "Utility", + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "query", + "summary": "Executes a WOQL query on the specified database and returns the results", + "examples": [ + "const result = await client.query(WOQL.star())" + ], + "section": "Query the database", + "parameters": [ + { + "@type": "Parameter", + "name": "woql", + "type": "WOQLQuery", + "summary": "an instance of the WOQLQuery class" + }, + { + "@type": "Parameter", + "name": "commitMsg", + "type": "string", + "summary": "a message describing the reason for the change that will\nbe written into the commit log (only relevant if the query contains an update)" + }, + { + "@type": "Parameter", + "name": "allWitnesses", + "type": "boolean" + }, + { + "@type": "Parameter", + "name": "lastDataVersion", + "type": "string", + "summary": "the last data version tracking id." + }, + { + "@type": "Parameter", + "name": "getDataVersion", + "type": "boolean", + "summary": "If true the function will return object having result\nand dataVersion." + }, + { + "@type": "Parameter", + "name": "resources", + "type": "Array.", + "summary": "csv resources supplied as strings" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object or object having *result*\nand *dataVersion* object if ***getDataVersion*** parameter is true, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "branch", + "summary": "Creates a new branch with a TerminusDB database, starting from the current context of\nthe client (branch / ref)", + "examples": [ + "client.branch(\"dev\")" + ], + "section": "Manage Branch", + "parameters": [ + { + "@type": "Parameter", + "name": "newBranchId", + "type": "string", + "summary": "local identifier of the new branch the ID of the new branch\nto be created" + }, + { + "@type": "Parameter", + "name": "isEmpty", + "type": "boolean", + "summary": "if isEmpty is true it will create a empty branch." + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "squashBranch", + "summary": "Squash branch commits", + "examples": [], + "section": "Manage Branch", + "parameters": [ + { + "@type": "Parameter", + "name": "branchId", + "type": "string", + "summary": "local identifier of the new branch" + }, + { + "@type": "Parameter", + "name": "commitMsg", + "type": "string", + "summary": "Textual message describing the reason for the update" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "resetBranch", + "summary": "Reset branch to a commit id, Reference ID or Commit ID are unique hashes that are\ncreated whenever a new commit is recorded", + "examples": [], + "section": "Manage Branch", + "parameters": [ + { + "@type": "Parameter", + "name": "branchId", + "type": "string", + "summary": "local identifier of the new branch" + }, + { + "@type": "Parameter", + "name": "commitId", + "type": "string", + "summary": "Reference ID or Commit ID" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "optimizeBranch", + "summary": "Optimize db branch", + "examples": [], + "section": "Manage Branch", + "parameters": [ + { + "@type": "Parameter", + "name": "branchId", + "type": "string", + "summary": "local identifier of the new branch" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "deleteBranch", + "summary": "Deletes a branch from database", + "examples": [], + "section": "Manage Branch", + "parameters": [ + { + "@type": "Parameter", + "name": "branchId", + "type": "string", + "summary": "local identifier of the branch" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "pull", + "summary": "Pull changes from a branch on a remote database to a branch on a local database", + "examples": [ + "client.pull({remote: \"origin\", remote_branch: \"main\", message: \"Pulling from remote\"})" + ], + "section": "Collaboration Api", + "parameters": [ + { + "@type": "Parameter", + "name": "remoteSourceRepo", + "type": "typedef.RemoteRepoDetails", + "summary": "an object describing the source of the pull" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "fetch", + "summary": "Fetch updates to a remote database to a remote repository with the local database", + "examples": [], + "section": "Collaboration Api", + "parameters": [ + { + "@type": "Parameter", + "name": "remoteId", + "type": "string", + "summary": "if of the remote to fetch (eg: 'origin')" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "push", + "summary": "Push changes from a branch on a local database to a branch on a remote database", + "examples": [ + "client.push({remote: \"origin\", remote_branch: \"main\", message: \"Pulling from remote\"})" + ], + "section": "Collaboration Api", + "parameters": [ + { + "@type": "Parameter", + "name": "remoteTargetRepo", + "type": "typedef.RemoteRepoDetails", + "summary": "an object describing the target of the push\n{remote: \"origin\", \"remote_branch\": \"main\", \"author\": \"admin\", \"message\": \"message\"}" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "rebase", + "summary": "Merges the passed branch into the current one using the rebase operation", + "examples": [ + "//from the branch head\nclient.rebase({rebase_from: \"admin/db_name/local/branch/branch_name\", message:\n\"Merging from dev\")\n//or from a commit id\nclient.rebase({rebase_from: \"admin/db_name/local/commit/9w8hk3y6rb8tjdy961de3i536ntkqd8\",\nmessage: \"Merging from dev\")" + ], + "section": "Collaboration Api", + "parameters": [ + { + "@type": "Parameter", + "name": "rebaseSource", + "type": "object", + "summary": "json describing the source branch to be used as a base" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "reset", + "summary": "Reset the current branch HEAD to the specified commit path", + "examples": [], + "section": "Collaboration Api", + "parameters": [ + { + "@type": "Parameter", + "name": "commitPath", + "type": "string", + "summary": "The commit path to set the current branch to" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "clonedb", + "summary": "Clones a remote repo and creates a local copy", + "examples": [ + "client.clonedb({remote_url: \"https://my.terminusdb.com/myorg/mydb\", label \"Cloned DB\", comment: \"Cloned from mydb\"}, newid: \"mydb\")" + ], + "section": "Collaboration Api", + "parameters": [ + { + "@type": "Parameter", + "name": "cloneSource", + "type": "typedef.CloneSourceDetails", + "summary": "object describing the source branch\nto be used as a base" + }, + { + "@type": "Parameter", + "name": "newDbId", + "type": "string", + "summary": "id of the new cloned database on the local server" + }, + { + "@type": "Parameter", + "name": "orgId", + "type": "string", + "summary": "id of the local organization that the new cloned database\nwill be created in (in desktop mode this is always “admin”)" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "dispatch", + "summary": "Common request dispatch function", + "examples": [], + "section": "Utility", + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "generateCommitInfo", + "summary": "Generates the json structure for commit messages", + "examples": [], + "section": "Utility", + "parameters": [ + { + "@type": "Parameter", + "name": "msg", + "type": "string", + "summary": "textual string describing reason for the change" + }, + { + "@type": "Parameter", + "name": "author", + "type": "string", + "summary": "optional author id string - if absent current user id will be used" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "object" + } + }, + { + "@type": "Definition", + "name": "generateCommitDescriptor", + "summary": "Generates the json structure for commit descriptor", + "examples": [], + "section": "Utility", + "parameters": [ + { + "@type": "Parameter", + "name": "commitId", + "type": "string", + "summary": "a valid commit id o" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "prepareRevisionControlArgs", + "summary": "Adds an author string (from the user object returned by connect) to the commit message.", + "examples": [], + "section": "Utility", + "parameters": [ + { + "@type": "Parameter", + "name": "rc_args", + "type": "object" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "object|boolean" + } + }, + { + "@type": "Definition", + "name": "addDocument", + "summary": "to add a new document or a list of new documents into the instance or the schema graph.", + "examples": [ + "const json = [{ \"@type\" : \"Class\",\n \"@id\" : \"Coordinate\",\n \"@key\" : { '@type' : 'Hash',\n '@fields' : ['x','y'] },\n \"x\" : \"xsd:decimal\",\n \"y\" : \"xsd:decimal\" },\n { \"@type\" : \"Class\",\n \"@id\" : \"Country\",\n \"@key\" : { '@type' : 'Lexical',\n '@fields' : [name] },\n \"name\" : \"xsd:string\",\n \"perimeter\" : { \"@type\" : \"List\",\n \"@class\" : \"Coordinate\" } }]\nclient.addDocument(json,{\"graph_type\":\"schema\"},\"mydb\",\"add new schema documents\")\n\n//if we would like to override the entire schema\nconst json = [\n{\"@base\": \"terminusdb:///data/\",\n \"@schema\": \"terminusdb:///schema#\",\n \"@type\": \"@context\"\n },\n {\n \"@id\": \"Person\",\n \"@key\": {\n \"@type\": \"Random\"\n },\n \"@type\": \"Class\",\n \"name\": {\n \"@class\": \"xsd:string\",\n \"@type\": \"Optional\"\n }\n }]\n\n// client.addDocument(json,{\"graph_type\":\"schema\",\"full_replace:true\"},\n \"mydb\",\"update the all schema\");\n\n// Here we will pass true to show how to get dataVersion\n\nconst response = await client.addDocument(json, {\"graph_type\": \"schema\"},\n \"mydb\",\n \"add new schema\", '',\n true\n)\nconsole.log(response);\n\n // This will output:\n // {\n // result: [ ...... ],\n // dataVersion: 'branch:5fs681tlycnn6jh0ceiqcq4qs89pdfs'\n // }\n\n // Now we can use the data version we recieved as a response in previous\n // function call and used it is next function call as lastDataVersion\n\nconst response1 = await client.addDocument(json, {\"graph_type\": \"schema\"},\n \"mydb\",\n \"add new schema\", response.dataVersion,\n)" + ], + "section": "Manage Documents", + "parameters": [ + { + "@type": "Parameter", + "name": "json", + "type": "object" + }, + { + "@type": "Parameter", + "name": "params", + "type": "typedef.DocParamsPost", + "summary": "the post parameters {@link #typedef.DocParamsPost}" + }, + { + "@type": "Parameter", + "name": "dbId", + "type": "string", + "summary": "the dbid" + }, + { + "@type": "Parameter", + "name": "string", + "type": "message", + "summary": "the insert commit message" + }, + { + "@type": "Parameter", + "name": "lastDataVersion", + "type": "string", + "summary": "the last data version tracking id." + }, + { + "@type": "Parameter", + "name": "getDataVersion", + "type": "boolean", + "summary": "If true the function will return object having result\nand dataVersion." + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object or object having *result*\nand *dataVersion* object if ***getDataVersion*** parameter is true, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "queryDocument", + "summary": "Use {@link #getDocument} instead.", + "examples": [ + "const query = {\n \"type\": \"Person\",\n \"query\": { \"age\": 42 },\n }\nclient.queryDocument(query, {\"as_list\":true})\n\n\n// Here we will pass true to show how to get dataVersion\nconst query = {\n \"type\": \"Person\",\n \"query\": { \"age\": 42 },\n }\n\nconst response = await client.queryDocument(query, {\"as_list\": true}, '', '','',true);\nconsole.log(response);\n\n // This will output:\n // {\n // result: [\n // {\n // '@id': 'Person/052d60ffbd114bf5e7331b03f07fcb7',\n // '@type': 'Person',\n // age: 42,\n // name: 'John',\n // },\n // ],\n // dataVersion: 'branch:5fs681tlycnn6jh0ceiqcq4qs89pdfs'\n // }\n\n // Now we can use the data version we recieved as a response in previous\n // query and used it is next query as lastDataVersion\n const query = {\n \"type\": \"Person\",\n \"query\": { \"age\": 18 },\n }\n\n const response1 = await client.queryDocument(query, {\"as_list\": true}, '',\n '',\n response.dataVersion\n );" + ], + "section": "Api Deprecated", + "parameters": [ + { + "@type": "Parameter", + "name": "query", + "type": "object", + "summary": "the query template" + }, + { + "@type": "Parameter", + "name": "params", + "type": "typedef.DocParamsGet", + "summary": "the get parameters" + }, + { + "@type": "Parameter", + "name": "dbId", + "type": "string", + "summary": "the database id" + }, + { + "@type": "Parameter", + "name": "branch", + "type": "string", + "summary": "the database branch" + }, + { + "@type": "Parameter", + "name": "lastDataVersion", + "type": "string", + "summary": "the last data version tracking id." + }, + { + "@type": "Parameter", + "name": "getDataVersion", + "type": "boolean", + "summary": "If true the function will return object having result\nand dataVersion." + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object or object having *result*\nand *dataVersion* object if ***getDataVersion*** parameter is true, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "getDocument", + "examples": [ + "//return the schema graph as a json array\nclient.getDocument({\"graph_type\":\"schema\",\"as_list\":true}).then(result={\n console.log(result)\n})\n\n//retutn the Country class document from the schema graph\nclient.getDocument({\"graph_type\":\"schema\",\"as_list\":true,\"id\":\"Country\"}).then(result={\n console.log(result)\n})\n\n//pass a document query template to query the document interface\nconst queryTemplate = { \"name\": \"Ireland\"}\nclient.getDocument({\"as_list\":true, \"@type\":\"Country\"\n query:queryTemplate}).then(result=>{\n console.log(result)\n})\n\n\n// Here we will pass true to show how to get dataVersion\nconst response = await client.getDocument({\"graph_type\":\"schema\",\"as_list\":true},\n \"\",\n \"\",\n \"\",\n true\n)\nconsole.log(response);\n\n // This will output:\n // {\n // result: [ ...... ],\n // dataVersion: 'branch:5fs681tlycnn6jh0ceiqcq4qs89pdfs'\n // }\n\n // Now we can use the data version we recieved as a response in previous\n // function call and used it is next function call as lastDataVersion\n\nconst response1 = await client.getDocument({\"graph_type\":\"schema\",\"as_list\":true},\n \"\",\n \"\",\n response.dataVersion,\n)" + ], + "section": "Query the database", + "parameters": [ + { + "@type": "Parameter", + "name": "params", + "type": "typedef.DocParamsGet", + "summary": "the get parameters,\nyou can pass document query search template with the params" + }, + { + "@type": "Parameter", + "name": "dbId", + "type": "string", + "summary": "the database id" + }, + { + "@type": "Parameter", + "name": "branch", + "type": "string", + "summary": "the database branch" + }, + { + "@type": "Parameter", + "name": "lastDataVersion", + "type": "string", + "summary": "the last data version tracking id." + }, + { + "@type": "Parameter", + "name": "getDataVersion", + "type": "boolean", + "summary": "If true the function will return object having result\nand dataVersion." + }, + { + "@type": "Parameter", + "name": "query", + "type": "object", + "summary": "document query search template" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object or object having *result*\nand *dataVersion* object if ***getDataVersion*** parameter is true, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "updateDocument", + "examples": [ + "client.updateDocument(\n{\n \"@id\": \"Person\",\n \"@key\": {\n \"@type\": \"Random\",\n },\n \"@type\": \"Class\",\n label: \"xsd:string\",\n },\n{ graph_type: \"schema\" }\n);\n\n\n// Here we will pass true to show how to get dataVersion\n\n const response = await client.updateDocument(\n {\n \"@id\": \"Person\",\n \"@key\": {\n \"@type\": \"Random\",\n },\n \"@type\": \"Class\",\n label: \"xsd:string\",\n },\n { graph_type: \"schema\" },\n \"\",\n \"\",\n \"\",\n true\n );\nconsole.log(response);\n\n // This will output:\n // {\n // result: [ ...... ],\n // dataVersion: 'branch:5fs681tlycnn6jh0ceiqcq4qs89pdfs'\n // }\n\n // Now we can use the data version we recieved as a response in previous\n // function call and used it is next function call as lastDataVersion\n\nconst response1 = await client.updateDocument(\n {\n \"@id\": \"Person\",\n \"@key\": {\n \"@type\": \"Random\",\n },\n \"@type\": \"Class\",\n label: \"xsd:string\",\n },\n { graph_type: \"schema\" },\n \"\",\n \"\",\n response.dataVersion\n );\n\n // update a document and create the linked document together\n // we are update the document \"Person/Person01\"\n // and create a new document {\"@type\": \"Person\",\"name\": \"child01\"} at the same time\n const response1 = await client.updateDocument(\n {\n \"@id\": \"Person/Person01\",\n \"@type\": \"Person\",\n \"name\": \"Person01\"\n \"children\":[{\"@type\": \"Person\",\"name\": \"child01\"}]\n },{create:true})" + ], + "section": "Manage Documents", + "parameters": [ + { + "@type": "Parameter", + "name": "json", + "type": "object" + }, + { + "@type": "Parameter", + "name": "params", + "type": "typedef.DocParamsPut", + "summary": "the Put parameters {@link #typedef.DocParamsPut}" + }, + { + "@type": "Parameter", + "name": "dbId", + "type": "*", + "summary": "the database id" + }, + { + "@type": "Parameter", + "name": "message", + "type": "*", + "summary": "the update commit message" + }, + { + "@type": "Parameter", + "name": "lastDataVersion", + "type": "string", + "summary": "the last data version tracking id." + }, + { + "@type": "Parameter", + "name": "getDataVersion", + "type": "boolean", + "summary": "If true the function will return object having result\nand dataVersion." + }, + { + "@type": "Parameter", + "name": "compress", + "type": "boolean", + "summary": "If true, the function will create a new document if it doesn't exist." + }, + { + "@type": "Parameter", + "name": "create", + "type": "boolean", + "summary": "Perform an *upsert* which inserts if the document\nis not present (also works on nested documents)" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object or object having *result*\nand *dataVersion* object if ***getDataVersion*** parameter is true, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "deleteDocument", + "summary": "to delete the document", + "examples": [ + "client.deleteDocument({\"graph_type\":\"schema\",id:['Country','Coordinate']})\n\n\n// Here we will pass true to show how to get dataVersion\n\nconst response = await client.deleteDocument({\"graph_type\":\"schema\",id:['Country','Coordinate']},\n \"\",\n \"\",\n \"\",\n true\n)\nconsole.log(response);\n\n // This will output:\n // {\n // result: [ ...... ],\n // dataVersion: 'branch:5fs681tlycnn6jh0ceiqcq4qs89pdfs'\n // }\n\n // Now we can use the data version we recieved as a response in previous\n // function call and used it is next function call as lastDataVersion\n\nconst response1 = await client.deleteDocument({\"graph_type\":\"schema\",\n id:['Country','Coordinate']},\n \"\",\n \"\",\n response.dataVersion,\n)" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "params", + "type": "typedef.DocParamsDelete" + }, + { + "@type": "Parameter", + "name": "dbId", + "type": "string", + "summary": "the database id" + }, + { + "@type": "Parameter", + "name": "message", + "type": "string", + "summary": "the delete message" + }, + { + "@type": "Parameter", + "name": "lastDataVersion", + "type": "string", + "summary": "the last data version tracking id." + }, + { + "@type": "Parameter", + "name": "getDataVersion", + "type": "boolean", + "summary": "If true the function will return object having result\nand dataVersion." + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object or object having *result*\nand *dataVersion* object if ***getDataVersion*** parameter is true, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "getSchemaFrame", + "summary": "The purpose of this method is to quickly discover the supported fields of a particular type.", + "examples": [ + "client.getSchemaFrame(\"Country\")" + ], + "section": "Manage Documents", + "parameters": [ + { + "@type": "Parameter", + "name": "type", + "type": "string", + "summary": "If given, the type to get information for. If omitted, information\nfor all types is returned" + }, + { + "@type": "Parameter", + "name": "dbId", + "type": "string", + "summary": "the database id" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "getSchema", + "summary": "get the database schema in json format", + "examples": [ + "client.getSchema()" + ], + "section": "Manage Documents", + "parameters": [ + { + "@type": "Parameter", + "name": "dbId", + "type": "string", + "summary": "the database id" + }, + { + "@type": "Parameter", + "name": "branch", + "type": "string", + "summary": "specific a branch/collection" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "getClasses", + "summary": "get all the schema classes (documents,subdocuments,abstracts)", + "examples": [ + "client.getClasses()" + ], + "section": "Manage Documents", + "parameters": [ + { + "@type": "Parameter", + "name": "dbId", + "type": "string", + "summary": "the database id" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "getEnums", + "summary": "get all the Enum Objects", + "examples": [ + "client.getEnums()" + ], + "section": "Manage Documents", + "parameters": [ + { + "@type": "Parameter", + "name": "dbId", + "type": "string" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "getClassDocuments", + "summary": "get all the Document Classes (no abstract or subdocument)", + "examples": [ + "client.getClassDocuments()" + ], + "section": "Manage Documents", + "parameters": [ + { + "@type": "Parameter", + "name": "dbId", + "type": "string" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "getBranches", + "summary": "get the database collections list", + "examples": [ + "client.getBranches()" + ], + "section": "Manage Branch", + "parameters": [ + { + "@type": "Parameter", + "name": "dbId", + "type": "string", + "summary": "the database id" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "getCommitsLog", + "summary": "get the database collections list", + "examples": [ + "client.getCommitsLog(count=10)" + ], + "section": "Manage Branch", + "parameters": [ + { + "@type": "Parameter", + "name": "start", + "type": "number", + "summary": "where to start printing the commit\n information in the log (starting from the head of the current branch)" + }, + { + "@type": "Parameter", + "name": "count", + "type": "number", + "summary": "The number of total commit log records to return" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "getPrefixes", + "summary": "get the database prefixes object", + "examples": [ + "client.getPrefixes()\n//return object example\n{\n'@base': 'terminusdb:///data/',\n'@schema': 'terminusdb:///schema#',\n'@type': 'Context'}" + ], + "section": "Manage Documents", + "parameters": [ + { + "@type": "Parameter", + "name": "dbId", + "type": "string", + "summary": "the database id" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "getUserOrganizations", + "summary": "Get the list of the user's organizations and the database related", + "examples": [ + "async funtion callGetUserOrganizations(){\n await getUserOrganizations()\n console.log(client.userOrganizations())\n}" + ], + "section": "Manage Organization", + "parameters": [], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "userOrganizations", + "summary": "Get/Set the list of the user's organizations (id, organization, label, comment).", + "examples": [ + "async funtion callGetUserOrganizations(){\n await client.getUserOrganizations()\n console.log(client.userOrganizations())\n}" + ], + "section": "Manage Organization", + "parameters": [ + { + "@type": "Parameter", + "name": "orgList", + "type": "array", + "summary": "a list of user's Organization" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "the user Organizations list", + "type": "array" + } + }, + { + "@type": "Definition", + "name": "patch", + "summary": "Apply a patch object to another object", + "examples": [ + "client.patch(\n { \"@id\" : \"Person/Jane\", \"@type\" : \"Person\", \"name\" : \"Jane\"},\n { \"name\" : { \"@op\" : \"ValueSwap\", \"@before\" : \"Jane\", \"@after\": \"Janine\" }}\n ).then(patchResult=>{\n console.log(patchResult)\n})\n//result example\n//{ \"@id\" : \"Person/Jane\", \"@type\" : \"Person\", \"name\" : \"Jannet\"}" + ], + "section": "Collaboration Api", + "parameters": [ + { + "@type": "Parameter", + "name": "before", + "type": "object", + "summary": "The current state of JSON document" + }, + { + "@type": "Parameter", + "name": "patch", + "type": "object", + "summary": "The patch object" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "patchResource", + "summary": "Apply a patch object to the current resource", + "examples": [ + "const patch = [\n {\n \"@id\": \"Obj/id1\",\n \"name\": {\n \"@op\": \"SwapValue\",\n \"@before\": \"foo\",\n \"@after\": \"bar\"\n }\n },\n {\n \"@id\": \"Obj/id2\",\n \"name\": {\n \"@op\": \"SwapValue\",\n \"@before\": \"foo\",\n \"@after\": \"bar\"\n }\n }\n]\nclient.db(\"mydb\")\nclient.checkout(\"mybranch\")\nclient.patchResource(patch,\"apply patch to mybranch\").then(patchResult=>{\n console.log(patchResult)\n})\n// result example\n// [\"Obj/id1\",\n// \"Obj/id2\"]\n// or conflict error 409\n// {\n// \"@type\": \"api:PatchError\",\n// \"api:status\": \"api:conflict\",\n// \"api:witnesses\": [\n// {\n// \"@op\": \"InsertConflict\",\n// \"@id_already_exists\": \"Person/Jane\"\n// }\n//]\n//}" + ], + "section": "Collaboration Api", + "parameters": [ + { + "@type": "Parameter", + "name": "patch", + "type": "array", + "summary": "The patch object" + }, + { + "@type": "Parameter", + "name": "message", + "type": "string", + "summary": "The commit message" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "getJSONDiff", + "summary": "Get the patch of difference between two documents.", + "examples": [ + "client.getJSONDiff(\n { \"@id\": \"Person/Jane\", \"@type\": \"Person\", name: \"Jane\" },\n { \"@id\": \"Person/Jane\", \"@type\": \"Person\", name: \"Janine\" }\n ).then(diffResult=>{\n console.log(diffResult)\n})\n//result example\n//{'@id': 'Person/Jane',\n// name: { '@after': 'Janine', '@before': 'Jane', '@op': 'SwapValue' }}" + ], + "section": "Collaboration Api", + "parameters": [ + { + "@type": "Parameter", + "name": "before", + "type": "object", + "summary": "The current state of JSON document" + }, + { + "@type": "Parameter", + "name": "after", + "type": "object", + "summary": "The updated state of JSON document" + }, + { + "@type": "Parameter", + "name": "options", + "type": "object", + "summary": "{keep:{}} Options to send to the diff endpoint.\nThe diff api outputs the changes between the input,\nin options you can list the properties that you would like to see in the diff result in any case." + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "getVersionObjectDiff", + "summary": "Get the patch of difference between two documents.", + "examples": [ + "const jsonObj = { \"@id\": \"Person/Jane\", \"@type\": \"Person\", name: \"Janine\" }\nclient.getVersionObjectDiff(\"main\",jsonObj\n \"Person/Jane\").then(diffResp=>{\n console.log(diffResp)\n})" + ], + "section": "Collaboration Api", + "parameters": [ + { + "@type": "Parameter", + "name": "dataVersion", + "type": "string", + "summary": "The version from which to compare the object" + }, + { + "@type": "Parameter", + "name": "jsonObject", + "type": "object", + "summary": "The updated state of JSON document" + }, + { + "@type": "Parameter", + "name": "id", + "type": "string", + "summary": "The document id to be diffed" + }, + { + "@type": "Parameter", + "name": "options", + "type": "object", + "summary": "{keep:{}} Options to send to the diff endpoint\nthe diff api outputs the changes between the input,\nbut you can list the properties that you would like to see in the diff result in any case." + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "getVersionDiff", + "summary": "Get the patch of difference between branches or commits.", + "examples": [ + "//This is to view all the changes between two commits\nconst beforeCommit = \"a73ssscfx0kke7z76083cgswszdxy6l\"\nconst afterCommit = \"73rqpooz65kbsheuno5dsayh71x7wf4\"\n\nclient.getVersionDiff( beforeCommit, afterCommit).then(diffResult=>{\n console.log(diffResult)\n})\n\n//This is to view the changes between two commits but only for the given document\nclient.getVersionDiff( beforeCommit, afterCommit, \"Person/Tom\").then(diffResult=>{\n console.log(diffResult)\n})\n\n//This is to view the changes between a branch (head) and a commit for the given document\nclient.getVersionDiff(\"main\", afterCommit, \"Person/Tom\" ).then(diffResult=>{\n console.log(diffResult)\n})\n\n//This is to view the changes between two branches with the keep options\nconst options = {\"keep\":{\"@id\":true, \"name\": true}, start:0, count:10}\nclient.getVersionDiff(\"main\",\"mybranch\",options).then(diffResult=>{\n console.log(diffResult)\n})" + ], + "section": "Collaboration Api", + "parameters": [ + { + "@type": "Parameter", + "name": "beforeVersion", + "type": "string", + "summary": "Before branch/commit to compare" + }, + { + "@type": "Parameter", + "name": "afterVersion", + "type": "string", + "summary": "After branch/commit to compare" + }, + { + "@type": "Parameter", + "name": "id", + "type": "string", + "summary": "The document id to be diffed,\nif it is omitted all the documents will be compared" + }, + { + "@type": "Parameter", + "name": "options", + "type": "typedef.DiffObject", + "summary": "{keep:{},count:10,start:0}\nOptions to send to the diff endpoint.\nThe diff api outputs the changes between the input (branches or commits),\nin options you can list the properties that you would like to see in the diff result in any case." + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + }, + { + "@type": "Definition", + "name": "apply", + "summary": "Diff two different commits and apply changes on the current branch/commit.\nIf you would like to change branch or commit before apply use client.checkout(\"branchName\")", + "examples": [ + "client.checkout(\"mybranch\")\nclient.apply(\"mybranch\",\"mybranch_new\",\"merge main\").then(result=>{\n console.log(result)\n})" + ], + "section": "Collaboration Api", + "parameters": [ + { + "@type": "Parameter", + "name": "beforeVersion", + "type": "string", + "summary": "Before branch/commit to compare" + }, + { + "@type": "Parameter", + "name": "afterVersion", + "type": "string", + "summary": "After branch/commit to compare" + }, + { + "@type": "Parameter", + "name": "message", + "type": "string", + "summary": "apply commit message" + }, + { + "@type": "Parameter", + "name": "matchFinalState", + "type": "boolean", + "summary": "the default value is false" + }, + { + "@type": "Parameter", + "name": "options", + "type": "object", + "summary": "{keep:{}} Options to send to the apply endpoint" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "getDocumentHistory", + "summary": "Get the document's history for a specific database or branch", + "examples": [ + "//this will return the last 5 commits for the Person/Anna document\nclient.checkout(\"mybranch\")\nclient.docHistory(\"Person/Anna\",{start:0,count:5}).then(result=>{\n console.log(result)\n})\n//this will return the last and the first commit for the Person/Anna document\nclient.docHistory(\"Person/Anna\",{updated:true,created:true}).then(result=>{\n console.log(result)\n})" + ], + "section": null, + "parameters": [ + { + "@type": "Parameter", + "name": "id", + "type": "string", + "summary": "id of document to report history of" + }, + { + "@type": "Parameter", + "name": "historyParams", + "type": "typedef.DocHistoryParams" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "type": "void" + } + }, + { + "@type": "Definition", + "name": "sendCustomRequest", + "summary": "Call a custom Api endpoit", + "examples": [ + "client.sendCustomRequest(\"GET\", \"http://localhost:3030/changes/\").then(result=>{\n console.log(result)\n})" + ], + "section": "Utility", + "parameters": [ + { + "@type": "Parameter", + "name": "requestType", + "type": "string", + "summary": "The current state of JSON document" + }, + { + "@type": "Parameter", + "name": "customRequestURL", + "type": "string", + "summary": "The patch object" + }, + { + "@type": "Parameter", + "name": "payload", + "type": "object", + "summary": "the request payload" + } + ], + "returns": { + "@type": "Returns", + "name": "", + "summary": "A promise that returns the call response object, or an Error if rejected.", + "type": "Promise" + } + } + ] + } + ] + } + ] +} diff --git a/schema/python.json b/schema/python.json new file mode 100644 index 0000000..547f4c8 --- /dev/null +++ b/schema/python.json @@ -0,0 +1 @@ +{"@type": "Application", "version": "10.2.6", "name": "terminusdb-client", "summary": "TerminusDB client library for accessing the Terminus DB API", "language": "Python", "license": "Apache 2.0", "modules": [{"@type": "Module", "name": "terminusdb_client", "classes": [{"@type": "Class", "name": "Client", "summary": "Client for TerminusDB server.", "memberVariables": [{"@type": "Parameter", "type": "str", "name": "server_url", "summary": "URL of the server that this client connected."}, {"@type": "Parameter", "type": "str", "name": "api", "summary": "API endpoint for this client."}, {"@type": "Parameter", "type": "str", "name": "team", "summary": "Team that this client is using. \"admin\" for local dbs."}, {"@type": "Parameter", "type": "str", "name": "db", "summary": "Database that this client is connected to."}, {"@type": "Parameter", "type": "str", "name": "user", "summary": "TerminiusDB user that this client is using. \"admin\" for local dbs."}, {"@type": "Parameter", "type": "str", "name": "branch", "summary": "Branch of the database that this client is connected to. Default to \"main\"."}, {"@type": "Parameter", "type": "str, None", "name": "ref", "summary": "Ref setting for the client. Default to None."}, {"@type": "Parameter", "type": "str", "name": "repo", "summary": "Repo identifier of the database that this client is connected to. Default to \"local\"."}], "memberFunctions": [{"@type": "Definition", "name": "__init__", "parameters": [{"@type": "Parameter", "type": "str", "name": "server_url", "summary": "URL of the server that this client will connect to."}, {"@type": "Parameter", "type": "optional, str", "name": "user_agent", "summary": "User agent header when making requests. Defaults to terminusdb-client-python with the version appended."}, {"@type": "Parameter", "type": "", "name": "**kwargs", "summary": "Extra configuration options"}], "returns": {"@type": "Returns", "name": "", "type": "void"}, "examples": null, "summary": "The Client constructor."}, {"@type": "Definition", "name": "connect", "parameters": [{"@type": "Parameter", "type": "str", "name": "team", "summary": "Name of the team, default to be \"admin\""}, {"@type": "Parameter", "type": "optional, str", "name": "db", "summary": "Name of the database connected"}, {"@type": "Parameter", "type": "optional, dict", "name": "remote_auth", "summary": "Remote Auth setting"}, {"@type": "Parameter", "type": "optional, str", "name": "key", "summary": "API key for connecting, default to be \"root\""}, {"@type": "Parameter", "type": "optional, str", "name": "user", "summary": "Name of the user, default to be \"admin\""}, {"@type": "Parameter", "type": "bool", "name": "use_token", "summary": "Use token to connect. If both `jwt_token` and `api_token` is not provided (None), then it will use the ENV variable TERMINUSDB_ACCESS_TOKEN to connect as the API token"}, {"@type": "Parameter", "type": "optional, str", "name": "jwt_token", "summary": "The Bearer JWT token to connect. Default to be None."}, {"@type": "Parameter", "type": "optional, strs", "name": "api_token", "summary": "The API token to connect. Default to be None."}, {"@type": "Parameter", "type": "optional, str", "name": "branch", "summary": "Branch to be connected, default to be \"main\""}, {"@type": "Parameter", "type": "optional, str", "name": "ref", "summary": "Ref setting"}, {"@type": "Parameter", "type": "optional, str", "name": "repo", "summary": "Local or remote repo, default to be \"local\""}, {"@type": "Parameter", "type": "", "name": "**kwargs", "summary": "Extra configuration options."}], "returns": {"@type": "Returns", "name": "", "type": "void"}, "examples": [">>> client = Client(\"http://127.0.0.1:6363\")\n>>> client.connect(key=\"root\", team=\"admin\", user=\"admin\", db=\"example_db\")"], "summary": "Connect to a Terminus server at the given URI with an API key."}, {"@type": "Definition", "name": "close", "parameters": [], "returns": {"@type": "Returns", "name": "", "type": "void"}, "examples": null, "summary": "Undo connect and close the connection."}, {"@type": "Definition", "name": "_check_connection", "parameters": [], "returns": {"@type": "Returns", "name": "", "type": "void"}, "examples": null, "summary": "Raise connection InterfaceError if not connected\nDefaults to check if a db is connected"}, {"@type": "Definition", "name": "info", "parameters": [], "returns": {"@type": "Returns", "name": "", "type": "dict", "summary": "Dict with version information:\n```\n{\n \"@type\": \"api:InfoResponse\",\n \"api:info\": {\n \"authority\": \"anonymous\",\n \"storage\": {\n \"version\": \"1\"\n },\n \"terminusdb\": {\n \"git_hash\": \"53acb38f9aedeec6c524f5679965488788e6ccf5\",\n \"version\": \"10.1.5\"\n },\n \"terminusdb_store\": {\n \"version\": \"0.19.8\"\n }\n },\n \"api:status\": \"api:success\"\n}\n```"}, "examples": null, "summary": "Get info of a TerminusDB database server"}, {"@type": "Definition", "name": "ok", "parameters": [], "returns": {"@type": "Returns", "name": "", "type": "bool"}, "examples": null, "summary": "Check whether the TerminusDB server is still OK.\n Status is not OK when this function returns false\n or throws an exception (mostly ConnectTimeout)"}, {"@type": "Definition", "name": "log", "parameters": [], "returns": {"@type": "Returns", "name": "", "type": "list", "summary": "List of the following commit objects:\n```\n {\n \"@id\":\"InitialCommit/hpl18q42dbnab4vzq8me4bg1xn8p2a0\",\n \"@type\":\"InitialCommit\",\n \"author\":\"system\",\n \"identifier\":\"hpl18q42dbnab4vzq8me4bg1xn8p2a0\",\n \"message\":\"create initial schema\",\n \"schema\":\"layer_data:Layer_4234adfe377fa9563a17ad764ac37f5dcb14de13668ea725ef0748248229a91b\",\n \"timestamp\":1660919664.9129035\n }\n```"}, "examples": null, "summary": "Get commit history of a database\nParameters\n----------\nteam : str, optional\n The team from which the database is. Defaults to the class property.\ndb : str, optional\n The database. Defaults to the class property.\nstart : int, optional\n Commit index to start from. Defaults to 0.\ncount : int, optional\n Amount of commits to get. Defaults to -1 which gets all."}, {"@type": "Definition", "name": "get_commit_history", "parameters": [{"@type": "Parameter", "type": "int, optional", "name": "max_history", "summary": "maximum number of commit that would return, counting backwards from your current commit. Default is set to 500. It needs to be nop-negative, if input is 0 it will still give the last commit."}], "returns": {"@type": "Returns", "name": "", "type": "list"}, "examples": null, "summary": "Get the whole commit history.\nCommit history - Commit id, author of the commit, commit message and the commit time, in the current branch from the current commit, ordered backwards in time, will be returned in a dictionary in the follow format:\n```\n{ \"commit_id\":\n { \"author\": \"commit_author\",\n \"message\": \"commit_message\",\n \"timestamp: \"\n }\n}\n```"}, {"@type": "Definition", "name": "get_all_branches", "parameters": [], "returns": {"@type": "Returns", "name": "", "type": "void"}, "examples": null, "summary": "Get all the branches available in the database."}, {"@type": "Definition", "name": "rollback", "parameters": [], "returns": {"@type": "Returns", "name": "", "type": "void"}, "examples": null, "summary": "Curently not implementated. Please check back later."}, {"@type": "Definition", "name": "copy", "parameters": [], "returns": {"@type": "Returns", "name": "", "type": "Client", "summary": "The copied client instance."}, "examples": [">>> client = Client(\"http://127.0.0.1:6363/\")\n>>> clone = client.copy()\n>>> assert client is not clone"], "summary": "Create a deep copy of this client."}, {"@type": "Definition", "name": "set_db", "parameters": [{"@type": "Parameter", "type": "str", "name": "dbid", "summary": "Database identifer to set in the config."}, {"@type": "Parameter", "type": "str", "name": "team", "summary": "Team identifer to set in the config. If not passed in, it will use the current one."}], "returns": {"@type": "Returns", "name": "", "type": "str", "summary": "The current database identifier."}, "examples": [">>> client = Client(\"http://127.0.0.1:6363\")\n>>> client.set_db(\"database1\")\n'database1'"], "summary": "Set the connection to another database. This will reset the connection."}, {"@type": "Definition", "name": "_get_prefixes", "parameters": [], "returns": {"@type": "Returns", "name": "", "type": "void"}, "examples": null, "summary": "Get the prefixes for a given database"}, {"@type": "Definition", "name": "create_database", "parameters": [{"@type": "Parameter", "type": "str", "name": "dbid", "summary": "Unique identifier of the database."}, {"@type": "Parameter", "type": "str, optional", "name": "team", "summary": "ID of the Team in which to create the DB (defaults to 'admin')"}, {"@type": "Parameter", "type": "str, optional", "name": "label", "summary": "Database name."}, {"@type": "Parameter", "type": "str, optional", "name": "description", "summary": "Database description."}, {"@type": "Parameter", "type": "dict, optional", "name": "prefixes", "summary": "Optional dict containing ``\"@base\"`` and ``\"@schema\"`` keys.\n\n@base (str)\n IRI to use when ``doc:`` prefixes are expanded. Defaults to ``terminusdb:///data``.\n@schema (str)\n IRI to use when ``scm:`` prefixes are expanded. Defaults to ``terminusdb:///schema``."}, {"@type": "Parameter", "type": "bool", "name": "include_schema", "summary": "If ``True``, a main schema graph will be created, otherwise only a main instance graph will be created."}], "returns": {"@type": "Returns", "name": "", "type": "void"}, "examples": [">>> client = Client(\"http://127.0.0.1:6363/\")\n>>> client.create_database(\"someDB\", \"admin\", \"Database Label\", \"My Description\")"], "summary": "Create a TerminusDB database by posting\na terminus:Database document to the Terminus Server."}, {"@type": "Definition", "name": "delete_database", "parameters": [{"@type": "Parameter", "type": "str", "name": "dbid", "summary": "ID of the database to delete"}, {"@type": "Parameter", "type": "str, optional", "name": "team", "summary": "the team in which the database resides (defaults to \"admin\")"}, {"@type": "Parameter", "type": "bool", "name": "force", "summary": ""}], "returns": {"@type": "Returns", "name": "", "type": "void"}, "examples": [">>> client = Client(\"http://127.0.0.1:6363/\")\n>>> client.delete_database(\"\", \"\")"], "summary": "Delete a TerminusDB database."}, {"@type": "Definition", "name": "get_triples", "parameters": [{"@type": "Parameter", "type": "GraphType", "name": "graph_type", "summary": "Graph type, either GraphType.INSTANCE or GraphType.SCHEMA."}], "returns": {"@type": "Returns", "name": "", "type": "str"}, "examples": null, "summary": "Retrieves the contents of the specified graph as triples encoded in turtle format"}, {"@type": "Definition", "name": "update_triples", "parameters": [{"@type": "Parameter", "type": "GraphType", "name": "graph_type", "summary": "Graph type, either GraphType.INSTANCE or GraphType.SCHEMA."}, {"@type": "Parameter", "type": "", "name": "content", "summary": "Valid set of triples in Turtle or Trig format."}, {"@type": "Parameter", "type": "str", "name": "commit_msg", "summary": "Commit message."}], "returns": {"@type": "Returns", "name": "", "type": "void"}, "examples": null, "summary": "Updates the contents of the specified graph with the triples encoded in turtle format.\n Replaces the entire graph contents"}, {"@type": "Definition", "name": "insert_triples", "parameters": [{"@type": "Parameter", "type": "GraphType", "name": "graph_type", "summary": "Graph type, either GraphType.INSTANCE or GraphType.SCHEMA."}, {"@type": "Parameter", "type": "", "name": "content", "summary": "Valid set of triples in Turtle or Trig format."}, {"@type": "Parameter", "type": "str", "name": "commit_msg", "summary": "Commit message."}], "returns": {"@type": "Returns", "name": "", "type": "void"}, "examples": null, "summary": "Inserts into the specified graph with the triples encoded in turtle format."}, {"@type": "Definition", "name": "query_document", "parameters": [{"@type": "Parameter", "type": "dict", "name": "document_template", "summary": "Template for the document that is being retrived"}, {"@type": "Parameter", "type": "GraphType", "name": "graph_type", "summary": "Graph type, either GraphType.INSTANCE or GraphType.SCHEMA."}, {"@type": "Parameter", "type": "bool", "name": "as_list", "summary": "If the result returned as list rather than an iterator."}, {"@type": "Parameter", "type": "bool", "name": "get_data_version", "summary": "If the data version of the document(s) should be obtained. If True, the method return the result and the version as a tuple."}], "returns": {"@type": "Returns", "name": "", "type": "Iterable"}, "examples": null, "summary": "Retrieves all documents that match a given document template"}, {"@type": "Definition", "name": "get_document", "parameters": [{"@type": "Parameter", "type": "str", "name": "iri_id", "summary": "Iri id for the document that is to be retrieved"}, {"@type": "Parameter", "type": "GraphType", "name": "graph_type", "summary": "Graph type, either GraphType.INSTANCE or GraphType.SCHEMA."}, {"@type": "Parameter", "type": "bool", "name": "get_data_version", "summary": "If the data version of the document(s) should be obtained. If True, the method return the result and the version as a tuple."}, {"@type": "Parameter", "type": "", "name": "kwargs", "summary": "Additional boolean flags for retriving. Currently avaliable: \"prefixed\", \"minimized\", \"unfold\""}], "returns": {"@type": "Returns", "name": "", "type": "dict"}, "examples": null, "summary": "Retrieves the document of the iri_id"}, {"@type": "Definition", "name": "get_documents_by_type", "parameters": [{"@type": "Parameter", "type": "str", "name": "doc_type", "summary": "Specific type for the docuemnts that is retriving"}, {"@type": "Parameter", "type": "GraphType, optional", "name": "graph_type", "summary": "Graph type, either GraphType.INSTANCE or GraphType.SCHEMA."}, {"@type": "Parameter", "type": "int", "name": "skip", "summary": "The starting posiion of the returning results, default to be 0"}, {"@type": "Parameter", "type": "int or None", "name": "count", "summary": "The maximum number of returned result, if None (default) it will return all of the avalible result."}, {"@type": "Parameter", "type": "bool", "name": "as_list", "summary": "If the result returned as list rather than an iterator."}, {"@type": "Parameter", "type": "bool", "name": "get_data_version", "summary": "If the version of the document(s) should be obtained. If True, the method return the result and the version as a tuple."}, {"@type": "Parameter", "type": "", "name": "kwargs", "summary": "Additional boolean flags for retriving. Currently avaliable: \"prefixed\", \"unfold\""}], "returns": {"@type": "Returns", "name": "", "type": "iterable", "summary": "Stream of dictionaries"}, "examples": null, "summary": "Retrieves the documents by type"}, {"@type": "Definition", "name": "get_all_documents", "parameters": [{"@type": "Parameter", "type": "GraphType, optional", "name": "graph_type", "summary": "Graph type, either GraphType.INSTANCE or GraphType.SCHEMA."}, {"@type": "Parameter", "type": "int", "name": "skip", "summary": "The starting posiion of the returning results, default to be 0"}, {"@type": "Parameter", "type": "int or None", "name": "count", "summary": "The maximum number of returned result, if None (default) it will return all of the avalible result."}, {"@type": "Parameter", "type": "bool", "name": "as_list", "summary": "If the result returned as list rather than an iterator."}, {"@type": "Parameter", "type": "bool", "name": "get_data_version", "summary": "If the version of the document(s) should be obtained. If True, the method return the result and the version as a tuple."}, {"@type": "Parameter", "type": "", "name": "kwargs", "summary": "Additional boolean flags for retriving. Currently avaliable: \"prefixed\", \"unfold\""}], "returns": {"@type": "Returns", "name": "", "type": "iterable", "summary": "Stream of dictionaries"}, "examples": null, "summary": "Retrieves all avalibale the documents"}, {"@type": "Definition", "name": "get_existing_classes", "parameters": [], "returns": {"@type": "Returns", "name": "", "type": "void"}, "examples": null, "summary": "Get all the existing classes (only ids) in a database."}, {"@type": "Definition", "name": "insert_document", "parameters": [{"@type": "Parameter", "type": "dict or list of dict", "name": "document", "summary": "Document(s) to be inserted."}, {"@type": "Parameter", "type": "GraphType", "name": "graph_type", "summary": "Graph type, either GraphType.INSTANCE or GraphType.SCHEMA."}, {"@type": "Parameter", "type": "bool", "name": "full_replace", "summary": "If True then the whole graph will be replaced. WARNING: you should also supply the context object as the first element in the list of documents if using this option."}, {"@type": "Parameter", "type": "str", "name": "commit_msg", "summary": "Commit message."}, {"@type": "Parameter", "type": "str", "name": "last_data_version", "summary": "Last version before the update, used to check if the document has been changed unknowingly"}, {"@type": "Parameter", "type": "str or int", "name": "compress", "summary": "If it is an integer, size of the data larger than this (in bytes) will be compress with gzip in the request (assume encoding as UTF-8, 0 = always compress). If it is `never` it will never compress the data."}, {"@type": "Parameter", "type": "bool", "name": "raw_json", "summary": "Update as raw json"}], "returns": {"@type": "Returns", "name": "", "type": "list", "summary": "list of ids of the inseted docuemnts"}, "examples": null, "summary": "Inserts the specified document(s)"}, {"@type": "Definition", "name": "replace_document", "parameters": [{"@type": "Parameter", "type": "dict or list of dict", "name": "document", "summary": "Document(s) to be updated."}, {"@type": "Parameter", "type": "GraphType", "name": "graph_type", "summary": "Graph type, either GraphType.INSTANCE or GraphType.SCHEMA."}, {"@type": "Parameter", "type": "str", "name": "commit_msg", "summary": "Commit message."}, {"@type": "Parameter", "type": "str", "name": "last_data_version", "summary": "Last version before the update, used to check if the document has been changed unknowingly"}, {"@type": "Parameter", "type": "str or int", "name": "compress", "summary": "If it is an integer, size of the data larger than this (in bytes) will be compress with gzip in the request (assume encoding as UTF-8, 0 = always compress). If it is `never` it will never compress the data."}, {"@type": "Parameter", "type": "bool", "name": "create", "summary": "Create the document if it does not yet exist."}, {"@type": "Parameter", "type": "bool", "name": "raw_json", "summary": "Update as raw json"}], "returns": {"@type": "Returns", "name": "", "type": "void"}, "examples": null, "summary": "Updates the specified document(s)"}, {"@type": "Definition", "name": "update_document", "parameters": [{"@type": "Parameter", "type": "dict or list of dict", "name": "document", "summary": "Document(s) to be updated."}, {"@type": "Parameter", "type": "GraphType", "name": "graph_type", "summary": "Graph type, either GraphType.INSTANCE or GraphType.SCHEMA."}, {"@type": "Parameter", "type": "str", "name": "commit_msg", "summary": "Commit message."}, {"@type": "Parameter", "type": "str", "name": "last_data_version", "summary": "Last version before the update, used to check if the document has been changed unknowingly"}, {"@type": "Parameter", "type": "str or int", "name": "compress", "summary": "If it is an integer, size of the data larger than this (in bytes) will be compress with gzip in the request (assume encoding as UTF-8, 0 = always compress). If it is `never` it will never compress the data."}], "returns": {"@type": "Returns", "name": "", "type": "void"}, "examples": null, "summary": "Updates the specified document(s). Add the document if not existed."}, {"@type": "Definition", "name": "delete_document", "parameters": [{"@type": "Parameter", "type": "str or list of str", "name": "document", "summary": "Document(s) (as dictionary or DocumentTemplate objects) or id(s) of document(s) to be updated."}, {"@type": "Parameter", "type": "GraphType", "name": "graph_type", "summary": "Graph type, either GraphType.INSTANCE or GraphType.SCHEMA."}, {"@type": "Parameter", "type": "str", "name": "commit_msg", "summary": "Commit message."}, {"@type": "Parameter", "type": "str", "name": "last_data_version", "summary": "Last version before the update, used to check if the document has been changed unknowingly"}], "returns": {"@type": "Returns", "name": "", "type": "void"}, "examples": null, "summary": "Delete the specified document(s)"}, {"@type": "Definition", "name": "has_doc", "parameters": [{"@type": "Parameter", "type": "str", "name": "doc_id", "summary": "Id of document to be checked."}, {"@type": "Parameter", "type": "GraphType", "name": "graph_type", "summary": "Graph type, either GraphType.INSTANCE or GraphType.SCHEMA."}], "returns": {"@type": "Returns", "name": "", "type": "Bool", "summary": "if the document exist"}, "examples": null, "summary": "Check if a certain document exist in a database"}, {"@type": "Definition", "name": "get_class_frame", "parameters": [{"@type": "Parameter", "type": "str", "name": "class_name", "summary": "Name of the class"}], "returns": {"@type": "Returns", "name": "", "type": "dict", "summary": "Dictionary containing information"}, "examples": null, "summary": "Get the frame of the class of class_name. Provide information about all the avaliable properties of that class."}, {"@type": "Definition", "name": "commit", "parameters": [], "returns": {"@type": "Returns", "name": "", "type": "void"}, "examples": null, "summary": "Not implementated: open transactions currently not suportted. Please check back later."}, {"@type": "Definition", "name": "query", "parameters": [{"@type": "Parameter", "type": "dict or WOQLQuery object", "name": "woql_query", "summary": "A woql query as an object or dict"}, {"@type": "Parameter", "type": "str", "name": "commit_mg", "summary": "A message that will be written to the commit log to describe the change"}, {"@type": "Parameter", "type": "bool", "name": "get_data_version", "summary": "If the data version of the query result(s) should be obtained. If True, the method return the result and the version as a tuple."}, {"@type": "Parameter", "type": "str", "name": "last_data_version", "summary": "Last version before the update, used to check if the document has been changed unknowingly"}, {"@type": "Parameter", "type": "**deprecated**", "name": "file_dict", "summary": "File dictionary to be associated with post name => filename, for multipart POST"}], "returns": {"@type": "Returns", "name": "", "type": "dict"}, "examples": [">>> Client(server=\"http://localhost:6363\").query(woql, \"updating graph\")"], "summary": "Updates the contents of the specified graph with the triples encoded in turtle format Replaces the entire graph contents"}, {"@type": "Definition", "name": "create_branch", "parameters": [{"@type": "Parameter", "type": "str", "name": "new_branch_id", "summary": "New branch identifier."}, {"@type": "Parameter", "type": "bool", "name": "empty", "summary": "Create an empty branch if true (no starting commit)"}], "returns": {"@type": "Returns", "name": "", "type": "void"}, "examples": null, "summary": "Create a branch starting from the current branch."}, {"@type": "Definition", "name": "delete_branch", "parameters": [{"@type": "Parameter", "type": "str", "name": "branch_id", "summary": "Branch to delete"}], "returns": {"@type": "Returns", "name": "", "type": "void"}, "examples": null, "summary": "Delete a branch"}, {"@type": "Definition", "name": "pull", "parameters": [{"@type": "Parameter", "type": "str", "name": "remote", "summary": "remote to pull from, default \"origin\""}, {"@type": "Parameter", "type": "str, optional", "name": "remote_branch", "summary": "remote branch to pull from, default to be your current barnch"}, {"@type": "Parameter", "type": "str, optional", "name": "message", "summary": "optional commit message"}, {"@type": "Parameter", "type": "str, optional", "name": "author", "summary": "option to overide the author of the operation"}], "returns": {"@type": "Returns", "name": "", "type": "dict"}, "examples": [">>> client = Client(\"http://127.0.0.1:6363/\")\n>>> client.pull()"], "summary": "Pull updates from a remote repository to the current database."}, {"@type": "Definition", "name": "fetch", "parameters": [{"@type": "Parameter", "type": "str", "name": "remote_id", "summary": "id of the remote"}], "returns": {"@type": "Returns", "name": "", "type": "void"}, "examples": null, "summary": "Fatch the brach from a remote"}, {"@type": "Definition", "name": "push", "parameters": [{"@type": "Parameter", "type": "str", "name": "remote", "summary": "remote to push to, default \"origin\""}, {"@type": "Parameter", "type": "str, optional", "name": "remote_branch", "summary": "remote branch to push to, default to be your current barnch"}, {"@type": "Parameter", "type": "str, optional", "name": "message", "summary": "optional commit message"}, {"@type": "Parameter", "type": "str, optional", "name": "author", "summary": "option to overide the author of the operation"}, {"@type": "Parameter", "type": "dict, optional", "name": "remote_auth", "summary": "optional remote authorization (uses client remote auth otherwise)"}], "returns": {"@type": "Returns", "name": "", "type": "dict"}, "examples": [">>> Client(server=\"http://localhost:6363\").push(remote=\"origin\", remote_branch = \"main\", author = \"admin\", message = \"commit message\"})"], "summary": "Push changes from a branch to a remote repo"}, {"@type": "Definition", "name": "rebase", "parameters": [{"@type": "Parameter", "type": "str, optional", "name": "branch", "summary": "the branch for the rebase"}, {"@type": "Parameter", "type": "str, optional", "name": "rebase_source", "summary": "the source branch for the rebase"}, {"@type": "Parameter", "type": "str, optional", "name": "message", "summary": "the commit message"}, {"@type": "Parameter", "type": "str, optional", "name": "author", "summary": "the commit author"}], "returns": {"@type": "Returns", "name": "", "type": "dict"}, "examples": [">>> client = Client(\"http://127.0.0.1:6363/\")\n>>> client.rebase(\"the_branch\")"], "summary": "Rebase the current branch onto the specified remote branch. Need to specify one of 'branch','commit' or the 'rebase_source'."}, {"@type": "Definition", "name": "reset", "parameters": [{"@type": "Parameter", "type": "string", "name": "commit", "summary": "Commit id or path to the commit (if use_path is True), for instance '234980523ffaf93' or 'admin/database/local/commit/234980523ffaf93'. If not provided, it will reset to the newest commit (useful when need to go back after a soft reset)."}, {"@type": "Parameter", "type": "bool", "name": "soft", "summary": "Flag indicating if the reset if soft, that is referencing to a previous commit instead of resetting to a previous commit in the backend and wipping newer commits."}, {"@type": "Parameter", "type": "bool", "name": "use_path", "summary": "Wheather or not the commit given is an id or path. Default using id and use_path is False."}], "returns": {"@type": "Returns", "name": "", "type": "void"}, "examples": [">>> client = Client(\"http://127.0.0.1:6363/\")\n>>> client.reset('234980523ffaf93')\n>>> client.reset('admin/database/local/commit/234980523ffaf93', use_path=True)"], "summary": "Reset the current branch HEAD to the specified commit path. If `soft` is not True, it will be a hard reset, meaning reset to that commit in the backend and newer commit will be wipped out. If `soft` is True, the client will only reference to that commit and can be reset to the newest commit when done."}, {"@type": "Definition", "name": "optimize", "parameters": [{"@type": "Parameter", "type": "string", "name": "path", "summary": "Path to optimize, for instance admin/database/_meta for the repo graph."}], "returns": {"@type": "Returns", "name": "", "type": "void"}, "examples": [">>> client = Client(\"http://127.0.0.1:6363/\")\n>>> client.optimize('admin/database') # optimise database branch (here main)\n>>> client.optimize('admin/database/_meta') # optimise the repository graph (actually creates a squashed flat layer)\n>>> client.optimize('admin/database/local/_commits') # commit graph is optimised"], "summary": "Optimize the specified path."}, {"@type": "Definition", "name": "squash", "parameters": [{"@type": "Parameter", "type": "string", "name": "message", "summary": "Message for the newly created squash commit"}, {"@type": "Parameter", "type": "string", "name": "author", "summary": "Author of the commit"}, {"@type": "Parameter", "type": "bool", "name": "reset", "summary": "Perform reset after squash"}], "returns": {"@type": "Returns", "name": "", "type": "str", "summary": "commit id to be reset"}, "examples": [">>> client = Client(\"http://127.0.0.1:6363/\")\n>>> client.connect(user=\"admin\", key=\"root\", team=\"admin\", db=\"some_db\")\n>>> client.squash('This is a squash commit message!')"], "summary": "Squash the current branch HEAD into a commit"}, {"@type": "Definition", "name": "apply", "parameters": [{"@type": "Parameter", "type": "string", "name": "before_version", "summary": "Before branch/commit to compare"}, {"@type": "Parameter", "type": "string", "name": "after_object", "summary": "After branch/commit to compare"}, {"@type": "Parameter", "type": "string", "name": "branch", "summary": "Branch to apply to. Optional."}], "returns": {"@type": "Returns", "name": "", "type": "void"}, "examples": null, "summary": "Diff two different commits and apply changes on branch"}, {"@type": "Definition", "name": "diff_object", "parameters": [{"@type": "Parameter", "type": "string", "name": "before_object", "summary": "Before object to compare"}, {"@type": "Parameter", "type": "string", "name": "after_object", "summary": "After object to compare"}], "returns": {"@type": "Returns", "name": "", "type": "void"}, "examples": null, "summary": "Diff two different objects."}, {"@type": "Definition", "name": "diff_version", "parameters": [{"@type": "Parameter", "type": "string", "name": "before_version", "summary": "Commit or branch of the before version to compare"}, {"@type": "Parameter", "type": "string", "name": "after_version", "summary": "Commit or branch of the after version to compare"}], "returns": {"@type": "Returns", "name": "", "type": "void"}, "examples": null, "summary": "Diff two different versions. Can either be a branch or a commit"}, {"@type": "Definition", "name": "diff", "parameters": [], "returns": {"@type": "Returns", "name": "", "type": "obj", "summary": "Patch object"}, "examples": [">>> client = Client(\"http://127.0.0.1:6363/\")\n>>> client.connect(user=\"admin\", key=\"root\", team=\"admin\", db=\"some_db\")\n>>> result = client.diff({ \"@id\" : \"Person/Jane\", \"@type\" : \"Person\", \"name\" : \"Jane\"}, { \"@id\" : \"Person/Jane\", \"@type\" : \"Person\", \"name\" : \"Janine\"})\n>>> result.to_json = '{ \"name\" : { \"@op\" : \"SwapValue\", \"@before\" : \"Jane\", \"@after\": \"Janine\" }}'"], "summary": "DEPRECATED"}, {"@type": "Definition", "name": "patch", "parameters": [{"@type": "Parameter", "type": "dict", "name": "before", "summary": "Object before to patch"}, {"@type": "Parameter", "type": "Patch", "name": "patch", "summary": "Patch object to apply to the dict"}], "returns": {"@type": "Returns", "name": "", "type": "dict", "summary": "After object"}, "examples": [">>> client = Client(\"http://127.0.0.1:6363/\")\n>>> client.connect(user=\"admin\", key=\"root\", team=\"admin\", db=\"some_db\")\n>>> patch_obj = Patch(json='{\"name\" : { \"@op\" : \"ValueSwap\", \"@before\" : \"Jane\", \"@after\": \"Janine\" }}')\n>>> result = client.patch({ \"@id\" : \"Person/Jane\", \"@type\" : Person\", \"name\" : \"Jane\"}, patch_obj)\n>>> print(result)\n'{ \"@id\" : \"Person/Jane\", \"@type\" : Person\", \"name\" : \"Janine\"}'"], "summary": "Apply the patch object to the before object and return an after object. Note that this change does not commit changes to the graph."}, {"@type": "Definition", "name": "patch_resource", "parameters": [], "returns": {"@type": "Returns", "name": "", "type": "dict", "summary": "After object"}, "examples": [">>> client = Client(\"http://127.0.0.1:6363/\")\n>>> client.connect(user=\"admin\", key=\"root\", team=\"admin\", db=\"some_db\")\n>>> patch_obj = Patch(json='{\"name\" : { \"@op\" : \"ValueSwap\", \"@before\" : \"Jane\", \"@after\": \"Janine\" }}')\n>>> result = client.patch_resource(patch_obj,branch=\"main\")\n>>> print(result)\n'[\"Person/Jane\"]'"], "summary": "Apply the patch object to the given resource"}, {"@type": "Definition", "name": "clonedb", "parameters": [{"@type": "Parameter", "type": "str", "name": "clone_source", "summary": "The source url of the repo to be cloned."}, {"@type": "Parameter", "type": "str", "name": "newid", "summary": "Identifier of the new repository to create."}, {"@type": "Parameter", "type": "str, optional", "name": "Description", "summary": "Optional description about the cloned database."}, {"@type": "Parameter", "type": "str, optional", "name": "remote_auth", "summary": "Optional remote authorization (uses client remote auth otherwise)"}], "returns": {"@type": "Returns", "name": "", "type": "void"}, "examples": [">>> client = Client(\"http://127.0.0.1:6363/\")\n>>> client.clonedb(\"http://terminusdb.com/some_user/test_db\", \"my_test_db\")"], "summary": "Clone a remote repository and create a local copy."}, {"@type": "Definition", "name": "_generate_commit", "parameters": [{"@type": "Parameter", "type": "str", "name": "msg", "summary": "Commit message."}, {"@type": "Parameter", "type": "str", "name": "author", "summary": "Commit author."}], "returns": {"@type": "Returns", "name": "", "type": "dict", "summary": "Formatted commit info."}, "examples": [">>> client = Client(\"http://127.0.0.1:6363/\")\n>>> client._generate_commit(\"\", \"\")\n{'author': '', 'message': ''}"], "summary": "Pack the specified commit info into a dict format expected by the server."}, {"@type": "Definition", "name": "create_organization", "parameters": [{"@type": "Parameter", "type": "str", "name": "org", "summary": "The id of the organization"}], "returns": {"@type": "Returns", "name": "", "type": "dict or None if failed"}, "examples": null, "summary": "Add a new organization"}, {"@type": "Definition", "name": "get_organization_users", "parameters": [{"@type": "Parameter", "type": "str", "name": "org", "summary": ""}], "returns": {"@type": "Returns", "name": "", "type": "dict or None if not found"}, "examples": null, "summary": "Returns a list of users in an organization."}, {"@type": "Definition", "name": "get_organization_user", "parameters": [{"@type": "Parameter", "type": "str", "name": "org", "summary": ""}, {"@type": "Parameter", "type": "str", "name": "username", "summary": ""}], "returns": {"@type": "Returns", "name": "", "type": "dict or None if not found"}, "examples": null, "summary": "Returns user info related to an organization."}, {"@type": "Definition", "name": "get_organization_user_databases", "parameters": [{"@type": "Parameter", "type": "str", "name": "org", "summary": ""}, {"@type": "Parameter", "type": "str", "name": "username", "summary": ""}], "returns": {"@type": "Returns", "name": "", "type": "dict or None if not found"}, "examples": null, "summary": "Returns the databases available to a user which are inside an organization"}, {"@type": "Definition", "name": "get_organizations", "parameters": [], "returns": {"@type": "Returns", "name": "", "type": "dict or None if not found"}, "examples": null, "summary": "Returns a list of organizations in the database."}, {"@type": "Definition", "name": "get_organization", "parameters": [{"@type": "Parameter", "type": "str", "name": "org", "summary": "The id of the organization"}], "returns": {"@type": "Returns", "name": "", "type": "dict or None if not found"}, "examples": null, "summary": "Returns a specific organization"}, {"@type": "Definition", "name": "delete_organization", "parameters": [{"@type": "Parameter", "type": "str", "name": "org", "summary": "The id of the organization"}], "returns": {"@type": "Returns", "name": "", "type": "dict or None if request failed"}, "examples": null, "summary": "Deletes a specific organization"}, {"@type": "Definition", "name": "change_capabilities", "parameters": [{"@type": "Parameter", "type": "dict", "name": "capability_change", "summary": "Dict for the capability change request.\n\nExample:\n{\n \"operation\": \"revoke\",\n \"scope\": \"UserDatabase/f5a0ef94469b32e1aee321678436c7dfd5a96d9c476672b3282ae89a45b5200e\",\n \"user\": \"User/admin\",\n \"roles\": [\n \"Role/consumer\",\n \"Role/admin\"\n ]\n}"}], "returns": {"@type": "Returns", "name": "", "type": "dict or None if request failed"}, "examples": null, "summary": "Change the capabilities of a certain user"}, {"@type": "Definition", "name": "add_role", "parameters": [{"@type": "Parameter", "type": "dict", "name": "role", "summary": "The role dict"}], "returns": {"@type": "Returns", "name": "", "type": "dict or None if failed"}, "examples": [">>> client = Client(\"http://127.0.0.1:6363\")\n>>> client.connect(key=\"root\", team=\"admin\", user=\"admin\", db=\"example_db\")\n>>> role = {\n \"name\": \"Grand Pubah\",\n \"action\": [\n \"branch\",\n \"class_frame\",\n \"clone\",\n \"commit_read_access\",\n \"commit_write_access\",\n \"create_database\",\n \"delete_database\",\n \"fetch\",\n \"instance_read_access\",\n \"instance_write_access\",\n \"manage_capabilities\",\n \"meta_read_access\",\n \"meta_write_access\",\n \"push\",\n \"rebase\",\n \"schema_read_access\",\n \"schema_write_access\"\n ]\n }\n>>> client.add_role(role)"], "summary": "Add a new role"}, {"@type": "Definition", "name": "change_role", "parameters": [{"@type": "Parameter", "type": "dict", "name": "role", "summary": "Role dict"}], "returns": {"@type": "Returns", "name": "", "type": "dict or None if failed"}, "examples": [">>> client = Client(\"http://127.0.0.1:6363\")\n>>> client.connect(key=\"root\", team=\"admin\", user=\"admin\", db=\"example_db\")\n>>> role = {\n \"name\": \"Grand Pubah\",\n \"action\": [\n \"branch\",\n \"class_frame\",\n \"clone\",\n \"commit_read_access\",\n \"commit_write_access\",\n \"create_database\",\n \"delete_database\",\n \"fetch\",\n \"instance_read_access\",\n \"instance_write_access\",\n \"manage_capabilities\",\n \"meta_read_access\",\n \"meta_write_access\",\n \"push\",\n \"rebase\",\n \"schema_read_access\",\n \"schema_write_access\"\n ]\n }\n>>> client.change_role(role)"], "summary": "Change role actions for a particular role"}, {"@type": "Definition", "name": "get_available_roles", "parameters": [], "returns": {"@type": "Returns", "name": "", "type": "dict or None if failed"}, "examples": null, "summary": "Get the available roles for the current authenticated user"}, {"@type": "Definition", "name": "add_user", "parameters": [{"@type": "Parameter", "type": "str", "name": "username", "summary": "The username of the user"}, {"@type": "Parameter", "type": "str", "name": "password", "summary": "The user's password"}], "returns": {"@type": "Returns", "name": "", "type": "dict or None if failed"}, "examples": null, "summary": "Add a new user"}, {"@type": "Definition", "name": "get_user", "parameters": [{"@type": "Parameter", "type": "str", "name": "username", "summary": "The username of the user"}], "returns": {"@type": "Returns", "name": "", "type": "dict or None if failed"}, "examples": null, "summary": "Get a user"}, {"@type": "Definition", "name": "get_users", "parameters": [], "returns": {"@type": "Returns", "name": "", "type": "dict or None if failed"}, "examples": null, "summary": "Get all users"}, {"@type": "Definition", "name": "delete_user", "parameters": [{"@type": "Parameter", "type": "str", "name": "username", "summary": "The username of the user"}], "returns": {"@type": "Returns", "name": "", "type": "dict or None if failed"}, "examples": null, "summary": "Delete a user"}, {"@type": "Definition", "name": "change_user_password", "parameters": [{"@type": "Parameter", "type": "str", "name": "username", "summary": "The username of the user"}, {"@type": "Parameter", "type": "str", "name": "password", "summary": "The new password"}], "returns": {"@type": "Returns", "name": "", "type": "dict or None if failed"}, "examples": null, "summary": "Change user's password"}, {"@type": "Definition", "name": "get_database", "parameters": [], "returns": {"@type": "Returns", "name": "", "type": "dict"}, "examples": null, "summary": "Returns metadata (id, organization, label, comment) about the requested database\nParameters\n----------\ndbid : str\n The id of the database\nteam : str\n The organization of the database (default self.team)"}, {"@type": "Definition", "name": "has_database", "parameters": [{"@type": "Parameter", "type": "str", "name": "dbid", "summary": "The id of the database"}, {"@type": "Parameter", "type": "str", "name": "team", "summary": "The organization of the database (default self.team)"}], "returns": {"@type": "Returns", "name": "", "type": "True or False if not found"}, "examples": null, "summary": "Check whether a database exists"}, {"@type": "Definition", "name": "get_databases", "parameters": [], "returns": {"@type": "Returns", "name": "", "type": "list of dicts"}, "examples": null, "summary": "Returns a list of database metadata records for all databases the user has access to"}, {"@type": "Definition", "name": "list_databases", "parameters": [], "returns": {"@type": "Returns", "name": "", "type": "list of dicts"}, "examples": null, "summary": "Returns a list of database ids for all databases the user has access to"}]}]}]} diff --git a/src/app/docs/access-control-with-javascript/page.md b/src/app/docs/access-control-with-javascript/page.md new file mode 100644 index 0000000..c1ebfc1 --- /dev/null +++ b/src/app/docs/access-control-with-javascript/page.md @@ -0,0 +1,1157 @@ +--- +title: Access Control Reference Guide +slug: js-access-control +seo: + title: Access Control Reference Guide + description: 'A driver to manage access control with the JS Client ' + og_image: >- + https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png +media: [] +--- + +**License**: Apache Version 2 + +## new AccessControl() + +AccessControl is a driver to work with the TerminusDB and TerminusCMS access control API. + +For credentials, you can use a JWT token, an API token or basic authentication with username and password. + +**Example** + +```javascript +//connect with the API token +//(to request a token create an account in https://terminusdb.com/) +const accessContol = new AccessControl("https://servername.com", +{organization:"my_team_name", +token:"dGVybWludXNkYjovLy9kYXRhL2tleXNfYXB........"}) +accessControl.getOrgUsers().then(result=>{ + console.log(result) +}) + +//connect with the jwt token this type of connection is only for the dashboard +//or for application integrate with our login workflow +const accessContol = new AccessControl("https://servername.com", +{organization:"my_team_name", +jwt:"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IkpXUjBIOXYyeTFORUd........"}) +accessControl.getOrgUsers().then(result=>{ + console.log(result) +}) + +//if the jwt is expired you can change it with +accessControl.setJwtToken("eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IkpXUjBIOXYy +eTFORUd.......") + +//connect with the base authentication this type of connection is only for the local installation +const accessContol = new AccessControl("http://localhost:6363", +{organization:"my_team_name", user:"admin" +key:"mykey"}) +accessControl.getOrgUsers().then(result=>{ + console.log(result) +}) +``` + +## getDefaultOrganization + +##### accessControl.getDefaultOrganization(params) ⇒ `string` | `undefined` + +Get a organization from parameters. + +**Returns**: `string` | `undefined` - - organization + +{% table %} + +- Param +- Type +- Description + +--- + +- params +- `object` +- The parameters + +{% /table %} + +## setJwtToken + +##### accessControl.setJwtToken(jwt) + +Sets the Jwt token for the object + +Param + +Type + +Description + +jwt + +`string` + +The jwt api token to use + +## setApiToken + +##### accessControl.setApiToken(atokenpi) + +Sets the API token for the object. Create a TerminusCMS account to [get your API token](/docs/how-to-connect-terminuscms/). + +Param + +Type + +Description + +atokenpi + +`string` + +The API token to use to connect with TerminusCMS + +## setApiKey + +##### accessControl.setApiKey(atokenpi) + +Sets the API token for the object, to request a token create an account in https://terminusdb.com/ + +Param + +Type + +Description + +atokenpi + +`string` + +The API token to use to connect with TerminusCMS + +## getAPIUrl + +##### accessControl.getAPIUrl(cloudAPIUrl) ⇒ `string` + +Get a API url from cloudAPIUrl + +**Returns**: `string` - apiUrl + +Param + +Type + +Description + +cloudAPIUrl + +`string` + +The base url for cloud + +## customHeaders + +##### accessControl.customHeaders(customHeaders) ⇒ `object` + +add extra headers to your request + +Param + +Type + +customHeaders + +`object` + +## getOrganization + +##### accessControl.getOrganization(organization) ⇒ `object` + +\-- TerminusDB API --- Get an organization from the TerminusDB API. + +**Returns**: `object` - - organization + +Param + +Type + +Description + +organization + +`string` + +The organization + +## getAllOrganizations + +##### accessControl.getAllOrganizations() ⇒ `Promise` + +\-- TerminusDB API --- This end point works in basic authentication, admin user Get list of organizations + +**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected. + +## createOrganization + +##### accessControl.createOrganization(orgName) ⇒ `Promise` + +\-- TerminusDB API --- This end point works in basic authentication, admin user Create an organization + +**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected. + +Param + +Type + +Description + +orgName + +`string` + +The organization name to create + +**Example** + +```javascript +accessControl.createOrganization("my_org_name").then(result=>{ + console.log(result) +}) +``` + +## deleteOrganization + +##### accessControl.deleteOrganization(orgName) ⇒ `Promise` + +\-- TerminusDB API --- Delete an Organization + +**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected. + +Param + +Type + +Description + +orgName + +`string` + +The organization name to delete + +**Example** + +```javascript +accessControl.createOrganization("my_org_name").then(result=>{ + console.log(result) +}) +``` + +## createRole + +##### accessControl.createRole(\[name\], \[actions\]) ⇒ `Promise` + +\--TerminusDB API --- basic authentication, admin user. Create a new role in the system database. + +**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected. + +Param + +Type + +Description + +\[name\] + +`string` + +The role name. + +\[actions\] + +`typedef.RolesActions` + +A list of actions + +**Example** + +```javascript +accessControl.createRole("Reader",[ACTIONS.INSTANCE_READ_ACCESS]).then(result=>{ + console.log(result) +}) +``` + +## deleteRole + +##### accessControl.deleteRole(\[name\]) ⇒ `Promise` + +\-- TerminusDB API --- basic Authentication, admin user. Delete role in the system database, (this api is enabled only in the local installation) + +**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected. + +Param + +Type + +Description + +\[name\] + +`string` + +The role name. + +**Example** + +```javascript +accessControl.deleteRole("Reader").then(result=>{ + console.log(result) +}) +``` + +## getAllUsers + +##### accessControl.getAllUsers() ⇒ `Promise` + +\-- TerminusDB API --- basic Authentication, admin user. Return the list of all the users (this api is enabled only in the local installation) + +**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected. +**Example** + +```javascript +accessControl.getAllUsers().then(result=>{ + console.log(result) +}) +``` + +## createUser + +##### accessControl.createUser(name, \[password\]) ⇒ `Promise` + +\-- TerminusDB API --- basic Authentication, admin user. Add the user into the system database + +**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected. + +Param + +Type + +Description + +name + +`string` + +the user name + +\[password\] + +`string` + +you need the password for basic authentication + +**Example** + +```javascript +accessControl.deleteUser(userId).then(result=>{ + console.log(result) +}) +``` + +## deleteUser + +##### accessControl.deleteUser(userId) ⇒ `Promise` + +\-- TerminusDB API --- basic Authentication, admin user. Remove the user from the system database. + +**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected. + +Param + +Type + +Description + +userId + +`string` + +the document user id + +**Example** + +```javascript +accessControl.deleteUser(userId).then(result=>{ + console.log(result) +}) +``` + +## manageCapability + +##### accessControl.manageCapability(userName, resourceName, rolesArr, operation, scopeType) ⇒ `Promise` + +\-- TerminusDB API --- Grant/Revoke Capability + +**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected. + +Param + +Type + +Description + +userName + +`string` + +the document user id + +resourceName + +`string` + +the name of a (database or team) + +rolesArr + +`array` + +the roles name list + +operation + +`typedef.CapabilityCommand` + +grant/revoke operation + +scopeType + +`typedef.ScopeType` + +the resource type (database or organization) + +**Example** + +```javascript +//we add an user to an organization and manage users' access +//the user myUser can access the Organization and all the database under the organization with "reader" Role +client.manageCapability(myUser,myteam,[reader],"grant","organization").then(result=>{ + console.log(result) +}) + +//the user myUser can access the database db__001 under the organization myteam +//with "writer" Role +client.manageCapability(myUser,myteam/db__001,[writer],"grant","database").then(result=>{ + consol.log(result) +}) +``` + +## getAccessRoles + +##### accessControl.getAccessRoles() ⇒ `Promise` + +\--TerminusCMS and TerminusDB API --- Get all the system database roles types. + +**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected. + +## getOrgUsers + +##### accessControl.getOrgUsers(\[orgName\]) ⇒ `Promise` + +\-- TerminusCMS and TerminusDB API -- Get all the organization's users and roles, + +**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected. + +Param + +Type + +Description + +\[orgName\] + +`string` + +The organization name. + +**Example** + +```javascript +accessControl.getOrgUsers().then(result=>{ + console.log(result) +}) + +//this function will return an array of capabilities with users and roles +//-- TerminusCMS -- response array example +//[{capability: "Capability/3ea26e1d698821c570afe9cb4fe81a3......" +// email: {@type: "xsd:string", @value: "user@terminusdb.com"} +// picture: {@type: "xsd:string",…} +// role: "Role/dataReader" +// scope: "Organization/my_org_name" +// user: "User/auth0%7C613f5dnndjdjkTTT"}] +// +// +// -- Local Installation -- response array example +//[{ "@id":"User/auth0%7C615462f8ab33f4006a6bee0c", +// "capability": [{ +// "@id":"Capability/c52af34b71f6f8916ac0115ecb5fe0e31248ead8b1e3d100852015...", +// "@type":"Capability", +// "role": [{ +// "@id":"Role/admin", +// "@type":"Role", +// "action": ["instance_read_access"], +// "name":"Admin Role" +// }], +// "scope":"Organization/@team"}]] +``` + +## getTeamUserRoles + +##### accessControl.getTeamUserRoles(\[userName\], \[orgName\]) ⇒ `Promise` + +\-- TerminusCMS and TerminusDB API -- Get the user roles for a given organization or the default organization, + +**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected. + +Param + +Type + +Description + +\[userName\] + +`string` + +The organization name. + +\[orgName\] + +`string` + +The organization name. + +**Example** + +```javascript +accessControl.getTeamUserRole("myUser").then(result=>{ + console.log(result) +}) + +//response object example +{ + "@id": "User/myUser", + "capability": [ + { + "@id":"Capability/server_access", + "@type":"Capability", + "role": [{ + "@id":"Role/reader", + "@type":"Role", + "action": [ + "instance_read_access", + ], + "name":"reader" + }], + "scope":"Organization/myteam" + } + ], + "name": "myUser" +} +``` + +## ifOrganizationExists + +##### accessControl.ifOrganizationExists(orgName) ⇒ `Promise` + +\-- TerminusCMS API --- Check if the organization exists. it is a Head call . IMPORTANT This does not work with the API-TOKEN. + +**Returns**: `Promise` - A promise that returns the call status object, 200: if the organization exists and 404: if the organization does not exist + +Param + +Type + +Description + +orgName + +`string` + +The organization name to check if exists. + +## createOrganizationRemote + +##### accessControl.createOrganizationRemote(orgName) ⇒ `Promise` + +\-- TerminusCMS API --- + +IMPORTANT This does not work with the API-TOKEN. Create an organization + +**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected. + +Param + +Type + +Description + +orgName + +`string` + +The organization name to create + +**Example** + +```javascript +accessControl.createOrganization("my_org_name").then(result=>{ + console.log(result) +}) +``` + +## getPendingOrgInvites + +##### accessControl.getPendingOrgInvites(\[orgName\]) ⇒ `Promise` + +\-- TerminusCMS API --- + +Get the pending invitations list. + +**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected. + +Param + +Type + +Description + +\[orgName\] + +`string` + +The organization name. + +**Example** + +```javascript +const invitationList = accessControl.getPendingOrgInvites().then(result=>{ + console.log(invitationList) + +}) +//this will return an array of invitations object like this +//[{@id: "Organization/my_team_name/invitations/Invitation/7ad0c9eb82b6175bcda9c0dfc2ac51161ef5ba +cb0988d992c4bce82b3fa5d25" +// @type: "Invitation" +// creation_date: "2021-10-22T11:13:28.762Z" +// email_to: "new_user@terminusdb.com" +// invited_by: "User/auth0%7C6162f8ab33567406a6bee0c" +// role: "Role/dataReader" +// status: "needs_invite"}] +``` + +## sendOrgInvite + +##### accessControl.sendOrgInvite(userEmail, role, \[note\], \[orgName\]) ⇒ `Promise` + +\-- TerminusCMS API --- + +Send a new invitation + +**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected. + +Param + +Type + +Description + +userEmail + +`string` + +The email of user. + +role + +`string` + +The role for user. (the document @id role like Role/collaborator) + +\[note\] + +`string` + +The note to send with the invitation. + +\[orgName\] + +`string` + +The organization name. + +**Example** + +```javascript +accessControl.sendOrgInvite("new_user@terminusdb.com","Role/admin", +"please join myteam").then(result=>{ + console.log(result) +}) +``` + +## getOrgInvite + +##### accessControl.getOrgInvite(inviteId, \[orgName\]) ⇒ `Promise` + +\-- TerminusCMS API --- Get the invitation info + +**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected. + +Param + +Type + +Description + +inviteId + +`string` + +The invite id to retrieve. + +\[orgName\] + +`string` + +The organization name. + +**Example** + +```javascript +const fullInviteId="Organization/my_team_name/invitations/Invitation/7ad0c9eb82b6175bcda9c0dfc +2ac51161ef5ba7cb0988d992c4bce82b3fa5d25" +accessControl.getOrgInvite(fullInviteId).then(result=>{ + console.log(result) +}) +``` + +## deleteOrgInvite + +##### accessControl.deleteOrgInvite(inviteId, \[orgName\]) ⇒ `Promise` + +\-- TerminusCMS API --- + +Delete an invitation + +**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected. + +Param + +Type + +Description + +inviteId + +`string` + +The invite id to delete. + +\[orgName\] + +`string` + +The organization name. + +**Example** + +```javascript +const fullInviteId="Organization/my_team_name/invitations/Invitation/7ad0c9eb82b6175bcda9 +c0dfc2ac51161ef5ba7cb0988d992c4bce82b3fa5d25" +accessControl.deleteOrgInvite(fullInviteId).then(result=>{ + console.log(result) +}) +``` + +## updateOrgInviteStatus + +##### accessControl.updateOrgInviteStatus(inviteId, accepted, \[orgName\]) ⇒ `Promise` + +\-- TerminusCMS API --- + +Accept /Reject invitation. if the invitation has been accepted we add the current user to the organization. + +The only user that can accept this invitation is the user registered with the invitation email, we indentify the user with the JWT token + +**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected. + +Param + +Type + +Description + +inviteId + +`string` + +The invite id to updated. + +accepted + +`boolean` + +The status of the invitation. + +\[orgName\] + +`string` + +The organization name. + +**Example** + +```javascript +const fullInviteId="Organization/my_team_name/invitations/Invitation/7ad0c9eb82b6175bcda9 +c0dfc2ac51161ef5ba7cb0988d992c4bce82b3fa5d25" +accessControl.updateOrgInviteStatus(fullInviteId,true).then(result=>{ + console.log(result) +}) +``` + +## getTeamUserRole + +##### accessControl.getTeamUserRole(\[orgName\]) ⇒ `Promise` + +\-- TerminusCMS API --- + +Get the user role for a given organization or the default organization The user is identified by the jwt or the access token + +**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected. + +Param + +Type + +Description + +\[orgName\] + +`string` + +The organization name. + +**Example** + +```javascript +accessControl.getTeamUserRole().then(result=>{ + console.log(result) +}) + +//response object example +{"userRole":"Role/admin"} +``` + +## removeUserFromOrg + +##### accessControl.removeUserFromOrg(userId, \[orgName\]) ⇒ `Promise` + +\-- TerminusCMS API -- Remove an user from an organization, only an admin user can remove an user from an organization + +**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected. + +Param + +Type + +Description + +userId + +`string` + +The id of the user to be removed. (this is the document user's @id) + +\[orgName\] + +`string` + +The organization name in which the user is to be removed. + +**Example** + +```javascript +accessControl.removeUserFromOrg("User/auth0%7C613f5dnndjdjkTTT","my_org_name").then(result=>{ + console.log(result) +}) +``` + +## getDatabaseRolesOfUser + +##### accessControl.getDatabaseRolesOfUser(userId, \[orgName\]) ⇒ `Promise` + +\-- TerminusCMS API -- + +Get the user's role for every databases under the organization + +**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected. + +Param + +Type + +Description + +userId + +`string` + +The user's id. + +\[orgName\] + +`string` + +The organization name. + +**Example** + +```javascript +accessControl.getDatabaseRolesOfUser('User/auth0%7C61790e366377Yu6596a').then(result=>{ + console.log(result) +}) + +//this is a capabilities list of databases and roles +//[ {capability: "Capability/b395e8523d509dec6b33aefc9baed3b2e2bfadbd4c79d4ff9b20dce2b14e2edc" +//if there is an id we have a user specific capabality for this database + // name: {@type: "xsd:string", @value: "profiles_test"} + // role: "Role/dataUpdater" + // scope: "UserDatabase/7ebdfae5a02bc7e8f6d79sjjjsa4e179b1df9d4576a3b1d2e5ff3b4859" + // user: "User/auth0%7C61790e11a3966d006906596a"}, + +//{ capability: null +// if the capability id is null the user level of access for this database is the +same of the team + //name: {@type: "xsd:string", @value: "Collab002"} + //role: "Role/dataReader" + // scope: "UserDatabase/acfcc2db02b83792sssb15239ccdf586fc5b176846ffe4878b1aea6a36c8f" + //user: "User/auth0%7C61790e11a3966d006906596a"}] +``` + +## createUserRole + +##### accessControl.createUserRole(userId, scope, role, \[orgName\]) ⇒ `Promise` + +\-- TerminusCMS API -- + +Create a user's a role for a resource (organization/database) + +**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected. + +Param + +Type + +Description + +userId + +`string` + +The user's id. + +scope + +`string` + +The resource name/id. + +role + +`string` + +The user role to be assigned. + +\[orgName\] + +`string` + +The organization name. + +**Example** + +```javascript +const dbId = "UserDatabase/acfcc2db02b83792sssb15239ccdf586fc5b176846ffe4878b1aea6a36c8f" +accessControl.assignUserRole('User/auth0%7C61790e11a3966d006906596a',dbId, +"Role/collaborator").then(result=>{ + console.log(result) + +}) +``` + +## updateUserRole + +##### accessControl.updateUserRole(userId, capabilityId, scope, role, \[orgName\]) ⇒ `Promise` + +\-- TerminusCMS API -- + +Update user's a role for a resource (organization/database), (this api works only in TerminusCMS) + +**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected. + +Param + +Type + +Description + +userId + +`string` + +The user's id. + +capabilityId + +`string` + +The capability id. + +scope + +`string` + +The resource name/id. + +role + +`string` + +The user role to be updated. + +\[orgName\] + +`string` + +The organization name. + +**Example** + +```javascript +const dbId = "UserDatabase/acfcc2db02b83792sssb15239ccdf586fc5b176846ffe4878b1aea6a36c8f" +const capId= "Capability/b395e8523d509dec6b33aefc9baed3b2e2bfadbd4c79d4ff9b20dce2b14e2edc" +accessControl.updateUserRole('User/auth0%7C61790e11a3966d006906596a',capId,dbId, +"Role/dataUpdater").then(result=>{ + console.log(result) + +}) +``` + +## accessRequestsList + +##### accessControl.accessRequestsList(\[orgName\]) ⇒ `Promise` + +\-- TerminusCMS API -- + +Get all the access request list for a specify organization + +**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected. + +Param + +Type + +Description + +\[orgName\] + +`string` + +The organization name. + +**Example** + +```javascript +accessControl.accessRequestsList().then(result=>{ + console.log(result) +}) +``` + +## sendAccessRequest + +##### accessControl.sendAccessRequest(\[email\], \[affiliation\], \[note\], \[orgName\]) ⇒ `Promise` + +\-- TerminusCMS API -- + +Get all the access request list for a specify organization + +**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected. + +Param + +Type + +Description + +\[email\] + +`string` + +the user email. + +\[affiliation\] + +`string` + +the user affiliation, company, university etc.. + +\[note\] + +`string` + +the message for the team admin + +\[orgName\] + +`string` + +The organization name. + +**Example** + +```javascript +accessControl.sendAccessRequest("myemail@terminusdb.com", + "my_company", + "please add me to your team" +).then(result=>{ + console.log(result) +}) +``` + +## deleteAccessRequest + +##### accessControl.deleteAccessRequest(\[orgName\]) ⇒ `Promise` + +\-- TerminusCMS API -- + +Delete an access request to join your team, only an admin user can delete it + +**Returns**: `Promise` - A promise that returns the call response object, or an Error if rejected. + +Param + +Type + +Description + +\[orgName\] + +`string` + +The organization name. + +**Example** + +```javascript +accessControl.deleteAccessRequest("djjdshhsuuwewueueuiHYHYYW.......").then(result=>{ + console.log(result) +}) +``` \ No newline at end of file diff --git a/src/app/docs/acid-transactions-explanation/page.md b/src/app/docs/acid-transactions-explanation/page.md new file mode 100644 index 0000000..54b2e2d --- /dev/null +++ b/src/app/docs/acid-transactions-explanation/page.md @@ -0,0 +1,56 @@ +--- +title: Acid Transaction Explanation +slug: acid-transactions-explanation +seo: + title: Acid Transactions Explanation + description: >- + An explanation about Acid Transactions and how TerminusDB and TerminusCMS + ensures acid compliance + og_image: >- + https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png +media: [] +--- + +## What is ACID? + +ACID ([Atomicity](#atomicity), [Consistency](#consistency), [Isolation](#isolation), [Durability](#durability)) are properties of database transactions that are generally considered desirable for many applications. + +### Atomicity + +Atomicity is an all-or-nothing approach to database transactions. If a transaction starts but does not complete, then all data manipulation or modification operations carried out by that transaction are undone, and any affected data or objects remain unchanged. The database is returned to the state it was in before the transaction started. Atomicity, or atomic transactions, guarantee the consistency and integrity of data and objects, ensuring the database is not left in an inconsistent or partially changed state. + +#### Atomicity and immutability + +TerminusDB combines atomicity with [immutability](/docs/immutability-explanation/) to provide atomic transactions. + +### Consistency + +Consistency has multiple forms and can be interpreted in different ways. TerminusDB implements two forms of consistency - full and partial consistency. + +#### Full consistency + +Where a schema exists for a TerminusDB database, a transaction will not be completed unless all schema conditions are satisfied. The consistency of the schema is maintained under all conditions. + +#### Partial consistency + +When rebasing, transactions that complete under certain **read-conditions** can be _replayed_ by reordering their commits. Schema consistency is maintained but not under all conditions. + +### Isolation + +The isolation property gives a user the impression of being the sole user of a database. The user experiences no currency or conflicts with other users of the database. + +#### Read isolation + +TerminusDB uses inherent database [immutability](/docs/immutability-explanation/) to ensure each read query exists at a given layer providing each user with an isolated snapshot of the database. + +#### Write isolation + +Similar to read isolation, completing write transactions ensures isolation with optimistic concurrency, simply restarting any transactions failing mid-run. + +### Durability + +TerminusDB is durable. Transactions failing mid-run do not corrupt data. Data is protected from external sources of potential corruption such as operating system bugs. In the unlikely event of a partial commit, previous layers remain unchanged and recoverable. Backups are significantly simplified, requiring copy storage only to ensure a safely recoverable state. + +## Further Reading + +[**Documents in a knowledge graph and how to use them**](/docs/documents-explanation/). \ No newline at end of file diff --git a/src/app/docs/add-a-document/page.md b/src/app/docs/add-a-document/page.md new file mode 100644 index 0000000..c73c6db --- /dev/null +++ b/src/app/docs/add-a-document/page.md @@ -0,0 +1,43 @@ +--- +title: Add Documents +slug: add-a-document +seo: + title: Add Documents using the JavaScript Client + description: >- + A guide to show how to add documents to TerminusDB and TerminusCMS using the + JavaScript Client. + og_image: >- + https://github.com/terminusdb/terminusdb-web-assets/blob/master/docs/js-client-use-add-documents.png?raw=true +media: [] +--- + +After you have imported the terminusdb\_client, [created a client](/docs/connect-with-the-javascript-client/), [connected to a database](/docs/connect-to-a-database/), and [added a schema](/docs/add-a-schema/), you can then use this client to insert a document that conforms to the schema. + +## Insert documents + +Add documents to the schema using addDocument: + +```javascript +const objects = [ + { + "@type" : "Player", + name : "George", + position: "Center Back", + }, + { + "@type" : "Player", + name : "Doug", + position: "Full Back", + }, + { + "@type" : "Player", + name : "Karen", + position: "Center Forward" + } +]; + +const addDocs = async () => { + const result = await client.addDocument(objects); + console.log("the documents have been added", result) +} +``` \ No newline at end of file diff --git a/src/app/docs/add-a-schema-with-the-python-client/page.md b/src/app/docs/add-a-schema-with-the-python-client/page.md new file mode 100644 index 0000000..6852fba --- /dev/null +++ b/src/app/docs/add-a-schema-with-the-python-client/page.md @@ -0,0 +1,26 @@ +--- +title: Add a schema to TerminusCMS with the Python Client +slug: add-a-schema-with-the-python-client +seo: + title: Add a schema to TerminusCMS with the Python Client + description: >- + A guide to show how to add a schema to TerminusCMS projects with the Python + Client. + og_image: https://assets.terminusdb.com/docs/python-client-use-add-a-schema.png +media: [] +--- + +After you have imported the `terminusdb_client`, and [created a client](/docs/create-database-with-python-client/), and [connected to a database](/docs/connect-to-a-database-with-python-client/) you can create a schema. + +## Insert schema document(s) + +You can update the schema by adding well-formed JSON schema documents: + +```python +schema = [{ '@type' : 'Class', '@id' : 'Country'}, + { '@type' : 'Class', '@id' : 'Person', + 'name' : 'xsd:string', + 'nationality' : 'Country' + }] +results = client.insert_document(schema,graph_type="schema") +``` \ No newline at end of file diff --git a/src/app/docs/add-a-schema/page.md b/src/app/docs/add-a-schema/page.md new file mode 100644 index 0000000..5df2a07 --- /dev/null +++ b/src/app/docs/add-a-schema/page.md @@ -0,0 +1,37 @@ +--- +title: Add a Schema +slug: add-a-schema +seo: + title: Add a Schema using the JavaScript Client + description: >- + A guide to show how to add a schema to TerminusDB and TerminusCMS using the + TerminusDB JavaScript Client. + og_image: >- + https://github.com/terminusdb/terminusdb-web-assets/blob/master/docs/js-client-use-add-a-schema.png?raw=true +media: [] +--- + +After you have imported the terminusdb\_client, [created a client](/docs/connect-with-the-javascript-client/), and [connected to a database](/docs/connect-to-a-database/) you can create a schema. + +## Create a schema + +You can create a JSON schema, in this example, we'll create a schema with one object called Player with two properties name and position with the name forming the lexical key: + +```javascript +const schema = { "@type" : "Class", + "@id" : "Player", + "@key" : { "@type": "Lexical", "@fields": ["name"] }, + name : "xsd:string", + position: "xsd:string" }; +``` + +## Add the schema + +Add the schema object with: + +```javascript +const addSchema = async () => { + const result = await client.addDocument(schema, { graph_type: "schema" }); + console.log("the schema has been created", result) +} +``` \ No newline at end of file diff --git a/src/app/docs/add-documents-with-python-client/page.md b/src/app/docs/add-documents-with-python-client/page.md new file mode 100644 index 0000000..4328ccc --- /dev/null +++ b/src/app/docs/add-documents-with-python-client/page.md @@ -0,0 +1,41 @@ +--- +title: Add Documents with the Python Client +slug: add-documents-with-python-client +seo: + title: How To Add Documents with the Python Client + description: >- + A guide to show how to add documents to your TerminusCMS projects using the + Python Client. + og_image: https://assets.terminusdb.com/docs/python-client-use-add-documents.png +media: [] +--- + +After you have imported the `terminusdb_client`, and [created a client](/docs/connect-with-python-client/), [connected to a database](/docs/connect-with-python-client/), and [added a schema](/docs/add-a-schema-with-the-python-client/), you can then use this client to insert a document that conforms to the schema. + +## Insert a document + +To insert a document, you should use `insert_document`: + +```python +document = { '@type' : 'Person', 'name' : "Jim" } +results = client.insert_document(document) +``` + +## Insert multiple documents + +To insert multiple documents you can also invoke `insert_document`: + +```python +documents = [{ '@type' : 'Person', 'name' : "Jim" }, + { '@type' : 'Person', 'name' : "Jill" }] +results = client.insert_document(document) +``` + +## Insert schema document(s) + +Additionally, you can update the schema itself by adding schema documents: + +```python +schema = { '@type' : 'Class', '@id' : 'Person', 'name' : 'xsd:string'} +results = client.insert_document(schema,graph_type="schema") +``` \ No newline at end of file diff --git a/src/app/docs/add-documents-with-woql/page.md b/src/app/docs/add-documents-with-woql/page.md new file mode 100644 index 0000000..c8c6713 --- /dev/null +++ b/src/app/docs/add-documents-with-woql/page.md @@ -0,0 +1,31 @@ +--- +title: Add a document in WOQL +slug: add-documents-with-woql +seo: + title: How to add documents using WOQL + description: >- + A how-to guide with an example showing how to add documents using a WOQL + query. + og_image: https://assets.terminusdb.com/docs/woql-add-documents.png +media: [] +--- + +> To use this HowTo, first [clone the Star Wars demo](/docs/clone-a-demo-terminuscms-project/) into your team on TerminusCMS. You will then have full access to the data needed for this tutorial. + +## Add a document in WOQL + +You can add a document in WOQL using the `insert_document` keyword. + +```javascript +let v = Vars("id"); +insert_document(doc({'@type' : 'Planet', label: 'Planet-X'}), v.id) +``` + +We can also add documents by using a variable. For instance, we can create a new planet for each individual in the star wars universe as follows: + +```javascript +let v = Vars("person", "name"); +and(isa(v.person, "People"), + triple(v.person,"label",v.name), + insert_document(doc({'@type' : 'Planet', label: v.name}))) +``` \ No newline at end of file diff --git a/src/app/docs/advanced-filtering-with-graphql/page.md b/src/app/docs/advanced-filtering-with-graphql/page.md new file mode 100644 index 0000000..bd71c08 --- /dev/null +++ b/src/app/docs/advanced-filtering-with-graphql/page.md @@ -0,0 +1,273 @@ +--- +title: Advanced Filtering with GraphQL +slug: advanced-filtering-with-graphql +seo: + title: Advanced Filtering + description: Advanced Filtering with GraphQL + og_image: https://assets.terminusdb.com/docs/graphql-advanced-filter.png +media: [] +--- + +> To use this HowTo, first [clone the Star Wars demo](/docs/clone-a-demo-terminuscms-project/) into your team on TerminusCMS. You will then have full access to the data needed for this tutorial. + +TerminusDB exposes a _filter_ object, which can be used to select specific documents. See here for basic [Filtering](/docs/filter-with-graphql/) + +Now we can filter the homeworld of the people we are interested in. We will use a `regex` because Tatooine is hard to spell. + +```graphql +query{ + People(filter: { homeworld: { label: { regex : "Tat.*" }}}){ + label + homeworld{ + label + } + } +} +``` + +You can also find out what fields are available with the same `Ctrl-c` trick. Now, fire off the query above, and you'll see something like: + +```json +{ + "data": { + "People": [ + { + "label": "Luke Skywalker", + "homeworld": { + "label": "Tatooine" + } + }, + { + "label": "Anakin Skywalker", + "homeworld": { + "label": "Tatooine" + } + }, + { + "label": "C-3PO", + "homeworld": { + "label": "Tatooine" + } + }, + { + "label": "Darth Vader", + "homeworld": { + "label": "Tatooine" + } + }, + { + "label": "Shmi Skywalker", + "homeworld": { + "label": "Tatooine" + } + }, + { + "label": "Owen Lars", + "homeworld": { + "label": "Tatooine" + } + }, + { + "label": "Cliegg Lars", + "homeworld": { + "label": "Tatooine" + } + }, + { + "label": "Beru Whitesun lars", + "homeworld": { + "label": "Tatooine" + } + }, + { + "label": "R5-D4", + "homeworld": { + "label": "Tatooine" + } + }, + { + "label": "Biggs Darklighter", + "homeworld": { + "label": "Tatooine" + } + } + ] + } +} +``` + +## Adding conjunctions + +We can also add other elements to the filter, by using the `_and` keyword. This requires that both filters are true. + +```graphql +query{ + People(filter:{ _and : [ {homeworld : {label : {eq : "Coruscant"}}}, + {species : {label : { eq: "Human"}}}, + ]}){ + label + species{ + label + } + homeworld{ + label + } + } +} +``` + +Which yields: + +```json +{ + "data": { + "People": [ + { + "label": "Finis Valorum", + "species": { + "label": "Human" + }, + "homeworld": { + "label": "Coruscant" + } + }, + { + "label": "Jocasta Nu", + "species": { + "label": "Human" + }, + "homeworld": { + "label": "Coruscant" + } + } + ] + } +} +``` + +## `_not` and `_or` + +You can also use `_not` and `_or` keywords to create even more complex filters. To find all species, excluding droids with a lifespan greater than 500 who don't have a typical sort of skin colour, you can write the following: + +```graphql +{ + Species( + filter: {_and : [ + {_not :{label:{eq:"Droid"}}}, + {_or :[ + {average_lifespan:{gt : "500"}}, + {_not: + {skin_colors: + {anyOfTerms: ["blue", "black", "white", "green", "grey" + "brown", "red", "gray"]}}}] + }]} + ) { + label + } +} +``` + +And yields: + +```json +{ + "data": { + "Species": [ + { + "label": "Yoda's species" + }, + { + "label": "Pau'an" + }, + { + "label": "Hutt" + }, + { + "label": "Sullustan" + }, + { + "label": "Cerean" + }, + { + "label": "Iktotchi" + }, + { + "label": "Tholothian" + } + ] + } +} +``` + +## A Bit of GraphQL theory + +The filter is defined as part of the query for objects. If we look at the `People` query in the Star Wars demo we see the following: + +```graphql +type Query { + People( + id: ID + ids: [ID!] + + """skip N elements""" + offset: Int + + """limit results to N elements""" + limit: Int + filter: People_Filter + + """order by the given fields""" + orderBy: People_Ordering + ): [People!]! +} +``` + +This query exposes a `filter` argument, with the type of `People_Filter`. + +A `People_Filter` in turn looks like: + +```graphql +input People_Filter { + birth_year: StringFilter + created: DateTimeFilter + desc: CollectionStringFilter + edited: DateTimeFilter + eye_color: StringFilter + film: Film_Collection_Filter + gender: StringFilter + hair_colors: StringFilter + height: StringFilter + homeworld: Planet_Filter + label: StringFilter + mass: StringFilter + skin_colors: StringFilter + species: Species_Filter + starship: Starship_Collection_Filter + url: StringFilter + vehicle: Vehicle_Collection_Filter + _and: [People_Filter!] + _or: [People_Filter!] + _not: People_Filter +} +``` + +In this way we can recursively qualify all of the objects to which a `People` might point to, terminating at leaves that use the various concrete type filters. + +For instance, the `StringFilter` looks like: + +```graphql +input StringFilter { + eq: String + ne: String + lt: String + le: String + gt: String + ge: String + regex: String + startsWith: String + allOfTerms: [String!] + anyOfTerms: [String!] +} +``` + +We can specify any of these operands to narrow down our search. For more information on the operations against concrete datatypes, see the [GraphQL Reference](/docs/graphql-query-reference/) section. \ No newline at end of file diff --git a/src/app/docs/array/page.md b/src/app/docs/array/page.md new file mode 100644 index 0000000..0c3771b --- /dev/null +++ b/src/app/docs/array/page.md @@ -0,0 +1,172 @@ +--- +title: Array +slug: array +seo: + title: Array fields in the document UI + description: 'Examples of how array fields in the document UI ' + og_image: >- + https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png +media: [] +--- + +This example shows how `` appears for a document `ArrayExamplePerson` with array fields in Create/ Edit or View mode. If a field is described as array it means the field can have more than one value to it in an ordered fashion. The field can also be considered as an optional field meaning it can be empty or filled. + +## Demo + +Take a look at the **[](https://documents-ui-playground.terminusdb.com/Array)**[Demo](https://documents-ui-playground.terminusdb.com/Array) to view `` with Array properties in Create, edit or view mode. + +## Frame + +The below frame consists of an ArrayExamplePerson document + +```javascript + let frame = { + "@context": { + "@base": "terminusdb:///data/", + "@schema": "terminusdb:///schema#", + "@type": "Context", + "xsd": "http://www.w3.org/2001/XMLSchema#" + }, + "Address": { + "@documentation": [ + { + "@comment": "An Address", + "@label": "Address", + "@language": "en", + "@properties": { + "AddressLine1": { + "@comment": "Address Line one", + "@label": "Address Line 1" + }, + "Country": { + "@comment": "A Country ", + "@label": "Country" + }, + "postalCode": { + "@comment": "A valid Postal Code", + "@label": "Zip Code" + } + } + }, + { + "@comment": "მისამართი", + "@label": "მისამართი", + "@language": "ka", + "@properties": { + "AddressLine1": { + "@comment": "მისამართის ხაზი პირველი", + "@label": "მისამართის ხაზი 1" + }, + "Country": { + "@comment": "Ქვეყანა", + "@label": "ქვეყანა" + }, + "postalCode": { + "@comment": "მოქმედი საფოსტო კოდი", + "@label": "Ზიპ კოდი" + } + } + } + ], + "@key": { + "@type": "Random" + }, + "@subdocument": [], + "@type": "Class", + "AddressLine1": "xsd:string", + "City": { + "@class": "xsd:string", + "@type": "Optional" + }, + "Country": "xsd:string", + "postalCode": "xsd:string" + }, + "ArrayExamplePerson": { + "@key": { + "@type": "Random" + }, + "@type": "Class", + "hangs_out_at": { + "@class": { + "@class": "Address", + "@subdocument": [] + }, + "@type": "List" + }, + "likes_color": { + "@class": { + "@id": "Colors", + "@type": "Enum", + "@values": [ + "Red", + "Blue", + "Yellow", + "Green" + ] + }, + "@type": "List" + }, + "to_do": { + "@class": "xsd:string", + "@type": "List" + } + } + } +``` + +### Create + +```python +import { FrameViewer } from '@terminusdb/terminusdb-documents-ui' + + return // type of document +``` + +### Edit & View + +Note - make sure to provide document values for View mode. The form will be in read only mode for View. + +```javascript +let data = { + "@id": "ArrayExamplePerson/c92d269b0dce719299bf86fc19f2065937ec4ef82d8a2a53702867a326d6144b", + "@type": "OrderedPerson", + "hangs_out_at" : [ + { + "@id": "ArrayExamplePerson/3ca7d7a9c64ca2bc8319d83bca14b71697528ebb8536024e3e1795cbd049acdf/lived_at/Address/4f4fdae34ab4fa3b6297750917503a7137f75dc11589792de707e7a6d3502db3", + "@type": "Address", + "AddressLine1": "anywhere", + "City": "Nice", + "Country": "France", + "postalCode": "FR27836" + }, + { + "@id": "ArrayExamplePerson/3ca7d7a9c64ca2bc8319d83bca14b71697528ebb8536024e3e1795cbd049acdf/lived_at/Address/7aaeeb6b983710a0adbc75de8f7d8104278df427124beadc6644b35b9d6c30af", + "@type": "Address", + "AddressLine1": "somewhere", + "City": "Berlin", + "Country": "Germany", + "postalCode": "GER02398" + } + ], + "likes_color": [ + "Blue", + "Green", + "Red" + ], + "to_do": [ + "First Thing", + "Second Thing", + "Third Thing" + ] +} + +return +``` \ No newline at end of file diff --git a/src/app/docs/back-links-in-graphql/page.md b/src/app/docs/back-links-in-graphql/page.md new file mode 100644 index 0000000..85c10e9 --- /dev/null +++ b/src/app/docs/back-links-in-graphql/page.md @@ -0,0 +1,62 @@ +--- +title: Back Links in GraphQL +slug: back-links-in-graphql +seo: + title: Back Links + description: Back Links in GraphQL + og_image: https://assets.terminusdb.com/docs/graphql-backlink.png +media: [] +--- + +> To use this HowTo, first [clone the Star Wars demo](/docs/clone-a-demo-terminuscms-project/) into your team on TerminusCMS. You will then have full access to the data needed for this tutorial. + +## Using a Back Link + +Many times when we are looking at an object, we are interested in which objects are pointing to it. In TerminusCMS each object gets a number of extended queries which allows one to discover any objects which point at that object. + +Once you have cloned the Star Wars demo, go to the [GraphQL query panel](/docs/graphql-basics/) and type: + +```graphql +query{ + People(limit:1) { + █ + } +} +``` + +We would like to find the first person in the database, and then find out which starships they are the pilot of. A `Starship` has a `pilot` field, and the backlink is automatically constructed as the `pilot_of_Starship` by TerminusCMS. + +```graphql +query{ + People(limit:1){ + label + _pilot_of_Starship{ + label + } + } +} +``` + +This _back link_ will give us back the following: + +```json +{ + "data": { + "People": [ + { + "label": "Luke Skywalker", + "_pilot_of_Starship": [ + { + "label": "X-wing" + }, + { + "label": "Imperial shuttle" + } + ] + } + ] + } +} +``` + +Backlinking allows us to focus on modeling our data in a natural way, while still allowing us to follow the graph in either direction of a field or its opposite without bias. \ No newline at end of file diff --git a/src/app/docs/branch-a-project-with-the-python-client/page.md b/src/app/docs/branch-a-project-with-the-python-client/page.md new file mode 100644 index 0000000..ef9c7d0 --- /dev/null +++ b/src/app/docs/branch-a-project-with-the-python-client/page.md @@ -0,0 +1,99 @@ +--- +title: Branch a Project Using the Python Client +slug: branch-a-project-with-the-python-client +seo: + title: Branch a Project Using the Python Client + description: A guide to show how to branch a TerminusCMS project using the Python Client. + og_image: https://assets.terminusdb.com/docs/python-client-collaboration-branch.png +media: [] +--- + +Assuming you have [connected with the Python Client](/docs/connect-with-python-client/) and [created a database](/docs/create-database-with-python-client/) you can then create a branch of your project. + +Creating a branch is the same for TerminusDB and TerminusCMS. By default, in TerminusDB or TerminusCMS you are working in the main branch. + +## Create a new branch from main branch + +Use this code to create a new branch starting from the main branch head. + +```python +client.create_branch("mybranch") +client.branch("mybranch") +``` + +If you add documents to the `mybranch`, they won't end up in the `main` branch unless you merge them. + +## Create a new branch from mybranch branch + +Now you are in the branch called `mybranch`. + +You can create a new branch starting from the `mybranch` head. Since we are checked out on the "mybranch" already, we can just create a new branch from there. It will have `mybranch` as its parent. + +```python +client.create_branch("branch_from_mybranch") +client.branch("branch_from_mybranch") +``` + +## Get a branch list + +Get all of the data product's branches in a list using a method + +```python +branches = client.get_all_branches() +print(branches) +``` + +Response example + +```json +[ + { + "Branch":"terminusdb://ref/data/Branch/main", + "Head":"terminusdb://ref/data/InitialCommit/ohj33rrh5kmnmr9cq6vzfajfxog0629", + "Name":{ + "@type":"xsd:string", + "@value":"main" + }, + "Timestamp":{ + "@type":"xsd:decimal", + "@value":1678385706.694406 + }, + "commit_identifier":{ + "@type":"xsd:string", + "@value":"ohj33rrh5kmnmr9cq6vzfajfxog0629" + } + }, + { + "Branch":"terminusdb://ref/data/Branch/mybranch", + "Head":"terminusdb://ref/data/ValidCommit/prh0yvftqmsrgctn8gqvdxv7gc4i8p8", + "Name":{ + "@type":"xsd:string", + "@value":"mybranch" + }, + "Timestamp":{ + "@type":"xsd:decimal", + "@value":1678385762.7790234 + }, + "commit_identifier":{ + "@type":"xsd:string", + "@value":"prh0yvftqmsrgctn8gqvdxv7gc4i8p8" + } + }, + { + "Branch":"terminusdb://ref/data/Branch/branch_from_mybranch", + "Head":"terminusdb://ref/data/ValidCommit/prh0yvftqmsrgctn8gqvdxv7gc4i8p8", + "Name":{ + "@type":"xsd:string", + "@value":"branch_from_mybranch" + }, + "Timestamp":{ + "@type":"xsd:decimal", + "@value":1678385762.7790234 + }, + "commit_identifier":{ + "@type":"xsd:string", + "@value":"prh0yvftqmsrgctn8gqvdxv7gc4i8p8" + } + } + ] +``` \ No newline at end of file diff --git a/src/app/docs/branch-a-project/page.md b/src/app/docs/branch-a-project/page.md new file mode 100644 index 0000000..3ac4ef6 --- /dev/null +++ b/src/app/docs/branch-a-project/page.md @@ -0,0 +1,107 @@ +--- +title: Branch a Project using the TerminusDB JS Client +slug: branch-a-project +seo: + title: Branch a Project using the JavaScript Client + description: >- + A guide to show how to create a new branch in TerminusDB and TerminusCMS + using the JavaScript Client. + og_image: >- + https://github.com/terminusdb/terminusdb-web-assets/blob/master/docs/JS-client-collaboration-branch.png?raw=true +media: [] +--- + +Assuming you have [connected with the JavaScript Client](/docs/connect-with-the-javascript-client/) and [created a database](/docs/create-a-database/) you can then create a branch of your project. + +Creating a branch is the same for TerminusDB and TerminusCMS. By default, in TerminusDB or TerminusCMS you are working in the main branch. + +## Create a new branch from main branch + +Use this code to create a new branch starting from the main branch head. + +```javascript +const createBranch = async () => { + await client.branch("mybranch"); + client.checkout("mybranch") +} +``` + +## Create a new branch from mybranch branch + +Now you are in the branch called `mybranch`. + +You can create a new branch starting from the `mybranch` head + +```javascript +const createBranchFromMyBranch = async () => { + await client.branch("branch_from_mybranch","mybranch"); + client.checkout("branch_from_mybranch") +} +``` + +## Get a branch list + +Get all of the database's branches in a list using a \[WOQL\]() library method + +```javascript +const getBranchList = async () => { + const branchList = await TerminusClient.WOQL.lib().branches() + console.log("ExampleDatabase branch list", JSON.stringify(branchList.bindings,null,4)) + +} +``` + +Response example + +```json +[ + { + "Branch":"terminusdb://ref/data/Branch/main", + "Head":"terminusdb://ref/data/InitialCommit/ohj33rrh5kmnmr9cq6vzfajfxog0629", + "Name":{ + "@type":"xsd:string", + "@value":"main" + }, + "Timestamp":{ + "@type":"xsd:decimal", + "@value":1678385706.694406 + }, + "commit_identifier":{ + "@type":"xsd:string", + "@value":"ohj33rrh5kmnmr9cq6vzfajfxog0629" + } + }, + { + "Branch":"terminusdb://ref/data/Branch/mybranch", + "Head":"terminusdb://ref/data/ValidCommit/prh0yvftqmsrgctn8gqvdxv7gc4i8p8", + "Name":{ + "@type":"xsd:string", + "@value":"mybranch" + }, + "Timestamp":{ + "@type":"xsd:decimal", + "@value":1678385762.7790234 + }, + "commit_identifier":{ + "@type":"xsd:string", + "@value":"prh0yvftqmsrgctn8gqvdxv7gc4i8p8" + } + }, + { + "Branch":"terminusdb://ref/data/Branch/branch_from_mybranch", + "Head":"terminusdb://ref/data/ValidCommit/prh0yvftqmsrgctn8gqvdxv7gc4i8p8", + "Name":{ + "@type":"xsd:string", + "@value":"branch_from_mybranch" + }, + "Timestamp":{ + "@type":"xsd:decimal", + "@value":1678385762.7790234 + }, + "commit_identifier":{ + "@type":"xsd:string", + "@value":"prh0yvftqmsrgctn8gqvdxv7gc4i8p8" + } + } + ] +``` \ No newline at end of file diff --git a/src/app/docs/branch/page.md b/src/app/docs/branch/page.md new file mode 100644 index 0000000..47df40a --- /dev/null +++ b/src/app/docs/branch/page.md @@ -0,0 +1,55 @@ +--- +title: Branch a Project with the TerminusCMS Dashboard +slug: branch +seo: + title: Branch a Project using the TerminusCMS Dashboard + description: A guide to show how to branch projects using the TerminusCMS dashboard. + og_image: https://assets.terminusdb.com/docs/branch-project.png +media: + - alt: Branch the project + caption: '' + media_type: Image + title: Branch the project + value: https://assets.terminusdb.com/docs/branch-project.png + - alt: Create a new project branch in TerminusCMS + caption: '' + media_type: Image + title: Create a new project branch in TerminusCMS + value: https://assets.terminusdb.com/docs/branch-new.png + - alt: Branch Options + caption: '' + media_type: Image + title: Branch Options + value: https://assets.terminusdb.com/docs/branch-options.png +--- + +The TerminusCMS dashboard enables you to branch projects. To do this, choose the team and project you want to branch. You will be directed to the project home page. This is where you can branch it. + +Scroll down to see the manage `branch` section. + +![Branch the project](https://assets.terminusdb.com/docs/branch-project.png) + +Each project can have one or more branches, the default is called main. Each branch contains a snapshot of the data as it was at the time of branching. This is useful for experimenting or providing data to other teams when you want to keep them away from main. + +## Create a new branch + +Click the `new branch` button. + +![Create a new project branch in TerminusCMS](https://assets.terminusdb.com/docs/branch-new.png) + +Give the branch and ID. + +You then have two choices: + +1. Branch from the current head to include all of the data +2. Create an empty branch + +Click `new branch` to create it. + +You will then be switched to that branch. + +## Swap between branches + +From the manage branch section use the ellipsis symbol next to the branches to switch between branches and main. + +![Branch Options](https://assets.terminusdb.com/docs/branch-options.png) \ No newline at end of file diff --git a/src/app/docs/change-request-workflows/page.md b/src/app/docs/change-request-workflows/page.md new file mode 100644 index 0000000..84a911c --- /dev/null +++ b/src/app/docs/change-request-workflows/page.md @@ -0,0 +1,116 @@ +--- +title: Change Request Workflows in TerminusCMS +slug: change-request-workflows-terminuscms-tour +seo: + title: Change Request Workflows - TerminusCMS Tour + description: >- + This page details how change request workflows function in TerminusCMS to + enable safe collaboration + og_image: >- + https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png +media: + - alt: Opening a change request + caption: '' + media_type: Image + title: Opening a change request + value: https://assets.terminusdb.com/docs/open-change-request.png + - alt: In a change request + caption: '' + media_type: Image + title: In a change request + value: https://assets.terminusdb.com/docs/in-change-request.png + - alt: TerminusCMS change request screen + caption: '' + media_type: Image + title: TerminusCMS change request screen + value: https://assets.terminusdb.com/docs/change-request-screen.png + - alt: Change Request diff viewer + caption: '' + media_type: Image + title: Change Request diff viewer + value: https://assets.terminusdb.com/docs/cr-diff.png + - alt: See messages in a change request for context + caption: '' + media_type: Image + title: See messages in a change request for context + value: https://assets.terminusdb.com/docs/cr-review-messages.png + - alt: List of change requests for review + caption: '' + media_type: Image + title: List of change requests for review + value: https://assets.terminusdb.com/docs/cr-review-home.png + - alt: Change request screen + caption: '' + media_type: Image + title: Change request screen + value: https://assets.terminusdb.com/docs/cr-review-page.png +--- + +TerminusCMS features change request workflows to ensure that changes to data and content are made safely with reviews in place to check changes. + +## Creating a Change Request + +When someone goes to make a change to content and data, TerminusCMS automatically opens a change request. This is a branch of the database that does not impact main. Users can make one or many changes within the change request - + +![Opening a change request](https://assets.terminusdb.com/docs/open-change-request.png) + +## In a Change Request + +Users will see when they are in a change request. A banner with various options is included at the top of the page and there is also a notice on the left informing the user what they are connected to - + +![In a change request](https://assets.terminusdb.com/docs/in-change-request.png) + +> It is important to submit edits or additions in a change request. Without hitting the submit button, changes will not be saved to the change request. + +When in a change request a user has three options - + +1. Continue to make edits, deletions, and additions to the change request. +2. Exit the change request - This leaves the change request open and available to come back to at a later stage. +3. Submit the change request for review. + +## Change Request Admin + +Change requests are managed from the change request screen. + +![TerminusCMS change request screen](https://assets.terminusdb.com/docs/change-request-screen.png) + +The screen has four tabs - + +1. Open - Open change requests that can be continued with or submitted for review. +2. Review - Change requests that have been submitted for review. +3. Merged - Previous approved commits to the database. +4. Rejected - Rejected change requests. + +## Review Change Requests + +On the change request screen, select 'review'. Change requests that users have submitted for review are listed in chronological order. + +![Change Request diff viewer](https://assets.terminusdb.com/docs/cr-diff.png) + +_Change requests feature a diff viewer to see what's changed_ + +![See messages in a change request for context](https://assets.terminusdb.com/docs/cr-review-messages.png) + +_Write messages to add more context_ + +![List of change requests for review](https://assets.terminusdb.com/docs/cr-review-home.png) + +![Change request screen](https://assets.terminusdb.com/docs/cr-review-page.png) + +To review a change request, do the following - + +* Click the 'review' button for the corresponding change request. +* The next screen has all of the details of the change request with two tabs - + +* The first is the diff view with drop-down options to display the changes that have been made +* The second is the messages tab, this displays the messages entered when creating and submitting the change request and can provide context. + +* Users can either accept or reject a change request and leave a message explaining their reasoning behind each +* Accepted change requests will move the change request into the merged tab - users are able to view the diff to see the changes of past commits +* Rejected change requests move into the rejected tab on the change request home screen + +## Conflicts & Collaboration + +In order to avoid changes being squashed by other users when multiple people make changes to data and content, TerminusCMS checks the database to see if there have been changes made before a user reviews and merges a change request. + +In order to proceed. The user must rebase their change request to incorporate the latest changes into their own change request. A prompt tells the user what to do. \ No newline at end of file diff --git a/src/app/docs/choice-document/page.md b/src/app/docs/choice-document/page.md new file mode 100644 index 0000000..3430f4d --- /dev/null +++ b/src/app/docs/choice-document/page.md @@ -0,0 +1,211 @@ +--- +title: Choice Document +slug: choice-document +seo: + title: Choice Document in the Document UI + description: How document choice works in the document UI + og_image: >- + https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png +media: [] +--- + +This example shows how `` appears for a document `Guy` with choice document fields in Create/ Edit or View mode. + +In this example `Guy` has a mandatory property called `favorite_group` with the choice of documents called Art, Dance or Music, an optional `"second_favorite_group"` property also with the choice Art, Dance or Music, a set `member_of` property with the same choices, and a list `attends_group_in_order` property with the above same choices, in an ordered fashion. + +## Demo + +Take a look at the **[](https://documents-ui-playground.terminusdb.com/Choice%20Documents)**[Demo Playground](https://documents-ui-playground.terminusdb.com/Choice%20Documents) to view `` with Choice properties in Create, edit or view mode. + +The below Frames show the definition of Art, Dance or Music which are other document classes. + +## Frame + +The below Frame consists of the `Guy` document + +```javascript + let frame = { + "@context": { + "@base": "terminusdb:///data/", + "@schema": "terminusdb:///schema#", + "@type": "Context", + "xsd": "http://www.w3.org/2001/XMLSchema#" + }, + "Guy": { + "@key": { + "@type": "Random" + }, + "@type": "Class", + "attends_group_in_order": { + "@class": "Group", + "@type": "Set" + }, + "favorite_group": "Group", + "member_of": { + "@class": "Group", + "@type": "Set" + }, + "second_favorite_group": { + "@class": "Group", + "@type": "Optional" + } + }, + "Dance": { + "@documentation": [ + { + "@language": "en", + "@properties": { + "capacity": { + "@comment": "Max number of people in group", + "@label": "Capacity" + }, + "name": { + "@comment": "Title of the group", + "@label": "Name" + } + } + }, + { + "@language": "ka", + "@properties": { + "capacity": { + "@comment": "ადამიანების მაქსიმალური რაოდენობა ჯგუფში", + "@label": "ტევადობა" + }, + "name": { + "@comment": "ჯგუფის სათაური", + "@label": "სახელი" + } + } + } + ], + "@key": { + "@fields": [ + "name" + ], + "@type": "Lexical" + }, + "@type": "Class", + "capacity": "xsd:decimal", + "name": "xsd:string" + }, + "Art": { + "@documentation": [ + { + "@language": "en", + "@properties": { + "capacity": { + "@comment": "Max number of people in group", + "@label": "Capacity" + }, + "name": { + "@comment": "Title of the group", + "@label": "Name" + } + } + }, + { + "@language": "ka", + "@properties": { + "capacity": { + "@comment": "ადამიანების მაქსიმალური რაოდენობა ჯგუფში", + "@label": "ტევადობა" + }, + "name": { + "@comment": "ჯგუფის სათაური", + "@label": "სახელი" + } + } + } + ], + "@key": { + "@fields": [ + "name" + ], + "@type": "Lexical" + }, + "@type": "Class", + "capacity": "xsd:decimal", + "name": "xsd:string" + }, + "Music": { + "@documentation": [ + { + "@language": "en", + "@properties": { + "capacity": { + "@comment": "Max number of people in group", + "@label": "Capacity" + }, + "name": { + "@comment": "Title of the group", + "@label": "Name" + } + } + }, + { + "@language": "ka", + "@properties": { + "capacity": { + "@comment": "ადამიანების მაქსიმალური რაოდენობა ჯგუფში", + "@label": "ტევადობა" + }, + "name": { + "@comment": "ჯგუფის სათაური", + "@label": "სახელი" + } + } + } + ], + "@key": { + "@fields": [ + "name" + ], + "@type": "Lexical" + }, + "@type": "Class", + "capacity": "xsd:decimal", + "name": "xsd:string" + } + } +``` + +### Create + +```python +import { FrameViewer } from '@terminusdb/terminusdb-documents-ui' + + return // type of document +``` + +### Edit & View + +Note - make sure to provide document values for View mode. The form will be in read only mode for View. + +```javascript +let data = { + "@id": "Guy/4489199036b83dbf79a6e7527a1594fbd416d11b9dde2f8a67fe6fa495dae433", + "@type": "Guy", + "favorite_group": "Art/Charcoal%20Art%20Group", + "attends_group_in_order": [ + "Dance/Dance%20Everyday", + "Art/Pastel%20Art%20Group", + "Music/Music%2220Pop" + ], + "member_of": [ + "Art/Pastel%20Art%20Group", + "Dance/Dance%20Everyday" + ], + "second_favorite_group": "Dance/Dance%20Everyday", +} + +return +``` \ No newline at end of file diff --git a/src/app/docs/choice-subdocuments/page.md b/src/app/docs/choice-subdocuments/page.md new file mode 100644 index 0000000..23ab38f --- /dev/null +++ b/src/app/docs/choice-subdocuments/page.md @@ -0,0 +1,362 @@ +--- +title: Choice Sub-Documents +slug: choice-subdocuments +seo: + title: TerminusDB Document UI SDK - Using Choice Subdocuments + description: >- + A guide showing how to use multiple choice subdocuments with the TerminusDB + document UI SDK + og_image: >- + https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png +media: [] +--- + +This example shows how `` appears for a document called `Student` with choice subdocument fields in Create/ Edit or View mode. + +`Student` has a mandatory `favorite_subject` property with the choices of Zoology, Botony or Maths, an optional `"second_favorite_subject"` property with the same document choices, a set `studied` property with the above choices, and a list `study_time_table` property with the same choices in an ordered fashion. + +## Demo + +Take a look at the **[](https://documents-ui-playground.terminusdb.com/Choice%20SubDocuments)**[Demo](https://documents-ui-playground.terminusdb.com/Choice%20SubDocuments) to view `` with Choice subdocuments in Create, edit or view mode. + +The below Frames show the definition of Zoology, Botony or Maths which are subdocuments. + +## Frame + +The frame below consists of a `Student` document - + +```javascript + let frame = { + "@context": { + "@base": "terminusdb:///data/", + "@schema": "terminusdb:///schema#", + "@type": "Context", + "xsd": "http://www.w3.org/2001/XMLSchema#" + }, + "Student": { + "@key": { + "@type": "Random" + }, + "@type": "Class", + "favorite_subject": [ + { + "@class": "Zoology", + "@subdocument": [] + }, + { + "@class": "Botony", + "@subdocument": [] + }, + { + "@class": "Maths", + "@subdocument": [] + } + ], + "second_favorite_subject": { + "@class": [ + { + "@class": "Zoology", + "@subdocument": [] + }, + { + "@class": "Botony", + "@subdocument": [] + }, + { + "@class": "Maths", + "@subdocument": [] + } + ], + "@type": "Optional" + }, + "studied": { + "@class": [ + { + "@class": "Zoology", + "@subdocument": [] + }, + { + "@class": "Botony", + "@subdocument": [] + }, + { + "@class": "Maths", + "@subdocument": [] + } + ], + "@type": "Set" + }, + "study_time_table": { + "@class": [ + { + "@class": "Zoology", + "@subdocument": [] + }, + { + "@class": "Botony", + "@subdocument": [] + }, + { + "@class": "Maths", + "@subdocument": [] + } + ], + "@type": "List" + } + }, + "Zoology": { + "@documentation": [ + { + "@language": "en", + "@properties": { + "Number_of_classes_attended": { + "@comment": "Number of Classes Attended", + "@label": "Classes Attended" + }, + "course_start_date": { + "@comment": "Course Start Date", + "@label": "Start Date" + } + } + }, + { + "@language": "ka", + "@properties": { + "Number_of_classes_attended": { + "@comment": "კლასების რაოდენობა", + "@label": "კლასები დაესწრო" + }, + "course_start_date": { + "@comment": "კურსის დაწყების თარიღი", + "@label": "Დაწყების თარიღი" + } + } + } + ], + "@key": { + "@type": "Random" + }, + "@subdocument": [], + "@type": "Class", + "Grade": { + "@class": "xsd:string", + "@type": "Optional" + }, + "Notes": { + "@class": "xsd:string", + "@type": "Optional" + }, + "Number_of_classes_attended": { + "@class": "xsd:integer", + "@type": "Optional" + }, + "course_start_date": { + "@class": "xsd:dateTime", + "@type": "Optional" + } + } + "Botony": { + "@documentation": [ + { + "@language": "en", + "@properties": { + "Number_of_classes_attended": { + "@comment": "Number of Classes Attended", + "@label": "Classes Attended" + }, + "course_start_date": { + "@comment": "Course Start Date", + "@label": "Start Date" + } + } + }, + { + "@language": "ka", + "@properties": { + "Number_of_classes_attended": { + "@comment": "კლასების რაოდენობა", + "@label": "კლასები დაესწრო" + }, + "course_start_date": { + "@comment": "კურსის დაწყების თარიღი", + "@label": "Დაწყების თარიღი" + } + } + } + ], + "@key": { + "@type": "Random" + }, + "@subdocument": [], + "@type": "Class", + "Grade": { + "@class": "xsd:string", + "@type": "Optional" + }, + "Number_of_classes_attended": { + "@class": "xsd:integer", + "@type": "Optional" + }, + "course_start_date": { + "@class": "xsd:dateTime", + "@type": "Optional" + }, + "number_of_assignments": { + "@class": "xsd:integer", + "@type": "Optional" + } + }, + "Maths": { + "@documentation": [ + { + "@comment": "Maths", + "@label": "Maths", + "@language": "en", + "@properties": { + "Number_of_classes_attended": { + "@comment": "Number of Classes Attended", + "@label": "Classes Attended" + }, + "course_start_date": { + "@comment": "Course Start Date", + "@label": "Start Date" + }, + "level": { + "@comment": "Math level", + "@label": "Level" + }, + "love_maths": { + "@comment": "a choice to love maths", + "@label": "Do you like Maths?" + } + } + }, + { + "@comment": "მათემატიკა", + "@label": "მათემატიკა", + "@language": "ka", + "@properties": { + "Number_of_classes_attended": { + "@comment": "კლასების რაოდენობა", + "@label": "კლასები დაესწრო" + }, + "course_start_date": { + "@comment": "კურსის დაწყების თარიღი", + "@label": "Დაწყების თარიღი" + }, + "level": { + "@comment": "მათემატიკის დონე", + "@label": "დონე" + }, + "love_maths": { + "@comment": "არჩევანი გიყვარდეს მათემატიკა", + "@label": "მოგწონთ მათემატიკა?" + } + } + } + ], + "@key": { + "@type": "Random" + }, + "@subdocument": [], + "@type": "Class", + "Number_of_classes_attended": { + "@class": "xsd:integer", + "@type": "Optional" + }, + "course_start_date": { + "@class": "xsd:dateTime", + "@type": "Optional" + }, + "level": { + "@class": "xsd:string", + "@type": "Optional" + }, + "love_maths": { + "@class": "xsd:boolean", + "@type": "Optional" + } + } + } +``` + +## Create + +```python +import { FrameViewer } from '@terminusdb/terminusdb-documents-ui' + + return // type of document +``` + +## Edit & View + +Note - make sure the document is filled in View mode. The form will be in read only mode for View. + +```javascript +let data = { + "@id": "Student/6bf39891b3aaab89771cecdd88a7771dad8c613cfc0530d07bb79bdde6d55d51", + "@type": "Student", + "favorite_subject": { + "@id": "Student/6bf39891b3aaab89771cecdd88a7771dad8c613cfc0530d07bb79bdde6d55d51/favorite_subject/Botony/aef9f22fe04ece720d19f6630edcad27f85e546810a907e4724ee0b57aba4b52", + "@type": "Botony", + "Grade": "A", + "Number_of_classes_attended": 4, + "course_start_date": "2022-08-17T09:21:09Z", + "number_of_assignments": 5 + }, + "second_favorite_subject": { + "@id": "Student/6bf39891b3aaab89771cecdd88a7771dad8c613cfc0530d07bb79bdde6d55d51/second_favorite_subject/Zoology/2f0ab12e837a6d1bdbb15b41e556940b288167e7909061e1b32e56d91005431b", + "@type": "Zoology", + "Grade": "A", + "Notes": "loves zoology", + "Number_of_classes_attended": 5, + "course_start_date": "2022-08-17T09:21:20Z" + }, + "studied": [ + { + "@id": "Student/6bf39891b3aaab89771cecdd88a7771dad8c613cfc0530d07bb79bdde6d55d51/studied/Botony/cc7e311138c8244f9ba043ad5f96e846c6a0961d9190210ee3f297f96976fd00", + "@type": "Botony", + "Grade": "A", + "Number_of_classes_attended": 67, + "course_start_date": "2022-08-17T09:21:53Z", + "number_of_assignments": 23 + }, + { + "@id": "Student/6bf39891b3aaab89771cecdd88a7771dad8c613cfc0530d07bb79bdde6d55d51/studied/Maths/666ce31233a834b895f4c42e72b0b5250188ea4dcf2f2bb8bc0dc32e710ceb26", + "@type": "Maths", + "Number_of_classes_attended": 45, + "course_start_date": "2022-08-17T09:21:37Z", + "level": "Medium", + "love_maths": true + } + ], + "study_time_table": [ + { + "@id": "Student/6bf39891b3aaab89771cecdd88a7771dad8c613cfc0530d07bb79bdde6d55d51/study_time_table/0/Zoology/d0cade9042e0baee8e0b91a8ed0e85ec09db40084d0ff56532d92a454ff67c57", + "@type": "Zoology", + "Grade": "A", + "Notes": "Best student", + "Number_of_classes_attended": 5, + "course_start_date": "2022-08-17T09:22:06Z" + }, + { + "@id": "Student/6bf39891b3aaab89771cecdd88a7771dad8c613cfc0530d07bb79bdde6d55d51/study_time_table/1/Botony/be10b1f3c70c1fe28eb52ad3113352356ae53d3375436ae6719abe019dc28f76", + "@type": "Botony", + "Grade": "B", + "Number_of_classes_attended": 54, + "course_start_date": "2022-08-17T09:22:32Z", + "number_of_assignments": 34 + } + ] +} + +return +``` \ No newline at end of file diff --git a/src/app/docs/clone-a-database-with-python/page.md b/src/app/docs/clone-a-database-with-python/page.md new file mode 100644 index 0000000..5595679 --- /dev/null +++ b/src/app/docs/clone-a-database-with-python/page.md @@ -0,0 +1,40 @@ +--- +title: Cloning a Database with the Python Client +slug: clone-a-database-with-python +seo: + title: Cloning a Database with the Python Client + description: A guide to show how to clone a database using the Python Client. + og_image: https://assets.terminusdb.com/docs/python-client-collaboration-clone.png +media: [] +--- + +> Before starting, you should create an account on TerminusCMS and get an API Token. You can read about this [here](/docs/how-to-connect-terminuscms/). + +This how-to will show how to clone a public database from TerminusCMS into your own TerminusCMS team. + +## Running the Python client with the API Token + +Be sure to construct the Python client object first, and set the appropriate authentication token. + +```python +from terminusdb_client import Client +client = Client('https://cloud.terminusdb.com/MyTeam') +client.connect(team='MyTeam', api_token='YOUR_API_TOKEN_HERE') +``` + +## Cloning the database + +Check the TerminusCMS dashboard for a database that you want to clone. In this how-to, we will be using the Lego database as an example. + +```python +clone_url = 'https://cloud.terminusdb.com/MyTeam/Terminusdb_demo/lego' +client.clonedb(clone_url, 'my_lego', remote_auth={'type': 'token': 'key': 'YOUR_API_TOKEN_HERE'}) +``` + +You now have the my\_lego database cloned in your TerminusCMS team. + +To verify whether the database has been successfully cloned, you can run: + +```python +client.get_database('my_lego') +``` \ No newline at end of file diff --git a/src/app/docs/clone-a-demo-terminuscms-project/page.md b/src/app/docs/clone-a-demo-terminuscms-project/page.md new file mode 100644 index 0000000..e7b4f64 --- /dev/null +++ b/src/app/docs/clone-a-demo-terminuscms-project/page.md @@ -0,0 +1,29 @@ +--- +title: Clone a Demo Project +slug: clone-a-demo-terminuscms-project +seo: + title: How to clone a TerminusCMS demo project + description: >- + A guide to show how to clone TerminusCMS demo projects to explore and play + with. + og_image: https://assets.terminusdb.com/docs/how-to-clone-a-demo.png +media: + - alt: clone a demo project to get started with TerminusCMS + caption: '' + media_type: Image + title: clone a demo project to get started with TerminusCMS + value: https://assets.terminusdb.com/docs/how-to-clone-a-demo.png +--- + +You can clone a demo database by logging in to TerminusCMS and selecting a Team. Once selected you will see a "Create New Data Product" or a number of possible data sets to clone. To clone the data set, just click on the card, and it will clone it into your currently selected team. + +This clone is now yours to use. It shares data with the original, so cloning is fast even if the data set is very large. When you make edits, they will be private to you, but it will be indistinguishable to you from editing the main database. + +To get started with a demo dataset you can choose any of: + +* Star Wars +* Lego +* Nuclear +* CAMS (Critical Asset Management System) + +![clone a demo project to get started with TerminusCMS](https://assets.terminusdb.com/docs/how-to-clone-a-demo.png) \ No newline at end of file diff --git a/src/app/docs/clone-a-project/page.md b/src/app/docs/clone-a-project/page.md new file mode 100644 index 0000000..cce5ea6 --- /dev/null +++ b/src/app/docs/clone-a-project/page.md @@ -0,0 +1,30 @@ +--- +title: Cloning a Database +slug: clone-a-project +seo: + title: Cloning a Database + description: A guide to show how to clone a database with the JS WOQLClient. + og_image: >- + https://github.com/terminusdb/terminusdb-web-assets/blob/master/docs/js-client-collaboration-clone.png?raw=true +media: [] +--- + +## Clone a database from terminusdb.com to your local machine + +Assuming you have [connected with the JavaScript Client](/docs/connect-with-the-javascript-client/) you can clone your database. + +Cloning a database pulls down a full copy of all data at that point in time, including all document and schema versions. + +If the database that you are cloning is not public, you need to provide an APIKey to the client setting the remoteAuth For more info visit the ['How to get your API key'](/docs/how-to-connect-terminuscms/) page. + +```python +const cloneLocally = async () => { + client.remoteAuth( {"type":"apikey" , "key":myApiKey}) + const cloneDetails = {remote_url: "http://cloud.terminusdb.com/MyTeam/MyTeam/mydb", + label "Cloned DB", + comment: "Cloned from mydb"} + await client.clonedb(cloneDetails, "new_mydb") + + console.log("the database has been cloned") +} +``` \ No newline at end of file diff --git a/src/app/docs/clone/page.md b/src/app/docs/clone/page.md new file mode 100644 index 0000000..05c4460 --- /dev/null +++ b/src/app/docs/clone/page.md @@ -0,0 +1,28 @@ +--- +title: Clone a Project +slug: clone +seo: + title: Clone a Project using the TerminusCMS Dashboard + description: A guide to show how to clone a project using the TerminusCMS dashboard. + og_image: https://assets.terminusdb.com/docs/project-admin.png +media: + - alt: Clone a project from the project home page + caption: '' + media_type: Image + title: Clone a project from the project home page + value: https://assets.terminusdb.com/docs/project-admin.png +--- + +From the project home page, on the right you will see the `Clone Project` section. + +![Clone a project from the project home page](https://assets.terminusdb.com/docs/project-admin.png) + +You can clone the project with - + +* The same name to another team - choose this from the dropdown menu +* A different name to another team +* A different name to the same team + +Press the `Clone` button. + +You will be directed to the cloned project. If you clone to a different team, you will also move teams. \ No newline at end of file diff --git a/src/app/docs/collaboration-with-javascript-client/page.md b/src/app/docs/collaboration-with-javascript-client/page.md new file mode 100644 index 0000000..760e009 --- /dev/null +++ b/src/app/docs/collaboration-with-javascript-client/page.md @@ -0,0 +1,14 @@ +--- +title: Collaboration Features with the JavaScript Client +slug: collaboration-with-javascript-client +seo: + title: Collaboration Features with the JavaScript Client + description: >- + How to guides to help you use TerminusCMS and TerminusDB's collaboration + features using the JavaScript Client + og_image: >- + https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png +media: [] +--- + +[Clone with JS](/docs/clone-a-project/)[Branch with JS](/docs/branch-a-project/)[Reset with JS](/docs/reset-a-project/)[Squash with JS](/docs/squash-projects/)[Time Travel with JS](/docs/time-travel-to-previous-commits/)[Diff & Patch with JS](/docs/diff-and-patch-operations/) \ No newline at end of file diff --git a/src/app/docs/collaboration-with-python-client/page.md b/src/app/docs/collaboration-with-python-client/page.md new file mode 100644 index 0000000..783f2f6 --- /dev/null +++ b/src/app/docs/collaboration-with-python-client/page.md @@ -0,0 +1,14 @@ +--- +title: Collaboration Features with the Python Client +slug: collaboration-with-python-client +seo: + title: Collaboration Features with the Python Client + description: >- + How to guides to help you get to grips with TerminusCMS and TerminusDB's + collaboration features using the Python Client. + og_image: >- + https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png +media: [] +--- + +[Branch with Python](/docs/branch-a-project-with-the-python-client/)[Clone with Python](/docs/clone-a-database-with-python/)[Reset with Python](/docs/reset-to-a-commit-with-python/)[Squash with Python](/docs/squash-a-project-with-python/)[Time Travel with Python](/docs/time-travel-with-python/) \ No newline at end of file diff --git a/src/app/docs/collaboration-with-terminuscms-dashboard/page.md b/src/app/docs/collaboration-with-terminuscms-dashboard/page.md new file mode 100644 index 0000000..8c45cde --- /dev/null +++ b/src/app/docs/collaboration-with-terminuscms-dashboard/page.md @@ -0,0 +1,14 @@ +--- +title: Collaboration Features with the TerminusCMS Dashboard +slug: collaboration-with-terminuscms-dashboard +seo: + title: Collaboration Features with the TerminusCMS Dashboard + description: >- + How to guides for leveraging collaboration features using TerminusCMS + dashboard. + og_image: >- + https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png +media: [] +--- + +[Branch with Dashboard](/docs/branch/)[Clone with Dashboard](/docs/clone/)[Reset with Dashboard](/docs/reset/)[Squash with Dashboard](/docs/squash/)[Time Travel with Dashboard](/docs/time-travel/) \ No newline at end of file diff --git a/src/app/docs/connect-to-a-database-with-python-client/page.md b/src/app/docs/connect-to-a-database-with-python-client/page.md new file mode 100644 index 0000000..a2a77fb --- /dev/null +++ b/src/app/docs/connect-to-a-database-with-python-client/page.md @@ -0,0 +1,36 @@ +--- +title: Connect to a Database using the Python Client +slug: connect-to-a-database-with-python-client +seo: + title: Connect to a Database using the Python Client + description: >- + A guide to show how to connect to a TerminusCMS project using the Python + client. + og_image: https://assets.terminusdb.com/docs/python-client-use-connect-database.png +media: [] +--- + +## TerminusCMS + +If you have created a Team in TerminusCMS, and put an [API key](/docs/how-to-connect-terminuscms/) in your environment you can connect to an existing database in the following way: + +```python +team = "MyTeam", +client.connect(db="nuclear", team=team, use_token=True) +``` + +## TerminusDB + +You can connect to a database with basic authorization just by using the `connect` member function. + +```python +team = "MyTeam", +client.connect(db="nuclear") +``` + +If you want to connect as a specific user and with a specific password, you can pass them here: + +```python +team = "MyTeam", +client.connect(db="nuclear", team=team, key="your_password") +``` \ No newline at end of file diff --git a/src/app/docs/connect-to-a-database/page.md b/src/app/docs/connect-to-a-database/page.md new file mode 100644 index 0000000..bde939e --- /dev/null +++ b/src/app/docs/connect-to-a-database/page.md @@ -0,0 +1,23 @@ +--- +title: Connect to a Database +slug: connect-to-a-database +seo: + title: Connect to a Database using the JavaScript Client + description: >- + A guide to show how to connect to an existing database using the TerminusDB + JavaScript Client. + og_image: >- + https://github.com/terminusdb/terminusdb-web-assets/blob/master/docs/js-client-use-connect.png?raw=true +media: [] +--- + +Assuming you have [connected with the JavaScript Client](/docs/connect-with-the-javascript-client/), connecting to a database is the same for TerminusDB and TerminusCMS - + +The example code below registers your database in woqlClient parameters and then all your calls will be made to this db - + +```javascript +client.db('ExampleDatabase') +client.getSchema().then(result=>{ + console.log(result) +}) +``` \ No newline at end of file diff --git a/src/app/docs/connect-with-apollo-client/page.md b/src/app/docs/connect-with-apollo-client/page.md new file mode 100644 index 0000000..ec2094d --- /dev/null +++ b/src/app/docs/connect-with-apollo-client/page.md @@ -0,0 +1,142 @@ +--- +title: Connect with Apollo Client +slug: connect-with-apollo-client +seo: + title: Connect with Apollo Client to use GraphQL with TerminusCMS + description: >- + A reference guide to get you up and running with TerminusDB & TerminusCMS + using GraphQL and Apollo Client + og_image: >- + https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png +media: [] +--- + +1. Install dependencies + +```bash +npm install @apollo/client graphql +``` + +2. Initialize ApolloClient and Connect with TerminusDB + +Import the required dependencies needed - + +```python +import { ApolloClient, InMemoryCache, ApolloProvider, gql,HttpLink,ApolloLink } from '@apollo/client'; +``` + +Or + +```javascript +const Apollo = require( '@apollo/client'); + +const { ApolloClient, InMemoryCache, concat, gql,HttpLink,ApolloLink } = Apollo +``` + +Initialize ApolloClient by passing its constructor with a configuration object with the TerminusDB server endpoint, user credentials and cache fields. + +> Extra information about the Apollo client cache can be found on their [website](https://www.apollographql.com/docs/react/caching/overview) + +## Connect with TerminusDB Local + +```javascript +const orgName = "myOrganizationName" +const dbName = "myDBname" +const myBranch = "main" + +const user = "admin" +const password = "mypass" +const userPassEnc = btoa(`${user}:${password}`) + +const terminusdbURL = `http://127.0.0.1:6363/api/graphql/${orgName}/${dbName}/local/branch/${myBranch}/` + +const httpLink = new HttpLink({ uri: terminusdbURL }); +const authMiddleware = new ApolloLink((operation, forward) => { + // add the authorization to the headers + operation.setContext(({ headers = {} }) => ({ + headers: { + ...headers, + authorization: `Basic ${userPassEnc}`} + })); + return forward(operation); +}) + +const cache = new InMemoryCache({ + addTypename: false +}); + +const value = concat(authMiddleware, httpLink) + +const apolloClient = new ApolloClient({ + cache:cache, + link: value, +}); + +// Query your database + +apolloClient + .query({ + query: gql` + query{ + Person{ + _id + name + } + } + `, + }) + .then((result) => console.log(result.data)) + .catch(err =>console.log(err.message)); +``` + +## Connect with TerminusCMS + +> You will need to [get your API key](/docs/how-to-connect-terminuscms/) to connect with terminusCMS + +```javascript +const orgName = "myOrganizationName" +const dbName = "myDBname" +const myBranch = "main" + +const myAPIToken = 'replaceYourToken' + +const terminusdbURL = `https://cloud.terminusdb.com/${orgName}/api/graphql/${orgName}/${dbName}/local/branch/${myBranch}/` + +const httpLink = new HttpLink({ uri: terminusdbURL }); +const authMiddleware = new ApolloLink((operation, forward) => { + // add the authorization to the headers + operation.setContext(({ headers = {} }) => ({ + headers: { + ...headers, + authorization: `Token ${myAPIToken}`} + })); + return forward(operation); +}) + +const cache = new InMemoryCache({ + addTypename: false +}); + +const value = concat(authMiddleware, httpLink) + +const apolloClient = new ApolloClient({ + cache:cache, + link: value, +}); + +// Query your database + +apolloClient + .query({ + query: gql` + query{ + Person{ + _id + name + } + } + `, + }) + .then((result) => console.log(result.data)) + .catch(err =>console.log(err.message)); +``` \ No newline at end of file diff --git a/src/app/docs/connect-with-python-client/page.md b/src/app/docs/connect-with-python-client/page.md new file mode 100644 index 0000000..19840fd --- /dev/null +++ b/src/app/docs/connect-with-python-client/page.md @@ -0,0 +1,60 @@ +--- +title: How to Connect with the Python Client +slug: connect-with-python-client +seo: + title: How to Connect with the Python Client + description: >- + A guide to show how to connect with the Python Client for TerminusDB and + TerminusCMS. + og_image: https://assets.terminusdb.com/docs/python-client-use-connect.png +media: [] +--- + +First, you should install the Python client. For installation instructions, see [the Python install instructions](/docs/install-the-python-client/). + +## Connecting with the Python Client + +Depending on whether you are connecting to an instance you have set up yourself, or whether you are using TerminusCMS in the cloud, there are two different methods of connection. + +In both cases, you should load TerminusDB in your script with the following: + +```python +from terminusdb_client import Client +``` + +### TerminusCMS + +The TerminusCMS endpoint has the form `https://cloud.terminusdb.com/TEAM/` where `TEAM` is the name of the team you are using in TerminusCMS for the data products you want to access. + +In order to connect to this team, you will need to [get your API key](/docs/how-to-connect-terminuscms/) after selecting the team you want to use. + +You should put your access token in your environment, using the environment variable `TERMINUSDB_ACCESS_TOKEN`. This ensures that scripts do not leak the access token when checked into source control. + +```bash +export TERMINUSDB_ACCESS_TOKEN="..." +``` + +At this point, you can connect with the API key using the code: + +```python +team="MyTeam" +client.connect(team=team, use_token=True) +``` + +### Connecting to a TerminusDB installation + +Whether you are connecting to a local docker, a local server, or on a server that you've set up somewhere, you can use the following to log in to TerminusDB. + +```python +team="MyTeam", +client = Client("http://localhost:6363/") +client.connect(team=team, password="MyPassword") +``` + +If you are using TerminusDB locally, and you have not set up a specific team, or changed the password differently from the default, you can simply connect with: + +```python +team="admin", +client = Client("http://localhost:6363/") +client.connect(team=team) +``` \ No newline at end of file diff --git a/src/app/docs/connect-with-the-javascript-client/page.md b/src/app/docs/connect-with-the-javascript-client/page.md new file mode 100644 index 0000000..47b524a --- /dev/null +++ b/src/app/docs/connect-with-the-javascript-client/page.md @@ -0,0 +1,54 @@ +--- +title: Connect with the JavaScript Client +slug: connect-with-the-javascript-client +seo: + title: Connect with the JavaScript Client + description: >- + A guide to show how to connect to TerminusDB and TerminusCMS using the + JavaScript Client + og_image: >- + https://github.com/terminusdb/terminusdb-web-assets/blob/master/docs/js-client-use-connect-with-js-client.png?raw=true +media: [] +--- + +Ensure you have installed the JavaScript Client. See here for [installation instructions](/docs/install-terminusdb-js-client/) + +## Connecting with the JavaScript Client + +Depending on whether you are connecting to an instance you have set up yourself, or whether you are using TerminusCMS in the cloud, there are two different methods of connection. + +In both cases, you should load the TerminusDB client in your script with the following: + +```javascript +const TerminusClient = require("@terminusdb/terminusdb-client"); +``` + +## TerminusCMS + +The TerminusCMS endpoint has the form https://cloud.terminusdb.com/TEAM/ where TEAM is the name of the team you are using in TerminusCMS for the data products you want to access. + +In order to connect to this team, you will need to [get your API key](/docs/how-to-connect-terminuscms/) after selecting the team you want to use. + +To create a client use the following code within your script, ensuring to use your credentials. + +```javascript +const client = new TerminusClient.WOQLClient('https://cloud.terminusdb.com/Team', + {user:"myemail@something.com", organization:'Team'}) +​ +client.setApiKey(MY_ACCESS_TOKEN) +``` + +## Connecting to a TerminusDB installation + +Whether you are connecting to a local docker, a local server, or a server that you've set up somewhere, you can use the following to log in to TerminusDB. + +```javascript +const client = new TerminusClient.WOQLClient(SERVER_URL,{user:"admin",key:"myKey"}) + +async function getSchema() { + client.db("DB_NAME") + const schema = await client.getSchema() +} +``` + +> Try out the [Getting Started with the TerminusDB JavaScript Client](https://github.com/terminusdb/terminusdb-tutorials/blob/main/getting_started/javascript-client/lesson_1.md) five-part tutorial to get to grips with it. \ No newline at end of file diff --git a/src/app/docs/connecting-to-graphql-reference/page.md b/src/app/docs/connecting-to-graphql-reference/page.md new file mode 100644 index 0000000..6913400 --- /dev/null +++ b/src/app/docs/connecting-to-graphql-reference/page.md @@ -0,0 +1,85 @@ +--- +title: Connecting to GraphQL Reference Guide +slug: connecting-to-graphql-reference +seo: + title: Connecting to GraphQL Reference Guide + description: >- + A reference guide detailing connecting to GraphQL with TerminusDB and + TerminusCMS. + og_image: >- + https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png +media: + - alt: GraphiQL interface screen shot + caption: '' + media_type: Image + title: GraphiQL interface screen shot + value: https://assets.terminusdb.com/docs/how-to-query-graphql.png +--- + +TerminusDB hosts a GraphQL endpoint at: + +```url +SERVERNAME/api/graphql/ORG/DATAPRODUCT +``` + +For instance, with a data product named `admin/people`, and a locally installed TerminusDB, you can query it at: + +```url +http://127.0.0.1:6363/api/graphql/admin/people +``` + +For TerminusCMS you can use the following URL: + +```url +https://cloud.terminusdb.com/ORG/api/graphql/ORG/DATA_PRODUCT +``` + +Where `ORG` is your organization, and `DATA_PRODUCT` is the name of your data product. + +## Authentication + +Since TerminusDB requires authentication to access data products, you will need to use the authentication method that has been configured for your server. + +### Basic Auth + +Using Basic Auth, the default method in locally installed TerminusDBs, you can supply the Authorization header, with your basic auth. (To generate a Basic Auth string, see [Basic Auth Generator](https://www.blitter.se/utils/basic-authentication-header-generator/)). + +For example, if you would like to connect to `admin/people` with the apollo client to download the associated GraphQL schema, simply use: + +```bash +npx apollo client:download-schema --endpoint=http://127.0.0.1:6363/api/graphql/admin/people schema.graphql --header='Authorization: Basic YWRtaW46cm9vdA==' +``` + +### TerminusCMS + +In TerminusCMS you can use an API key with the following header. + +For instance, with the apollo client, you can download your schema as follows: + +```bash +npx apollo client:download-schema --endpoint=https://cloud.terminusdb.com/TEAM/api/graphql/TEAM/people schema.graphql --header="Authorization: Token $(cat ~/my_token_file)" +``` + +Where `my_token_file` contains an API token for TerminusCMS. + +## GraphiQL + +![GraphiQL interface screen shot](https://assets.terminusdb.com/docs/how-to-query-graphql.png) + +TerminusDB ships with a GraphiQL graphical GraphQL query interface and schema browser. This is a quick way to get acquainted with GraphQL in TerminusDB. + +You can reach this browser at: + +```url +http://127.0.0.1:6363/api/graphiql/admin/people +``` + +You will also need to set your Authorization header in the Header dialog box at the bottom center. + +For instance, in the default install, as: + +```json +{ + "Authorization": "Basic YWRtaW46cm9vdA==" +} +``` \ No newline at end of file diff --git a/src/app/docs/content-curation-terminuscms-tour/page.md b/src/app/docs/content-curation-terminuscms-tour/page.md new file mode 100644 index 0000000..2ce156b --- /dev/null +++ b/src/app/docs/content-curation-terminuscms-tour/page.md @@ -0,0 +1,114 @@ +--- +title: Content & Data Curation in TerminusCMS +slug: content-curation-terminuscms-tour +seo: + title: Content & Data Curation - TerminusCMS Tour + description: >- + Technical and non-technical users can curate content and data using the + TerminusCMS dashboard + og_image: >- + https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png +media: + - alt: TerminusCMS document explorer + caption: '' + media_type: Image + title: TerminusCMS document explorer + value: https://assets.terminusdb.com/docs/document-explorer.png + - alt: Document display + caption: '' + media_type: Image + title: Document display + value: https://assets.terminusdb.com/docs/document-display.png + - alt: GraphQL query generated from filter results + caption: '' + media_type: Image + title: GraphQL query generated from filter results + value: https://assets.terminusdb.com/docs/document-view-graphql-query.png + - alt: '' + caption: '' + media_type: Image + title: Image 4 + value: https://assets.terminusdb.com/docs/add-new-document.png + - alt: Linking to other documents + caption: '' + media_type: Image + title: Linking to other documents + value: https://assets.terminusdb.com/docs/linking-to-other-documents.png + - alt: 'Unfolded documents ' + caption: '' + media_type: Image + title: 'Unfolded documents ' + value: https://assets.terminusdb.com/docs/unfolded-documents.png + - alt: How to edit documents in the TerminusCMS dashboard + caption: '' + media_type: Image + title: How to edit documents in the TerminusCMS dashboard + value: https://assets.terminusdb.com/docs/edit-documents.png +--- + +TerminusCMS automatically generates document editing frames from the schema. Users can then add, edit, and delete content and data as needed. + +First, navigate to the document explorer from the left menu - + +![TerminusCMS document explorer](https://assets.terminusdb.com/docs/document-explorer.png) + +The document explorer lists all of the document types within the schema and displays how many of each there are. + +The left-hand menu also details the document names with the ability to search for something specific. + +## Filtering and Searching Documents + +Clicking on a document type displays a list of matching documents - + +![Document display](https://assets.terminusdb.com/docs/document-display.png) + +The document table allows users to - + +* Choose the properties to display in the table +* Search properties +* Perform advanced filters + +## GraphQL Query + +The GraphQL tab provides front-end developers with an overview of the GraphQL query structure of the document and includes JSON-LD details for applied filters - + +![GraphQL query generated from filter results](https://assets.terminusdb.com/docs/document-view-graphql-query.png) + +## Adding, Editing, & Deleting Docs + +In order to make changes to content and data, users need to create a change request. This is automated when selecting to edit, delete, or add content. Please refer to the [change request workflows section](/docs/change-request-workflows-terminuscms-tour/) for full details. + +A change request dialogue box opens and prompts the user to add a change request title and description. They can then go and make changes. + +### Adding Content & Data + +To add content and data, either click on the + symbol next to the document type name from the left menu or select the 'add new' button from the document explorer page - + +![](https://assets.terminusdb.com/docs/add-new-document.png) + +The document editing frame is generated from the schema and this includes things like - + +* Validation +* Localization +* Markdown +* Property types such as data, currency, and lists. + +The editing interface can also include links to other documents and subdocuments and this is all specified in the schema. The example below is a test project working on the TerminusDB documentation and features links to other document types. + +A page for example can link to sections and a body so the same piece of content can be used in multiple locations. The schema can also specify that the linked document types unfolded so they display ready for editing within a piece of content - + +![Linking to other documents](https://assets.terminusdb.com/docs/linking-to-other-documents.png) + +![Unfolded documents ](https://assets.terminusdb.com/docs/unfolded-documents.png) + +For details on how to specify markdown, unfolded, and other properties within the schema, please read the [schema reference guide](/docs/schema-reference-guide/). + +### Editing and Deleting Content & Data + +To edit a document, select the document to edit by clicking on it from the document explorer. This will open up the document for editing. + +Make the changes and ensure to press select submit to ensure changes are saved. + +![How to edit documents in the TerminusCMS dashboard](https://assets.terminusdb.com/docs/edit-documents.png) + +To delete a document, select the red bin icon. A warning message will display to confirm the deletion. \ No newline at end of file diff --git a/src/app/docs/create-a-database/page.md b/src/app/docs/create-a-database/page.md new file mode 100644 index 0000000..6d8af53 --- /dev/null +++ b/src/app/docs/create-a-database/page.md @@ -0,0 +1,37 @@ +--- +title: Create a Database +slug: create-a-database +seo: + title: Create a Database using the JavaScript Client + description: >- + A guide to show how to create a database using the TerminusDB JavaScript + Client. + og_image: >- + https://github.com/terminusdb/terminusdb-web-assets/blob/master/docs/js-client-use-create-a-db.png?raw=true +media: [] +--- + +To create a database with an already [connected client](/docs/connect-with-the-javascript-client/), you can write: + +```javascript +const createNewDB = async () => { + try { +​ + await client.createDatabase('ExampleDatabase', { + label: "ExampleDatabase", + comment: "Created new ExampleDatabase", + schema: true + }); +​ + console.log("Database created Successfully!") +​ + } catch (err) { + console.error(err) + } +}; +​ +``` + +After the database is created the client will be connected to it. + +> Try out the [Getting Started with the TerminusDB JavaScript Client](https://github.com/terminusdb/terminusdb-tutorials/blob/main/getting_started/javascript-client/lesson_1.md) five-part tutorial to get to grips with it. \ No newline at end of file diff --git a/src/app/docs/create-a-project-with-terminuscms/page.md b/src/app/docs/create-a-project-with-terminuscms/page.md new file mode 100644 index 0000000..4c763b0 --- /dev/null +++ b/src/app/docs/create-a-project-with-terminuscms/page.md @@ -0,0 +1,30 @@ +--- +title: Create a Project/Data Project in TerminusCMS +slug: create-a-project-with-terminuscms +seo: + title: How to create a project with TerminusCMS + description: >- + A how-to guide showing you how to create a new project using the TerminusCMS + dashboard + og_image: https://assets.terminusdb.com/docs/new-data-product.png +media: + - alt: how to create a project in the TerminusCMS dashboard + caption: '' + media_type: Image + title: how to create a project in the TerminusCMS dashboard + value: https://assets.terminusdb.com/docs/new-data-product.png +--- + +Follow this instructions to create a project/data product in TerminusCMS - + +1. Login to the dashboard at [dashboard.terminusdb.com](https://dashboard.terminusdb.com). +2. Select the team that you want the project to live. +3. Choose 'New Data Product' from the top menu. +4. Provide your project ID - this can only contain alphanumeric characters and underscores. +5. Name your project. +6. Provide a description for your project. This is useful if you are collaborating to provide context to other users. +7. Select 'Create New Data Product' button. + +![how to create a project in the TerminusCMS dashboard](https://assets.terminusdb.com/docs/new-data-product.png) + +Your project is created and you can now start working with it. To access it at any time, select the project from the list of projects on left of the dashboard. \ No newline at end of file diff --git a/src/app/docs/create-a-team-with-terminuscms/page.md b/src/app/docs/create-a-team-with-terminuscms/page.md new file mode 100644 index 0000000..0b62384 --- /dev/null +++ b/src/app/docs/create-a-team-with-terminuscms/page.md @@ -0,0 +1,39 @@ +--- +title: Create a Team with the TerminusCMS Dashboard +slug: create-a-team-with-terminuscms +seo: + title: Create teams using TerminusCMS + description: A how-to guide for creating teams using the TerminusCMS dashboard. + og_image: >- + https://assets.terminusdb.com/docs/manage-your-projects-create-a-new-team-2.pn +media: + - alt: select profile from the top menu + caption: '' + media_type: Image + title: select profile from the top menu + value: >- + https://assets.terminusdb.com/docs/manage-your-projects-create-a-new-team.png + - alt: Name your team and press create new team button + caption: '' + media_type: Image + title: Name your team and press create new team button + value: >- + https://assets.terminusdb.com/docs/manage-your-projects-create-a-new-team-2.png +--- + +Follow these instruction to create a new team in the TerminusCMS dashboard - + +> Note, if it is your first time logging in you will see the pricing page. Select Community Package to proceed and follow these instructions.\* + +1. In team selection screen, choose the team that was automatically generated upon your sign up (or any other). +2. In the resulting screen, choose profile by selecting the arrow next to your profile avitar/initials. + +![select profile from the top menu](https://assets.terminusdb.com/docs/manage-your-projects-create-a-new-team.png) + +3. Under your profile details, click the 'Create a New Team' button. + +![Name your team and press create new team button](https://assets.terminusdb.com/docs/manage-your-projects-create-a-new-team-2.png) + +4. Name your team and press the 'Create a New Team' button. + +You are now ready to [add projects](/docs/create-a-project-with-terminuscms/) to your team and [invite collaborators](/docs/invite-users-using-terminuscms/). \ No newline at end of file diff --git a/src/app/docs/create-database-with-python-client/page.md b/src/app/docs/create-database-with-python-client/page.md new file mode 100644 index 0000000..2d48db6 --- /dev/null +++ b/src/app/docs/create-database-with-python-client/page.md @@ -0,0 +1,30 @@ +--- +title: Create a Database with the Python Client +slug: create-database-with-python-client +seo: + title: Create a Database with the Python Client + description: >- + A guide showing how to create a TerminusDB or TerminusCMS database using the + Python Client. + og_image: https://assets.terminusdb.com/docs/python-client-use-create-a-db.png +media: [] +--- + +To create a database with an already [connected client](/docs/connect-with-python-client/), you can write: + +```python +dbid="MyDatabase" +label="My Database", +description="This is a database which is mine" +prefixes = {'@base' : 'iri:///mydatabase/', + '@schema' : 'iri:///mydatabase#'} +team="MyTeam" +client.create_database( + dbid, + team, + label=label, + description=description, + prefixes=prefixes) +``` + +This creates a new database called `"MyDatabase"` using the descriptive label `"My Database"`. It starts the database with special `@base` and `@schema` prefixes, all in the team named `"MyTeam"` \ No newline at end of file diff --git a/src/app/docs/curate-and-import-data/page.md b/src/app/docs/curate-and-import-data/page.md new file mode 100644 index 0000000..33d778b --- /dev/null +++ b/src/app/docs/curate-and-import-data/page.md @@ -0,0 +1,14 @@ +--- +title: How to Curate & Import Data +slug: curate-and-import-data +seo: + title: How to Curate & Import Data + description: >- + How to guides for curating and importing data into TerminusCMS and + TerminusDB + og_image: >- + https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png +media: [] +--- + +[Curate with Dashboard](/docs/use-the-admin-ui-curate-and-import-data/)[Import with Python](/docs/import-data-with-python-client/) \ No newline at end of file diff --git a/src/app/docs/datalog-explanation/page.md b/src/app/docs/datalog-explanation/page.md new file mode 100644 index 0000000..c8f6689 --- /dev/null +++ b/src/app/docs/datalog-explanation/page.md @@ -0,0 +1,64 @@ +--- +title: Datalog Explanation +slug: datalog-explanation +seo: + title: Datalog Explanation | TerminusCMS & TerminusDB + description: A brief explanation of Datalog and its benefits in database queries. + og_image: >- + https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png +media: [] +--- + +## What is Datalog? + +Datalog, a declarative subset of Prolog, is a flexible and powerful declarative query language proficient at dealing with the complex and multi-hop relationships that occur in graphs. Graph query languages not based on Datalog lack the level of clarity, simplicity, and logical framework that Datalog provides. + +### Predicates + +Similar to its super-set Prolog, Datalog is based on **predicates**. Predicates are similar to relations in relational languages such as SQL. Queries can use predicates with _logical variables_ to represent unknowns to which meaning is assigned based on a logical formula. Meaning is assigned by joining predicates with logical connectives or operators such as `and` and `or` and [unifying](#unificationandquery) logical variables. Repeated occurrences of the same variable require the query has identical solutions at given points. + +### Advantages of Datalog in queries + +Variables in Datalog are restricted to finite **atomic** values. The use of atomic values simplifies query optimization and guarantees the termination of queries even in the event of recursion. The finite atomic values restriction is relaxed in [WOQL](/docs/woql-explanation/) (the Web Object Query Language used in TerminusDB) to enable lists that are useful in aggregation and dis-aggregation queries such as `group by` and `member` respectively. However, TerminusDB retains the pure declarative quality of Datalog. + +#### Datalog compared with SQL + +Compared with relational databases, Datalog provides a more flexible logical framework that is easier to extend consistently with recursive and path-centric operations. Datalog also enables complex joins to be expressed more elegantly with a less verbose syntax. Datalog represents a stepping-stone from relational languages such as SQL to more fully-featured programming languages while retaining the declarative, robust, pervasive, and resilient properties of query languages. + +### Unification and query + +Unification in Datalog is the process of finding values of logical variables which are consistent for a given logical sentence or query. + +A logical variable for a query can only take on one value in a given solution. If the variable is used in two places then these two values must be the same. We can get the concrete value of solutions for a logical value either from an equation or from the definition of a predicate. + +When we search using datalog in WOQL, we implicitly ask for _all_ solutions (this can be restricted by using additional words such as `limit(n,Q)`). This gives us back something that looks quite similar to a table, but it is a list of solutions with bindings for all logical variables that took on a value during the course of searching for the solutions to the query. + +#### An Example + +Perhaps the most important predicate in WOQL is `triple` which gives results about edges in the current graph. + +Our logical variables are represented as strings with the prefix `"v:"`. Our edges are represented by having a position for the _subject_, _predicate_ and _object_ of the edge in the graph. The _predicate_ is the labeled name of the edge, and the _subject_ and _object_ nodes the source, and target respectively. + +```datalog +triple("v:Subject", "v:Predicate", "v:Object") +``` + +With this query, we simply get back the solutions for every possible assignment of subjects, predicates, and objects that our graph currently has, that is, all edges in the graph. The concrete referents for the subject, predicate and object are data points represented by a URI (a universal resource indicator). + +```javascript +triple("v:Subject", "v:Predicate", "v:Intermediate") +triple("v:Intermediate", "v:Predicate", "v:Object") +``` + +In this second query, we have _joined_ two predicates together by requiring that the target of the first edge is the source of the second. This gives us back all two-hop paths possible in the graph. + +```javascript +triple("My_Object", "v:Predicate", "v:Intermediate") +triple("v:Intermediate", "v:Predicate", "v:Object") +``` + +And here we refer to a specific starting node and search for every two-hop path starting from _this_ object. + +### Further Reading + +[**Documents in a knowledge graph and how to use them**](/docs/documents-explanation/). \ No newline at end of file diff --git a/src/app/docs/delete-a-document/page.md b/src/app/docs/delete-a-document/page.md new file mode 100644 index 0000000..ac3e072 --- /dev/null +++ b/src/app/docs/delete-a-document/page.md @@ -0,0 +1,22 @@ +--- +title: Delete a Document +slug: delete-a-document +seo: + title: Delete a Document using the JavaScript Client + description: >- + A guide to show how to delete a document in TerminusDB and TerminusCMS using + the JavaScript Client. + og_image: >- + https://github.com/terminusdb/terminusdb-web-assets/blob/master/docs/js-client-use-delete-a-document.png?raw=true +media: [] +--- + +In order to delete a document you need to know the document id. + +```javascript +const deleteDoc = async () => { + const docId = "Player/George" + await client.deleteDoc({id:docId}); + console.log(`the ${docId} has been deleted`) +} +``` \ No newline at end of file diff --git a/src/app/docs/delete-documents-with-python-client/page.md b/src/app/docs/delete-documents-with-python-client/page.md new file mode 100644 index 0000000..e97e76e --- /dev/null +++ b/src/app/docs/delete-documents-with-python-client/page.md @@ -0,0 +1,18 @@ +--- +title: Delete a Document with the Python Client +slug: delete-documents-with-python-client +seo: + title: How to delete a document using the Python client + description: >- + A guide to show how to delete a document from TerminusCMS using the Python + Client + og_image: https://assets.terminusdb.com/docs/python-client-use-delete-a-document.png +media: [] +--- + +In order to delete a document you need to know the document id. + +```python +doc_id = "Player/George" +client.delete_document(doc_id) +``` \ No newline at end of file diff --git a/src/app/docs/delete-documents-with-woql/page.md b/src/app/docs/delete-documents-with-woql/page.md new file mode 100644 index 0000000..759f491 --- /dev/null +++ b/src/app/docs/delete-documents-with-woql/page.md @@ -0,0 +1,32 @@ +--- +title: Delete a document in WOQL +slug: delete-documents-with-woql +seo: + title: How to delete documents using WOQL + description: A how-to guide showing how to construct a WOQL query to delete documents. + og_image: https://assets.terminusdb.com/docs/woql-delete-documents.png +media: [] +--- + +> To use this HowTo, first [clone the Star Wars demo](/docs/clone-a-demo-terminuscms-project/) into your team on TerminusCMS. You will then have access to the data needed for this tutorial. + +Deleting a document in WOQL is possible using the `delete_document` keyword. + +First, let's insert a document. + +```javascript +let v = Vars("id"); +insert_document(doc({'@type' : 'Planet', label: 'Planet-X'}), v.id) +``` + +Supposing we get back the following: + +```json +"Planet/01dd97a75800f01f43ab7ab55b6dd08f198dd34d2bdbbeeb7bf4edee45111863" +``` + +Now we can delete it with the following: + +```javascript +delete_document("Planet/01dd97a75800f01f43ab7ab55b6dd08f198dd34d2bdbbeeb7bf4edee45111863") +``` \ No newline at end of file diff --git a/src/app/docs/diff-and-patch-operations/page.md b/src/app/docs/diff-and-patch-operations/page.md new file mode 100644 index 0000000..f7f280c --- /dev/null +++ b/src/app/docs/diff-and-patch-operations/page.md @@ -0,0 +1,97 @@ +--- +title: Diff and Path with JavaScript +slug: diff-and-patch-operations +seo: + title: Diff an Object or a Database Branch with the JS Client + description: >- + A guide to show how to use the JS Client to diff an object or a database + branch. + og_image: >- + https://github.com/terminusdb/terminusdb-web-assets/blob/master/docs/js-client-collaboration-diff-patch.png?raw=true +media: [] +--- + +## Diff an object + +Return the diff from two objects + +```javascript +const diffObjects = async () => { + const before = { "@id" : "Person/Jane", "@type" : "Person", "name" : "Jane"} + const after = { "@id" : "Person/Jane", "@type" : "Person", "name" : "Janine"} + const options = {keep:{ "@id" : true, "name" : true }} + + //in the options you can list the properties that you would like to see in the diff result. + const diffResult = await client.getJSONDiff = function (before, after, options) { + + console.log("the diff result ", JSON.stringify(diffResult,null,4)) +} +``` + +Here is an example of a diff result between two objects + +```json +{ + "name":{ + "@op":"ValueSwap", + "@before":"Jane", + "@after":"Janine" + }, + "@id":"Person/Jane" +} +``` + +## Get the patch of differences between branches or commits. + +```javascript +const diffDocsVersion = async () => { + const beforeVersion = "a73ssscfx0kke7z76083cgswszdxy6l" + const afterVersion = "73rqpooz65kbsheuno5dsayh71x7wf4" + const options = {keep:{ "@id" : true, "name" : true }} + + const diffResult = await client.getVersionDiff = function (beforeVersion, afterVersion, null, options) { + + console.log("the diff result ", JSON.stringify(diffResult,null,4)) +} +``` + +Here is the example result + +```json +[ + { + "@id":"Person/Jane", + "@type":"Person", + "name" : "Jane" + "age":{ + "@after":23, + "@before":22, + "@op":"SwapValue" + } + }, + { + "@id":"Person/Tom", + "@type":"Person", + "name" : "Tom" + "age":{ + "@after":10, + "@before":null, + "@op":"SwapValue" + } + } +] +``` + +## Get the patch of difference between a document and an object. + +```javascript +const diffDocToObject = async () => { + const jsonObject = { "@id" : "Person/Jane", "@type" : "Person", "name" : "Jannet"} + const options = {keep:{ "@id" : true, "name" : true }} + + //in the options you can list the properties that you would like to see in the diff result. + const diffResult = await client.getVersionObjectDiff = function ("main", jsonObject, "Person/Jane", options) { + + console.log("the diff result ", JSON.stringify(diffResult,null,4)) +} +``` \ No newline at end of file diff --git a/src/app/docs/document-insertion/page.md b/src/app/docs/document-insertion/page.md new file mode 100644 index 0000000..fa86b63 --- /dev/null +++ b/src/app/docs/document-insertion/page.md @@ -0,0 +1,446 @@ +--- +title: Document Insertion Reference Guide +slug: document-insertion +seo: + title: TerminusCMS/DB Document Insertion Reference Guide + description: A reference guide for the TerminusCMS/DB document interface. +media: [] +--- + +FIXME: Tables need to be updated to new MarkDoc + +The document interface consists of two endpoints. The first endpoint, `document`, is how we get documents into and out of TerminusDB. Since schemas consist of documents too, this is also how you'd update the schema. + +The second endpoint, `schema`, is how we can easily get schema information out of TerminusDB. While technically it is possible to get all schema information through the document interface, the schema interface is more convenient for this purpose, as it takes class inheritance into account to give a complete image of all the properties that are usable on a certain class. + +## The document endpoint + +### Getting documents + +All document retrieval is done through GET requests on the following endpoint: + +```http +GET /api/document/ +``` + +Where resource path is the usual strings like `admin/foo` for database foo, or `_system` for the system graph, or `admin/foo/_meta` for the metadata graph of the foo database, etc. + +By default, this will return a stream of all documents to be found at this location. What exactly is returned can be modified using parameters, which are to be provided as query parameters. + +#### Parameters + +parameter + +default + +explanation + +graph\_type + +either instance or schema. Used to switch between getting documents from the instance or the schema graph. + +type + +If given, only documents of the given type are returned. + +id + +If given, only the document with the given ID is returned. + +prefixed + +true + +If true (the default), return IRIs using a prefixed notation wherever possible. If false, full IRIs are used. + +minimized + +false + +If true, forego pretty printing, and return the documents with very little whitespace. Each json document will be on its own line. + +unfold + +true + +If true (the default), any subdocuments contained in the returned document are returned too. If false, these are referred to by their ID instead. + +skip + +0 + +How many results to skip + +count + +How many results to return. If this option is absent, all results are returned. + +as\_list + +false + +If true, don't return a stream of json objects, but a list. This makes parsing the json easier in some environments. + +#### Alternate query mechanism + +The above table shows parameters that are supposed to be provided as query parameters. There's however another mechanism, where instead, the parameters are passed in as a posted JSON document. In this calling style, an additional parameter is allowed, `"query"`, by which the returned documents are filtered by matching against some template. + +The alternative method uses a POST rather than a get, specifies the header `X-HTTP-Method-Override: GET`, and posts a JSON document with the various query parameters instead: + +```json +{ + "@rdf:type": "Person", + "count": 10, + "query": { "age": 42 }, +} +``` + +The above example would find the first 10 documents of class `Person`, whose age is 42. + +This may provide a more convenient style for querying from a library, especially when a (large) query document has to be provided for filtering purposes. However, unlike a pure GET request with query parameters, a POST with a method override does not result in a page that can be bookmarked in a browser. If that is desirable, the GET style is better. + +### Posting documents + +All new document submission is done through POST requests on the following endpoint: + +```http +POST /api/document/ +``` + +Where resource path is the usual strings like `admin/foo` for database foo, or `_system` for the system graph, or `admin/foo/_meta` for the metadata graph of the foo database, etc. + +The documents to be submitted are given as post data. Multiple documents can be specified at once, either as a stream of JSON objects or as a JSON list containing the documents to be inserted. If a document is specified that already exists, and overwrite is false (the default), an error is returned. + +#### Parameters + +parameter + +default + +explanation + +author + +The commit author + +message + +The commit message + +graph\_type + +instance + +either instance or schema. Used to switch between submitting to the instance or the schema graph. + +full\_replace + +false + +If true, all existing documents are deleted before inserting the posted documents. This allows the full replacement of the contents of a database. This is especially useful for replacing the schema. + +raw\_json + +false + +If true, the input documents are treated as raw JSON , inserted as type `sys:JSONDocument` and are not subject to schema restrictions. + +#### Result + +After a successful post, the result will be a list of ids of the newly added documents. + +### Replacing documents + +Existing documents can be replaced through a PUT request on the following endpoint: + +```http +PUT /api/document/ +``` + +Where resource path is the usual strings like `admin/foo` for database foo, or `_system` for the system graph, or `admin/foo/_meta` for the metadata graph of the foo database, etc. + +The documents to be submitted are given as post data. Multiple documents can be specified at once, either as a stream of JSON objects or as a JSON list containing the documents to be replaced. If a document is specified that does not exist in the database, an error is returned unless `create` is set to `true` in which case it is inserted. + +#### Parameters + +parameter + +default + +explanation + +author + +The commit author + +message + +The commit message + +graph\_type + +instance + +either instance or schema. Used to switch between submitting to the instance or the schema graph. + +create + +false + +insert if the document was not already in the database. + +raw\_json + +false + +If true, the replaced documents are treated as raw JSON , they must be replacing a document of type `sys:JSONDocument` and they are not subject to schema restrictions. + +### Deleting documents + +Existing documents can be deleted through a DELETE request on the following endpoint: + +```http +DELETE /api/document/ +``` + +Where resource path is the usual strings like `admin/foo` for database foo, or `_system` for the system graph, or `admin/foo/_meta` for the metadata graph of the foo database, etc. + +#### Parameters + +parameter + +default + +explanation + +author + +The commit author + +message + +The commit message + +graph\_type + +instance + +either instance or schema. Used to switch between submitting to the instance or the schema graph. + +id + +If given, the document to delete. If not given, it is expected that the post data will contain a list of ids to delete. + +nuke + +false + +If true, delete everything at this resource location (dangerous!). + +#### Specifying what documents to delete + +As shown above, deleting a single document can be done through query parameters alone. If multiple documents are to be deleted at once, a document has to be posted of the following format: + +```json +[ "..id 1..", + "..id 2..", + ... +] +``` + +In other words, a JSON list of document IDs. + +### ID Capture for Doc Insert & Replace + +When inserting or replacing several documents at once, it may occur that some of these documents need to refer to each other. However, at insertion time, you may not know what the IDs of the new documents are going to be. This is especially the case for document types that generate their identifier randomly, but even for non-random key types, it may be convenient to rely on the server's ID generation algorithm, rather than trying to predict what IDs will get generated. Therefore, in order to support cross-references between newly inserted documents, the document interface allows you to capture newly generated document IDs in a variable, and then refer to that variable later in other documents. + +#### Capturing an identifier into a variable + +When inserting or replacing a document that we want to refer to in another document inserted in the same operation, you can use a `@capture` key in the document to associate the newly generated identifier with a variable. For example, + +```json +{ "@type": "Person", + "@capture": "Id_Tom", + "name": "Tom" +} +``` + +This will store the newly generated ID in a variable called `ID_Tom` for the duration of the document insert/replace operation. + +It is allowed to capture an ID and then never actually refer to it. + +It is an error to capture the same variable twice. Doing so will result in a `api:CaptureIdAlreadyBound` error with the following shape: + +```json +{"@type": "api:CaptureIdAlreadyBound", + "api:capture": "..capture id..", + "api:document": {..document where previously captured variable was captured again..} +``` + +#### Referring to an identifier using a variable + +When inserting or replacing a document that needs to refer to another document inserted in the same operation, you can use a json dictionary of the form `{"@ref": "..id.."}` in place of an ordinary id. For example, + +```json +{ "@type": "Person", + "name": "Jerry", + "rival": {"@ref": "Id_Tom"} +} +``` + +It is an error to refer to a variable that is never captured. Doing so will result in a `api:NotAllCapturesFound` error of the following shape: + +```json +{ "@type": "api:NotAllCapturesFound", + "api:captures": [..list of capture ids that were referenced but not found..] +} +``` + +#### Ordering of documents + +ID captures and ID references can be done in any order. That means that when you are submitting several documents, you're allowed to refer to a captured ID in an earlier document. This also allows you to do cross-references, where two documents refer to each other: + +```json +{ "@type": "Person", + "@capture": "Id_Tom", + "name": "Tom", + "rival": {"@ref": "Id_Jerry"} +} +{ "@type": "Person", + "@capture": "Id_Jerry", + "name": "Jerry", + "rival": {"@ref": "Id_Tom"} +} +``` + +In this example, Tom refers to Jerry, even though at that point in the submitted document stream, Jerry has not yet been processed. This is not a problem - both Tom and Jerry will get inserted referring to each other. + +#### Self-reference + +Using ID capture, it is possible to create a document that refers to itself: + +```json +{ "@type": "Person", + "@capture": "Captured_Id", + "name": "Elmo", + "friend": {"@ref": "Captured_Id"} +} +``` + +This will make Elmo be his own friend. + +#### ID capture only works within a single operation + +It is important to keep in mind that the ID capture mechanism only works within a single call to the document api. It is not possible to capture an ID in one operation, and then refer to it in a second operation. The `@capture` and `@ref` instructions do not get saved into the database. They are processed immediately and are then forgotten. + +If you need to refer to a document already in the database, the only way to do so is by referring to its ID. + +## The schema endpoint + +The schema endpoint can be used to query information about classes in a resource. These queries happen through a GET on the following endpoint: + +```http +GET /api/schema/ +``` + +Where resource path is the usual strings like `admin/foo` for database foo, or `_system` for the system graph, or `admin/foo/_meta` for the metadata graph of the foo database, etc. + +The purpose of this endpoint is to quickly discover the supported fields of a particular type. The primary envisioned use case for this is the automatic generation of forms and other UI elements, as well as client code generation. + +#### Parameters + +parameter + +default + +explanation + +type + +If given, the type to get information for. If omitted, information for all types is returned. + +#### Result + +The result of this GET is a stream of documents describing all the types in a particular resource. + +### Schema-checking and schemaless mode + +The schema endpoint can also be used to switch between schema checking and schemaless mode. + +Switching between checking or not checking does not delete the schema itself. After disabling schema checking it is still possible to update the schema or to query it through the schema endpoint. However, when disabled, it is possible to submit documents that do not match the schema. Re-enabling schema checking is only possible if all the documents in the given resource match the current schema. + +```http +POST /api/schema/ +``` + +#### Parameters + +parameter + +default + +explanation + +author + +The commit author + +message + +The commit message + +schema\_checking + +Value should be either enabled or disabled + +## The apply endpoint + +The schema endpoint can be used to query information about classes in a resource. These queries happen through a GET on the following endpoint: + +```http +POST /api/schema/ +``` + +Where resource path is the usual strings like `admin/foo` for database foo, or `admin/foo/local/branch/dev` for the `dev` branch of `admin/foo`. + +The purpose of this endpoint is to take the difference between any two commits and apply them to a branch. + +#### Parameters + +parameter + +default + +explanation + +before\_commit + +The first commit to compare in order to produce a diff + +after\_commit + +The last commit to compare in order to produce a diff + +commit\_info + +A JSON document with author and message + +match\_final\_state + +true + +Ignores conflicts if the final state would remain the same + +type + +squash + +What type of application to perform - currently can only be squash + +#### Result + +The result of this POST request is either an updated branch with a successful application of the difference between two commits, or an error giving the reason for an unresolvable conflict. + +## Further Reading + +**\*_[](/docs/documents-explanation/)_**_[Documents in a knowledge graph and how to use them](/docs/documents-explanation/)_[\*](/docs/documents-explanation/). \ No newline at end of file diff --git a/src/app/docs/document-ui-sdk-data-types/page.md b/src/app/docs/document-ui-sdk-data-types/page.md new file mode 100644 index 0000000..1d253ca --- /dev/null +++ b/src/app/docs/document-ui-sdk-data-types/page.md @@ -0,0 +1,381 @@ +--- +title: Documents UI SDK Data Types +slug: document-ui-sdk-data-types +seo: + title: Documents UI SDK Data Types + description: Understand the different data types to build data driven user interfaces + og_image: >- + https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png +media: [] +--- + +The TerminusDB documents user interface generates forms representing the properties or fields of document/s in your schema. For data entry, each field is one of several data types and is mandatory by default. Schema definitions enable the linking of documents and the specification of sets. + +[**Click here to find out how to get started with the Document UI SDK**](/docs/document-ui-sdk/) + +## Demo + +Take a look at the [**Document UI SDK Playground**](https://documents-ui-playground.terminusdb.com) to view the `` demo in Create, edit or view mode. + +## Data types + +### Basic data types + +The table below lists the basic data types supported and their specifications. + +**Data type** + +**Declaration** + +**Example** + +Boolean + +`"xsd:boolean"` + +`"active": "xsd:boolean"` + +Decimal + +`"xsd:decimal"` + +`"age": "xsd:decimal"` + +Enum + +`"@type: "Enum"` + +`"@values": ["red", "blue", "yellow", "green"]` + +Integer + +`"xsd:integer"` + +`"age": "xsd:integer"` + +Decimal + +`"xsd:decimal"` + +`"age": "xsd:decimal"` + +String + +`"xsd:string"` + +`"name": "xsd:string"` + +Temporal + +`"xsd:dateTime"` + +`"DOB": "xsd:dateTime"` + +### Data value optionality + +If a property in the Form is displayed with a (Required) tab, that means the property is mandatory & has to be filled in order to submit the form. To define a property as optional, use the `"@type": "Optional"` declaration meaning the property is optional. + +A property can also be defined as an array in the following ways - + +`"@type": "Set"` - property can hold multiple values in an unordered fashion & can be optional + +`"@type": "List"` - property can hold multiple values in an ordered fashion & requires at least one entry + +### An example of all basic types + +**Enum** + +The `"Enum"` data type in the example below specifies the colors a person likes - `"@id": "Colors`, `"Person"`, `"likes"`. This is rendered as a dropdown menu with the colors specified in the `"@values"` list. + +**Optional** + +The `"age"` of a `"Person"` is declared `"Optional"` + +```javascript +let frames = { + "@context": { + "@base": "terminusdb:///data/", + "@schema": "terminusdb:///schema#", + "@type": "@context" + }, + "Person": { + "@key": { + "@type": "Random" + }, + "@type": "Class", + "DOB": "xsd:dateTime", + "active": "xsd:boolean", + "age": { + "@class": "xsd:decimal", + "@type": "Optional" + }, + "name": "xsd:string", + "likes": { + "@id": "Colors", + "@type": "Enum", + "@values": [ + "red", + "blue", + "yellow", + "green" + ] + } + } +} + +let type = "Person" +let mode = "Create" + +return +``` + +## Link Properties + +Link properties enable links to other document or subdocument classes and are displayed as `Select` components. + +### Link Properties Example + +The example below demonstrates: + +* The property `work_as` linked to document class `Job` +* The property `lives_in` linked to a subdocument class `Address` + +```javascript +let frames = { + "@context": { + "@base": "terminusdb:///data/", + "@schema": "terminusdb:///schema#", + "@type": "@context" + }, + "Person": { + "@key": { + "@type": "Random" + }, + "@type": "Class", + "works_as": "Job", // Link to subdocument Job + "lives_in": "Address" // Link to subdocument Address + }, + "Job": { + "@key": { + "@type": "Random" + }, + "@type": "Class", + "title": "xsd:string" + }, + "Address": { + "@key": { + "@type": "Random" + }, + "@subdocument": [], + "@type": "Class", + "Address Line 1": "xsd:string", + "Code": "xsd:decimal", + "Country": "xsd:string" + } +} + +let type = "Person" +let mode = "Create" + +return +``` + +## Set properties + +A set specifies an **unordered set** of values of a class or data type. + +### Set property example + +In the example below, the document `Person` consists of several nicknames - property `"nickName"` of `"@type": "Set"`. A set consists of zero, one or multiple items. + +```javascript +let frames = { + "@context": { + "@base": "terminusdb:///data/", + "@schema": "terminusdb:///schema#", + "@type": "@context" + }, + "Person": { + "@key": { + "@type": "Random" + }, + "@type": "Class", + "name": "xsd:string", + "nickName": { + "@class": "xsd:string", + "@type": "Set" + } + } +} + +let type = "Person" +let mode = "Create" + +return +``` + +### Document Class Set Example + +In the example below, a `Person` has a property `works_as` defined as a set that links to the document `Job`, representing a person with multiple jobs. + +```javascript +let frames = { + "@context": { + "@base": "terminusdb:///data/", + "@schema": "terminusdb:///schema#", + "@type": "@context" + }, + "Person": { + "@key": { + "@type": "Random" + }, + "@type": "Class", + "name": "xsd:string", + "works_as": { + "@class": "Job", + "@type": "Set" + } + }, + "Job": { + "@key": { + "@type": "Random" + }, + "@type": "Class", + "title": "xsd:string" + } +} + +let type = "Person" +let mode = "Create" + +return +``` + +### Subdocument Class Set Example + +In the example below, a `Person` has a property `lived` defined as a set that links to the subdocument `Address`, representing a person's address history. + +```javascript +let frames = { + "@context": { + "@base": "terminusdb:///data/", + "@schema": "terminusdb:///schema#", + "@type": "@context" + }, + "Person": { + "@key": { + "@type": "Random" + }, + "@type": "Class", + "name": "xsd:string", + "lived": { + "@class": { + "@class": "Address", + "@subdocument": [] + }, + "@type": "Set" + } + }, + "Address": { + "@key": { + "@type": "Random" + }, + "@subdocument": [], + "@type": "Class", + "Address Line 1": "xsd:string", + "Code": "xsd:decimal", + "Country": "xsd:string" + } +} + +let type = "Person" +let mode = "Create" + +return +``` + +## List Properties + +A list specifies an **ordered collection** of values of a class or data type. An ordered collection means values are displayed in the order they are entered in the form. + +### List property example + +In the example below, a `Person` has two properties, `ordered_property` (a string data type) and `has_task` (a subdocument of type `"List"`.) + +```javascript +let frames = { + "@context": { + "@base": "terminusdb:///data/", + "@schema": "terminusdb:///schema#", + "@type": "@context" + }, + "Person": { + "@key": { + "@type": "Random" + }, + "@type": "Class", + "ordered_property": { + "@class": "xsd:string", + "@type": "List" + }, + "has_task": { + "@class": "Tasks", + "@type": "List" + } + }, + "Tasks": { + "@key": { + "@type": "Random" + }, + "@subdocument": [], + "@type": "Class", + "Address Line 1": "xsd:string", + "Code": "xsd:decimal", + "Country": "xsd:string" + } +} + +let type = "Person" +let mode = "Create" + +// call FrameViewer +return +``` + +For more information on data types, take a look at the individual types in more details: + +* [Array](/docs/array/) +* [Choice Document](/docs/choice-document/) +* [Choice Sub Document](/docs/choice-subdocuments/) +* [List](/docs/list/) +* [Mandatory](/docs/mandatory/) +* [One Of](/docs/oneof/) +* [Optional](/docs/optional/) +* [Order By](/docs/orderby/) +* [Render As](/docs/render-as/) +* [Set](/docs/set/) +* [sysJSON](/docs/sysjson/) + +## Document UI SDK Examples + +[Document UI SDK Playground](https://documents-ui-playground.terminusdb.com/) - An interactive example of document properties in add, edit, and view modes with example schema and code. + +[Lego Data Product UI CodeSandbox Example](https://codesandbox.io/s/github/terminusdb/dashboard-examples-sandbox/tree/main/terminusdb-documents-ui-examples/lego-dataproduct-npm) \ No newline at end of file diff --git a/src/app/docs/document-ui-sdk/page.md b/src/app/docs/document-ui-sdk/page.md new file mode 100644 index 0000000..8f0ee05 --- /dev/null +++ b/src/app/docs/document-ui-sdk/page.md @@ -0,0 +1,300 @@ +--- +title: How to Use the Document UI SDK +slug: document-ui-sdk +seo: + title: How to use the TerminusCMS Document UI SDK + description: How to use the TerminusCMS Document UI SDK + og_image: >- + https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png +media: [] +--- + +FIXME: Tables need to be updated + +Use the TerminusDB documents User Interface (UI) utility `terminusdb-documents-ui` to automatically generate user interfaces for the document definitions in your TerminusDB schema. The utility takes frames as input and outputs forms in HTML format. A frame is the JSON structure of a JSON document, including the document's inherited properties and IRIs. + +## Install and import + +Install the utility from `npm`: + +```bash +npm install @terminusdb/terminusdb-documents-ui --save +``` + +Import the `FrameViewer` component into your code: + +```python +import {FrameViewer} from '@terminusdb/terminusdb-documents-ui' +``` + +Import the `FrameViewer` css into your code: + +For dark mode include the below css + +```python +import '@terminusdb/terminusdb-documents-ui/dist/css/terminusdb__darkly.css' +``` + +light mode + +```python +import '@terminusdb/terminusdb-documents-ui/dist/css/terminusdb__light.css' +``` + +### The FrameViewer object + +Use the `FrameViewer` object of `terminusdb-documents-ui` to configure and display your forms. `FrameViewer` supports several parameters and functions. + +#### FrameViewer parameters + +**Parameter** + +**Description** + +`frame` + +The JSON frame structure of a TerminusDB schema. + +`mode` + +Form modes - `Create`, `Edit`, or `View`. + +`formData` + +The data entered into or provided for a form. Specify `formData` in `Edit` and `View` modes to display data. + +`type` + +document type of interest to be displayed in form. + +`language` + +language code parameters to support a wide variety of languages in UI as defined in schema + +#### FrameViewer functions + +**Function** + +**Description** + +`onSubmit` + +A customizable JavaScrpt (JS) callback function to process data submitted via a form. + +`onSelect` + +JS callback function to retrieve the selected values from a `Select` component. + +`onTraverse` + +Return the ID of a document on a click event. Useful for binding an `onClick` event with a document. + +#### FrameViewer Mandatory props + +props + +Mandatory + +frame + +true + +type + +true + +mode + +true + +formData + +formData has to be mandatory in Edit or View mode. If nothing to display then pass empty json {} + +### FrameViewer common usage + +A common use of `terminusdb-documents-ui` is as follows: + +1. Set up a Webpack. +2. Use the [TerminusDB JavaScript client](/docs/javascript/). +3. Use the client function `getSchemaFrame` to retrieve frame data from a TerminusDB database. +4. Set custom values and behaviour for `FrameViewer` parameters and functions as required. +5. Call `FrameViewer` to display frame data in the specified form. + +### Get schema frame data from a database + +A basic example below to get started with a TerminusDB JavaScript client. + +```python +const TerminusDBClient = require("@terminusdb/terminusdb-client"); +import '@terminusdb/terminusdb-documents-ui/dist/css/terminusdb__darkly.css' +import {FrameViewer} from '@terminusdb/terminusdb-documents-ui' + +try { + let type = "Person" // type is the a document class of interest + let frames = await woqlClient.getSchemaFrame(type, woqlClient.db()) + console.log(`Frames generated from ${woqlClient.db()}`, frames) +} catch(err) { + console.log("Error fetching frames", err) +} +``` + +### FrameViewer usage step-by-step + +Use three simple steps - input, configure, and output: + +[Step 1. Create frame data](#step1createframedata) + +[Step 2. Configure properties and functions](#step2configurepropertiesandfunctions) + +[Step 3. Generate the form](#step3generatetheform) + +#### Step 1. Create frame data + +For simplicity, all examples use the `frames` definition below consisting of one document `Person`. + +```javascript +let frames = { + "@context": { + "@base": "terminusdb:///data/", + "@schema": "terminusdb:///schema#", + "@type": "@context" + }, + "Person": { + "@key": { + "@type": "Random" + }, + "@type": "Class", + "DOB": "xsd:dateTime", + "active": "xsd:boolean", + "age": "xsd:decimal", + "name": "xsd:string" + } +} + +// The document to display the frame for. + +let type = "Person" +``` + +#### Step 2. Configure properties and functions + +The example below generates an empty frame for the attributes of the `Person` document. The callback function `handleSubmit` displays any user-entered form data. Add functionality to `handleSubmit` to suit your requirements. + +```javascript +// Mode "Create" displays an empty frame. + +let mode = "Create" + +// Callback to display form data. + +function handleSubmit(data) { + console.log("Form data: ", data) +} +``` + +#### Step 3. Generate the form + +Generate the form using the properties and functions defined in the previous step. + +```jsx +// Generate the form. + +return +``` + +### FrameViewer modes + +The `FrameViewer` object supports three modes: + +* [Create](#createmode) +* [Edit](#editmode) +* [View](#viewmode) + +#### Create mode + +The `Create` mode displays an empty frame as demonstrated in the previous example. + +#### Edit mode + +The `Edit` mode displays populated and empty frames. This mode requires the `formData` parameter. + +```javascript +// Mode "Edit" displays a frame with editable data. + +let mode = "Edit" + +// Add form data to populate the frame. + +let formData = { + "@id": "Person/John%20Doe", + "@type": "Person", + first_name: "John", + last_name: "Doe", + age: "17", + active: true, + DOB: "2022-03-31T10:01:11.000Z" +} + +// Callback to display form data. + +function handleSubmit(data) { + console.log("Form data: ", data) +} + +// Generate the form with formData paramter. + +return +``` + +#### View Mode + +The `View` mode displays populated frames for view-only - the **Submit** button is automatically hidden. If the `formData` parameter is omitted, an empty form is displayed. + +```javascript +// Mode "View" displays populated frames. + +let mode = "View" + +// Add form data to populate the frame. + +let formData = { + "@id": "Person/John%20Doe", + "@type": "Person", + first_name: "John", + last_name: "Doe", + age: "17", + active: true, + DOB: "2022-03-31T10:01:11.000Z" +} + +// Callback to display form data. + +function handleSubmit(data) { + console.log("Form data: ", data) +} + +// Generate the form with formData paramter. + +return +``` + +## Document UI SDK Examples + +[Document UI SDK Playground](https://documents-ui-playground.terminusdb.com/) - An interactive example of document properties in add, edit, and view modes with example schema and code. + +[Lego Data Product UI CodeSandbox Example](https://codesandbox.io/s/github/terminusdb/dashboard-examples-sandbox/tree/main/terminusdb-documents-ui-examples/lego-dataproduct-npm) \ No newline at end of file diff --git a/src/app/docs/document-ui-template/page.md b/src/app/docs/document-ui-template/page.md new file mode 100644 index 0000000..ac24455 --- /dev/null +++ b/src/app/docs/document-ui-template/page.md @@ -0,0 +1,34 @@ +--- +title: Document UI Template +slug: document-ui-template +seo: + title: Document UI Template + description: 'The document ui template has components to assemble a dashboard quickly. ' + og_image: >- + https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png +media: [] +--- + +A Software Development Kit (SDK) to build a UI from @terminusdb/terminusdb-documents-ui and the @terminusdb/terminusdb-react-table. + +This template has components to assemble a dashboard quickly. You also have the option to use our base components like the FramesViewer and TDBReactTable. + +## Installation + +Install the dependencies from npm + +```bash +npm install @terminusdb/terminusdb-documents-ui +npm install @terminusdb/terminusdb-react-table +npm install @terminusdb/terminusdb-documents-ui-templates +``` + +## Run a Dashboard Example in Code Sandbox + +`terminusdb-documents-ui-templates` are a collection of hooks to connect with the TerminusCMS server and a number of templates (components) for building a dashboard. + +The sandbox features an example and how to use the components and hooks to assemble your pages. + +[Source Code](https://github.com/terminusdb/dashboard-examples-sandbox/tree/main/terminusdb-documents-ui-template-example/dashboard-demo) + +[Code Sandbox](https://codesandbox.io/s/github/terminusdb/dashboard-examples-sandbox/tree/main/terminusdb-documents-ui-template-example/dashboard-demo) \ No newline at end of file diff --git a/src/app/docs/documentclassessummary/page.md b/src/app/docs/documentclassessummary/page.md new file mode 100644 index 0000000..be2a85a --- /dev/null +++ b/src/app/docs/documentclassessummary/page.md @@ -0,0 +1,91 @@ +--- +title: DocumentClassesSummary Component +slug: documentclassessummary +seo: + title: DocumentClassesSummary Component + description: >- + The DocumentClassesSummary component allows you to visualize document + classes using interactive cards. + og_image: >- + https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png +media: [] +--- + +The `DocumentClassesSummary` component allows you to visualize document classes using interactive cards. + +## Installation + +Install the dependencies from npm + +```bash +npm install @terminusdb/terminusdb-documents-ui +npm install @terminusdb/terminusdb-react-table +npm install @terminusdb/terminusdb-documents-ui-templates +``` + +## Properties + +{% table %} + +- Properties +- Description + +--- + +- `totalDocumentCount` +- The total number of documents + +--- + +- `perDocumentCount` +- The number of documents for a type + +--- + +- `onDocumentClick` +- A function that acts as a callback when the document class card is clicked + +{% /table %} + +## Example + +```python +import React, {useEffect} from "react" +import {DocumentClassesSummary,useTDBDocuments} from "@terminusdb/terminusdb-documents-ui-template" + +export const Documents = ({tdbClient}) => { + const {perDocumentCount, + totalDocumentCount, + getDocumentNumbers, + setError, + loading, + error}=useTDBDocuments(tdbClient) + + + useEffect(() => { + if(tdbClient)getDocumentNumbers() + }, [tdbClient]) + + function handleCardClick (doc) { + // do something after click the card, + // maybe navigate in the document list page + } + + if(!frames) return
{`Fetching frames for document type ${type} ...`}
+ const errorMessage = typeof error === "object" ? JSON.stringify(error,null,4) : error + + return
+ {error && {error &&
Server Error: {errorMessage}
} + +
+} +``` + +View the DocumentClassesSummary integrated inside a dashboard here + +[DocumentClassesSummary full example JS code](https://github.com/terminusdb/dashboard-examples-sandbox/blob/main/terminusdb-documents-ui-template-example/dashboard-demo/src/pages/Documents.js) + +[Code Sandbox](https://codesandbox.io/s/github/terminusdb/dashboard-examples-sandbox/tree/main/terminusdb-documents-ui-template-example/dashboard-demo) \ No newline at end of file diff --git a/src/app/docs/documents-explanation/page.md b/src/app/docs/documents-explanation/page.md new file mode 100644 index 0000000..f7ed81e --- /dev/null +++ b/src/app/docs/documents-explanation/page.md @@ -0,0 +1,315 @@ +--- +title: Documents Explanation +slug: documents-explanation +seo: + title: TerminusCMS Documents Explanation + description: >- + The types of documents available in TerminusDB and TerminusCMS with examples + of their definitions and interactions. + og_image: >- + https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png +media: + - alt: '' + caption: '' + media_type: Image + title: Image 1 + value: https://assets.terminusdb.com/docs/terminusdb-contact-graph-diagram.png +--- + +## The TerminusDB document store + +TerminusDB is a document store as well as a knowledge graph database. TerminusDB [schemata](/docs/schema-reference-guide/) describe how to interpret segments of graphs as self-contained documents. + +### TerminusDB storage structure + +The underlying storage structure of TerminusDB is a **labeled**, **directed**, and **edge-labeled** graph. Each source and target node has a distinct name, and every edge has a name and a direction. + +#### Graph segments as documents + +Segments of the graph are **documents**. Documents can be extracted as JSON objects, providing a convenient data package for applications. JSON objects can be updated by submitting modified versions. The graph's entire document segment can be deleted by deleting the document. However, the full graph structure is retained, allowing sophisticated search and traversal. + +#### Subdocuments overview + +Documents can contain **subdocuments**. A subdocument: + +* Is owned by its containing document. +* Is a segment of the graph which is solely pointed to by the containing document. +* Can have any number of outgoing links to other documents or subdocuments. + +See the [Subdocuments](#subdocuments) section for more information. + +### Simple documents + +Documents are described by creating a class definition in the [schema](/docs/schema-reference-guide/). The simplest document definition contains properties with data elements only. + +#### A simple document example + +The [Football roster CSV file](#datafootballrostercsvfile) is loaded using the [Football roster class definition](#codefootballrosterclassdefinition) below. This class definition describes the JSON document that can be submitted or retrieved from the graph. + +A valid [Football roster JSON document definition](#codefootballrosterjsondocumentdefinition), which corresponds to a row in the CSV file, is also shown below. + +#### Data: Football roster CSV file + +```csv +name, position +George, Centre Back +Doug, Full Back +Karen, Centre Forward +``` + +#### Code: Football roster class definition + +```json +{ "@type" : "@context", + "@schema" : "terminusdb://Roster/schema#", + "@base" : "terminusdb://Roster/document" } + +{ "@type" : "Class", + "@id" : "Player", + "name" : "xsd:string", + "position": "xsd:string" } +``` + +#### Code: Football roster JSON document definition + +```json +{ "@type" : "Player", + "@id" : "Player/George", + "@base" : "terminusdb://Roster/document", + "name" : "George", + "position": "Centre Back" } +``` + +#### The JSON document definition + +The following table describes the properties of the JSON document definition above. + +#### Table: Properties of the JSON document definition + +{% table %} + +- Property +- Value +- Description + +--- + +- `@type` +- `Player` +- The type of data held - a football player + +--- + +- `@id` +- `Player/George` +- The address of the document used for retrieval, update, or deletion, or as a reference used in other documents. If the address in `@id` is **unambiguous**, for example, when used in the same collection, then `@id` can be used as-is, i.e., as `Player/George`. Otherwise, the `@base` property is required. + +--- + +- `@base` +- `terminusdb://Roster/schema#` +- The **fully qualified** address for `Player/George` expanding to `terminusdb://Roster/document/Player/George`. + +{% /table %} + +#### Unique document @id + +It is important to ensure a unique document `@id`. The parameters `@key` and `@base` are available in the class definition, enabling you to use a calculated `@id`. Refer to the [Schema reference](/docs/schema-reference-guide/) for more information. + +### Documents with references + +TerminusDB enables references to other documents, forming a **graph of documents**. + +#### Create objects from data + +The [simple document example](#asimpledocumentexample) introduced above is convertible to an object that refers to each player, as demonstrated in the code-snippet [Player and roster classes](#codeplayerandrosterclasses). In this snippet, the `Roster` class points to a `Set` of `Player`s (or `Player` classes.) + +#### The Set property + +The `Set` property in the code-snippet is a _type family_ allowing us to state that the `player` property can have any number of `Player`s attached. `Set` does not provide ordering or multiplicity; a `Player` is either connected or not connected. For ordering and multiplicity, use `@type` `List` or `Array`. + +#### Code: Player and roster classes + +```json +{ "@type" : "@context", + "@schema": "terminusdb://Roster/schema#", + "@base" : "terminusdb://Roster/document" } + +{ "@type" : "Class", + "@id" : "Player", + "name" : "xsd:string", + "position": "xsd:string" } + +{ "@type" : "Class", + "@id" : "Roster", + "player" : { + "@type" : "Set", + "@class": "Player" } } +``` + +#### Create documents from class specifications + +A set of documents that meets the above specification and that represents the data in the [Football roster CSV file](#datafootballrostercsvfile) can be defined as: + +#### Code: CSV roster data in document form + +```json +{ "@type" : "Roster", + "@id" : "Roster/Wolves", + "player": [ "Player/George", "Player/Karen", "Player/Doug" ] } + +{ "@type" : "Player", + "@id" : "Player/George", + "name" : "George", + "position": "Centre Back" } + +{ "@type" : "Player", + "@id" : "Player/Doug", + "name" : "Doug", + "position": "Full Back" } + +{ "@type" : "Player", + "@id" : "Player/Karen", + "name" : "Karen", + "position": "Centre Forward" } +``` + +The `Roster` points to the various `Player` documents. When requesting the document `Roster/Wolves`, each player in the `player` array is retrieved. Each identifier can be queried in a similar way to retrieve all associated documents. + +### Subdocuments + +A subdocument can only be pointed to by its containing document. It is information internal to the identity of a document and not intended to be shared. This designation enables deeply nested JSON documents that are self-contained and retrievable using the TerminusDB [document interface](/docs/document-insertion/). + +#### A subdocument example + +In the subdocument example below, the schema specification defines players with a subdocument of `stats`. `Stats` is declared a subdocument using the `@subdocument` property and the special value `[]`. Also, it has a `Random` key, meaning the key is automatically generated if not provided. + +#### Code: An example of a player stats subdocument + +```json +{ "@type" : "@context", + "@schema": "terminusdb://Roster/schema#", + "@base" : "terminusdb://Roster/document" } + +{ "@type" : "Class", + "@id" : "Stats", + "@subdocument": [], + "@key" : { "@type" : "Random" }, + "strength" : "xsd:integer", + "intelligence": "xsd:integer", + "dexterity" : "xsd:integer", + "charisma" : "xsd:integer", + "wisdom" : "xsd:integer", + "constitution": "xsd:integer" } + +{ "@type": "Class", + "@id" : "Player", + "name" : "xsd:string", + "stats": "Stats" } +``` + +In the example below, the subdocument enables sending and retrieving `Stats` with the `Player` object. It is also possible for subdocuments to point recursively to other subdocuments or documents. + +#### Code: Stats with the player object + +```json +{ "@type" : "Player", + "@id" : "Player/Hieronymous", + "stats" : + { + "@type" : "Stats", + "strength" : 14, + "intelligence": 10, + "dexterity" : 14, + "charisma" : 8, + "wisdom" : 12, + "constitution": 9 + } +} +``` + +### Visualizing the Graph + +Documents and subdocuments, and references to other documents, provide the best of both worlds: document storage and knowledge graphs. However, visualizing what this means requires a bit of experience. + +#### A graph visualization example + +The following Contact graph diagram illustrates the boundaries around what constitutes a document and a subdocument. + +An example schema representing this scenario is provided in the code-snippet [Contact graph schema](#codecontactgraphschema) further below with an example of a corresponding [Contact graph document](#codecontactgraph-document) definition. + +With a bit of practice, designing your knowledge graphs in TerminusDB will become second nature. + +#### Diagram: Contact graph + +![](https://assets.terminusdb.com/docs/terminusdb-contact-graph-diagram.png) + +#### Code: Contact graph schema + +```json +{ "@type" : "@context", + "@schema": "terminusdb://Roster/schema#", + "@base" : "terminusdb://Roster/document" } + +{ "@type" : "Class", + "@id" : "Coordinate", + "@subdocument": [], + "@key" : { "@type" : "Random" }, + "lat" : "xsd:decimal", + "long" : "xsd:decimal" } + +{ "@type" : "Class", + "@id" : "Map", + "coordinates": { "@type" : "Array", + "@class": "Coordinate" } } + +{ "@type": "Class", + "@id" : "Country", + "name" : "xsd:string", + "map" : "Map" } + +{ "@type" : "Class", + "@id" : "Address", + "@subdocument": [], + "@key" : { "@type" : "Random" }, + "country" : "Country", + "street" : "xsd:string" } + +{ "@type" : "Class", + "@id" : "Person", + "name" : "xsd:string", + "address": "Address", + "friend" : "Person" } +``` + +#### Code: Contact graph document + +```json +{ "@type" : "Person", + "@id" : "Person/Joe", + "name" : "Joe Bloggs", + "address": { "@type" : "Address", + "@id" : "Adress/aa1264e404a5b34381abc37cad83fabd", + "street" : "Elm St.", + "country": "Country/USA" }, + "friend" : [ "Person/Jill" ] } + +{ "@type" : "Person", + "@id" : "Person/Jill", + "name" : "Jill Smith", + "address": { "@type" : "Address", + "@id" : "Adress/5fba7438dc2b23258d304bb8cd1222bd", + "street" : "Main St.", + "country": "Country/Ireland" }, + "friend" : [ "Person/Joe" ] } + +{ "@type" : "Country", + "@id" : "Country/USA", + "name" : "USA", + "coordinates": [ ... ] } + +{ "@type" : "Country", + "@id" : "Country/Ireland", + "name" : "Ireland", + "coordinates": [ ... ] } +``` \ No newline at end of file diff --git a/src/app/docs/documentsgraphqltable/page.md b/src/app/docs/documentsgraphqltable/page.md new file mode 100644 index 0000000..f4dacd8 --- /dev/null +++ b/src/app/docs/documentsgraphqltable/page.md @@ -0,0 +1,127 @@ +--- +title: DocumentsGraphqlTable Component +slug: documentsgraphqltable +seo: + title: DocumentsGraphqlTable Component + description: >- + The DocumentsGraphqlTable component allows you to use GraphQL queries and + visualize the results in a the TDBReactTable + og_image: >- + https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png +media: [] +--- + +The `DocumentsGraphqlTable` component allows you to use GraphQL queries and visualize the results in a the [TDBReactTable](/docs/tdb-react-table/), you need to pass your instace of ApolloClient, the GraphQL query and the table and advanced search configuration. [Read here for the configuration documentation](/docs/tdb-react-table/). + +## Installation + +Install the dependencies from npm + +```bash +npm install @terminusdb/terminusdb-documents-ui +npm install @terminusdb/terminusdb-react-table +npm install @terminusdb/terminusdb-documents-ui-templates +``` + +## Properties + +{% table %} + +- Properties +- Description + +--- + +- `type` +- The document type + +--- + +- `gqlQuery` +- The GraphQL query + +--- + +- `apolloClient` +- An apollo client instance - [Apollo Client documentation](https://www.apollographql.com/docs/react/) + +--- + +- `tableConfig` +- An object with the table configuration to pass to the [TDBReactTable Component](/docs/tdb-react-table/) + +--- + +- `advancedSearchConfig` +- An object with the advancedSearch configuration to pass to the [AdvancedSearch Component](/docs/tdb-react-table/#advancedsearch) + +--- + +- `onRowClick` +- A function that acts as a callback when the table row is clicked + +--- + +- `onViewButtonClick` +- A function that acts as a callback when the table row view button is clicked + +--- + +- `onEditButtonClick` +- A function that acts as a callback when the table row edit button is clicked + +--- + +- `onDeleteButtonClick` +- A function that acts as a callback when the table row delete button is clicked + +--- + +- `showGraphqlTab` +- A boolean property to enable the GraphQL query view tab + +{% /table %} + +## Example + +```python +import React,{useEffect} from "react" +import {DocumentsGraphqlTable,useTDBDocuments} from "@terminusdb/terminusdb-documents-ui-template" +import {gql} from "@apollo/client" +/** + * + * @param {*} setSelected function to get selected document link by user + * @param {*} doctype document type selected + * @returns + */ +export const DocumentSearchComponent = ({setSelected, doctype,apolloClient,tdbClient}) => { + const {documentTablesConfig,getGraphqlTablesConfig} = useTDBDocuments(tdbClient) + + useEffect(() => { + if(doctype){ + getGraphqlTablesConfig() + } + },[doctype]); + + const querystr = documentTablesConfig && documentTablesConfig.objQuery ? documentTablesConfig.objQuery[doctype].query : null + const gqlQuery = querystr ? gql`${querystr}` : null + const tableConfig = documentTablesConfig && documentTablesConfig.tablesColumnsConfig ? documentTablesConfig.tablesColumnsConfig[type] : [] + const advancedSearchConfig = documentTablesConfig && documentTablesConfig.advancedSearchObj ? documentTablesConfig.advancedSearchObj[type] : null + if(!gqlQuery || !tableConfig) return
+ + return + +} +``` + +View the DocumentsGraphqlTable component integrated inside a dashboard here + +[DocumentSearchComponent full example JS code](https://github.com/terminusdb/dashboard-examples-sandbox/blob/main/terminusdb-documents-ui-template-example/dashboard-demo/src/components/DocumentSearchComponent.js) + +[Code Sandbox](https://codesandbox.io/s/github/terminusdb/dashboard-examples-sandbox/tree/main/terminusdb-documents-ui-template-example/dashboard-demo) \ No newline at end of file diff --git a/src/app/docs/edit-a-document/page.md b/src/app/docs/edit-a-document/page.md new file mode 100644 index 0000000..c51fe84 --- /dev/null +++ b/src/app/docs/edit-a-document/page.md @@ -0,0 +1,30 @@ +--- +title: Edit a Document with the JavaScript Client +slug: edit-a-document +seo: + title: Edit a Document using the JavaScript Client + description: >- + A guide to show how to update a document in TerminusDB and TerminusCMS using + the JavaScript Client. + og_image: >- + https://github.com/terminusdb/terminusdb-web-assets/blob/master/docs/js-client-use-edit-a-document.png?raw=true +media: [] +--- + +To update documents in your database, you first need to [get the document](/docs/get-documents/) you want to change. You then need to make your changes and update it. This example shows how - + +```javascript +const docs = { + '@id' : 'Player/George', + '@type' : 'Player', + name : 'George', + position: 'Center Back' + } + +docs.position = "Full Back" + +const updateDocs = async () => { + const result = await client.updateDocument(docs); + console.log("updated document", result) +} +``` \ No newline at end of file diff --git a/src/app/docs/edit-document-component/page.md b/src/app/docs/edit-document-component/page.md new file mode 100644 index 0000000..ac5f35d --- /dev/null +++ b/src/app/docs/edit-document-component/page.md @@ -0,0 +1,131 @@ +--- +title: EditDocumentComponent +slug: edit-document-component +seo: + title: EditDocumentComponent + description: >- + The EditDocumentComponent allows you to edit an existing document using the + FrameViewer component + og_image: >- + https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png +media: [] +--- + +The `EditDocumentComponent` allows you to edit an existing document using the [FrameViewer](/docs/document-ui-sdk/) component. + +## Installation + +Install the dependencies from npm + +```bash +npm install @terminusdb/terminusdb-documents-ui +npm install @terminusdb/terminusdb-react-table +npm install @terminusdb/terminusdb-documents-ui-templates +``` + +## Properties + +{% table %} + +- Properties +- Description + +--- + +- `type` +- The document type + +--- + +- `documentJson` +- The document object + +--- + +- `documentID` +- The document ID + +--- + +- `frames` +- The database Class Frame, or object of all class frames + +--- + +- `closeButtonClick` +- A function that acts as a callback when the panel exit `x` button is clicked + +--- + +- `updateDocument` +- A function that acts as a callback when the `submit` button is clicked + +--- + +- `SearchComponent` +- A react component used as search component + +{% /table %} + +## Example + +```python +import React, {useEffect} from "react"; +import {EditDocumentComponent,useTDBDocuments} from "@terminusdb/terminusdb-documents-ui-template" + +export const DocumentEdit = ({type, documentID, tdbClient}) => { + const { + updateDocument, + getDocument, + selectedDocument, + getDocumentFrames, + frames, + error, + setError + } = useTDBDocuments(tdbClient) + + const updateDocumentHandler = async (jsonDoc) =>{ + const docUp = await updateDocument(jsonDoc) + if(docUp){ + getDocument(documentID) + // do somethig after update document + } + } + // implement the chage method + useEffect(() => { + getDocumentFrames() + getDocument(documentID) + },[]) + + const closeButtonClick = () =>{ + // do something after click the close panel button the interface + } + + const DocumentSearchComponent = () =>{ + //make you document search component + return
+ } + + if(!frames) return
{`Fetching frames for document type ${type} ...`}
+ const errorMessage = typeof error === "object" ? JSON.stringify(error,null,4) : error + + return + {error &&
Server Error: {errorMessage}
} + +
+} +``` + +View the EditDocumentComponent component integrated inside a dashboard here + +[EditDocumentComponent full example JS code](https://github.com/terminusdb/dashboard-examples-sandbox/blob/main/terminusdb-documents-ui-template-example/dashboard-demo/src/pages/DocumentEdit.js) + +[Code Sandbox](https://codesandbox.io/s/github/terminusdb/dashboard-examples-sandbox/tree/main/terminusdb-documents-ui-template-example/dashboard-demo) \ No newline at end of file diff --git a/src/app/docs/edit-documents-with-python-client/page.md b/src/app/docs/edit-documents-with-python-client/page.md new file mode 100644 index 0000000..32795a3 --- /dev/null +++ b/src/app/docs/edit-documents-with-python-client/page.md @@ -0,0 +1,24 @@ +--- +title: Edit a Document with the Python Client +slug: edit-documents-with-python-client +seo: + title: Edit a Document with the Python Client + description: >- + A guide to show how to update a document in TerminusDB and TerminusCMS using + the Python Client + og_image: https://assets.terminusdb.com/docs/python-client-use-edit-a-document.png +media: [] +--- + +To update a document in your database, you first need to [get the document](/docs/get-documents-with-python-client/) you want to change. You then need to make your changes and update them. This example shows how - + +```python +doc = { + '@id' : 'Player/George', + '@type' : 'Player', + 'name' : 'George', + 'position': 'Center Back' + } +doc["position"] = "Full Back" +client.update_document(doc) +``` \ No newline at end of file diff --git a/src/app/docs/edit-documents-with-woql/page.md b/src/app/docs/edit-documents-with-woql/page.md new file mode 100644 index 0000000..baabe25 --- /dev/null +++ b/src/app/docs/edit-documents-with-woql/page.md @@ -0,0 +1,29 @@ +--- +title: Edit documents in WOQL +slug: edit-documents-with-woql +seo: + title: Edit Documents using WOQL + description: A guide with example showing how to edit documents using WOQL + og_image: https://assets.terminusdb.com/docs/woql-edit-documents.png +media: [] +--- + +> To use this HowTo, first [clone the Star Wars demo](/docs/clone-a-demo-terminuscms-project/) into your team on TerminusCMS. You will then have full access to the data needed for this tutorial. + +We can get a document by Id, by using `read_document`. For instance, we can write: + +```javascript +let v = Vars("doc", "id"); +and(isa(v.id, "People"), + triple(v.id, "label", string("Bossk")), + read_document(v.id, v.doc)) +``` + +We can also add documents by using a variable. For instance, we can create a new planet for each individual in the star wars universe as follows: + +```javascript +let v = Vars("person", "name"); +and(isa(v.person, "People"), + triple(v.person,"label",v.name), + insert_document(doc({'@type' : 'Planet', label: v.name}))) +``` \ No newline at end of file diff --git a/src/app/docs/filter-with-graphql/page.md b/src/app/docs/filter-with-graphql/page.md new file mode 100644 index 0000000..7f157ad --- /dev/null +++ b/src/app/docs/filter-with-graphql/page.md @@ -0,0 +1,84 @@ +--- +title: Filter with GraphQL +slug: filter-with-graphql +seo: + title: Filter + description: Filter with GraphQL + og_image: >- + https://github.com/terminusdb/terminusdb-web-assets/blob/master/docs/graphql-filter.png?raw=true +media: [] +--- + +> To use this HowTo, first [clone the Star Wars demo](/docs/clone-a-demo-terminuscms-project/) into your team on TerminusCMS. You will then have full access to the data needed for this tutorial. + +## Using a Filter + +Once you have Star Wars, you can enter into the data product and you can type the following in the [GraphQL query panel](/docs/graphql-basics/): + +Let's choose `homeworld` + +```graphql +query{ + People(filter: { label : { █ }}){ + + } +} +``` + +Type `Ctrl-c` and you'll be given some filters which can be used to constrain the label field. + +Let's choose a regex which demonstrates the fondness the creators of Star Wars had for the 'oo' sound. + +```graphql +query{ + People(filter:{ label : {regex: ".*oo.*"}}){ + label + homeworld{ + label + } + } +} +``` + +This results in: + +```json +{ + "data": { + "People": [ + { + "label": "Roos Tarpals", + "homeworld": { + "label": "Naboo" + } + }, + { + "label": "Yarael Poof", + "homeworld": { + "label": "Quermia" + } + }, + { + "label": "Plo Koon", + "homeworld": { + "label": "Dorin" + } + }, + { + "label": "Dooku", + "homeworld": { + "label": "Serenno" + } + }, + { + "label": "Sly Moore", + "homeworld": { + "label": "Umbara" + } + } + ] + } +} +``` + +For more sophisticated filtering, see [Advanced filtering](/docs/advanced-filtering-with-graphql/). \ No newline at end of file diff --git a/src/app/docs/filter-with-woql/page.md b/src/app/docs/filter-with-woql/page.md new file mode 100644 index 0000000..651cc2f --- /dev/null +++ b/src/app/docs/filter-with-woql/page.md @@ -0,0 +1,115 @@ +--- +title: Writing a filter in WOQL +slug: filter-with-woql +seo: + title: How to filter with WOQL + description: >- + A guide showing how to filter with WOQL in your TerminusCMS and TerminusDB + projects + og_image: https://assets.terminusdb.com/docs/woql-filter.png +media: [] +--- + +> To use this HowTo, first [clone the Star Wars demo](/docs/clone-a-demo-terminuscms-project/) into your team on TerminusCMS. You will then have access to the data needed for this tutorial. + +Since WOQL is a datalog, filters are just part of the query. You can express negative information, or constraints on the variables in order to get a restriction down to the things you want. + +For instance, we can write the following query in the query panel for the Star Wars demo: + +```javascript +let v = Vars("person","person_name","vehicle","vehicle_name"); +limit(10) +.select(v.person_name, v.vehicle_name) + .and(triple(v.vehicle, "pilot", v.person), + triple(v.vehicle, "label", v.vehicle_name), + triple(v.person, "label", v.person_name)) +``` + +This results in: + +```json +[ {"person_name": {"@type":"xsd:string", "@value":"Chewbacca"}, + "vehicle_name": {"@type":"xsd:string", "@value":"Millennium Falcon"}}, + {"person_name": {"@type":"xsd:string", "@value":"Han Solo"}, + "vehicle_name": {"@type":"xsd:string", "@value":"Millennium Falcon"}}, + {"person_name": {"@type":"xsd:string", "@value":"Lando Calrissian"}, + "vehicle_name": {"@type":"xsd:string", "@value":"Millennium Falcon"}}, + {"person_name": {"@type":"xsd:string", "@value":"Nien Nunb"}, + "vehicle_name": {"@type":"xsd:string", "@value":"Millennium Falcon"}}, + {"person_name": {"@type":"xsd:string", "@value":"Luke Skywalker"}, + "vehicle_name": {"@type":"xsd:string", "@value":"X-wing"}}, + {"person_name": {"@type":"xsd:string", "@value":"Wedge Antilles"}, + "vehicle_name": {"@type":"xsd:string", "@value":"X-wing"}}, + {"person_name": {"@type":"xsd:string", "@value":"Jek Tono Porkins"}, + "vehicle_name": {"@type":"xsd:string", "@value":"X-wing"}}, + {"person_name": {"@type":"xsd:string", "@value":"Biggs Darklighter"}, + "vehicle_name": {"@type":"xsd:string", "@value":"X-wing"}}, + {"person_name": {"@type":"xsd:string", "@value":"Darth Vader"}, + "vehicle_name": {"@type":"xsd:string", "@value":"TIE Advanced x1"}}, + {"person_name": {"@type":"xsd:string", "@value":"Boba Fett"}, + "vehicle_name": {"@type":"xsd:string", "@value":"Slave 1"}} +] +``` + +We can ask for a _specific_ example of a vehicle name by filtering on equality. + +For instance: + +```javascript +let v = Vars("person","person_name","vehicle","vehicle_name"); +select(v.person_name, v.vehicle_name) + .and(triple(v.vehicle, "pilot", v.person), + triple(v.vehicle, "label", v.vehicle_name), + triple(v.person, "label", v.person_name), + eq(v.vehicle_name, string("Millennium Falcon"))) +``` + +Which results in: + +```json +[ {"person_name": {"@type":"xsd:string", "@value":"Chewbacca"}, + "vehicle_name": {"@type":"xsd:string", "@value":"Millennium Falcon"}}, + {"person_name": {"@type":"xsd:string", "@value":"Han Solo"}, + "vehicle_name": {"@type":"xsd:string", "@value":"Millennium Falcon"}}, + {"person_name": {"@type":"xsd:string", "@value":"Lando Calrissian"}, + "vehicle_name": {"@type":"xsd:string", "@value":"Millennium Falcon"}}, + {"person_name": {"@type":"xsd:string", "@value":"Nien Nunb"}, + "vehicle_name": {"@type":"xsd:string", "@value":"Millennium Falcon"}} +] +``` + +We can also write: + +```javascript +let v = Vars("person","person_name","vehicle","vehicle_name"); +select(v.person_name, v.vehicle_name) + .and(triple(v.vehicle, "pilot", v.person), + triple(v.vehicle, "label", v.vehicle_name), + triple(v.person, "label", v.person_name), + not(eq(v.vehicle_name, string("Millennium Falcon")))) +``` + +In which we get the complement of the above. + +Or, we can use the regex operator to get a wider variety, for instance: + +```javascript +let v = Vars("person","person_name","vehicle","vehicle_name","pattern"); +select(v.person_name, v.vehicle_name) + .and(triple(v.vehicle, "pilot", v.person), + triple(v.vehicle, "label", v.vehicle_name), + triple(v.person, "label", v.person_name), + regex("W.*", v.vehicle_name, [v.pattern])) +``` + +In this case, we get the following back in JSON format: + +```json +[ {"person_name": {"@type":"xsd:string", "@value":"Darth Vader"}, + "vehicle_name": {"@type":"xsd:string", "@value":"TIE Advanced x1"}}, + {"person_name": {"@type":"xsd:string", "@value":"Arvel Crynyd"}, + "vehicle_name": {"@type":"xsd:string", "@value":"A-wing"}}, + {"person_name": {"@type":"xsd:string", "@value":"Chewbacca"}, + "vehicle_name": {"@type":"xsd:string", "@value":"AT-ST"}} +] +``` \ No newline at end of file diff --git a/src/app/docs/get-documents-with-python-client/page.md b/src/app/docs/get-documents-with-python-client/page.md new file mode 100644 index 0000000..815aec5 --- /dev/null +++ b/src/app/docs/get-documents-with-python-client/page.md @@ -0,0 +1,61 @@ +--- +title: Get Documents with the Python Client +slug: get-documents-with-python-client +seo: + title: Get Documents with the Python Client + description: >- + A guide to show how-to get documents from TerminusDB and TerminusCMS using + the Python Client + og_image: https://assets.terminusdb.com/docs/python-client-use-get-documents.png +media: [] +--- + +This guide assumes that you are already connected to the database using the Python client. + +## Get a single document + +To get a single document to make changes or simply to view it, use the following code: + +```python +document = client.get_document("Player/Doug") +``` + +```python + { + '@id' : 'Player/Doug', + '@type' : 'Player', + name : 'Doug', + position: 'Full Back' + } +``` + +## Get a list of all documents + +To get a list of all documents in the database, you can use the `get_all_documents` function. + +```python +documents = client.get_all_documents() +``` + +```python +[ + { + '@id' : 'Player/Doug', + '@type' : 'Player', + name : 'Doug', + position: 'Full Back' + }, + { + '@id' : 'Player/George', + '@type' : 'Player', + name : 'George', + position: 'Center Back' + }, + { + '@id' : 'Player/Karen', + '@type' : 'Player', + name : 'Karen', + position: 'Center Forward' + } +] +``` \ No newline at end of file diff --git a/src/app/docs/get-documents/page.md b/src/app/docs/get-documents/page.md new file mode 100644 index 0000000..3ae1821 --- /dev/null +++ b/src/app/docs/get-documents/page.md @@ -0,0 +1,66 @@ +--- +title: Get Documents +slug: get-documents +seo: + title: Get Documents using the JavaScript Client + description: >- + A guide to show how to get documents to TerminusDB and TerminusCMS using the + JavaScript Client + og_image: >- + https://github.com/terminusdb/terminusdb-web-assets/blob/master/docs/js-client-use-get-documents.png?raw=true +media: [] +--- + +## Get a single document + +To get a single document to make changes or simply to view it, use the following code - + +```javascript +const getDoc = async () => { + const doc = await client.getDocument({id:"Player/Doug"}); + console.log("Player/Doug", doc) +} +``` + +```typescript +{ + '@id' : 'Player/Doug', + '@type' : 'Player', + name : 'Doug', + position: 'Full Back' +} +``` + +## Get a list of all documents + +Get a list of all documents in the database using getDocument as\_list. The results are shown further below. + +```javascript +const getDocs = async () => { + const documents = await client.getDocument({ as_list: "true" }); + console.log("All Documents", documents) +} +``` + +```typescript +[ + { + '@id' : 'Player/Doug', + '@type' : 'Player', + name : 'Doug', + position: 'Full Back' + }, + { + '@id' : 'Player/George', + '@type' : 'Player', + name : 'George', + position: 'Center Back' + }, + { + '@id' : 'Player/Karen', + '@type' : 'Player', + name : 'Karen', + position: 'Center Forward' + } +] +``` \ No newline at end of file diff --git a/src/app/docs/get-started-with-terminusdb/page.md b/src/app/docs/get-started-with-terminusdb/page.md new file mode 100644 index 0000000..6f0e843 --- /dev/null +++ b/src/app/docs/get-started-with-terminusdb/page.md @@ -0,0 +1,80 @@ +--- +title: Get Started with TerminusDB +slug: get-started-with-terminusdb +seo: + title: Get Started with TerminusDB + description: ' An overview of the ways to get started with TerminusDB.' + og_image: >- + https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png +media: [] +--- + +TerminusDB is an open-source document graph database with a collaboration model providing Git-like features. It stores documents as [JSON documents](/docs/documents-explanation/) and the schema language connects these into a [graph](/docs/graphs-explanation/). It comes with [GraphQL](/docs/graphql-query-reference/), User Interface, [CLI](/docs/terminusdb-cli-commands/), [JavaScript](/docs/use-the-javascript-client/), and [Python Clients](/docs/use-the-python-client/). + +## Starting overview + +Get started in minutes on Windows, macOS, or Linux with the steps below. + +### Install + +Install a TerminusDB server. + +### Run + +Start a TerminusDB server. + +### Go + +Create, query, and maintain your databases using several [programmatic interfaces](#interfacesoverview). + +## Installation Overview + +Interaction with TerminusDB databases is through the TerminusBD Server. The server provides a **RESTful** API using the **JSON-LD** exchange format. This enables you to develop applications with your toolchain to utilize the powerful features of graph search and storage. + +To install a TerminusDB server and use TerminusDB databases programmatically in your applications, the installation options below are available. Click on an option for detailed install instructions. + +### Source code + +Install from the [source code](/docs/install-terminusdb-from-source-code/) in [GitHub](https://github.com/terminusdb/terminusdb). + +### Docker container + +Install as a [Docker container](/docs/install-terminusdb-as-a-docker-container/) also referred to as the **TerminusDB bootstrap**. + +## GraphQL + +TerminusDB comes with GraphQL for more information visit the [GraphQL reference guide](/docs/graphql-query-reference/). + +## Javascript client + +Install as a [Node.js](https://nodejs.org/en/download/)\-based [JavaScript Client](/docs/install-terminusdb-js-client/). + +## Python client + +Install as a [Python Client](/docs/install-the-python-client/). Also requires a [Docker container](/docs/install-terminusdb-as-a-docker-container/) installation. + +## Interfaces Overview + +TerminusDB provides several interfaces for creating, querying, and maintaining your databases. Depending on the component/s you choose to install, you can interact with TerminusDB using one or more of the available interfaces listed below. + +Use one or a combination of several TerminusDB interfaces. + +### GraphQL + +TerminusDB automatically generates GraphQL schema to query data. Read the [GraphQL reference](/docs/graphql-query-reference/) guide for more information. + +### Command Line Interface + +The TerminusDB [Command Line Interface](/docs/terminusdb-cli-commands/) (CLI.) + +### Dashboard + +The TerminusDB [dashboard](https://dashboard.terminusdb.com) provides a visual interface. + +### APIs + +The TerminusDB [Javascript](/docs/use-the-javascript-client/) and [Python Client](/docs/use-the-python-client/) APIs. + +### Query + +The TerminusDB [Web Object Query Language](/docs/woql-explanation/) (WOQL.) \ No newline at end of file diff --git a/src/app/docs/get-started/page.md b/src/app/docs/get-started/page.md new file mode 100644 index 0000000..81d1d8f --- /dev/null +++ b/src/app/docs/get-started/page.md @@ -0,0 +1,37 @@ +--- +title: Getting Started +slug: get-started +seo: + title: TerminusDB/CMS Technical Documentation + description: 'Technical documentation for TerminusDB and TerminusCMS. ' + og_image: >- + https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png +media: + - alt: Clone a demo data product from the TerminusCMS dashboard + caption: >- + Your team home page features a number of demo projects to clone and + experiment with. + media_type: Image + title: Clone a demo data product from the TerminusCMS dashboard + value: https://assets.terminusdb.com/docs/how-to-clone-a-demo.png +--- + +TerminusCMS is a headless content management system. It is designed to give devs a solution for complex content and knowledge infrastructures. Bringing together change request workflows, analytics, and complex integrations, TerminusCMS aims to be a content platform that sits at the convergence of content and knowledge. + +TerminusCMS is free to get started. When you sign up, you are assigned the community package. This comes with generous limits to allow you to build for free, and then upgrade when needed. + +## Steps to get started + +1. Sign up at [https://dashboard.terminusdb.com](https://dashboard.terminusdb.com) +2. Take a look through the [product tour](/docs/projects-terminuscms-tour/) to familiarise yourself with TerminusCMS +3. Install the [JavaScript](/docs/install-terminusdb-js-client/) or [Python](/docs/install-the-python-client/) Client +4. [Get your API key to use a client with TerminusCMS.](/docs/how-to-connect-terminuscms/) +5. [Familiarize yourself with the client API](/docs/connect-with-the-javascript-client/) to start building with TerminusCMS. + +## Demo Projects + +There are several demo projects available to clone and experiment with. Sign up and visit your team home page to clone these projects. + +![Clone a demo data product from the TerminusCMS dashboard](https://assets.terminusdb.com/docs/how-to-clone-a-demo.png) + +Your team home page features a number of demo projects to clone and experiment with. \ No newline at end of file diff --git a/src/app/docs/get-your-api-key-from-terminuscms/page.md b/src/app/docs/get-your-api-key-from-terminuscms/page.md new file mode 100644 index 0000000..a277464 --- /dev/null +++ b/src/app/docs/get-your-api-key-from-terminuscms/page.md @@ -0,0 +1,51 @@ +--- +title: Get your API key from TerminusCMS +slug: get-your-api-key-from-terminuscms +seo: + title: How to get your API key using TerminusCMS + description: >- + A how-to guide showing how to get your API key to set up and configure your + environment to use with a client. + og_image: https://assets.terminusdb.com/docs/get-your-api-key.png +media: [] +--- + +## Generate your API key + +To use the Python or JavaScropt client with TerminusCMS, an API key is required. The API key is obtained in the TerminusCMS dashboard by using the steps below. + +**1\. Log in** + +Log in to the user interface dashboard [dashboard.terminusdb.com](https://dashboard.terminusdb.com) + +**2\. Select a Team** + +The teams are listed in the centre of the screen after logging in (and selecting a plan if you have not already done so). This will be the team in which the API key will be generated. + +**3\. Select your profile** + +Select your `Profile` by clicking on ▼ at the top-right corner of the screen. + +**4\. Generate a Personal Access Token** + +Enter a description in `Add a Token Description` then click `Generate New Token`. Copy the token generated. + +**5\. Copy the required code snippet** + +Select the `Python` or `JavaScript` tab then copy the code snippet. + +## Set up your environment + +Assign your token to the environment variable `TERMINUSDB_ACCESS_TOKEN` in your code snippet. The example below is in `bash`. + +### Code: API key environment configuration + +```bash +export TERMINUSDB_ACCESS_TOKEN="my API key here" +``` + +You are now ready to start with a client - + +[Connect to JavaScript Client](/docs/connect-with-the-javascript-client/) + +[Connect to Python Client](/docs/connect-with-python-client/) \ No newline at end of file diff --git a/src/app/docs/glossary/page.md b/src/app/docs/glossary/page.md new file mode 100644 index 0000000..bed731e --- /dev/null +++ b/src/app/docs/glossary/page.md @@ -0,0 +1,182 @@ +--- +title: Glossary of Terms +slug: glossary +seo: + title: TerminusCMS/DB Glossary of Terms + description: A glossary of terms for TerminusDB and TerminusCMS + og_image: >- + https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png +media: [] +--- + +> **Context:** Unless otherwise stated, the context for all definitions is computer, data, or information science. +> +> **Source:** Unless otherwise stated, the source of all definitions is [Wikipedia](https://en.wikipedia.org/wiki/Main_Page) + +## Graph concepts + +### Knowledge Graph + +There are numerous definitions of knowledge graphs. One one the simpler definitions is: A digital structure that represents knowledge as concepts and the relationships between them (facts.) A knowledge graph can include an [ontology](#ontology) that allows both humans and machines to understand and reason about its contents. + +[Read more](https://en.wikipedia.org/wiki/Knowledge_graph#Definitions) + +### Graph database + +A database that uses [graph structures](#graphstructure) for [semantic queries](#semanticquery) with [nodes](#node), [edges](#edge), and [properties](#property) to represent and store data. The edges form the graph. The graph relates the data items in the store to a collection of nodes and edges, the edges representing the relationships between the nodes. The relationships allow data in the store to be linked together directly and, in many cases, retrieved with one operation. Graph databases hold the relationships between data as a priority. Querying relationships is fast because they are perpetually stored in the database. Relationships can be intuitively visualized using graph databases, making them useful for heavily inter-connected data + +[Read more](https://en.wikipedia.org/wiki/Graph_database) + +### Graph Structure + +An abstract data type for implementing the graph theory concepts of [Undirected](#undirectedgraph) and [Directed](#directedgraph) graphs. The former concept consists of **unordered pairs** of vertices (also called [nodes](#node) or points.) The latter consists of **ordered pairs** of vertices. + +A graph data structure consists of a finite set of vertices, together with a set of unordered or ordered pairs of these vertices as defined above. These pairs are known as [edges](#edge) (also called links or lines, and sometimes called arrows or arcs for a directed graph.) The vertices may be part of the graph structure, or may be external [entities](#entity) represented by integer indices or references. + +A graph data structure may also associate an edge value to each edge, such as a symbolic label or a numeric attribute (cost, capacity, length, etc.) + +[Read more](https://en.wikipedia.org/wiki/Graph_\(abstract_data_type\)) + +### Directed Graph + +A directed graph (or **digraph**) is a graph made up of vertices connected by directed [edges](#edge) often called **arcs**. + +[Read more](https://en.wikipedia.org/wiki/Directed_graph) + +### Ontology + +A way of showing the properties of a subject area and how they are related, by defining a set of concepts and categories that represent the subject. An ontology encompasses a representation, formal naming and definition of the categories, properties and relations between the concepts, data and entities that substantiate one, many, or all [domains](#domain) of discourse. + +[Read more](https://en.wikipedia.org/wiki/Ontology_\(information_science\)) + +### Semantic Query + +Semantic queries allow for queries and analytics of an associative and contextual nature. Semantic queries enable the retrieval of both explicitly and implicitly derived information based on syntactic, semantic and structural information contained in data. They are designed to deliver precise results (possibly the distinctive selection of one single piece of information) or to answer more fuzzy and wide-open questions through pattern matching and digital reasoning. + +[Read more](https://en.wikipedia.org/wiki/Semantic_query) + +### Node + +A **vertex** (plural vertices) or **node** is the fundamental unit of which graphs are formed: an undirected graph consists of a set of vertices and a set of [edges](#edge) (unordered pairs of vertices), while a directed graph consists of a set of vertices and a set of **arcs** (ordered pairs of vertices). In a diagram of a graph, a vertex is usually represented by a circle with a label, and an edge is represented by a line or arrow extending from one vertex to another. + +[Read more](https://en.wikipedia.org/wiki/Vertex_\(graph_theory\)) + +### Edge + +An edge (together with [vertices](#node)) is one of the two basic units out of which graphs are constructed. Each edge has two (or in hypergraphs, more) vertices to which it is attached, called its **endpoints**. Edges may be [directed](#directedgraph) or undirected; undirected edges are also called **lines** and directed edges are also called **arcs** or **arrows**. In an undirected simple graph, an edge may be represented as the set of its [vertices](#node), and in a directed simple graph it may be represented as an ordered pair of its vertices. An edge that connects vertices x and y is sometimes written xy. + +[Read more](https://en.wikipedia.org/wiki/Glossary_of_graph_theory#edge) + +## Data + +### Delta Encoding + +A way of storing and transmitting data in the form of **deltas** (differences) between sequential data rather than complete files; sometimes referred to as data differencing. Delta encoding is sometimes called delta compression, particularly where archival histories of changes are required, for example, in revision control systems such as [GitHub](https://github.com) and the **TerminusDB** version-controlled graph databases. + +[Read more](https://en.wikipedia.org/wiki/Delta_encoding) + +### Metadata + +Metadata is data that provides information about other data, but not the content of the data, such as the text of a message or an image. There are many distinct types of metadata. + +[Read more](https://en.wikipedia.org/wiki/Metadata) + +### RDF + +The **Resource Description Framework** (RDF) is a family of **W3C** specifications used as a general method for conceptual description or modeling of information that is implemented in web resources, using a variety of syntax notations and data [serialization](#serialization) formats. + +### Triple + +A **semantic triple**, or **RDF triple** or simply **triple**, is the atomic data entity in the [RDF](#rdf) data model. A triple is a set of three entities that codifies a statement about [semantic data](#semantic-data) in the form of [subject](#subject)–[predicate](#predicate)–[object](#object) expressions. Examples: + +#### Table: Subject-Predicate-Object examples + +{% table %} + +- Subject +- Predicate +- Object + +--- + +- Bob +- knows +- John + +--- + +- Bob +- is +- 35 + +{% /table %} + +This format enables knowledge to be represented in a machine-readable way. Every part of an RDF triple is individually addressable via unique URIs. For example, the statement "Bob knows John" might be represented in RDF as: + +```rdf +http://example.name#Bob12 http://xmlns.com/foaf/0.1/knows http://example.name#John34 +``` + +[Read more](https://en.wikipedia.org/wiki/Semantic_triple) + +### Semantic Data + +Semantic data or **Semantic Data Model** (SDM) is a high-level semantics-based database description or model. This database model is designed to capture more of the meaning of an application environment than is possible with contemporary database models. + +[Read more](https://en.wikipedia.org/wiki/Semantic_data_model) + +### Serialization + +The process of translating a data structure or object state into a format that can be stored (for example, in a file or memory) or transmitted (for example, over a computer network) and reconstructed later (possibly in a different computer environment.) + +[Read more](https://en.wikipedia.org/wiki/Serialization) + +### Schema + +The organization of data as a blueprint of how the database is constructed. + +[Read more](https://en.wikipedia.org/wiki/Database_schema) + +### Attribute + +The columns of a table in relational databases. Similar to properties in graph databases. + +### Entity + +Tables in relational databases. Similar to nodes in graph databases. + +### Relationship + +The relationships between two tables in relational databases. In graph databases, relationships are directed and named connections between two nodes. + +## TerminusDB specific + +### WOQL + +WOQL (**Web Object Query Language**) is TerminusDB's query language for querying complex data patterns and structures. WOQL is based on three fundamental concepts: WOQL [triples](#triples), WOQL **variables** and WOQL **operators**. WOQL also provides [PCRE](#pcre). + +> WOQL does not use the [SPARQL](https://en.wikipedia.org/wiki/SPARQL) protocol. + +### Immutable + +In programming, the state of an immutable object is unchangeable, i.e., its state cannot be modified after it is created. In TerminusDB, **immutable data** means an instance of data that cannot be changed after it is created. Newer instances or versions of that data can be created, but the tat version is immutable. + +[Read more](https://en.wikipedia.org/wiki/Immutable_object) + +### Mutable + +In contrast to an [immutable](#immutable) object, a mutable object is changeable. + +[Read more](https://en.wikipedia.org/wiki/Immutable_object) + +### PCRE + +**Perl Compatible Regular Expressions** (PCRE) is a library that implements a regular expression engine, inspired by the capabilities of the Perl programming language. PCRE's syntax is more powerful and flexible than many other regular-expression libraries. + +[Read more](https://en.wikipedia.org/wiki/Perl_Compatible_Regular_Expressions) + +### IRI + +The **Internationalized Resource Identifier** (IRI) is an internet protocol standard that builds on the Uniform Resource Identifier (URI) protocol by greatly expanding the set of permitted characters. IRIs extend URIs by using the Universal Character Set, where URIs were limited to ASCII, with far fewer characters. IRIs may be represented by a sequence of octets but by definition are defined as a sequence of characters, because IRIs may be spoken or written by hand. + +[Read more](https://en.wikipedia.org/wiki/Internationalized_Resource_Identifier) \ No newline at end of file diff --git a/src/app/docs/graphql-and-woql-query-terminuscms-tour/page.md b/src/app/docs/graphql-and-woql-query-terminuscms-tour/page.md new file mode 100644 index 0000000..aa184f5 --- /dev/null +++ b/src/app/docs/graphql-and-woql-query-terminuscms-tour/page.md @@ -0,0 +1,57 @@ +--- +title: GraphQL & WOQL Query Tools +slug: graphql-and-woql-query-terminuscms-tour +seo: + title: GraphQL & WOQL Query Tools - TerminusCMS Tour + description: An overview of the GraphQL and WOQL tools in the TerminusCMS dashboard + og_image: >- + https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png +media: + - alt: GraphQL playground + caption: '' + media_type: Image + title: GraphQL playground + value: https://assets.terminusdb.com/docs/graphql-playground.png + - alt: Test out your WOQL queries in the TerminusCMS dashboard + caption: '' + media_type: Image + title: Test out your WOQL queries in the TerminusCMS dashboard + value: https://assets.terminusdb.com/docs/woql-playground.jpg +--- + +TerminusCMS features query panes for [GraphQL](/docs/graphql-basics/) and [WOQL](/docs/woql-basics/). + +## GraphQL Query Pane + +![GraphQL playground](https://assets.terminusdb.com/docs/graphql-playground.png) + +TerminusCMS includes GraphiQL to experiment and test queries. It automatically generates the GraphQL schema based on the project's schema. + +It includes - + +* List of root types within the project +* Autofill to aid query construction +* Pretty print +* Results panel +* Error reporting + +For more details about the types of queries available with GraphQL, such as path queries, filters, and arguments, please refer to the [GraphQL reference guide](/docs/graphql-query-reference/). + +### WOQL Query Pane + +![Test out your WOQL queries in the TerminusCMS dashboard](https://assets.terminusdb.com/docs/woql-playground.jpg) + +Web Object Query Language ([WOQL](/docs/woql-explanation/)) is a powerful and sophisticated query language which allows you to concisely express complex patterns over arbitrary data structures. + +The playground enables users to build WOQL queries to experiment and test. Users can also - + +* Add, edit, and delete documents +* View query as JSON-LD format +* Copy the query +* See results +* Select query parameters based on the schema (left side of the screen) + +Please see these other resources for understanding and using WOQL - + +* [WOQL Basics](/docs/woql-basics/) +* [WOQL reference guide](/docs/woql-class-reference-guide/) \ No newline at end of file diff --git a/src/app/docs/graphql-basics/page.md b/src/app/docs/graphql-basics/page.md new file mode 100644 index 0000000..656ae55 --- /dev/null +++ b/src/app/docs/graphql-basics/page.md @@ -0,0 +1,171 @@ +--- +title: Query with GraphQL +slug: graphql-basics +seo: + title: Learn the GraphQL Basics for TerminusCMS + description: >- + Learn to query TerminusDB and TerminusCMS using GraphQL and a Star Wars data + project that you can clone from the dashboard. + og_image: https://assets.terminusdb.com/docs/graphqll-basics.png +media: + - alt: Clone a demo project from the dashboard + caption: '' + media_type: Image + title: Clone a demo project from the dashboard + value: https://assets.terminusdb.com/docs/how-to-clone-a-demo.png + - alt: GraphQL query playground + caption: '' + media_type: Image + title: GraphQL query playground + value: https://assets.terminusdb.com/docs/how-to-query-graphql.png +--- + +> To use this HowTo, first [clone the Star Wars demo](/docs/clone-a-demo-terminuscms-project/) into your team on TerminusCMS. You will then have full access to the data needed for this tutorial. + +![Clone a demo project from the dashboard](https://assets.terminusdb.com/docs/how-to-clone-a-demo.png) + +Once you have cloned the database, go to the GraphQL icon (triangle in hexagon) on the left hand side and select the filing cabinet icon. + +![GraphQL query playground](https://assets.terminusdb.com/docs/how-to-query-graphql.png) + +Now you have two panels, one on the left for query, and one on the right for results. + +## Entering a query + +First type `query{` into the query panel. It should look like this: + +```graphql +query{ + █ +} +``` + +If at the cursor point you type: `Ctrl-c` you'll get a list of options you can choose from. These options are legal GraphQL syntax according to your provided schema. Let's search for people from the Star Wars universe. + +```graphql +query{ + People{ + label + } +} +``` + +The `label` property in this schema, supplies the name of the person we are interested in. Of course this query might give us a bit too much, so let us also limit it. + +```graphql +query{ + People(limit: 5){ + label + } +} +``` + +This should result in: + +```json +{ + "data": { + "People": [ + { + "label": "Luke Skywalker" + }, + { + "label": "Obi-Wan Kenobi" + }, + { + "label": "Anakin Skywalker" + }, + { + "label": "Wilhuff Tarkin" + }, + { + "label": "Chewbacca" + } + ] + } +} +``` + +To get more fields in our query, we can just add words, using `Ctrl-c` if we are stuck for names of fields. + +```graphql +query{ + People(limit: 5){ + label + } +} +``` + +When following links to other objects, we have to embed a query inside our query. So, for instance, if we want to know the homeworld that each of these people come from we can write: + +```graphql +query{ + People(limit: 2){ + label + homeworld{ + label + } + } +} +``` + +This will get us: + +```json +{ + "data": { + "People": [ + { + "label": "Luke Skywalker", + "homeworld": { + "label": "Tatooine" + } + }, + { + "label": "Obi-Wan Kenobi", + "homeworld": { + "label": "Stewjon" + } + } + ] + } +} +``` + +## Paging + +If we want to page the results, we can also add an offset to our query, and we'll get _the next_ results. + +```graphql +query{ + People(limit: 2, offset:2){ + label + homeworld{ + label + } + } +} +``` + +And now we get two more: + +```json +{ + "data": { + "People": [ + { + "label": "Anakin Skywalker", + "homeworld": { + "label": "Tatooine" + } + }, + { + "label": "Wilhuff Tarkin", + "homeworld": { + "label": "Eriadu" + } + } + ] + } +} +``` \ No newline at end of file diff --git a/src/app/docs/graphql-naming-conventions-reference/page.md b/src/app/docs/graphql-naming-conventions-reference/page.md new file mode 100644 index 0000000..fbcb3cb --- /dev/null +++ b/src/app/docs/graphql-naming-conventions-reference/page.md @@ -0,0 +1,60 @@ +--- +title: GraphQL Naming Conventions Reference Guide +slug: graphql-naming-conventions-reference +seo: + title: GraphQL Naming Conventions Reference Guide + description: >- + A reference guide detail the GraphQL naming conventions in TerminusDB and + TerminusCMS. + og_image: >- + https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png +media: [] +--- + +TerminusDB has its own flexible schema language which is designed to be compatible with RDF. The RDF world identifies resources with IRIs which are flexible, and use a relatively large space of available characters. + +GraphQL, by contrast, has a very restrictive allowed character set for naming. Essentially only Alphanumeric characters using un-accented Latin. That is, it is essentially restricted to `[A-Z][a-z][0-9][_]`. + +Because of this, we have some naming conventions to translate automatically from TerminusDB classes and properties to GraphQL named classes and properties. While we have endevoured to do so in a way that is unlikely to create naming collisions, these are never-the-less possible. + +TerminusDB generates GraphQL schema automatically as a mapping from TerminusDB. TerminusDB's definition language is a strict super-set of GraphQL and so is able to faithfully represent GraphQL features. + +For each class in TerminusDB, there is a range of classes that are defined automatically by TerminusDB in the associated GraphQL schema. + +## Underscore as reserved + +When names are likely to create conflicts with user-defined names, TerminusDB will typically use an `_` at the beginning to avoid naming conflicts. This is done on filter fields that share the same object level with user-defined properties for instance: `_and`, `_or` and `_not`. + +## Translation + +All names of GraphQL classes in TerminusDB and all properties of TerminusDB classes, as well as all enums, are translated to viable GraphQL names. This is done by replacing each non-representable character with an `_`. In addition, underscores at the beginning of a class name or property are disallowed. This is to ensure there are no collisions with TerminusDB's own auto-generated properties and classes. + +Should a collision arise, TerminusDB should give a GraphQL error on retrieval of the schema. In future, we will allow this check to occur at schema submission time, and will also allow explicit renaming in TerminusDB classes. + +For instance, the TerminusDB class is defined as: + +```json +{ "@type" : "Class", + "@id" : "Galactic-Civilisation", + "name" : "xsd:string", + "kardashev-scale" : "xsd:integer" } +``` + +will be translated to: + +```graphql +type Query { + Galatic_Civilisation( + id: ID + """skip N elements""" + offset: Int + """limit results to N elements""" + limit: Int + filter: Galactic_Civilisation_Filter + """order by the given fields""" + orderBy: Galactic_Civilisation_Ordering + ): [GalaticCivilsiation!]! + name : String! + kardashev_scale: BigInt! +} +``` \ No newline at end of file diff --git a/src/app/docs/graphql-query-reference/page.md b/src/app/docs/graphql-query-reference/page.md new file mode 100644 index 0000000..9a3eb8c --- /dev/null +++ b/src/app/docs/graphql-query-reference/page.md @@ -0,0 +1,436 @@ +--- +title: GraphQL Query Reference Guide +slug: graphql-query-reference +seo: + title: GraphQL Query Reference Guide + description: >- + A GraphQL query reference guide explaining the workings of GraphQL queries + with TerminusDB and TerminusCMS + og_image: >- + https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png +media: [] +--- + +GraphQL queries are composed of: + +* Queries +* Arguments +* Fields + +Each Class in TerminusDB automatically generates a top-level Query. Each property of the class automatically generates both arguments and fields. + +The names of the types of arguments and fields are generated automatically [subject to name mapping](/docs/graphql-naming-conventions-reference/). + +In turn, each property which is an edge leading to a new object of a class will have its own field with arguments. + +Each concrete data query will be terminal and will generate a specific field parameter for search. + +## Example + +For example, using the following TerminusDB schema: + +```json +{ "@type" : "Class", + "@id" : "Person", + "name" : "xsd:string", + "dob" : "xsd:dateTime", + "friend" : {"@type" : "Set", "@class" : "Person" }} +``` + +TerminusDB will generate the following GraphQL class. + +```graphql +type Query { + Person( + id: ID + """skip N elements""" + offset: Int + """limit results to N elements""" + limit: Int + filter: Person_Filter + """order by the given fields""" + orderBy: Person_Ordering + ): [Person!]! +} +type Person { + dob: DateTime! + friend( + id: ID + """skip N elements""" + offset: Int + """limit results to N elements""" + limit: Int + filter: Person_Filter + """order by the given fields""" + orderBy: Person_Ordering + ): [Person!]! + name: String! + id: ID! +} +``` + +The `Person` query, allows you to query for a person at the top level, along with a number of arguments, including: a `filter` (for search), a `limit` for reducing to a defined length of results, an `offset`, for obtaining results starting from some offset (for use in _paging_) and an `orderBy` to obtain the results in a defined order. + +In addition, we have the various _fields_ of a `Person` object, each of which may have arguments if they are objects or simple data types for terminal fields. + +One can use such a query by using the [GraphQL endpoint](/docs/connecting-to-graphql-reference/). + +## Arguments + +Arguments are restrictions or meta-fields about the query. These can be used to limit results, or filter to specific results, as well as perform ordering. + +### `id` + +The id of an object can be directly supplied, in order to ensure that we only obtain the specific object of interest. + +A person might be retrieved by supplying the id as a variable in the following way: + +```graphql +query Person(id:$id){ + name +} +``` + +### `offset` + +GraphQL will retrieve all objects in the database for a given class type, unless `offset` and `limit` are supplied. `offset` will start a query from a given result offset, allowing the query user to _page_ results. + +```graphql +query Person(limit: 3 offset: 3){ + name + Person( + id: ID + """skip N elements""" + offset: Int + """limit results to N elements""" + limit: Int + filter: Person_Filter + """order by the given fields""" + orderBy: Person_Ordering + ): [Person!]! +} +``` + +This query retrieves the second page of a 3-object page of persons. + +### `limit` + +GraphQL will retrieve all objects in the database for a given class type, unless `offset` and `limit` are supplied. `limit` will only find the limit-number of results, allowing the query user to _page_ results. + +```graphql +query Person(limit: 3 offset: 3){ + name +} +``` + +This query retrieves the second page of a 3-object page of persons. + +### `orderBy` + +The orderBy filter allows the user to order results according to some data in the object. For instance, to create an ordering on people, we might write: + +```graphql +query Person(limit: 3 offset: 3, orderBy: { dob: DESC, name: ASC}){ + name + dob +} +``` + +This will yield Persons from youngest to oldest, ordering by name in the event of a "tie" on date of birth. + +## `filter` + +Filters allow you to restrict to specific results by reducing the set to those objects which match the filter fields. + +Each filter is an input object, defined for the specific class and generated automatically by TerminusDB. The `Person` object defined above gets the input objects: + +```graphql +input Person_Filter { + dob: DateTimeFilterInputObject + friend: Person_Collection_Filter + name: StringFilterInputObject + _and: [Person_Filter!] + _or: [Person_Filter!] + _not: Person_Filter +} +input Person_Collection_Filter { + someHave: Person_Filter + allHave: Person_Filter +} +input StringFilterInputObject { + eq: String + ne: String + lt: String + le: String + gt: String + ge: String + regex: String + startsWith: String + allOfTerms: [String!] + anyOfTerms: [String!] +} +input DateTimeFilterInputObject { + eq: DateTime + ne: DateTime + lt: DateTime + le: DateTime + gt: DateTime + ge: DateTime +} +``` + +Filters can apply to immediate values, such as the `dob` (date of birth), which can be restricted using a time comparison, or they can be filters on linked objects, such as the `Person_Collection_Filter` which allows us to compare with our friends. + +In GraphQL we might write a simple query over people as: + +```graphql +query Person(orderBy: { name: ASC}, + filter: { name: {regex: "(Joe|Joseph)"}, + _and: [{friend: + {someHave: + {name: {regex: "(Jim|James)"}}}}]}){ + name + dob +} +``` + +This finds name and date of birth of all people who have a name which contains "Joe" or "Joesph" and who are friends with someone named "Jim" or "James", in order of ascending name. + +## Filter Builtin Types + +Filters have to work with all of the GraphQL base types, along with the extensions which TerminusDB currently supports (`DateTime`, and `BigInt`). + +### BigIntFilterInputObject + +Big integers use the widely available `BigInt` type extension to GraphQL. + +The Filters available for BigInt are: + +* `eq`: Equality +* `ne`: disequality +* `lt`: Less than +* `le`: Less than or equal +* `gt`: Greater than +* `ge`: Greater than or equal + +When a field of an object refers to a `BigInt`, we can filter it by writing a query along the following lines: + +```graphql +query { + Event(filter : { years_since_big_bang : { ge : "8000000000"}}){ + event_name + years_since_big_bang + } +} +``` + +### DateTimeFilterInputObject + +Date time objects use the widely available `DateTime` type extension to GraphQL. + +The Filters available for BigInt are: + +* `eq`: Equality +* `ne`: disequality +* `lt`: Less than +* `le`: Less than or equal +* `gt`: Greater than +* `ge`: Greater than or equal + +```graphql +query { + Event(filter : { date_of_event : { ge : "2000-01-01T00:00:00Z"}}){ + event_name + date_of_event + } +} +``` + +### StringFilterInputObject + +Strings are native GraphQL types. TerminusDB exposes the following filter options for strings: + +* `eq`: Equality +* `ne`: Disequality +* `lt`: Less than +* `le`: Less than or equal +* `gt`: Greater than +* `ge`: Greater than or equal +* `regex`: Matches regex +* `startsWith`: Matches the string prefix +* `allOfTerms`: Contains all terms in the list of terms +* `anyOfTerms`: Contains any of the terms in the list of terms + +A query filter using strings could be written as follows: + +```graphql +query { + Event(filter : { event_name : { regex : "[Cc]elstial [Ee]vent"}}){ + event_name + } +} +``` + +### BooleanFilterInputObject + +Booleans are native GraphQL types. TerminusDB exposes the following filter options: + +* `eq`: Equality +* `ne`: Disequality + +A query filter using booleans could be written as follows: + +```graphql +query { + Event(filter : { is_super_nova : { eq : true}}){ + event_name + } +} +``` + +### SmallIntegerFilterInputObject + +Integers (signed, 32-bit integers) are native GraphQL types. TerminusDB exposes the following filter options: + +* `eq`: Equality +* `ne`: disequality +* `lt`: Less than +* `le`: Less than or equal +* `gt`: Greater than +* `ge`: Greater than or equal + +A query filter using booleans could be written as follows: + +```graphql +query { + Civilization(filter : { kardashev_scale : { ge : 3}}){ + name + kardashev_scale + } +} +``` + +### `_and` + +The `_and` filter combinator allows us to chain constraints. It takes two filter objects relevant at the current level. + +We can find all civilizations of a high Kardashev scale using a query such as: + +```graphql +query { + Civilization(filter : {_and : [{ kardashev_scale : { le : 5}} + { kardashev_scale : { ge : 3}}]){ + name + kardashev_scale + } +} +``` + +### `_or` + +The `_or` filter combinator allows us to make choices of constraints. It takes two filter objects relevant at the current level. It is implicitly combined as if with `_and`, with any filters at the current level. We can find all civilizations of a high Kardashev scale, which is also a galactic civilisation using a query such as: + +```graphql +query { + Civilization(filter : { galactic_scale : {eq : true}, + _or : [{ kardashev_scale : { eq : 2}} + { kardashev_scale : { eq : 3}}]){ + name + kardashev_scale + } +} +``` + +### `_not` + +The `_not` operator allows us to combine other constraints with _dis-constraints_, which remove any elements which match its sub-filter. We can ask for galactic civilizations which have not mastered energy acquisition at level 3 on the Kardashev scale. + +```graphql +query { + Civilization(filter : { galactic_scale : {eq : true}, + _not : { kardashev_scale : { eq : 3}}}){ + name + kardashev_scale + } +} +``` + +## Fields + +Each TerminusDB class has associated with it, some number of fields. These fields include each field that is defined in the class. For instance, given the TerminusDB class: + +```json +{ "@type" : "Class", + "@id" : "Person", + "name" : "xsd:string", + "dob" : "xsd:dateTime", + "friend" : {"@type" : "Set", "@class" : "Person" }} +``` + +We have a query field for each of `name`, `dob` and `friend`. However we also have the following specially defined fields: + +### `_id` + +This returns the fully qualified URI of the given instance of the `Person` class being returned. + +### `_type` + +This returns the class at which this instance is instantiated. This is useful when a super-class is queried, as we can obtain what concrete subclass it corresponds to. + +### Backlinks + +`_PROPERTY_of_CLASS` + +The _backlink_ is a way to find all instances that _point_ to a given class. The backlink is generated automatically for every edge which terminates at the current class. For example, with the Person class: + +```json +{ "@type" : "Class", + "@id" : "Person", + "name" : "xsd:string", + "dob" : "xsd:dateTime", + "friend" : {"@type" : "Set", "@class" : "Person" }} +``` + +We automatically get the backlink `_friend_of_Person` that says which people view us as their friends. For instance, we can construct the following query: + +```graphql +{ + Person{ + name + _friend_of_Person{ + name + } + } +} +``` + +This will find the name of every person who views the top level `Person` us as their friend (i.e. has a `friend` link to the current person). + +### Path Queries + +`_path_to_CLASS` + +A path query allows us to use regular graph expressions to follow links from the current object to another object of `CLASS`. Using the `Person` example: + +```json +{ "@type" : "Class", + "@id" : "Person", + "name" : "xsd:string", + "dob" : "xsd:dateTime", + "friend" : {"@type" : "Set", "@class" : "Person" }} +``` + +We can find everyone within 2-degrees of separation with the following path query: + +```graphql +{ + Person{ + name + _path_to_Person(path: "friend{1,3}"){ + name + } + } +} +``` + +See the [complete syntax for path queries](/docs/path-query-reference-guide/) for more details on the semantics of the path argument. \ No newline at end of file diff --git a/src/app/docs/graphs-explanation/page.md b/src/app/docs/graphs-explanation/page.md new file mode 100644 index 0000000..7f21fe9 --- /dev/null +++ b/src/app/docs/graphs-explanation/page.md @@ -0,0 +1,95 @@ +--- +title: Graphs Explanation +slug: graphs-explanation +seo: + title: Graphs Explanation + description: >- + An introduction to the hierarchy and system of graphs used by TerminusDB and + TerminusCMS for collaboration and revision control. + og_image: >- + https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png +media: [] +--- + +## Graph hierarchy + +A TerminusDB database is a hierarchical collection of [data graphs](#datagraphs) and [control graphs](#controlgraphs). These graphs are key to providing a graph database system with **collaboration** and **revision control**. + +### Data graphs + +Data graphs keep track of data and information about data. Each level of the database hierarchy is a combination of the following data graphs. + +* **Instance graphs** contain data for a given level in a hierarchy. +* **Schema graphs** contain information about what data is allowed and how to interpret it. +* **Inference graphs** enable facts to be inferred about the data. + +### Control graphs + +Control graphs govern data graphs and database functionality. Each level of the control graph hierarchy, listed below, consists of one or more data graphs. The remainder of this article explains each control graph and the lowest level of the hierarchy - layers. + +* **Repository graphs** for collaboration. +* **Commit graphs** for revision control. +* **Branch graphs** for data storage and correctness. +* **Layers** for storing data changes. + +## Repository graphs + +Repository graphs provide collaboration and communication with other TerminusDB instances and keep track of other TerminusDB repositories. + +### Referencing repository graphs + +Repository graphs are referenced using the name `_meta` which contains links with various repositories. + +### Repository naming + +A repository is addressed by specifying its organization and name. For example, organization `admin`, database name `foo` expressed as `admin/foo`. + +### Local repositories + +The identifier `local` is used for specifying local repositories, for example, `admin/foo/local`. + +A local repository in the repository instance data has **layer identifiers** that point to associated commit graphs. + +### Remote repositories + +An identifier other than `local` is used for specifying remote repositories (or remotes.) For example `admin/foo/origin`. + +A remote in the repository instance data has layer identifiers **and** the URL of the remote. The URL enables communication with the remote and enables push and pull from various remotes to update and synchronize with the local repository. + +## Commit graphs + +Commit graphs provide revision control. They contain the information required for time-travel, branch, squash, reset and rebase operations. Commit graphs hold information about branches and all commits on them. + +### Referencing commit graphs + +Commit graphs are referenced by appending the name `_commits` to the database identifier, for example: `admin/foo/local/_commits`. Commits are trackable on local and remote TerminusDB instances enabling synchronization with different instances. + +### Branch objects in commit graphs + +Branch objects in a commit-graph point to a commit object. A commit object is associated with layers representing the branch of interest. A commit object also has parent commits if the commit has a history. + +## Branch graphs + +Branch graphs store data in a queryable format and ensure the correctness of data by maintaining a schema. + +### Referencing branch graphs + +Branch graphs are referenced with the name `branch` followed by the branch of interest. The default is `main`. For example `admin/foo/local/branch/main`. + +## Layers + +The lowest level of the hierarchy is a single graph composed of a sequence of layers. Layers specify each change to data such as additions and deletions. + +## Transactions in graphs + +A transaction in a graph is also a hierarchical operation, ensuring [ACID transactions](/docs/acid-transactions-explanation/). An update transaction has the following stages: + +* The layers of a branch graph are updated, resulting in the addition of new layers. +* A schema check is performed. If the check succeeds, the layer names of the updated graphs are obtained (an update can affect several graphs simultaneously.) +* New layers are written as commit objects in the commit instance graph, and the head of the branch is moved, resulting in a new instance graph for the commit-graph. +* The layer name of the new instance graph is written to the repository graph, enabling the identification of the current, most recent state of the repository. +* The layer name of the repository graph is labeled as the newest version and kept in the layer store as a named pointer to a layer. + +## Further Reading + +### [Documents in a knowledge graph and how to use them](/docs/documents-explanation/) \ No newline at end of file diff --git a/src/app/docs/group-query-results/page.md b/src/app/docs/group-query-results/page.md new file mode 100644 index 0000000..64d16b6 --- /dev/null +++ b/src/app/docs/group-query-results/page.md @@ -0,0 +1,94 @@ +--- +title: How to Group Results in WOQL +slug: group-query-results +seo: + title: How to Group Results in WOQL + description: >- + A guide to show how to group results of data in your TerminusCMS and + TerminusDB projects using WOQL. + og_image: https://assets.terminusdb.com/docs/woql-group-query-results.png +media: [] +--- + +> To use this HowTo, first [clone the Star Wars demo](/docs/clone-a-demo-terminuscms-project/) into your team on TerminusCMS. You will then have full access to the data needed for this tutorial. + +## How to use Group By + +If we need to group variables according to some criteria, we can create an aggregate of solutions using `group_by`. + +A group by is composed of a _focus_, a _template_, and a _group_ together with a query. + +We will demonstrate this with the following query: + +```javascript +let v = Vars("person", "label", "eyes", "group"); +limit(1) +.group_by( + "eyes", + ["label"], + v.group, + and(triple(v.person, "rdf:type", "@schema:People"), + triple(v.person, "label", v.label), + triple(v.person, "eye_color", v.eyes))) +``` + +The first argument, here `"eyes"` refers to the eyes variable, and is the variable around which to form the group, the _focus_. + +The second `["label"]` is the _template_, which refers to the variable `"label"`. The template will be those things grouped under the first variable. + +The third variable `v.group`, is the _group_ variable, which will include groups of templates for each set of solutions which shares a _focus_. + +This raw query output will be: + +```json +{ + "eyes": { + "@type": "xsd:string", + "@value": "black" + }, + "group": [ + [{ + "@type": "xsd:string", + "@value": "Greedo" + }], + [{ + "@type": "xsd:string", + "@value": "Nien Nunb" + }], + [{ + "@type": "xsd:string", + "@value": "Gasgano" + }], + [{ + "@type": "xsd:string", + "@value": "Kit Fisto" + }], + [{ + "@type": "xsd:string", + "@value": "Plo Koon" + }], + [{ + "@type": "xsd:string", + "@value": "Lama Su" + }], + [{ + "@type": "xsd:string", + "@value": "Taun We" + }], + [{ + "@type": "xsd:string", + "@value": "Shaak Ti" + }], + [{ + "@type": "xsd:string", + "@value": "Tion Medon" + }], + [{ + "@type": "xsd:string", + "@value": "BB8" + }] + ], + "label": null, + "person": null +} +``` \ No newline at end of file diff --git a/src/app/docs/how-to-connect-terminuscms/page.md b/src/app/docs/how-to-connect-terminuscms/page.md new file mode 100644 index 0000000..dc08b04 --- /dev/null +++ b/src/app/docs/how-to-connect-terminuscms/page.md @@ -0,0 +1,27 @@ +--- +title: How to connect to TerminusCMS +slug: how-to-connect-terminuscms +seo: + title: How to connect with TerminusCMS + description: How to connect with TerminusCMS using an API key + og_image: >- + https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png +media: + - alt: Client examples + caption: '' + media_type: Image + title: Client examples + value: https://cdn.terminusdb.com/img/terminus-cms/client_api_connection.jpeg +--- + +Go to [https://dashboard.terminusdb.com](https://dashboard.terminusdb.com) to sign in to TerminusCMS. Register an account if you haven't already. + +If you haven't selected a subscription yet, choose one. The subscription selection screen will only appear when you haven't done so already. + +Click on the **team** that you wish to use or create a new one. A default one will be already created for you. After selecting your team, click on your profile icon in the upper-right corner and click on `Profile`. + +In this screen, you can create an API Token and view instructions for different clients. Give the token a description and click "Generate New Token". The token will appear on the screen. Be sure to save it somewhere safe, as the token gives access to your databases. For security reasons, we only display it once on this screen. + +Choose one of the code snippets. Which is either Python, JavaScript, or a cURL example. + +![Client examples](https://cdn.terminusdb.com/img/terminus-cms/client_api_connection.jpeg) \ No newline at end of file diff --git a/src/app/docs/how-to-query-with-graphql/page.md b/src/app/docs/how-to-query-with-graphql/page.md new file mode 100644 index 0000000..870001b --- /dev/null +++ b/src/app/docs/how-to-query-with-graphql/page.md @@ -0,0 +1,12 @@ +--- +title: How to Query with GraphQL +slug: how-to-query-with-graphql +seo: + title: How to Query with GraphQL + description: Bit sized how to guides for querying TerminusCMS and TerminusDB with GraphQL + og_image: >- + https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png +media: [] +--- + +[GraphQL Basics](/docs/graphql-basics/)[GraphQL Filter](/docs/filter-with-graphql/)[GraphQL Advanced Filter](/docs/advanced-filtering-with-graphql/)[GraphQL Limit](/docs/limit-results-in-graphql/)[GraphQL Order By](/docs/order-by-in-graphql/)[GraphQL Offset](/docs/offset-to-provide-paging/)[GraphQL Path Queries](/docs/path-queries-in-graphql/)[GraphQL Back Links](/docs/back-links-in-graphql/) \ No newline at end of file diff --git a/src/app/docs/how-to-query-with-woql/page.md b/src/app/docs/how-to-query-with-woql/page.md new file mode 100644 index 0000000..1e01f1e --- /dev/null +++ b/src/app/docs/how-to-query-with-woql/page.md @@ -0,0 +1,12 @@ +--- +title: How to Query with WOQL +slug: how-to-query-with-woql +seo: + title: How to Query with WOQL + description: Bite sized how to guides to query TerminusCMS and TerminusDB using WOQL + og_image: >- + https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png +media: [] +--- + +[WOQL Basics](/docs/woql-basics/)[WOQL Add Docs](/docs/add-documents-with-woql/)[WOQL Edit Docs](/docs/edit-documents-with-woql/)[WOQL Delete Docs](/docs/delete-documents-with-woql/)[WOQL Read Docs](/docs/read-documents-with-woql/)[WOQL Filter](/docs/filter-with-woql/)[WOQL Order By](/docs/order-by-with-woql/)[WOQL Query Arrays](/docs/query-arrays-and-sets-in-woql/)[WOQL Group Results](/docs/group-query-results/)[WOQL Path Queries](/docs/path-queries-in-woql/)[WOQL Math Queries](/docs/maths-based-queries-in-woql/)[WOQL Schema Queries](/docs/schema-queries-with-woql/) \ No newline at end of file diff --git a/src/app/docs/how-to-query/page.md b/src/app/docs/how-to-query/page.md new file mode 100644 index 0000000..48a8318 --- /dev/null +++ b/src/app/docs/how-to-query/page.md @@ -0,0 +1,12 @@ +--- +title: How to Query TerminusCMS and TerminusDB +slug: how-to-query +seo: + title: How to Query TerminusCMS and TerminusDB + description: Guides showing how to query using GraphQL and WOQL + og_image: >- + https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png +media: [] +--- + +[GraphQL Query](/docs/how-to-query-with-graphql/)[WOQL Query](/docs/how-to-query-with-woql/) \ No newline at end of file diff --git a/src/app/docs/immutability-explanation/page.md b/src/app/docs/immutability-explanation/page.md new file mode 100644 index 0000000..08ea959 --- /dev/null +++ b/src/app/docs/immutability-explanation/page.md @@ -0,0 +1,44 @@ +--- +title: Immutability Explanation +slug: immutability-explanation +seo: + title: TerminusCMS Immutability Explanation + description: >- + An explanation of how TerminusDB & TerminusCMS implements immutability, and + handles deleted and new data. + og_image: >- + https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png +media: [] +--- + +TerminusDB is an immutable data store. When data is written to a store, it does not change or mutate existing data. Any deleted data is masked, any new data resulting from a transaction is added on top of the mask. + +## Advantages of immutability + +Immutability has several advantages, including: + +* [Transaction safety](#transactionsafety) +* [Lock-free concurrency](#lockfreeconcurrency) +* [Commit and branch time travel](#commitandbranchtimetravel) +* [Change audit](#changeaudit) +* [Collaboration and synchronization](#collaborationandsynchronization) + +### Transaction safety + +Transactions are safer and more reliable in an immutable store and any issues during transactions are easier to handle. In most cases, even in system crashes, TerminusDB resumes operation with data integrity intact and any incomplete transactions are undone. + +### Lock-free concurrency + +TerminusDB uses immutable data structures making it lock-free in most cases. The query engine uses optimistic concurrency allowing transactions to retry if their state changed while executing. The lack of locking simplifies the engine and makes deadlocks very unlikely while providing [ACID](/docs/acid-transactions-explanation/) guarantees. + +### Commit and branch time travel + +The transaction history of TerminusDB databases is preserved. It is easy to travel back in time to a commit or branch and create a new database starting at any commit. All data and information at a commit point are immediately available, eliminating the requirement to rebuild the state of a past commit. + +### Change audit + +Time travel is supplemented with information about what was committed, at what date and time, and by whom. Data provenance is reliably tracked adding significant value to data in regulated environments. + +### Collaboration and synchronization + +Historical commit information is also required for TerminusDB collaboration functionality. The state of two databases that share a common lineage can be compared. Commits made by different authors can be rerun on the current database using a rebase operation, enabling the synchronization of both databases. \ No newline at end of file diff --git a/src/app/docs/import-data-with-python-client/page.md b/src/app/docs/import-data-with-python-client/page.md new file mode 100644 index 0000000..3c5506e --- /dev/null +++ b/src/app/docs/import-data-with-python-client/page.md @@ -0,0 +1,26 @@ +--- +title: Import Data with the Python Client +slug: import-data-with-python-client +seo: + title: Import Data with the Python Client + description: >- + A guide to show how to import CSV data into TerminusCMS & DB using the + Python Client + og_image: https://assets.terminusdb.com/docs/python-client-use-import-data.png +media: [] +--- + +This how-to assumes that you are already connected to a database and have a schema that matches the CSV you want to import. + +## Importing a CSV file + +You can import CSV files easily by importing them into dictionaries using Python's built-in libraries. Those dictionary objects can be inserted into the database using the `insert_document` function. + +```python +import csv +objects = [] +with open('test.csv', 'r') as f: + csv_reader = csv.DictReader(f) + objects = list(csv_reader) +client.insert_document(objects) +``` \ No newline at end of file diff --git a/src/app/docs/index-your-data/page.md b/src/app/docs/index-your-data/page.md new file mode 100644 index 0000000..9e98b65 --- /dev/null +++ b/src/app/docs/index-your-data/page.md @@ -0,0 +1,19 @@ +--- +title: Index Your Data +slug: index-your-data +seo: + title: Index Your Data with VectorLink + description: How to index your content and data with VectorLink + og_image: https://assets.terminusdb.com/docs/vectorlink-semantic-cms.png +media: [] +--- + +Once you have configured OpenAI, you can index your data. Indexing happens on a commit level so to start indexing you need a new commit. + +To do this, create and approve a change request. The indexing process will begin. + +You can see the commit index history by clicking on the cog symbol on the left. Here you can also restart indexing processes. + +Once you have indexed your data, you can ask the semantic index server questions about your data and content. + +To sumbit prompts about your data, select the magnifying glass icon from the left and fill in the form with your prompts. \ No newline at end of file diff --git a/src/app/docs/install-on-kubernetes/page.md b/src/app/docs/install-on-kubernetes/page.md new file mode 100644 index 0000000..1f48feb --- /dev/null +++ b/src/app/docs/install-on-kubernetes/page.md @@ -0,0 +1,119 @@ +--- +title: Install on Kubernetes +slug: install-on-kubernetes +seo: + title: TerminusDB on Kubernetes + description: Install TerminusDB on a Kubernetes cluster +media: [] +--- + +TerminusDB can also be deployed on Kubernetes. There are several strategies to do this. One is a high-availability solution using shared storage like NFS and one is a more simple strategy that is more performant on reads/writes by using one deployment at the cost of scalability. In this document, we will guide you on how to deploy using the latter strategy with a very minimal example. + +## Prerequisites + +We assume that you have `minikube` set up locally or have a Kubernetes cluster set up somewhere else that you can reach through `kubectl`. Therefore, when you run `kubectl apply -f some_yaml_file.yaml` we assume that it will deploy on a cluster, locally or remotely on a cloud provider. + +## Creating a TerminusDB deployment + +```yaml +apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2 +kind: Deployment +metadata: + name: terminusdb-server +spec: + selector: + matchLabels: + app: terminusdb-server + replicas: 1 + template: + metadata: + labels: + app: terminusdb-server + spec: + terminationGracePeriodSeconds: 30 + nodeSelector: + organization: terminusdb + containers: + - name: terminusdb-server + image: terminusdb/terminusdb-server:latest + tty: true + stdin: true + livenessProbe: + httpGet: + path: /api/ok + port: 6363 + initialDelaySeconds: 30 + periodSeconds: 180 + ports: + - containerPort: 6363 + envFrom: + - secretRef: + name: db-user-pass + env: + - name: TERMINUSDB_SERVER_PORT + value: "6363" + - name: TERMINUSDB_ENABLE_DASHBOARD + value: "false" + - name: TERMINUSDB_SERVER_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: TERMINUSDB_LOG_LEVEL + value: DEBUG + - name: TERMINUSDB_LOG_FORMAT + value: json + - name: TERMINUSDB_LRU_CACHE_SIZE + value: "1200" + volumeMounts: + - name: pvc-storage + mountPath: "/app/terminusdb/storage" + volumes: + - name: pvc-storage + persistentVolumeClaim: + claimName: pv-claim +``` + +Some interesting things to note in this example are that we set `TERMINUSDB_ENABLE_DASHBOARD` to false. If you are using TerminusDB in a Kubernetes deployment, you probably don’t want to expose the dashboard to other applications, unless you want your users to use the dashboard themselves. The `LOG_FORMAT` is set to `json` because this makes the logs easier to parse and search for in different cloud logging environments. We also inherit the ENV variables from a secret called `db-user-pass`. We assume that the environment variable `TERMINUSDB_ADMIN_PASS` is set to the appropriate password. If you are just playing around with this deployment, you could leave it out and it will default as `root`. But don’t do this for any application. + +The livenessProbe will take every 180 seconds whether TerminusDB is still up by calling the `ok` endpoint. This is a lightweight endpoint that just returns 200 if the request succeeds. + +We assume that a volume claim has been created for a specific cloud environment or for Minikube using the hostPath option. + +## Creating a service for the deployment + +In order to make the deployment easily available for other Kubernetes applications, we have to create a service. + +The service can look like this: + +```yaml +apiVersion: v1 +kind: Service +metadata: + name: terminusdb-server +spec: + selector: + app: terminusdb-server + ports: + - protocol: TCP + port: 6363 + targetPort: 6363 +``` + +It will expose the TerminusDB server deployment on port 6363 with the DNS name http://terminusdb-server:6363. Any Kubernetes application in the same namespace will be able to access TerminusDB server this way. + +## Testing the deployment + +To test whether the deployment is available, we will be using the port-forwarding features of `kubectl`. To expose the TerminusDB service to your local computer, run: + +`kubectl port-forward service/terminusdb-server 6363:6363` + +This will expose TerminusDB locally on your computer on `localhost:6363`. You can see whether the deployment is successful by running `curl http://localhost:6363/api/info`. If the deployment is successful, it will return information about the version of TerminusDB running on the cluster. For instance: + +```json +{"@type":"api:InfoResponse", "api:info": +{"authority":"terminusdb://system/data/User/anonymous", "storage": +{"version":"2"}, "terminusdb": +{"git_hash":"19029acffcd25c9277451aa30ee0ff4c3029ae67", +"version":"11.1.0"}, "terminusdb_store": {"version":"0.19.8"}}, +"api:status":"api:success"} +``` \ No newline at end of file diff --git a/src/app/docs/install-terminusdb-as-a-docker-container/page.md b/src/app/docs/install-terminusdb-as-a-docker-container/page.md new file mode 100644 index 0000000..73d8ce0 --- /dev/null +++ b/src/app/docs/install-terminusdb-as-a-docker-container/page.md @@ -0,0 +1,156 @@ +--- +title: Install TerminusDB as a Docker Container +slug: install-terminusdb-as-a-docker-container +seo: + title: Install TerminusDB as a Docker Container + description: >- + Everything you need to install and run TerminusDB server as a docker + container on your computer or on a remote server + og_image: >- + https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png +media: [] +--- + +> **Docker memory allocation on Windows**\\ On Windows, the default memory allocated for the Docker is **2GB**. TerminusDB is an in-memory database so it is advised to increase the allocation in Docker desktop settings. **Install TerminusDB on Windows with Docker Guide** +> +> For a comprehensive guide to installing on Windows, our friends at DFRNT put this blog together - [Run TerminusDB on Windows with Docker](https://dfrnt.com/blog/2023-02-25-run-terminusdb-on-windows-with-docker/) +> +> **Linux package manager**\\ On Linux, use your distro's package manager for containerized deployments or [find more information here](https://www.docker.com/products/container-runtime). + +## Install steps + +Install and run the TerminusDB container with the following steps. + +* [Clone the TerminusDB repo](#cloneterminusdb) +* [Run the container](#runthecontainer) +* [Use the console](#usetheconsole) + +### Clone TerminusDB + +`clone` the `terminusdb` repository and `cd` to it. + +```bash +git clone https://github.com/terminusdb/terminusdb +``` + +```bash +cd terminusdb +``` + +### Run the container + +Run the container using `docker compose`. + +#### Running for the first time + +First, set up a `.env` in the cloned directory with the following contents: + +```bash +OPENAI_KEY=YOUR_OPENAI_KEY_HERE +# And optionally specify number of pages for the vector database +# for instance +BUFFER_AMOUNT=120000 +``` + +The OPENAI\_KEY is not mandatory to use, but without it, the AI indexing will not work. Of course, all the document graph database functionality will still work as intended. + +Run the container with the command `docker compose up`. See [Environment configuration](#environmentconfiguration) for further configuration options. + +```bash +docker compose up +``` + +This generates the message: `terminusdb-server container started http://127.0.0.1:6363/`. This is the TerminusDB Server and [Console](#usetheconsole) URL. + +#### Subsequent runs + +* Remove previous volumes. Enter `y` to confirm removal when prompted. +* Rerun the container. + +> **Warning:** Removing previous volumes will erase local data. + +```bash +docker compose rm +docker compose run +``` + +### Use the console + +Open the TerminusDB console in a web browser using the URL. + +```bash +http://127.0.0.1:6363/dashboard +``` + +### Use the Dashboard + +The TerminusDB local dashboard is included within TerminusDB. The dashboard is a UI to create and manage data products, model data, and test queries. To use the dashboard visit: + +```bash +http://127.0.0.1:6363/dashboard/ +``` + +### Use GraphQL + +TerminusDB hosts a GraphQL endpoint at: + +```bash +SERVERNAME/api/graphql/ORG/DATAPRODUCT +``` + +For instance, with a data product named `admin/people`, and a locally installed TerminusDB, you can query it at: + +```bash +http://127.0.0.1:6363/api/graphql/admin/people +``` + +TerminusDB ships with a GraphiQL graphical GraphQL query interface and schema browser. This is a quick way to get acquainted with GraphQL in TerminusDB. + +You can reach this browser at: + +```bash +http://127.0.0.1:6363/api/graphiql/admin/people +``` + +## Environment configuration + +The container uses a set of environment variables with default values. You can configure the environment by setting these variables. You can set additional ENV variables or override already set ones by creating a `.env` file. + +## Migrating from terminusdb-bootstrap + +In order to migrate from the default terminusdb-bootstrap installation while stil keeping the data of your previous installation, run the docker compose commands the following way: + +```bash +docker compose -f docker-compose.yml -f distribution/docker-compose/bootstrap_storage.yaml +``` + +For instance, for the `up` command to start the server, run: + +```bash +docker compose -f docker-compose.yml -f distribution/docker-compose/bootstrap_storage.yaml up +``` + +## Using the CLI + +To access the TerminusDB CLI from the Docker Compose, run: + +```bash +docker compose run terminusdb-server ./terminusdb +``` + +Or use `exec` when you have the service already running + +## Server deployment + +> The TerminusDB server is deployed to your computer by default. + +### Local computer deployment + +By default, the Docker container binds to IP `127.0.0.1`. This prevents insecure deployments and ensures the TerminusDB server is accessible on a local computer only. + +### Remote server deployment + +To deploy the TerminusDB server to a remote machine: + +* Enable HTTPS with a remote proxy like Nginx +* Don't use the `X-Forward-Header` ENV variables unless you really know what you are doing \ No newline at end of file diff --git a/src/app/docs/install-terminusdb-from-source-code/page.md b/src/app/docs/install-terminusdb-from-source-code/page.md new file mode 100644 index 0000000..292178a --- /dev/null +++ b/src/app/docs/install-terminusdb-from-source-code/page.md @@ -0,0 +1,134 @@ +--- +title: Install TerminusDB from Source Code +slug: install-terminusdb-from-source-code +seo: + title: Install TerminusDB from Source Code + description: Everything you need to install TerminusDB from source code. + og_image: >- + https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png +media: [] +--- + +## Install steps + +Install, build and run TerminusDB from source code with the following steps. + +* [Install SWI-Prolog](#installswiprolog) +* [Clone the TerminusDB repository](#clonetheterminusdbrepository) +* [Make the TerminusDB Command Line Interface](#maketheterminusdbcommandlineinterface) +* [Run the TerminusDB system database](#runtheterminusdbsystemdatabase) + +> **Install from source code on Windows:** +> +> Install [WSL](https://ubuntu.com/wsl) and [Ubuntu](https://ubuntu.com/#download) +> +> In Ubuntu terminal: `sudo apt install make libgmp-dev` +> +> In Ubuntu terminal: `curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh` +> +> Follow the install steps below for **Debian or Ubuntu** + +## Install SWI-Prolog, Rust and clang + +### Linux + +Install [Rust](https://www.rust-lang.org/tools/install) by following the Rust installation guide. + +* * * + +**Arch Linux** + +Install all dependencies of all the required libraries using [sudo](https://www.sudo.ws/download.html) and [git](https://git-scm.com/downloads). + +```bash +sudo pacman -S git swi-prolog make automake autoconf libtool zlib pkgconf gcc clang gmp +``` + +* * * + +**Debian or Ubuntu** + +Install using the apt package manager. + +```bash +cat /etc/*release | grep ubuntu > /dev/null && (sudo apt-get install software-properties-common; sudo apt-add-repository ppa:swi-prolog/stable) +sudo apt-get update +sudo apt install swi-prolog clang libgmp-dev +``` + +* * * + +**Fedora or Red Hat** + +Install using [sudo](https://www.sudo.ws/download.html). + +```bash +sudo dnf install pl pl-devel clang gmp-devel +``` + +### macOS + +Install `swi-prolog` and `rust` using [homebrew](https://brew.sh). + +```bash +brew install gmp +brew install swi-prolog +brew install rust +``` + +## Clone the TerminusDB repository + +Identical for all operating systems: Clone the `terminusdb` repository from GitHub. + +```bash +git clone https://github.com/terminusdb/terminusdb +``` + +## Make the TerminusDB Command Line Interface + +`make` the `terminusdb` [Command Line Interface (CLI)](/docs/terminusdb-cli-commands/) binary. + +### Linux + +```bash +cd terminusdb +make install-tus +make +make install-dashboard +``` + +### macOS + +```bash +cd terminusdb +make install-tus +make +make install-dashboard +``` + +## Run the TerminusDB system database + +### Linux + +Initialize the system database and choose a password for the admin user. + +* Server starts on `http://127.0.0.1:6363` + +```bash +./terminusdb store init --key "my_password_here" +./terminusdb serve +``` + +### macOS + +* Initialize the system database. +* Server starts on `http://127.0.0.1:6363` + +```bash +./terminusdb store init --key root +./terminusdb serve +``` + +## Further Reading + +[**The TerminusDB Command Line Interface**](/docs/terminusdb-cli-commands/) \ No newline at end of file diff --git a/src/app/docs/install-terminusdb-js-client/page.md b/src/app/docs/install-terminusdb-js-client/page.md new file mode 100644 index 0000000..b390095 --- /dev/null +++ b/src/app/docs/install-terminusdb-js-client/page.md @@ -0,0 +1,40 @@ +--- +title: Install the TerminusDB JavaScript Client +slug: install-terminusdb-js-client +seo: + title: Install the TerminusDB JavaScript Client + description: Installation instruction for the TerminusDB JavaScript Client + og_image: >- + https://assets.terminusdb.com/docs/technical-documentation-terminuscms-og.png +media: [] +--- + +## Requirements + +Node.js version 10+ if using the TerminusDB client library as a Node.js package + +## Installation + +The TerminusDB JavaScript client library can be used either as a Node.js package or as a script that runs in the browser. + +### NPM Package + +> If you don't already have Node.js installed, install it first. [node-install](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) + +To install the `terminusdb-client` package as a dependency in an existing package, run: + +```bash +npm install --save @terminusdb/terminusdb-client +``` + +This command updates your `package.json`. + +### Script + +To use the `terminusdb-client` script on a webpage sourced from a CDN, add this to your HTML: + +```html + +``` + +Alternatively, you can download the latest [`terminusdb-client.min.js`](https://unpkg.com/@terminusdb/terminusdb-client/dist/terminusdb-client.min.js), add it to your sources, and use that in the ` + + + + ) +} diff --git a/src/app/not-found.tsx b/src/app/not-found.tsx new file mode 100644 index 0000000..5e1c8f0 --- /dev/null +++ b/src/app/not-found.tsx @@ -0,0 +1,25 @@ +import Link from 'next/link' + +export default function NotFound() { + return ( +
+
+

+ 404 +

+

+ Page not found +

+

+ Sorry, we couldn’t find the page you’re looking for. +

+ + Go back home + +
+
+ ) +} diff --git a/src/app/page.md b/src/app/page.md new file mode 100644 index 0000000..8a9088a --- /dev/null +++ b/src/app/page.md @@ -0,0 +1,28 @@ +--- +title: Getting started +--- + +Learn how to get TerminusDB set up in your project in under thirty minutes. {% .lead %} + +{% quick-links %} + +{% quick-link title="Installation" icon="installation" href="/docs/get-started/" description="Step-by-step guides to setting up your system and installing the library." /%} + +{% quick-link title="Architecture guide" icon="presets" href="/docs/terminusdb-explanation/" description="Learn how the internals work and contribute." /%} + +{% quick-link title="Plugins" icon="plugins" href="/docs/documents-explanation/" description="Extend TerminusDB with third-party plugins or write your own." /%} + +{% quick-link title="API reference" icon="theming" href="/docs/openapi/" description="Learn to easily customize and modify your app's visual design to fit your brand." /%} + +{% /quick-links %} + +TerminusDB includes many features to build content infrastructures for complex environments with content repositories at it's heart, also known as data products. The [product tour](/docs/product-tour/) aims to provide you with an understanding of how to navigate the product and get started on your projects. + +--- + +## Quick start + +The easiest way to get started with the open source community version on your own computer is by [getting started with Docker](/docs/install-terminusdb-as-a-docker-container/). + + + diff --git a/src/app/providers.tsx b/src/app/providers.tsx new file mode 100644 index 0000000..d16b648 --- /dev/null +++ b/src/app/providers.tsx @@ -0,0 +1,11 @@ +'use client' + +import { ThemeProvider } from 'next-themes' + +export function Providers({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ) +} diff --git a/src/components/Button.tsx b/src/components/Button.tsx new file mode 100644 index 0000000..04791ac --- /dev/null +++ b/src/components/Button.tsx @@ -0,0 +1,30 @@ +import Link from 'next/link' +import clsx from 'clsx' + +const variantStyles = { + primary: + 'rounded-full bg-sky-300 py-2 px-4 text-sm font-semibold text-slate-900 hover:bg-sky-200 focus:outline-hidden focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-sky-300/50 active:bg-sky-500', + secondary: + 'rounded-full bg-slate-800 py-2 px-4 text-sm font-medium text-white hover:bg-slate-700 focus:outline-hidden focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white/50 active:text-slate-400', +} + +type ButtonProps = { + variant?: keyof typeof variantStyles +} & ( + | React.ComponentPropsWithoutRef + | (React.ComponentPropsWithoutRef<'button'> & { href?: undefined }) +) + +export function Button({ + variant = 'primary', + className, + ...props +}: ButtonProps) { + className = clsx(variantStyles[variant], className) + + return typeof props.href === 'undefined' ? ( + + + + + +
+
+ +
+
+ + +
+
+
+
+
+
+ +
+ {tabs.map((tab) => ( +
+
+ {tab.name} +
+
+ ))} +
+
+ + + {({ + className, + style, + tokens, + getLineProps, + getTokenProps, + }) => ( +
+                          
+                            {tokens.map((line, lineIndex) => (
+                              
+ {line.map((token, tokenIndex) => ( + + ))} +
+ ))} +
+
+ )} +
+
+
+
+
+
+
+
+
+ ) +} diff --git a/src/components/HeroBackground.tsx b/src/components/HeroBackground.tsx new file mode 100644 index 0000000..5f0adb4 --- /dev/null +++ b/src/components/HeroBackground.tsx @@ -0,0 +1,188 @@ +import { useId } from 'react' + +export function HeroBackground(props: React.ComponentPropsWithoutRef<'svg'>) { + let id = useId() + + return ( + + ) +} diff --git a/src/components/Icon.tsx b/src/components/Icon.tsx new file mode 100644 index 0000000..bea7e8a --- /dev/null +++ b/src/components/Icon.tsx @@ -0,0 +1,96 @@ +import { useId } from 'react' +import clsx from 'clsx' + +import { InstallationIcon } from '@/components/icons/InstallationIcon' +import { LightbulbIcon } from '@/components/icons/LightbulbIcon' +import { PluginsIcon } from '@/components/icons/PluginsIcon' +import { PresetsIcon } from '@/components/icons/PresetsIcon' +import { ThemingIcon } from '@/components/icons/ThemingIcon' +import { WarningIcon } from '@/components/icons/WarningIcon' + +const icons = { + installation: InstallationIcon, + presets: PresetsIcon, + plugins: PluginsIcon, + theming: ThemingIcon, + lightbulb: LightbulbIcon, + warning: WarningIcon, +} + +const iconStyles = { + blue: '[--icon-foreground:var(--color-slate-900)] [--icon-background:var(--color-white)]', + amber: + '[--icon-foreground:var(--color-amber-900)] [--icon-background:var(--color-amber-100)]', +} + +export function Icon({ + icon, + color = 'blue', + className, + ...props +}: { + color?: keyof typeof iconStyles + icon: keyof typeof icons +} & Omit, 'color'>) { + let id = useId() + let IconComponent = icons[icon] + + return ( + + ) +} + +const gradients = { + blue: [ + { stopColor: '#0EA5E9' }, + { stopColor: '#22D3EE', offset: '.527' }, + { stopColor: '#818CF8', offset: 1 }, + ], + amber: [ + { stopColor: '#FDE68A', offset: '.08' }, + { stopColor: '#F59E0B', offset: '.837' }, + ], +} + +export function Gradient({ + color = 'blue', + ...props +}: { + color?: keyof typeof gradients +} & Omit, 'color'>) { + return ( + + {gradients[color].map((stop, stopIndex) => ( + + ))} + + ) +} + +export function LightMode({ + className, + ...props +}: React.ComponentPropsWithoutRef<'g'>) { + return +} + +export function DarkMode({ + className, + ...props +}: React.ComponentPropsWithoutRef<'g'>) { + return +} diff --git a/src/components/Layout.tsx b/src/components/Layout.tsx new file mode 100644 index 0000000..fdf5589 --- /dev/null +++ b/src/components/Layout.tsx @@ -0,0 +1,90 @@ +'use client' + +import { useEffect, useState } from 'react' +import Link from 'next/link' +import { usePathname } from 'next/navigation' +import clsx from 'clsx' + +import { Hero } from '@/components/Hero' +import { Logo } from '@/components/Logo' +import { MobileNavigation } from '@/components/MobileNavigation' +import { Navigation } from '@/components/Navigation' +import { Search } from '@/components/Search' +import { ThemeSelector } from '@/components/ThemeSelector' + +function GitHubIcon(props: React.ComponentPropsWithoutRef<'svg'>) { + return ( + + ) +} + +function Header() { + let [isScrolled, setIsScrolled] = useState(false) + + useEffect(() => { + function onScroll() { + setIsScrolled(window.scrollY > 0) + } + onScroll() + window.addEventListener('scroll', onScroll, { passive: true }) + return () => { + window.removeEventListener('scroll', onScroll) + } + }, []) + + return ( +
+
+ +
+
+ + + +
+
+ +
+
+ + + + +
+
+ ) +} + +export function Layout({ children }: { children: React.ReactNode }) { + let pathname = usePathname() + let isHomePage = pathname === '/' + + return ( +
+
+ + {isHomePage && } + +
+
+
+
+
+
+ +
+
+ {children} +
+
+ ) +} diff --git a/src/components/Logo.tsx b/src/components/Logo.tsx new file mode 100644 index 0000000..eacf500 --- /dev/null +++ b/src/components/Logo.tsx @@ -0,0 +1,51 @@ +import * as React from 'react' +export const Logo: React.FC<{className?: string}> = (props) => ( + + + + + + + + + + +) \ No newline at end of file diff --git a/src/components/MobileNavigation.tsx b/src/components/MobileNavigation.tsx new file mode 100644 index 0000000..f36d906 --- /dev/null +++ b/src/components/MobileNavigation.tsx @@ -0,0 +1,103 @@ +'use client' + +import { Suspense, useCallback, useEffect, useState } from 'react' +import Link from 'next/link' +import { usePathname, useSearchParams } from 'next/navigation' +import { Dialog, DialogPanel } from '@headlessui/react' + +import { Navigation } from '@/components/Navigation' +import { Logo } from './Logo' + +function MenuIcon(props: React.ComponentPropsWithoutRef<'svg'>) { + return ( + + ) +} + +function CloseIcon(props: React.ComponentPropsWithoutRef<'svg'>) { + return ( + + ) +} + +function CloseOnNavigation({ close }: { close: () => void }) { + let pathname = usePathname() + let searchParams = useSearchParams() + + useEffect(() => { + close() + }, [pathname, searchParams, close]) + + return null +} + +export function MobileNavigation() { + let [isOpen, setIsOpen] = useState(false) + let close = useCallback(() => setIsOpen(false), [setIsOpen]) + + function onLinkClick(event: React.MouseEvent) { + let link = event.currentTarget + if ( + link.pathname + link.search + link.hash === + window.location.pathname + window.location.search + window.location.hash + ) { + close() + } + } + + return ( + <> + + + + + close()} + className="fixed inset-0 z-50 flex items-start overflow-y-auto bg-slate-900/50 pr-10 backdrop-blur-sm lg:hidden" + aria-label="Navigation" + > + +
+ + + + +
+ +
+
+ + ) +} diff --git a/src/components/Navigation.tsx b/src/components/Navigation.tsx new file mode 100644 index 0000000..25a47bd --- /dev/null +++ b/src/components/Navigation.tsx @@ -0,0 +1,200 @@ +import Link from 'next/link' +import { usePathname, useRouter } from 'next/navigation' +import { useState, useEffect } from 'react' +import clsx from 'clsx' + +// Define indicator style types +type IndicatorStyle = 'plusMinus' | 'chevron' | 'border' + +import { navigation, SubNavigation } from '@/lib/navigation' + +export function Navigation({ + className, + onLinkClick, +}: { + className?: string + onLinkClick?: React.MouseEventHandler +}) { + // State for indicator style selection + const [indicatorStyle, setIndicatorStyle] = + useState('plusMinus') + let pathname = usePathname() + + // Toggle between indicator styles + const toggleIndicatorStyle = () => { + setIndicatorStyle((current) => { + if (current === 'plusMinus') return 'chevron' + if (current === 'chevron') return 'border' + return 'plusMinus' + }) + } + + return ( + + ) +} + +function SubNavigationMap({ + links, + onLinkClick, + indicatorStyle = 'border', +}: { + links: SubNavigation[] + onLinkClick?: React.MouseEventHandler + indicatorStyle?: IndicatorStyle +}) { + const pathname = usePathname() + + // Helper function to check if a link or any of its children are active + const isLinkActive = (link: SubNavigation): boolean => { + // Ensure pathname is not null + if (!pathname) return false; + + // Check if the current link matches the pathname + if (link.href) { + // Check exact match + if (pathname === link.href) return true + + // Check with trailing slash + if (pathname === link.href + '/') return true + + // Check if pathname starts with link.href (for nested routes) + if (pathname.startsWith(link.href + '/')) return true + } + + // Recursively check children links + if (link.links && link.links.length > 0) { + return link.links.some((childLink) => isLinkActive(childLink)) + } + + return false + } + + // Initialize open state for each section + const [openSections, setOpenSections] = useState>({}) + + // Set initial open state based on active links + useEffect(() => { + const initialOpenState: Record = {} + links.forEach((link) => { + if (link.links) { + const key = link.href ?? link.title + initialOpenState[key] = isLinkActive(link) + } + }) + setOpenSections(initialOpenState) + }, [pathname]) + + // Toggle section open/closed + const toggleSection = (key: string, event: React.MouseEvent) => { + event.preventDefault() + setOpenSections((prev) => ({ + ...prev, + [key]: !prev[key], + })) + } + const router = useRouter() + + return ( +
    + {links.map((link) => { + const key = link.href ?? link.title + const isActive = isLinkActive(link) + const isOpen = openSections[key] ?? false + + return ( +
  • + {link.href && !link.links && ( + + {link.title} + + )} + {link.links && ( + <> +
    { + link.href && router.push(link.href); + toggleSection(key, e); + }} + > +

    + {link.title} + {/* Indicator based on selected style */} + {indicatorStyle === 'plusMinus' && ( + + {isOpen ? '−' : '+'} + + )} + + {indicatorStyle === 'chevron' && ( + + {isOpen ? '‹' : '›'} + + )} + + {indicatorStyle === 'border' && ( + + + + )} +

    +
    + {isOpen && ( +
    + +
    + )} + + )} +
  • + ) + })} +
+ ) +} diff --git a/src/components/PrevNextLinks.tsx b/src/components/PrevNextLinks.tsx new file mode 100644 index 0000000..50793e0 --- /dev/null +++ b/src/components/PrevNextLinks.tsx @@ -0,0 +1,70 @@ +'use client' + +import Link from 'next/link' +import { usePathname } from 'next/navigation' +import clsx from 'clsx' + +import { navigation } from '@/lib/navigation' + +function ArrowIcon(props: React.ComponentPropsWithoutRef<'svg'>) { + return ( + + ) +} + +function PageLink({ + title, + href, + dir = 'next', + ...props +}: Omit, 'dir' | 'title'> & { + title: string + href?: string + dir?: 'previous' | 'next' +}) { + return ( +
+
+ {dir === 'next' ? 'Next' : 'Previous'} +
+
+ + {title} + + +
+
+ ) +} + +export function PrevNextLinks() { + let pathname = usePathname() + let allLinks = navigation.flatMap((section) => section.links) + let linkIndex = allLinks.findIndex((link) => link.href === pathname) + let previousPage = linkIndex > -1 ? allLinks[linkIndex - 1] : null + let nextPage = linkIndex > -1 ? allLinks[linkIndex + 1] : null + + if (!nextPage && !previousPage) { + return null + } + + return ( +
+ {previousPage && } + {nextPage && } +
+ ) +} diff --git a/src/components/Prose.tsx b/src/components/Prose.tsx new file mode 100644 index 0000000..37e9e85 --- /dev/null +++ b/src/components/Prose.tsx @@ -0,0 +1,33 @@ +import clsx from 'clsx' + +export function Prose({ + as, + className, + ...props +}: React.ComponentPropsWithoutRef & { + as?: T +}) { + let Component = as ?? 'div' + + return ( + + ) +} diff --git a/src/components/QuickLinks.tsx b/src/components/QuickLinks.tsx new file mode 100644 index 0000000..24f234e --- /dev/null +++ b/src/components/QuickLinks.tsx @@ -0,0 +1,41 @@ +import Link from 'next/link' + +import { Icon } from '@/components/Icon' + +export function QuickLinks({ children }: { children: React.ReactNode }) { + return ( +
+ {children} +
+ ) +} + +export function QuickLink({ + title, + description, + href, + icon, +}: { + title: string + description: string + href: string + icon: React.ComponentProps['icon'] +}) { + return ( +
+
+
+ +

+ + + {title} + +

+

+ {description} +

+
+
+ ) +} diff --git a/src/components/Search.tsx b/src/components/Search.tsx new file mode 100644 index 0000000..3e3d14e --- /dev/null +++ b/src/components/Search.tsx @@ -0,0 +1,464 @@ +'use client' + +import { + forwardRef, + Fragment, + Suspense, + useCallback, + useEffect, + useId, + useRef, + useState, +} from 'react' +import Highlighter from 'react-highlight-words' +import { usePathname, useRouter, useSearchParams } from 'next/navigation' +import { + type AutocompleteApi, + type AutocompleteCollection, + type AutocompleteState, + createAutocomplete, +} from '@algolia/autocomplete-core' +import { Dialog, DialogPanel } from '@headlessui/react' +import clsx from 'clsx' + +import { navigation } from '@/lib/navigation' +import { type Result } from '@/markdoc/search.mjs' + +type EmptyObject = Record + +type Autocomplete = AutocompleteApi< + Result, + React.SyntheticEvent, + React.MouseEvent, + React.KeyboardEvent +> + +function SearchIcon(props: React.ComponentPropsWithoutRef<'svg'>) { + return ( + + ) +} + +function useAutocomplete({ + close, +}: { + close: (autocomplete: Autocomplete) => void +}) { + let id = useId() + let router = useRouter() + let [autocompleteState, setAutocompleteState] = useState< + AutocompleteState | EmptyObject + >({}) + + function navigate({ itemUrl }: { itemUrl?: string }) { + if (!itemUrl) { + return + } + + router.push(itemUrl) + + if ( + itemUrl === + window.location.pathname + window.location.search + window.location.hash + ) { + close(autocomplete) + } + } + + let [autocomplete] = useState(() => + createAutocomplete< + Result, + React.SyntheticEvent, + React.MouseEvent, + React.KeyboardEvent + >({ + id, + placeholder: 'Find something...', + defaultActiveItemId: 0, + onStateChange({ state }) { + setAutocompleteState(state) + }, + shouldPanelOpen({ state }) { + return state.query !== '' + }, + navigator: { + navigate, + }, + getSources({ query }) { + return import('@/markdoc/search.mjs').then(({ search }) => { + return [ + { + sourceId: 'documentation', + getItems() { + return search(query, { limit: 5 }) + }, + getItemUrl({ item }) { + return item.url + }, + onSelect: navigate, + }, + ] + }) + }, + }), + ) + + return { autocomplete, autocompleteState } +} + +function LoadingIcon(props: React.ComponentPropsWithoutRef<'svg'>) { + let id = useId() + + return ( + + ) +} + +function HighlightQuery({ text, query }: { text: string; query: string }) { + return ( + + ) +} + +function SearchResult({ + result, + autocomplete, + collection, + query, +}: { + result: Result + autocomplete: Autocomplete + collection: AutocompleteCollection + query: string +}) { + let id = useId() + + let sectionTitle = navigation.find((section) => + section.links.find((link) => link.href === result.url.split('#')[0]), + )?.title + let hierarchy = [sectionTitle, result.pageTitle].filter( + (x): x is string => typeof x === 'string', + ) + + return ( +
  • + + {hierarchy.length > 0 && ( + + )} +
  • + ) +} + +function SearchResults({ + autocomplete, + query, + collection, +}: { + autocomplete: Autocomplete + query: string + collection: AutocompleteCollection +}) { + if (collection.items.length === 0) { + return ( +

    + No results for “ + + {query} + + ” +

    + ) + } + + return ( +
      + {collection.items.map((result) => ( + + ))} +
    + ) +} + +const SearchInput = forwardRef< + React.ElementRef<'input'>, + { + autocomplete: Autocomplete + autocompleteState: AutocompleteState | EmptyObject + onClose: () => void + } +>(function SearchInput({ autocomplete, autocompleteState, onClose }, inputRef) { + let inputProps = autocomplete.getInputProps({ inputElement: null }) + + return ( +
    + + { + if ( + event.key === 'Escape' && + !autocompleteState.isOpen && + autocompleteState.query === '' + ) { + // In Safari, closing the dialog with the escape key can sometimes cause the scroll position to jump to the + // bottom of the page. This is a workaround for that until we can figure out a proper fix in Headless UI. + if (document.activeElement instanceof HTMLElement) { + document.activeElement.blur() + } + + onClose() + } else { + inputProps.onKeyDown(event) + } + }} + /> + {autocompleteState.status === 'stalled' && ( +
    + +
    + )} +
    + ) +}) + +function CloseOnNavigation({ + close, + autocomplete, +}: { + close: (autocomplete: Autocomplete) => void + autocomplete: Autocomplete +}) { + let pathname = usePathname() + let searchParams = useSearchParams() + + useEffect(() => { + close(autocomplete) + }, [pathname, searchParams, close, autocomplete]) + + return null +} + +function SearchDialog({ + open, + setOpen, + className, +}: { + open: boolean + setOpen: (open: boolean) => void + className?: string +}) { + let formRef = useRef>(null) + let panelRef = useRef>(null) + let inputRef = useRef>(null) + + let close = useCallback( + (autocomplete: Autocomplete) => { + setOpen(false) + autocomplete.setQuery('') + }, + [setOpen], + ) + + let { autocomplete, autocompleteState } = useAutocomplete({ + close() { + close(autocomplete) + }, + }) + + useEffect(() => { + if (open) { + return + } + + function onKeyDown(event: KeyboardEvent) { + if (event.key === 'k' && (event.metaKey || event.ctrlKey)) { + event.preventDefault() + setOpen(true) + } + } + + window.addEventListener('keydown', onKeyDown) + + return () => { + window.removeEventListener('keydown', onKeyDown) + } + }, [open, setOpen]) + + return ( + <> + + + + close(autocomplete)} + className={clsx('fixed inset-0 z-50', className)} + > +
    + +
    + +
    +
    + setOpen(false)} + /> +
    + {autocompleteState.isOpen && ( + + )} +
    + +
    +
    +
    +
    + + ) +} + +function useSearchProps() { + let buttonRef = useRef>(null) + let [open, setOpen] = useState(false) + + return { + buttonProps: { + ref: buttonRef, + onClick() { + setOpen(true) + }, + }, + dialogProps: { + open, + setOpen: useCallback((open: boolean) => { + let { width = 0, height = 0 } = + buttonRef.current?.getBoundingClientRect() ?? {} + if (!open || (width !== 0 && height !== 0)) { + setOpen(open) + } + }, []), + }, + } +} + +export function Search() { + let [modifierKey, setModifierKey] = useState() + let { buttonProps, dialogProps } = useSearchProps() + + useEffect(() => { + setModifierKey( + /(Mac|iPhone|iPod|iPad)/i.test(navigator.platform) ? '⌘' : 'Ctrl ', + ) + }, []) + + return ( + <> + + + + ) +} diff --git a/src/components/TableOfContents.tsx b/src/components/TableOfContents.tsx new file mode 100644 index 0000000..2a8ce2e --- /dev/null +++ b/src/components/TableOfContents.tsx @@ -0,0 +1,119 @@ +'use client' + +import { useCallback, useEffect, useState } from 'react' +import Link from 'next/link' +import clsx from 'clsx' + +import { type Section, type Subsection } from '@/lib/sections' + +export function TableOfContents({ + tableOfContents, +}: { + tableOfContents: Array
    +}) { + let [currentSection, setCurrentSection] = useState(tableOfContents[0]?.id) + + let getHeadings = useCallback((tableOfContents: Array
    ) => { + return tableOfContents + .flatMap((node) => [node.id, ...node.children.map((child) => child.id)]) + .map((id) => { + let el = document.getElementById(id) + if (!el) return null + + let style = window.getComputedStyle(el) + let scrollMt = parseFloat(style.scrollMarginTop) + + let top = window.scrollY + el.getBoundingClientRect().top - scrollMt + return { id, top } + }) + .filter((x): x is { id: string; top: number } => x !== null) + }, []) + + useEffect(() => { + if (tableOfContents.length === 0) return + let headings = getHeadings(tableOfContents) + function onScroll() { + let top = window.scrollY + let current = headings[0].id + for (let heading of headings) { + if (top >= heading.top - 10) { + current = heading.id + } else { + break + } + } + setCurrentSection(current) + } + window.addEventListener('scroll', onScroll, { passive: true }) + onScroll() + return () => { + window.removeEventListener('scroll', onScroll) + } + }, [getHeadings, tableOfContents]) + + function isActive(section: Section | Subsection) { + if (section.id === currentSection) { + return true + } + if (!section.children) { + return false + } + return section.children.findIndex(isActive) > -1 + } + + return ( +
    + +
    + ) +} diff --git a/src/components/ThemeSelector.tsx b/src/components/ThemeSelector.tsx new file mode 100644 index 0000000..bfa0c7a --- /dev/null +++ b/src/components/ThemeSelector.tsx @@ -0,0 +1,125 @@ +import { useEffect, useState } from 'react' +import { useTheme } from 'next-themes' +import { + Label, + Listbox, + ListboxButton, + ListboxOption, + ListboxOptions, +} from '@headlessui/react' +import clsx from 'clsx' + +const themes = [ + { name: 'Light', value: 'light', icon: LightIcon }, + { name: 'Dark', value: 'dark', icon: DarkIcon }, + { name: 'System', value: 'system', icon: SystemIcon }, +] + +function LightIcon(props: React.ComponentPropsWithoutRef<'svg'>) { + return ( + + ) +} + +function DarkIcon(props: React.ComponentPropsWithoutRef<'svg'>) { + return ( + + ) +} + +function SystemIcon(props: React.ComponentPropsWithoutRef<'svg'>) { + return ( + + ) +} + +export function ThemeSelector( + props: React.ComponentPropsWithoutRef>, +) { + let { theme, setTheme } = useTheme() + let [mounted, setMounted] = useState(false) + + useEffect(() => { + setMounted(true) + }, []) + + if (!mounted) { + return
    + } + + return ( + + + + + + + + {themes.map((theme) => ( + + clsx( + 'flex cursor-pointer items-center rounded-[0.625rem] p-1 select-none', + { + 'text-sky-500': selected, + 'text-slate-900 dark:text-white': focus && !selected, + 'text-slate-700 dark:text-slate-400': !focus && !selected, + 'bg-slate-100 dark:bg-slate-900/40': focus, + }, + ) + } + > + {({ selected }) => ( + <> +
    + +
    +
    {theme.name}
    + + )} +
    + ))} +
    +
    + ) +} diff --git a/src/components/_onThisPage.tsx b/src/components/_onThisPage.tsx index 08df2a4..00755a5 100644 --- a/src/components/_onThisPage.tsx +++ b/src/components/_onThisPage.tsx @@ -68,12 +68,12 @@ export const OnThisPageContent = (props) => { if (!listArray.length) return ( -
    +
    ) return ( -
    -
    +
    +

    On this page diff --git a/src/components/icons/InstallationIcon.tsx b/src/components/icons/InstallationIcon.tsx new file mode 100644 index 0000000..c81a5e3 --- /dev/null +++ b/src/components/icons/InstallationIcon.tsx @@ -0,0 +1,47 @@ +import { DarkMode, Gradient, LightMode } from '@/components/Icon' + +export function InstallationIcon({ + id, + color, +}: { + id: string + color?: React.ComponentProps['color'] +}) { + return ( + <> + + + + + + + + + + + + + ) +} diff --git a/src/components/icons/LightbulbIcon.tsx b/src/components/icons/LightbulbIcon.tsx new file mode 100644 index 0000000..7367f51 --- /dev/null +++ b/src/components/icons/LightbulbIcon.tsx @@ -0,0 +1,52 @@ +import { DarkMode, Gradient, LightMode } from '@/components/Icon' + +export function LightbulbIcon({ + id, + color, +}: { + id: string + color?: React.ComponentProps['color'] +}) { + return ( + <> + + + + + + + + + + + + + + + ) +} diff --git a/src/components/icons/PluginsIcon.tsx b/src/components/icons/PluginsIcon.tsx new file mode 100644 index 0000000..2caf217 --- /dev/null +++ b/src/components/icons/PluginsIcon.tsx @@ -0,0 +1,69 @@ +import { DarkMode, Gradient, LightMode } from '@/components/Icon' + +export function PluginsIcon({ + id, + color, +}: { + id: string + color?: React.ComponentProps['color'] +}) { + return ( + <> + + + + + + + + + + + + + + + + + + + + + + + ) +} diff --git a/src/components/icons/PresetsIcon.tsx b/src/components/icons/PresetsIcon.tsx new file mode 100644 index 0000000..e01b953 --- /dev/null +++ b/src/components/icons/PresetsIcon.tsx @@ -0,0 +1,49 @@ +import { DarkMode, Gradient, LightMode } from '@/components/Icon' + +export function PresetsIcon({ + id, + color, +}: { + id: string + color?: React.ComponentProps['color'] +}) { + return ( + <> + + + + + + + + + + + + + + + + + + + ) +} diff --git a/src/components/icons/ThemingIcon.tsx b/src/components/icons/ThemingIcon.tsx new file mode 100644 index 0000000..02876f7 --- /dev/null +++ b/src/components/icons/ThemingIcon.tsx @@ -0,0 +1,65 @@ +import { DarkMode, Gradient, LightMode } from '@/components/Icon' + +export function ThemingIcon({ + id, + color, +}: { + id: string + color?: React.ComponentProps['color'] +}) { + return ( + <> + + + + + + + + + + + + + + + + ) +} diff --git a/src/components/icons/WarningIcon.tsx b/src/components/icons/WarningIcon.tsx new file mode 100644 index 0000000..abed5e3 --- /dev/null +++ b/src/components/icons/WarningIcon.tsx @@ -0,0 +1,61 @@ +import { DarkMode, Gradient, LightMode } from '@/components/Icon' + +export function WarningIcon({ + id, + color, +}: { + id: string + color?: React.ComponentProps['color'] +}) { + return ( + <> + + + + + + + + + + + + + + + ) +} diff --git a/src/components/seo.tsx b/src/components/seo.tsx index 87eeeff..d45c491 100644 --- a/src/components/seo.tsx +++ b/src/components/seo.tsx @@ -1,4 +1,5 @@ import Head from "next/head" +import Script from "next/script" export default function SeoComponent(props) { if (typeof props.seo_metadata === "undefined") { diff --git a/src/fonts/lexend.txt b/src/fonts/lexend.txt new file mode 100644 index 0000000..ef5fbbc --- /dev/null +++ b/src/fonts/lexend.txt @@ -0,0 +1,93 @@ +Copyright 2018 The Lexend Project Authors (https://github.com/googlefonts/lexend), with Reserved Font Name “RevReading Lexend”. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/src/fonts/lexend.woff2 b/src/fonts/lexend.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..00384e46d72aa385eaee91c994545d4f7e2e0da0 GIT binary patch literal 71760 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�Db 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 + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/images/blur-cyan.png b/src/images/blur-cyan.png new file mode 100644 index 0000000000000000000000000000000000000000..e98d7b90e6e78f839fc35f75a46e8ae0ae0d3169 GIT binary patch literal 218615 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
      oVMlV@j6F5073O!= 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
      O!4FFt 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

      w0( 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�B&NRQDbQzt_lK4uFwq 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 U%7!u=jQ{`u07*qoM6N<$f=$f)FaQ7m literal 0 HcmV?d00001 diff --git a/src/lib/navigation.ts b/src/lib/navigation.ts new file mode 100644 index 0000000..159d1af --- /dev/null +++ b/src/lib/navigation.ts @@ -0,0 +1,994 @@ +export interface Navigation { + title: string + links: SubNavigation[] +} + +export interface SubNavigation { + title: string + href?: string + links?: SubNavigation[] +} + +export const navigation: Navigation[] = [ + { + title: 'Start with TerminusCMS', + links: [ + { + title: 'Get Started', + href: '/docs/get-started', + }, + { + title: 'Product Tour', + href: '/docs/product-tour', + links: [ + { + title: 'Overview', + href: '/docs/projects-terminuscms-tour', + }, + { + title: 'Teams & Users', + href: '/docs/manage-teams-users-terminuscms-tour', + }, + { + title: 'Curate Data', + href: '/docs/content-curation-terminuscms-tour', + }, + { + title: 'Change Requests', + href: '/docs/change-request-workflows-terminuscms-tour', + }, + { + title: 'GraphQL & WOQL Query', + href: '/docs/graphql-and-woql-query-terminuscms-tour', + }, + ], + }, + { + title: 'Connect to TerminusCMS', + href: '/docs/how-to-connect-terminuscms', + }, + ], + }, + { + title: 'Start with TerminusDB', + links: [ + { + title: 'Get Started with TerminusDB', + href: '/docs/get-started-with-terminusdb', + }, + { + title: 'Install Options', + href: '/docs/terminusdb-install-options', + links: [ + { + title: 'Install on Kubernetes', + href: '/docs/install-on-kubernetes', + }, + { + title: 'Install as a Docker Container', + href: '/docs/install-terminusdb-as-a-docker-container', + }, + { + title: 'Install from Source Code', + href: '/docs/install-terminusdb-from-source-code', + }, + ], + }, + { + title: 'CLI Commands', + href: '/docs/terminusdb-cli-commands', + }, + ], + }, + { + title: 'How-To Guides', + links: [ + { + title: 'Clone a Demo Project', + href: '/docs/clone-a-demo-terminuscms-project', + }, + { + title: 'Use the Clients', + href: '/docs/use-the-clients', + links: [ + { + title: 'Use the JS Client', + href: '/docs/use-the-javascript-client', + links: [ + { + title: 'Install JS Client', + href: '/docs/install-terminusdb-js-client', + }, + { + title: 'Connect to JS Client', + href: '/docs/connect-with-the-javascript-client', + }, + { + title: 'Create DB with JS', + href: '/docs/create-a-database', + }, + { + title: 'Connect to DB with JS', + href: '/docs/connect-to-a-database', + }, + { + title: 'Add a Schema with JS', + href: '/docs/add-a-schema', + }, + { + title: 'Add Doc with JS', + href: '/docs/add-a-document', + }, + { + title: 'Edit Docs with JS', + href: '/docs/edit-a-document', + }, + { + title: 'Delete Docs with JS', + href: '/docs/delete-a-document', + }, + { + title: 'Get Docs with JS', + href: '/docs/get-documents', + }, + { + title: 'Query Docs with JS', + href: '/docs/query-documents', + }, + { + title: 'Run WOQL Query', + href: '/docs/run-woql-query', + }, + ], + }, + { + title: 'Use the Python Client', + href: '/docs/use-the-python-client', + links: [ + { + title: 'Install Python Client', + href: '/docs/install-the-python-client', + }, + { + title: 'Connect with Python Client', + href: '/docs/connect-with-python-client', + }, + { + title: 'Create DB with Python', + href: '/docs/create-database-with-python-client', + }, + { + title: 'Connect to DB with Python', + href: '/docs/connect-to-a-database-with-python-client', + }, + { + title: 'Add Docs with Python', + href: '/docs/add-documents-with-python-client', + }, + { + title: 'Add Schema with Python', + href: '/docs/add-a-schema-with-the-python-client', + }, + { + title: 'Edit Docs with Python', + href: '/docs/edit-documents-with-python-client', + }, + { + title: 'Get Docs with Python', + href: '/docs/get-documents-with-python-client', + }, + { + title: 'Delete Docs with Python', + href: '/docs/delete-documents-with-python-client', + }, + { + title: 'Import Data with Python', + href: '/docs/import-data-with-python-client', + }, + { + title: 'WOQL Query with Python', + href: '/docs/woql-query-with-python-client', + }, + ], + }, + ], + }, + { + title: 'Collaboration Features', + href: '/docs/use-the-collaboration-features', + links: [ + { + title: 'Collaboration with JS', + href: '/docs/collaboration-with-javascript-client', + links: [ + { + title: 'Clone with JS', + href: '/docs/clone-a-project', + }, + { + title: 'Branch with JS', + href: '/docs/branch-a-project', + }, + { + title: 'Reset with JS', + href: '/docs/reset-a-project', + }, + { + title: 'Squash with JS', + href: '/docs/squash-projects', + }, + { + title: 'Time Travel with JS', + href: '/docs/time-travel-to-previous-commits', + }, + { + title: 'Diff & Patch with JS', + href: '/docs/diff-and-patch-operations', + }, + ], + }, + { + title: 'Collaboration with Python', + href: '/docs/collaboration-with-python-client', + links: [ + { + title: 'Branch with Python', + href: '/docs/branch-a-project-with-the-python-client', + }, + { + title: 'Clone with Python', + href: '/docs/clone-a-database-with-python', + }, + { + title: 'Reset with Python', + href: '/docs/reset-to-a-commit-with-python', + }, + { + title: 'Squash with Python', + href: '/docs/squash-a-project-with-python', + }, + { + title: 'Time Travel with Python', + href: '/docs/time-travel-with-python', + }, + ], + }, + { + title: 'Collaboration Dashboard', + href: '/docs/collaboration-with-terminuscms-dashboard', + links: [ + { + title: 'Branch with Dashboard', + href: '/docs/branch', + }, + { + title: 'Clone with Dashboard', + href: '/docs/clone', + }, + { + title: 'Reset with Dashboard', + href: '/docs/reset', + }, + { + title: 'Squash with Dashboard', + href: '/docs/squash', + }, + { + title: 'Time Travel with Dashboard', + href: '/docs/time-travel', + }, + ], + }, + ], + }, + { + title: 'Use VectorLink', + href: '/docs/use-vectorlink', + links: [ + { + title: 'Add OpenAI Key', + href: '/docs/set-up-vectorlink', + }, + { + title: 'Configure Vector Embeddings', + href: '/docs/openai-handlebars-config', + }, + { + title: 'Index Your Data', + href: '/docs/index-your-data', + }, + ], + }, + { + title: 'Build Schema', + href: '/docs/model-schema', + links: [ + { + title: 'Model Schema UI', + href: '/docs/use-the-model-builder-ui', + }, + { + title: 'JSON Editor', + href: '/docs/use-the-json-editor', + }, + ], + }, + { + title: 'Manage Projects', + href: '/docs/manage-projects-with-terminuscms', + links: [ + { + title: 'Create Teams with UI', + href: '/docs/create-a-team-with-terminuscms', + }, + { + title: 'Create Projects with UI', + href: '/docs/create-a-project-with-terminuscms', + }, + { + title: 'Invite Users with UI', + href: '/docs/invite-users-using-terminuscms', + }, + { + title: 'Get API Key', + href: '/docs/get-your-api-key-from-terminuscms', + }, + ], + }, + { + title: 'Query', + href: '/docs/how-to-query', + links: [ + { + title: 'Query Examples', + href: '/docs/woql-query-examples', + links: [ + { + title: 'Customer Data Processing', + href: '/docs/python-woql-customer-data-processing-example', + }, + ], + }, + { + title: 'GraphQL Query', + href: '/docs/how-to-query-with-graphql', + links: [ + { + title: 'GraphQL Basics', + href: '/docs/graphql-basics', + }, + { + title: 'GraphQL Filter', + href: '/docs/filter-with-graphql', + }, + { + title: 'GraphQL Advanced Filter', + href: '/docs/advanced-filtering-with-graphql', + }, + { + title: 'GraphQL Limit', + href: '/docs/limit-results-in-graphql', + }, + { + title: 'GraphQL Order By', + href: '/docs/order-by-in-graphql', + }, + { + title: 'GraphQL Offset', + href: '/docs/offset-to-provide-paging', + }, + { + title: 'GraphQL Path Queries', + href: '/docs/path-queries-in-graphql', + }, + { + title: 'GraphQL Back Links', + href: '/docs/back-links-in-graphql', + }, + ], + }, + { + title: 'WOQL Query', + href: '/docs/how-to-query-with-woql', + links: [ + { + title: 'WOQL Basics', + href: '/docs/woql-basics', + }, + { + title: 'WOQL Add Docs', + href: '/docs/add-documents-with-woql', + }, + { + title: 'WOQL Edit Docs', + href: '/docs/edit-documents-with-woql', + }, + { + title: 'WOQL Delete Docs', + href: '/docs/delete-documents-with-woql', + }, + { + title: 'WOQL Read Docs', + href: '/docs/read-documents-with-woql', + }, + { + title: 'WOQL Filter', + href: '/docs/filter-with-woql', + }, + { + title: 'WOQL Order By', + href: '/docs/order-by-with-woql', + }, + { + title: 'WOQL Query Arrays', + href: '/docs/query-arrays-and-sets-in-woql', + }, + { + title: 'WOQL Group Results', + href: '/docs/group-query-results', + }, + { + title: 'WOQL Path Queries', + href: '/docs/path-queries-in-woql', + }, + { + title: 'WOQL Math Queries', + href: '/docs/maths-based-queries-in-woql', + }, + { + title: 'WOQL Schema Queries', + href: '/docs/schema-queries-with-woql', + }, + ], + }, + ], + }, + { + title: 'Curate & Import Data', + href: '/docs/curate-and-import-data', + links: [ + { + title: 'Curate with Dashboard', + href: '/docs/use-the-admin-ui-curate-and-import-data', + }, + { + title: 'Import with Python', + href: '/docs/import-data-with-python-client', + }, + ], + }, + ], + }, + { + title: 'Reference Guides', + links: [ + { + title: 'Schema Reference', + href: '/docs/schema-reference-guide', + }, + { + title: 'JS Client Reference', + href: '/docs/javascript', + }, + { + title: 'Python Client Reference', + href: '/docs/python', + }, + { + title: 'GraphQL Reference', + href: '/docs/graphql-query-reference', + links: [ + { + title: 'Connecting to GraphQL', + href: '/docs/connecting-to-graphql-reference', + }, + { + title: 'GraphQL Naming Conventions', + href: '/docs/graphql-naming-conventions-reference', + }, + { + title: 'System Graph Interface', + href: '/docs/system-graph-graphql-interface-reference', + }, + { + title: 'Connect with Apollo Client', + href: '/docs/connect-with-apollo-client', + }, + ], + }, + { + title: 'HTTP OpenAPI Reference', + href: '/docs/openapi', + }, + { + title: 'Access Control', + href: '/docs/js-access-control', + }, + { + title: 'Supported Data Types', + href: '/docs/terminuscms-data-types', + }, + { + title: 'Document Insertion', + href: '/docs/document-insertion', + }, + { + title: 'TerminusCMS Dashboard', + href: '/docs/terminuscms-dashboard-reference', + }, + { + title: 'JSON Diff and Patch', + href: '/docs/json-diff-and-patch', + }, + { + title: 'Path Queries', + href: '/docs/path-query-reference-guide', + }, + { + title: 'Schema Migration', + href: '/docs/schema-migration-reference-guide', + }, + { + title: 'WOQL Class Reference', + href: '/docs/woql-class-reference-guide', + }, + ], + }, + { + title: 'UI SDK', + links: [ + { + title: 'Use the Document UI SDK', + href: '/docs/document-ui-sdk', + links: [ + { + title: 'UI SDK Data Types', + href: '/docs/document-ui-sdk-data-types', + links: [ + + { + title: 'Choice Document', + href: '/docs/choice-document', + }, + { + title: 'Choice Sub-Document', + href: '/docs/choice-subdocuments', + }, + + { + title: 'Mandatory', + href: '/docs/mandatory', + }, + { + title: 'One Of', + href: '/docs/oneof', + }, + { + title: 'Optional', + href: '/docs/optional', + }, + { + title: 'Order By', + href: '/docs/orderby', + }, + { + title: 'Render As', + href: '/docs/render-as', + }, + + { + title: 'sysJSON', + href: '/docs/sysjson', + }, + ], + }, + { + title: 'UI SDK GeoJSON', + href: '/docs/ui-sdk-geojson', + }, + ], + }, + { + title: 'Document UI Template', + href: '/docs/document-ui-template', + links: [ + { + title: 'TDB React Table', + href: '/docs/tdb-react-table', + }, + { + title: 'Use TDB Documents', + href: '/docs/usetdbdocuments', + }, + { + title: 'Use TDB GraphQL Query', + href: '/docs/usetdbgraphqlquery', + }, + { + title: 'UI Components', + href: '/docs/ui-components', + links: [ + { + title: 'Document Classes Summary', + href: '/docs/documentclassessummary', + }, + { + title: 'Documents GraphQL Table', + href: '/docs/documentsgraphqltable', + }, + { + title: 'Edit Documents', + href: '/docs/edit-document-component', + }, + { + title: 'List Documents', + href: '/docs/list-documents-component', + }, + { + title: 'New Documents', + href: '/docs/newdocumentcomponent', + }, + { + title: 'View Documents', + href: '/docs/viewdocumentcomponent', + }, + ], + }, + ], + }, + ], + }, + { + title: 'Explanations', + links: [ + { + title: 'Acid Transactions', + href: '/docs/acid-transactions-explanation', + }, + { + title: 'Datalog', + href: '/docs/datalog-explanation', + }, + { + title: 'Documents', + href: '/docs/documents-explanation', + }, + { + title: 'Glossary', + href: '/docs/glossary', + }, + { + title: 'Graphs', + href: '/docs/graphs-explanation', + }, + { + title: 'Immutability', + href: '/docs/immutability-explanation', + }, + { + title: 'TerminusDB', + href: '/docs/terminusdb-explanation', + }, + { + title: 'Schema Weakening', + href: '/docs/what-is-schema-weakening', + }, + { + title: 'WOQL', + href: '/docs/woql-explanation', + }, + ], + }, +] + +export const old = [ + { + title: 'Start with TerminusCMS', + links: [ + { + title: 'Get Started', + href: '/docs/get-started', + }, + { + title: 'Product Tour', + href: '/docs/product-tour', + links: [ + { + title: 'Overview', + href: '/docs/projects-terminuscms-tour', + }, + { + title: 'Teams & Users', + href: '/docs/manage-teams-users-terminuscms-tour', + }, + { + title: 'Curate Data', + href: '/docs/content-curation-terminuscms-tour', + }, + { + title: 'Change Requests', + href: '/docs/change-request-workflows-terminuscms-tour', + }, + { + title: 'GraphQL & WOQL Query', + href: '/docs/graphql-and-woql-query-terminuscms-tour', + }, + ], + }, + { + title: 'Connect to TerminusCMS', + href: '/docs/how-to-connect-terminuscms', + }, + ], + }, + { + title: 'Start with TerminusDB', + links: [ + { + title: 'Get Started with TerminusDB', + href: '/docs/get-started-with-terminusdb', + }, + { + title: 'Install Options', + href: '/docs/terminusdb-install-options', + links: [ + { + title: 'Install on Kubernetes', + href: '/docs/install-on-kubernetes', + }, + { + title: 'Install as a Docker Container', + href: '/docs/install-terminusdb-as-a-docker-container', + }, + { + title: 'Install from Source Code', + href: '/docs/install-terminusdb-from-source-code', + }, + ], + }, + { + title: 'CLI Commands', + href: '/docs/terminusdb-cli-commands', + }, + ], + }, + { + title: 'How-To Guides', + links: [ + { + title: 'Clone a Demo Project', + href: '/docs/clone-a-demo-terminuscms-project', + }, + { + title: 'Use the Clients', + href: '/docs/use-the-clients', + links: [ + { + title: 'Use the JS Client', + href: '/docs/use-the-javascript-client', + links: [ + { + title: 'Install JS Client', + href: '/docs/install-terminusdb-js-client', + }, + { + title: 'Connect with JS', + href: '/docs/connect-with-the-javascript-client', + }, + { + title: 'Create DB with JS', + href: '/docs/create-a-database-with-javascript', + }, + { + title: 'Add Schema with JS', + href: '/docs/add-a-schema-with-javascript', + }, + { + title: 'Add Docs with JS', + href: '/docs/add-documents-with-javascript', + }, + { + title: 'Get Docs with JS', + href: '/docs/get-documents-with-javascript', + }, + { + title: 'Edit Docs with JS', + href: '/docs/edit-a-document', + }, + { + title: 'Delete Docs with JS', + href: '/docs/delete-a-document', + }, + { + title: 'Access Control with JS', + href: '/docs/access-control-with-javascript', + }, + { + title: 'Run WOQL Query', + href: '/docs/run-woql-query', + }, + ], + }, + { + title: 'Use the Python Client', + href: '/docs/use-the-python-client', + links: [ + { + title: 'Install Python Client', + href: '/docs/install-the-python-client', + }, + { + title: 'Connect with Python', + href: '/docs/connect-with-the-python-client', + }, + { + title: 'Create DB with Python', + href: '/docs/create-a-database-with-python-client', + }, + { + title: 'Get Schema with Python', + href: '/docs/get-schema-with-python-client', + }, + { + title: 'Add Schema with Python', + href: '/docs/add-a-schema-with-the-python-client', + }, + { + title: 'Edit Docs with Python', + href: '/docs/edit-documents-with-python-client', + }, + { + title: 'Get Docs with Python', + href: '/docs/get-documents-with-python-client', + }, + { + title: 'Delete Docs with Python', + href: '/docs/delete-documents-with-python-client', + }, + { + title: 'WOQL Query with Python', + href: '/docs/woql-query-with-python-client', + }, + ], + }, + ], + }, + { + title: 'Collaboration Features', + href: '/docs/use-the-collaboration-features', + links: [ + { + title: 'Branch Management', + href: '/docs/branch-management', + }, + { + title: 'Change Request Workflows', + href: '/docs/change-request-workflows', + }, + ], + }, + { + title: 'Schema Design', + href: '/docs/schema-design', + links: [ + { + title: 'Schema Builder', + href: '/docs/schema-builder', + }, + { + title: 'Schema JSON', + href: '/docs/schema-json', + }, + ], + }, + ], + }, + { + title: 'UI Development', + links: [ + { + title: 'UI SDK', + href: '/docs/ui-sdk', + links: [ + { + title: 'UI SDK Components', + href: '/docs/ui-sdk-components', + }, + { + title: 'UI SDK GeoJSON', + href: '/docs/ui-sdk-geojson', + }, + ], + }, + { + title: 'Document UI Template', + href: '/docs/document-ui-template', + links: [ + { + title: 'TDB React Table', + href: '/docs/tdb-react-table', + }, + { + title: 'Use TDB Documents', + href: '/docs/usetdbdocuments', + }, + { + title: 'Use TDB GraphQL Query', + href: '/docs/usetdbgraphqlquery', + }, + { + title: 'UI Components', + href: '/docs/ui-components', + links: [ + { + title: 'Document Classes Summary', + href: '/docs/documentclassessummary', + }, + { + title: 'Documents GraphQL Table', + href: '/docs/documentsgraphqltable', + }, + { + title: 'Edit Documents', + href: '/docs/edit-document-component', + }, + { + title: 'List Documents', + href: '/docs/list-documents-component', + }, + { + title: 'New Documents', + href: '/docs/newdocumentcomponent', + }, + { + title: 'View Documents', + href: '/docs/viewdocumentcomponent', + }, + ], + }, + ], + }, + ], + }, + { + title: 'Explanations', + links: [ + { + title: 'Acid Transactions', + href: '/docs/acid-transactions-explanation', + }, + { + title: 'Datalog', + href: '/docs/datalog-explanation', + }, + { + title: 'Documents', + href: '/docs/documents-explanation', + }, + { + title: 'Glossary', + href: '/docs/glossary', + }, + { + title: 'Graphs', + href: '/docs/graphs-explanation', + }, + { + title: 'Immutability', + href: '/docs/immutability-explanation', + }, + { + title: 'TerminusDB', + href: '/docs/terminusdb-explanation', + }, + { + title: 'Schema Weakening', + href: '/docs/what-is-schema-weakening', + }, + { + title: 'WOQL', + href: '/docs/woql-explanation', + }, + ], + }, +] diff --git a/src/lib/sections.ts b/src/lib/sections.ts new file mode 100644 index 0000000..afb1bfe --- /dev/null +++ b/src/lib/sections.ts @@ -0,0 +1,97 @@ +import { type Node } from '@markdoc/markdoc' +import { slugifyWithCounter } from '@sindresorhus/slugify' + +interface HeadingNode extends Node { + type: 'heading' + attributes: { + level: 1 | 2 | 3 | 4 | 5 | 6 + id?: string + [key: string]: unknown + } +} + +type H2Node = HeadingNode & { + attributes: { + level: 2 + } +} + +type H3Node = HeadingNode & { + attributes: { + level: 3 + } +} + +function isHeadingNode(node: Node): node is HeadingNode { + return ( + node.type === 'heading' && + [1, 2, 3, 4, 5, 6].includes(node.attributes.level) && + (typeof node.attributes.id === 'string' || + typeof node.attributes.id === 'undefined') + ) +} + +function isH2Node(node: Node): node is H2Node { + return isHeadingNode(node) && node.attributes.level === 2 +} + +function isH3Node(node: Node): node is H3Node { + return isHeadingNode(node) && node.attributes.level === 3 +} + +function getNodeText(node: Node) { + let text = '' + for (let child of node.children ?? []) { + if (child.type === 'text') { + text += child.attributes.content + } + text += getNodeText(child) + } + return text +} + +export type Subsection = H3Node['attributes'] & { + id: string + title: string + children?: undefined +} + +export type Section = H2Node['attributes'] & { + id: string + title: string + children: Array +} + +export function collectSections( + nodes: Array, + slugify = slugifyWithCounter(), +) { + let sections: Array

      = [] + + for (let node of nodes) { + if (isH2Node(node) || isH3Node(node)) { + let title = getNodeText(node) + if (title) { + let id = slugify(title) + if (isH3Node(node)) { + if (!sections[sections.length - 1]) { + throw new Error( + 'Cannot add `h3` to table of contents without a preceding `h2`', + ) + } + sections[sections.length - 1].children.push({ + ...node.attributes, + id, + title, + }) + } else { + sections.push({ ...node.attributes, id, title, children: [] }) + } + } + } + + sections.push(...collectSections(node.children ?? [], slugify)) + } + + return sections +} diff --git a/src/markdoc/nodes.js b/src/markdoc/nodes.js new file mode 100644 index 0000000..0ce5031 --- /dev/null +++ b/src/markdoc/nodes.js @@ -0,0 +1,63 @@ +import { nodes as defaultNodes, Tag } from '@markdoc/markdoc' +import { slugifyWithCounter } from '@sindresorhus/slugify' +import yaml from 'js-yaml' + +import { DocsLayout } from '@/components/DocsLayout' +import { Fence } from '@/components/Fence' + +let documentSlugifyMap = new Map() + +const nodes = { + document: { + ...defaultNodes.document, + render: DocsLayout, + transform(node, config) { + documentSlugifyMap.set(config, slugifyWithCounter()) + + return new Tag( + this.render, + { + frontmatter: yaml.load(node.attributes.frontmatter), + nodes: node.children, + }, + node.transformChildren(config), + ) + }, + }, + heading: { + ...defaultNodes.heading, + transform(node, config) { + let slugify = documentSlugifyMap.get(config) + let attributes = node.transformAttributes(config) + let children = node.transformChildren(config) + let text = children.filter((child) => typeof child === 'string').join(' ') + let id = attributes.id ?? slugify(text) + + return new Tag( + `h${node.attributes.level}`, + { ...attributes, id }, + children, + ) + }, + }, + th: { + ...defaultNodes.th, + attributes: { + ...defaultNodes.th.attributes, + scope: { + type: String, + default: 'col', + }, + }, + }, + fence: { + render: Fence, + attributes: { + language: { + type: String, + }, + }, + }, +} + +export default nodes diff --git a/src/markdoc/search.mjs b/src/markdoc/search.mjs new file mode 100644 index 0000000..95b9de5 --- /dev/null +++ b/src/markdoc/search.mjs @@ -0,0 +1,145 @@ +import Markdoc from '@markdoc/markdoc' +import { slugifyWithCounter } from '@sindresorhus/slugify' +import glob from 'fast-glob' +import * as fs from 'fs' +import * as path from 'path' +import { createLoader } from 'simple-functional-loader' +import * as url from 'url' +import javascript from "../../schema/javascript.json" assert { type: "json" }; + +const __filename = url.fileURLToPath(import.meta.url) +const slugify = slugifyWithCounter() + +function toString(node) { + let str = + node.type === 'text' && typeof node.attributes?.content === 'string' + ? node.attributes.content + : '' + if ('children' in node) { + for (let child of node.children) { + str += toString(child) + } + } + return str +} + +function extractSections(node, sections, isRoot = true) { + if (isRoot) { + slugify.reset() + } + if (node.type === 'heading' || node.type === 'paragraph') { + let content = toString(node).trim() + if (node.type === 'heading' && node.attributes.level <= 2) { + let hash = node.attributes?.id ?? slugify(content) + sections.push([content, hash, []]) + } else { + sections.at(-1)[2].push(content) + } + } else if ('children' in node) { + for (let child of node.children) { + extractSections(child, sections, false) + } + } +} + +export default function withSearch(nextConfig = {}) { + let cache = new Map() + + return Object.assign({}, nextConfig, { + webpack(config, options) { + config.module.rules.push({ + test: __filename, + use: [ + createLoader(function () { + let pagesDir = path.resolve('./src/app') + this.addContextDependency(pagesDir) + + let files = glob.sync('**/page.md', { cwd: pagesDir }) + let data = files.map((file) => { + let url = + file === 'page.md' ? '/' : `/${file.replace(/\/page\.md$/, '')}` + let md = fs.readFileSync(path.join(pagesDir, file), 'utf8') + + let sections + + if (cache.get(file)?.[0] === md) { + sections = cache.get(file)[1] + } else { + let ast = Markdoc.parse(md) + let title = + ast.attributes?.frontmatter?.match( + /^title:\s*(.*?)\s*$/m, + )?.[1] + sections = [[title, null, []]] + extractSections(ast, sections) + cache.set(file, [md, sections]) + } + + return { url, sections } + }) + + // FIXME: Enable search of javascript and python too + // const javascriptSections = javascript.modules.map((module) => { + + // return [module.title, null, []] + // }) + + // When this file is imported within the application + // the following module is loaded: + return ` + import FlexSearch from 'flexsearch' + + let sectionIndex = new FlexSearch.Document({ + tokenize: 'full', + document: { + id: 'url', + index: 'content', + store: ['title', 'pageTitle'], + }, + context: { + resolution: 9, + depth: 2, + bidirectional: true + } + }) + + let data = ${JSON.stringify(data)} + + for (let { url, sections } of data) { + for (let [title, hash, content] of sections) { + sectionIndex.add({ + url: url + (hash ? ('#' + hash) : ''), + title, + content: [title, ...content].join('\\n'), + pageTitle: hash ? sections[0][0] : undefined, + }) + } + } + + export function search(query, options = {}) { + let result = sectionIndex.search(query, { + ...options, + enrich: true, + }) + if (result.length === 0) { + return [] + } + return result[0].result.map((item) => ({ + url: item.id, + title: item.doc.title, + pageTitle: item.doc.pageTitle, + })) + } + ` + }), + ], + }) + + if (typeof nextConfig.webpack === 'function') { + return nextConfig.webpack(config, options) + } + + return config + }, + }) +} diff --git a/src/markdoc/tags.js b/src/markdoc/tags.js new file mode 100644 index 0000000..957b1d0 --- /dev/null +++ b/src/markdoc/tags.js @@ -0,0 +1,47 @@ +import { Callout } from '@/components/Callout' +import { QuickLink, QuickLinks } from '@/components/QuickLinks' + +const tags = { + callout: { + attributes: { + title: { type: String }, + type: { + type: String, + default: 'note', + matches: ['note', 'warning'], + errorLevel: 'critical', + }, + }, + render: Callout, + }, + figure: { + selfClosing: true, + attributes: { + src: { type: String }, + alt: { type: String }, + caption: { type: String }, + }, + render: ({ src, alt = '', caption }) => ( +
      + {/* eslint-disable-next-line @next/next/no-img-element */} + {alt} +
      {caption}
      +
      + ), + }, + 'quick-links': { + render: QuickLinks, + }, + 'quick-link': { + selfClosing: true, + render: QuickLink, + attributes: { + title: { type: String }, + description: { type: String }, + icon: { type: String }, + href: { type: String }, + }, + }, +} + +export default tags diff --git a/src/pages/404.tsx b/src/pages/404.tsx deleted file mode 100644 index 0854d1f..0000000 --- a/src/pages/404.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { Layout } from "../components/_layout" -import menu from "../menu.json" - -export default function Custom404() { - const not_found = ( -

      - We've moved our documentation from Gitbook to TerminusCMS to improve - the user experience. Some URLs have changed and we're waiting for the - search engines to catch up. Please use the menu to find what you were - looking for. -

      - ) - return ( - - ) -} diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx deleted file mode 100644 index dab6c5c..0000000 --- a/src/pages/_app.tsx +++ /dev/null @@ -1,67 +0,0 @@ -//import '@/styles/globals.css' -import React, { useEffect, useCallback } from "react" -//import "../styles/tailwind.css" -import "flowbite" -import "../styles/globals.css" -//import "../styles/test.css" -//import "../styles/prism-one-dark.css" -import type { Metadata } from "next" -import type { AppProps } from "next/app" - -/** function to handle theme switcher */ -function handleThemeSwitch() { - var themeToggleDarkIcon = document.getElementById("theme-toggle-dark-icon") - var themeToggleLightIcon = document.getElementById("theme-toggle-light-icon") - - // Change the icons inside the button based on previous settings - if ( - localStorage.getItem("color-theme") === "dark" || - (!("color-theme" in localStorage) && - window.matchMedia("(prefers-color-scheme: dark)").matches) - ) { - themeToggleLightIcon.classList.remove("hidden") - document.documentElement.classList.add("dark") - } else { - themeToggleDarkIcon.classList.remove("hidden") - document.documentElement.classList.remove("dark") - } - - var themeToggleBtn = document.getElementById("theme-toggle") - - themeToggleBtn.addEventListener("click", function (e) { - e.stopPropagation() - e.preventDefault() - - // toggle icons inside button - themeToggleDarkIcon.classList.toggle("hidden") - themeToggleLightIcon.classList.toggle("hidden") - - // if set via local storage previously - if (localStorage.getItem("color-theme")) { - if (localStorage.getItem("color-theme") === "light") { - document.documentElement.classList.add("dark") - localStorage.setItem("color-theme", "dark") - } else { - document.documentElement.classList.remove("dark") - localStorage.setItem("color-theme", "light") - } - // if NOT set via local storage previously - } else { - if (document.documentElement.classList.contains("dark")) { - document.documentElement.classList.remove("dark") - localStorage.setItem("color-theme", "light") - } else { - document.documentElement.classList.add("dark") - localStorage.setItem("color-theme", "dark") - } - } - }) -} - -export default function App({ Component, pageProps }: AppProps) { - useEffect(() => { - // handleThemeSwitch(); - }, []) - - return -} diff --git a/src/pages/_document.tsx b/src/pages/_document.tsx deleted file mode 100644 index d11c34e..0000000 --- a/src/pages/_document.tsx +++ /dev/null @@ -1,45 +0,0 @@ -/* eslint-disable @next/next/no-img-element */ -import { Html, Head, Main, NextScript } from "next/document" -import Script from "next/script" -import "flowbite" - -/** - * - * @returns if (li.href.includes(current)) { -li.classList.add('active'); -} - */ - -export default function Document() { - const basePath = process.env.BASE_PATH || "" - return ( - - - */} - - - - ) -} - -//

      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