diff --git a/.github/scripts/docs/preview-deploy.js b/.github/scripts/docs/preview-deploy.js new file mode 100644 index 00000000000..27e8be7d29f --- /dev/null +++ b/.github/scripts/docs/preview-deploy.js @@ -0,0 +1,191 @@ +const DOCS_SITE_REPO = { + org: "edgedb", + repo: "edgedb.com", + ref: "new-new-docs", +}; + +module.exports = async ({ github, context }) => { + const { VERCEL_TOKEN, VERCEL_TEAM_ID } = process.env; + + if (!VERCEL_TOKEN || !VERCEL_TEAM_ID) { + throw new Error( + `cannot run docs preview deploy workflow, ` + + `VERCEL_TOKEN or VERCEL_TEAM_ID secrets are missing` + ); + } + + const prBranch = context.payload.pull_request.head.ref; + const commitSHA = context.payload.pull_request.head.sha; + const shortCommitSHA = commitSHA.slice(0, 8); + + const existingComments = ( + await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + }) + ).data; + + const commentHeader = `### Docs preview deploy\n`; + let commentMessage = commentHeader; + + let updateComment = existingComments.find( + (c) => + c.performed_via_github_app?.slug === "github-actions" && + c.body?.startsWith(commentHeader) + ); + + let deploymentError = null; + let deployment; + try { + deployment = await vercelFetch("https://api.vercel.com/v13/deployments", { + name: "edgedb-docs", + gitSource: { + type: "github", + ...DOCS_SITE_REPO, + }, + projectSettings: { + buildCommand: `EDGEDB_REPO_BRANCH=${prBranch} EDGEDB_REPO_SHA=${commitSHA} yarn vercel-build`, + }, + }); + + commentMessage += `\nπŸ”„ Deploying docs preview for commit ${shortCommitSHA}:\n\n`; + } catch (e) { + deploymentError = e; + commentMessage += `\n❌ Failed to deploy docs preview for commit ${shortCommitSHA}:\n\n\`\`\`\n${e.message}\n\`\`\``; + } + + commentMessage += `\n\n(Last updated: ${formatDatetime(new Date())})`; + + if (updateComment) { + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: updateComment.id, + body: commentMessage, + }); + } else { + updateComment = ( + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: commentMessage, + }) + ).data; + } + + if (deploymentError) { + throw new Error(`Docs preview deployment failed: ${e.message}`); + } + + let i = 0; + while (i < 40) { + await sleep(15_000); + i++; + + const status = ( + await vercelFetch( + `https://api.vercel.com/v13/deployments/${deployment.id}` + ) + ).status; + + const latestComment = await github.rest.issues.getComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: updateComment.id, + }); + + if (!latestComment.data.body.includes(shortCommitSHA)) { + console.log("Skipping further updates, new deployment has started"); + return; + } + + if (status === "READY" || status === "ERROR" || status === "CANCELED") { + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: updateComment.id, + body: `${commentHeader}${ + status === "READY" + ? `\nβœ… Successfully deployed docs preview for commit ${shortCommitSHA}:` + : `\n❌ Docs preview deployment ${ + status === "CANCELED" ? "was canceled" : "failed" + } for commit ${shortCommitSHA}:` + }\n\n\n\n(Last updated: ${formatDatetime( + new Date() + )})`, + }); + if (status !== "READY") { + throw new Error( + `Docs preview deployment failed with status ${status}: https://${deployment.url}` + ); + } + return; + } + } + + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: updateComment.id, + body: `${commentHeader} +❌ Timed out waiting for deployment status to succeed or fail for commit ${shortCommitSHA}:\n\n\n\n(Last updated: ${formatDatetime(new Date())})`, + }); + throw new Error("Timed out waiting for deployment status to succeed or fail"); +}; + +async function vercelFetch(url, body) { + const { VERCEL_TOKEN, VERCEL_TEAM_ID } = process.env; + const _url = new URL(url); + url = `${_url.origin}${_url.pathname}?${new URLSearchParams({ + teamId: VERCEL_TEAM_ID, + })}`; + + let res; + try { + res = await fetch(url, { + body: body ? JSON.stringify(body) : undefined, + headers: { + Authorization: `Bearer ${VERCEL_TOKEN}`, + "Content-Type": body ? "application/json" : undefined, + }, + method: body ? "post" : "get", + }); + } catch (e) { + throw new Error(`vercel api request failed: ${e}`); + } + + if (res.ok) { + return await res.json(); + } else { + let body; + try { + body = await res.text(); + } catch (e) { + // ignore + } + throw new Error( + `vercel api request failed: ${res.status} ${res.statusText}, ${body}` + ); + } +} + +function formatDatetime(date) { + return date.toLocaleString("en-US", { + year: "numeric", + month: "short", + day: "numeric", + hour: "numeric", + minute: "numeric", + second: "numeric", + hourCycle: "h24", + timeZoneName: "short", + }); +} + +function sleep(milliseconds) { + return new Promise((resolve) => setTimeout(resolve, milliseconds)); +} diff --git a/.github/workflows/docs-preview-deploy.yml b/.github/workflows/docs-preview-deploy.yml new file mode 100644 index 00000000000..3b16ed62385 --- /dev/null +++ b/.github/workflows/docs-preview-deploy.yml @@ -0,0 +1,21 @@ +name: Docs Preview Deploy + +on: + pull_request: + paths: + - "docs/**" + +jobs: + deploy: + runs-on: ubuntu-latest + permissions: write-all + steps: + - uses: actions/checkout@v4 + - uses: actions/github-script@v7 + env: + VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} + VERCEL_TEAM_ID: ${{ secrets.VERCEL_TEAM_ID }} + with: + script: | + const script = require('./.github/scripts/docs/preview-deploy.js'); + await script({github, context}); diff --git a/docs/ai/index.rst b/docs/ai/index.rst index 64d186fba28..88134092fdf 100644 --- a/docs/ai/index.rst +++ b/docs/ai/index.rst @@ -12,9 +12,9 @@ AI python reference -:edb-alt-title: Using EdgeDB AI +:edb-alt-title: Using Gel AI -EdgeDB AI allows you to ship AI-enabled apps with practically no effort. It +|Gel| AI allows you to ship AI-enabled apps with practically no effort. It automatically generates embeddings for your data. Works with OpenAI, Mistral AI, Anthropic, and any other provider with a compatible API. @@ -22,8 +22,8 @@ AI, Anthropic, and any other provider with a compatible API. Enable extension in your schema =============================== -AI is an EdgeDB extension. To enable it, you will need to add the extension -to your app’s schema: +AI is a |Gel| extension. To enable it, you will need to add the extension +to your app's schema: .. code-block:: sdl @@ -34,12 +34,12 @@ Extension configuration ======================= The AI extension may be configured via our UI or via EdgeQL. To use the -built-in UI, access it by running ``edgedb ui``. If you have the extension +built-in UI, access it by running :gelcmd:`ui`. If you have the extension enabled in your schema as shown above and have migrated that schema change, you will see the "AI Admin" icon in the left-hand toolbar. .. image:: images/ui-ai.png - :alt: The EdgeDB local development server UI highlighting the AI admin + :alt: The Gel local development server UI highlighting the AI admin icon in the left-hand toolbar. The icon is two stars, one larger and one smaller, the smaller being a light pink color and the larger being a light blue when selected. @@ -69,7 +69,7 @@ Provider" button, selecting the appropriate API, and pasting your key in the "Secret" field. .. image:: images/ui-ai-add-provider.png - :alt: The "Add Provider" form of the EdgeDB local development server UI. + :alt: The "Add Provider" form of the Gel local development server UI. On the left, the sidebar navigation for the view showing Playground, Prompts, and Providers options, with Provider selected (indicated with a purple border on the left). The main content area shows a @@ -85,7 +85,7 @@ You may alternatively configure a provider via EdgeQL: .. code-block:: edgeql - configure current database + configure current branch insert ext::ai::OpenAIProviderConfig { secret := 'sk-....', }; @@ -104,13 +104,13 @@ We have provider config types for each of the three supported APIs: Usage ===== -Using EdgeDB AI requires some changes to your schema. +Using |Gel| AI requires some changes to your schema. Add an index ------------ -To start using EdgeDB AI on a type, create an index: +To start using |Gel| AI on a type, create an index: .. code-block:: sdl-diff @@ -124,8 +124,8 @@ To start using EdgeDB AI on a type, create an index: In this example, we have added an AI index on the ``Astronomy`` type's ``content`` property using the ``text-embedding-3-small`` model. Once you have -the index in your schema, :ref:`create ` and -:ref:`apply ` your migration, and you're ready +the index in your schema, :ref:`create ` and +:ref:`apply ` your migration, and you're ready to start running queries! .. note:: @@ -154,13 +154,13 @@ can define an AI index on an expression: .. note:: When AI indexes aren't working… If you find your queries are not returning the expected results, try - inspecting your instance logs. On an EdgeDB Cloud instance, use the "Logs" + inspecting your instance logs. On a |Gel| Cloud instance, use the "Logs" tab in your instance dashboard. On local or :ref:`CLI-linked remote - instances `, use ``edgedb instance logs -I - ``. You may find the problem there. + instances `, use :gelcmd:`instance logs -I + `. You may find the problem there. Providers impose rate limits on their APIs which can often be the source of - AI index problems. If index creation hits a rate limit, EdgeDB will wait + AI index problems. If index creation hits a rate limit, |Gel| will wait the ``indexer_naptime`` (see the docs on :ref:`ext::ai configuration `) and resume index creation. @@ -209,13 +209,13 @@ Use RAG via HTTP ---------------- By making an HTTP request to -``https://:/branch//ai/rag``, you can generate +``https://:/branch//ai/rag``, you can generate text via the generative AI API of your choice within the context of a type with a deferred embedding index. .. note:: - Making HTTP requests to EdgeDB requires :ref:`authentication + Making HTTP requests to |Gel| requires :ref:`authentication `. .. code-block:: bash @@ -224,7 +224,7 @@ a deferred embedding index. "query": "What color is the sky on Mars?", "model": "gpt-4-turbo-preview", "context": {"query":"select Astronomy"} - }' https://:/branch//ai/rag + }' https://:/branch//ai/rag {"response": "The sky on Mars is red."} Since LLMs are often slow, it may be useful to stream the response. To do this, @@ -243,14 +243,14 @@ add ``"stream": true`` to your request JSON. Use RAG via JavaScript ---------------------- -``@edgedb/ai`` offers a convenient wrapper around ``ext::ai``. Install it with -``npm install @edgedb/ai`` (or via your package manager of choice) and +``@gel/ai`` offers a convenient wrapper around ``ext::ai``. Install it with +``npm install @gel/ai`` (or via your package manager of choice) and implement it like this example: .. code-block:: typescript - import { createClient } from "edgedb"; - import { createAI } from "@edgedb/ai"; + import { createClient } from "gel"; + import { createAI } from "@gel/ai"; const client = createClient(); diff --git a/docs/ai/javascript.rst b/docs/ai/javascript.rst index 12a4c5ab0e3..e1822023cef 100644 --- a/docs/ai/javascript.rst +++ b/docs/ai/javascript.rst @@ -4,32 +4,32 @@ JavaScript ========== -:edb-alt-title: EdgeDB AI's JavaScript package +:edb-alt-title: Gel AI's JavaScript package -``@edgedb/ai`` offers a convenient wrapper around ``ext::ai``. Install it with +``@gel/ai`` offers a convenient wrapper around ``ext::ai``. Install it with npm or via your package manager of choice: .. code-block:: bash - $ npm install @edgedb/ai # or - $ yarn add @edgedb/ai # or - $ pnpm add @edgedb/ai # or - $ bun add @edgedb/ai + $ npm install @gel/ai # or + $ yarn add @gel/ai # or + $ pnpm add @gel/ai # or + $ bun add @gel/ai Usage ===== -Start by importing ``createClient`` from ``edgedb`` and ``createAI`` from -``@edgedb/ai``: +Start by importing ``createClient`` from ``gel`` and ``createAI`` from +``@gel/ai``: .. code-block:: typescript - import { createClient } from "edgedb"; - import { createAI } from "@edgedb/ai"; + import { createClient } from "gel"; + import { createAI } from "@gel/ai"; -Create an EdgeDB client. Create an instance of the AI client by passing in the -EdgeDB client and any options for the AI provider (like the text generation +Create a |Gel| client. Create an instance of the AI client by passing in the +Gel client and any options for the AI provider (like the text generation model): .. code-block:: typescript @@ -93,16 +93,16 @@ API Reference .. js:function:: createAI( \ client: Client, \ options: Partial = {} \ - ): EdgeDBAI + ): GelAI - Creates an instance of ``EdgeDBAI`` with the specified client and options. + Creates an instance of ``GelAI`` with the specified client and options. :param client: - An EdgeDB client instance. + A |Gel| client instance. :param string options.model: Required. Specifies the AI model to use. This could be a version of GPT - or any other model supported by EdgeDB AI. + or any other model supported by |Gel| AI. :param options.prompt: Optional. Defines the input prompt for the AI model. The prompt can be @@ -111,22 +111,22 @@ API Reference interactions. The default is the built-in system prompt. -EdgeDBAI --------- +GelAI +----- -Instances of ``EdgeDBAI`` offer methods for client configuration and utilizing +Instances of ``GelAI`` offer methods for client configuration and utilizing RAG. Public methods ^^^^^^^^^^^^^^ -.. js:method:: withConfig(options: Partial): EdgeDBAI +.. js:method:: withConfig(options: Partial): GelAI - Returns a new ``EdgeDBAI`` instance with updated configuration options. + Returns a new ``GelAI`` instance with updated configuration options. :param string options.model: Required. Specifies the AI model to use. This could be a version of GPT - or any other model supported by EdgeDB AI. + or any other model supported by |Gel| AI. :param options.prompt: Optional. Defines the input prompt for the AI model. The prompt can be @@ -134,9 +134,9 @@ Public methods structure that includes roles and content for more complex interactions. The default is the built-in system prompt. -.. js:method:: withContext(context: Partial): EdgeDBAI +.. js:method:: withContext(context: Partial): GelAI - Returns a new ``EdgeDBAI`` instance with an updated query context. + Returns a new ``GelAI`` instance with an updated query context. :param string context.query: Required. Specifies an expression to determine the relevant objects and @@ -179,11 +179,11 @@ Public methods Can be used in two ways: - - as **an async iterator** - if you want to process streaming data in + - as **an async iterator** - if you want to process streaming data in real-time as it arrives, ideal for handling long-running streams. - - as **a Promise that resolves to a full Response object** - you have - complete control over how you want to handle the stream, this might be + - as **a Promise that resolves to a full Response object** - you have + complete control over how you want to handle the stream, this might be useful when you want to manipulate the raw stream or parse it in a custom way. :param string message: diff --git a/docs/ai/python.rst b/docs/ai/python.rst index 87ffa2f6048..19d0af9a791 100644 --- a/docs/ai/python.rst +++ b/docs/ai/python.rst @@ -4,39 +4,39 @@ Python ====== -:edb-alt-title: EdgeDB AI's Python package +:edb-alt-title: Gel AI's Python package -The ``edgedb.ai`` package is an optional binding of the AI extension in EdgeDB. -To use the AI binding, you need to install ``edgedb-python`` with the ``ai`` -extra dependencies: +The ``gel.ai`` package is an optional binding of the AI extension in |Gel|. +To use the AI binding, you need to install ``gel`` Python package with the +``ai`` extra dependencies: .. code-block:: bash - $ pip install 'edgedb[ai]' + $ pip install 'gel[ai]' Usage ===== -Start by importing ``edgedb`` and ``edgedb.ai``: +Start by importing ``gel`` and ``gel.ai``: .. code-block:: python - import edgedb - import edgedb.ai + import gel + import gel.ai Blocking -------- -The AI binding is built on top of the regular EdgeDB client objects, providing +The AI binding is built on top of the regular |Gel| client objects, providing both blocking and asynchronous versions of its API. For example, a blocking AI client is initialized like this: .. code-block:: python - client = edgedb.create_client() - gpt4ai = edgedb.ai.create_ai( + client = gel.create_client() + gpt4ai = gel.ai.create_ai( client, model="gpt-4-turbo-preview" ) @@ -76,12 +76,12 @@ To use an async client instead, do this: .. code-block:: python - import asyncio # alongside the EdgeDB imports + import asyncio # alongside the Gel imports - client = edgedb.create_async_client() + client = gel.create_async_client() async def main(): - gpt4ai = await edgedb.ai.create_async_ai( + gpt4ai = await gel.ai.create_async_ai( client, model="gpt-4-turbo-preview" ) @@ -103,15 +103,15 @@ To use an async client instead, do this: API reference ============= -.. py:function:: create_ai(client, **kwargs) -> EdgeDBAI +.. py:function:: create_ai(client, **kwargs) -> GelAI - Creates an instance of ``EdgeDBAI`` with the specified client and options. + Creates an instance of ``GelAI`` with the specified client and options. This function ensures that the client is connected before initializing the AI with the specified options. :param client: - An EdgeDB client instance. + A |Gel| client instance. :param kwargs: Keyword arguments that are passed to the ``AIOptions`` data class to @@ -122,15 +122,15 @@ API reference ``None`` will result in the client using the default prompt. (default: ``None``) -.. py:function:: create_async_ai(client, **kwargs) -> AsyncEdgeDBAI +.. py:function:: create_async_ai(client, **kwargs) -> AsyncGelAI - Creates an instance of ``AsyncEdgeDBAI`` w/ the specified client & options. + Creates an instance of ``AsyncGelAI`` w/ the specified client & options. This function ensures that the client is connected asynchronously before initializing the AI with the specified options. :param client: - An asynchronous EdgeDB client instance. + An asynchronous |Gel| client instance. :param kwargs: Keyword arguments that are passed to the ``AIOptions`` data class to @@ -144,12 +144,12 @@ AI client classes ----------------- -BaseEdgeDBAI -^^^^^^^^^^^^ +BaseGelAI +^^^^^^^^^ -.. py:class:: BaseEdgeDBAI +.. py:class:: BaseGelAI - The base class for EdgeDB AI clients. + The base class for |Gel| AI clients. This class handles the initialization and configuration of AI clients and provides methods to modify their configuration and context dynamically. @@ -168,7 +168,7 @@ BaseEdgeDBAI A placeholder for the client class, should be implemented by subclasses. :param client: - An instance of EdgeDB client, which could be either a synchronous or + An instance of |Gel| client, which could be either a synchronous or asynchronous client. :param options: @@ -210,12 +210,12 @@ BaseEdgeDBAI objects returned by the query. -EdgeDBAI -^^^^^^^^ +GelAI +^^^^^ -.. py:class:: EdgeDBAI +.. py:class:: GelAI - A synchronous class for creating EdgeDB AI clients. + A synchronous class for creating |Gel| AI clients. This class provides methods to send queries and receive responses using both blocking and streaming communication modes synchronously. @@ -254,12 +254,12 @@ EdgeDBAI instance. -AsyncEdgeDBAI -^^^^^^^^^^^^^ +AsyncGelAI +^^^^^^^^^^ -.. py:class:: AsyncEdgeDBAI +.. py:class:: AsyncGelAI - An asynchronous class for creating EdgeDB AI clients. + An asynchronous class for creating |Gel| AI clients. This class provides methods to send queries and receive responses using both blocking and streaming communication modes asynchronously. diff --git a/docs/ai/reference.rst b/docs/ai/reference.rst index 0fa10daab46..85557ff33fb 100644 --- a/docs/ai/reference.rst +++ b/docs/ai/reference.rst @@ -4,7 +4,7 @@ ext::ai ======= -To activate EdgeDB AI functionality, you can use the :ref:`extension +To activate |Gel| AI functionality, you can use the :ref:`extension ` mechanism: .. code-block:: sdl @@ -58,12 +58,12 @@ Providers --------- Provider configs are required for AI indexes (for embedding generation) and for -RAG (for text generation). They may be added via :ref:`ref_cli_edgedb_ui` or by +RAG (for text generation). They may be added via :ref:`ref_cli_gel_ui` or by via EdgeQL: .. code-block:: edgeql - configure current database + configure current branch insert ext::ai::OpenAIProviderConfig { secret := 'sk-....', }; @@ -93,7 +93,7 @@ Available values are ``ext::ai::ProviderAPIStyle.OpenAI`` and Prompts ------- -You may add prompts either via :ref:`ref_cli_edgedb_ui` or via EdgeQL. Here's +You may add prompts either via :ref:`ref_cli_gel_ui` or via EdgeQL. Here's an example of how you might add a prompt with a single message: .. code-block:: edgeql @@ -184,13 +184,13 @@ When indexes aren't working… ---------------------------- If you find your queries are not returning the expected results, try -inspecting your instance logs. On an EdgeDB Cloud instance, use the "Logs" +inspecting your instance logs. On a |Gel| Cloud instance, use the "Logs" tab in your instance dashboard. On local or :ref:`CLI-linked remote -instances `, use ``edgedb instance logs -I -``. You may find the problem there. +instances `, use :gelcmd:`instance logs -I +`. You may find the problem there. Providers impose rate limits on their APIs which can often be the source of -AI index problems. If index creation hits a rate limit, EdgeDB will wait +AI index problems. If index creation hits a rate limit, Gel will wait the ``indexer_naptime`` (see the docs on :ref:`ext::ai configuration `) and resume index creation. @@ -296,7 +296,7 @@ Functions .. note:: The ``query`` argument should *not* be a textual query but the - embeddings generated *from* a textual query. To have EdgeDB generate + embeddings generated *from* a textual query. To have |Gel| generate the query for you along with a text response, try :ref:`our built-in RAG `. @@ -328,16 +328,16 @@ using your AI indexes or to generate embeddings against a model of your choice. .. note:: - All EdgeDB server HTTP endpoints require :ref:`authentication + All |Gel| server HTTP endpoints require :ref:`authentication `. By default, you may use `HTTP Basic Authentication `_ - with your EdgeDB username and password. + with your Gel username and password. RAG --- -``POST``: ``https://:/branch//ai/rag`` +``POST``: ``https://:/branch//ai/rag`` Responds with text generated by the specified text generation model in response to the provided query. @@ -425,7 +425,7 @@ these properties: "query": "What color is the sky on Mars?", "model": "gpt-4-turbo-preview", "context": {"query":"Knowledge"} - }' http://:/branch/main/ai/rag + }' http://:/branch/main/ai/rag Response @@ -596,7 +596,7 @@ stream. Embeddings ---------- -``POST``: ``https://:/branch//ai/embeddings`` +``POST``: ``https://:/branch//ai/embeddings`` Responds with embeddings generated by the specified embeddings model in response to the provided input. diff --git a/docs/changelog/1_0_a2.rst b/docs/changelog/1_0_a2.rst index 2b15f77c5ce..86f86ab8c21 100644 --- a/docs/changelog/1_0_a2.rst +++ b/docs/changelog/1_0_a2.rst @@ -13,7 +13,7 @@ This changelog summarizes new features and breaking changes in New JavaScript Driver ===================== -EdgeDB has a new high-performance native +|EdgeDB| has a new high-performance native `EdgeDB driver `_ for NodeJS 10+. The driver is written in strict TypeScript, thoroughly tested, and has @@ -24,7 +24,7 @@ Install it with ``npm`` or ``yarn``: .. code-block:: bash - $ npm install edgedb + $ npm install gel and it is ready for use: @@ -47,7 +47,7 @@ and it is ready for use: main(); -The documentation can be found :ref:`here `. +The documentation can be found :ref:`here `. Standard Library @@ -145,10 +145,10 @@ Other Fixes and Enhancements Dump / Restore ============== -The new :ref:`edgedb dump ` and -:ref:`edgedb restore ` commands can be used to -safely dump and restore EdgeDB databases, including when upgrading to new -versions of EdgeDB. +The new :ref:`edgedb dump ` and +:ref:`edgedb restore ` commands can be used to +safely dump and restore |EdgeDB| databases, including when upgrading to new +versions of |EdgeDB|. EdgeQL @@ -339,7 +339,7 @@ Generic Describe ---------------- The new :eql:stmt:`describe` introspection command can generate DDL, -SDL, or a descriptive text summary of any schema object in EdgeDB. A +SDL, or a descriptive text summary of any schema object in |EdgeDB|. A few examples: .. code-block:: edgeql-repl @@ -456,7 +456,7 @@ Server Postgres 12 ----------- -EdgeDB is now based on PostgreSQL 12. +|EdgeDB| is now based on PostgreSQL 12. Other Fixes and Enhancements ---------------------------- diff --git a/docs/changelog/1_0_a4.rst b/docs/changelog/1_0_a4.rst index 22f7d5637e4..0ad3e32b3ac 100644 --- a/docs/changelog/1_0_a4.rst +++ b/docs/changelog/1_0_a4.rst @@ -40,7 +40,7 @@ CLI === * We have a new ``edgedb server`` group of commands that ships with - the default EdgeDB CLI. Check out the details in this `RFC 1001 + the default |EdgeDB| CLI. Check out the details in this `RFC 1001 `_. * The ``edgedb`` REPL prompt now has a transaction indicator: diff --git a/docs/changelog/1_0_a5.rst b/docs/changelog/1_0_a5.rst index 7de1a2b48a6..dd4e9307d5f 100644 --- a/docs/changelog/1_0_a5.rst +++ b/docs/changelog/1_0_a5.rst @@ -108,7 +108,7 @@ CLI Bindings ======== -* Add transaction :ref:`API ` to JS binding +* Add transaction :ref:`API ` to JS binding (`#61 `_). Here's an example of using transactions: diff --git a/docs/changelog/1_0_a6.rst b/docs/changelog/1_0_a6.rst index fa0b95c6506..0d20058ab69 100644 --- a/docs/changelog/1_0_a6.rst +++ b/docs/changelog/1_0_a6.rst @@ -7,7 +7,7 @@ =========== This changelog summarizes new features and breaking changes in -EdgeDB 1.0 alpha 6 "Wolf". +|EdgeDB| 1.0 alpha 6 "Wolf". EdgeQL diff --git a/docs/changelog/1_0_a7.rst b/docs/changelog/1_0_a7.rst index 62a73879ad0..3f808d04064 100644 --- a/docs/changelog/1_0_a7.rst +++ b/docs/changelog/1_0_a7.rst @@ -108,7 +108,7 @@ with a default value: ... }; We use :eql:stmt:`describe current migration as json ` to see what EdgeDB is proposing. The JSON format makes it +migration>` to see what |EdgeDB| is proposing. The JSON format makes it easier to potentially integrate this with other tools. For this example it's worth turning on ``json`` output mode for edgedb REPL: @@ -196,7 +196,7 @@ Command-Line Tools * Default user and default database are now simply ``edgedb`` and no longer named after the system user. -* Add ``--connect-timeout`` to control how long to wait for EdgeDB +* Add ``--connect-timeout`` to control how long to wait for |EdgeDB| response (`#191 `_). * Add ``--dsn`` as a connection option (`#176 `_). diff --git a/docs/changelog/1_0_b1.rst b/docs/changelog/1_0_b1.rst index b1d7ebebee6..2773ca89182 100644 --- a/docs/changelog/1_0_b1.rst +++ b/docs/changelog/1_0_b1.rst @@ -7,7 +7,7 @@ ========== This changelog summarizes new features and breaking changes in -EdgeDB 1.0 beta 1 "Sirius". +|EdgeDB| 1.0 beta 1 "Sirius". Migrations @@ -41,11 +41,11 @@ Let's say we start with the following schema for a simple chat app: We create a directory ``app_schema`` and write the above into a ``app_schema/schema.esdl`` file inside it. Then we can initialize our project database by running :ref:`edgedb create-migration -`: +`: .. code-block:: bash - $ edgedb -I chatapp create-migration --schema-dir app_schema + $ gel -I chatapp create-migration --schema-dir app_schema did you create object type 'default::User'? [y,n,l,c,b,s,q,?] ? @@ -71,7 +71,7 @@ following command: .. code-block:: bash - $ edgedb -I chatapp migrate --schema-dir app_schema + $ gel -I chatapp migrate --schema-dir app_schema Applied m1ufwaxcqiwcq3ttcujnxv6f3jewhfrywc442z6gjk3sm3e5fgyr4q (00001.edgeql) @@ -107,12 +107,12 @@ schema to be: }; And we apply the changes by using :ref:`edgedb -create-migration ` and :ref:`edgedb -migrate ` commands again: +create-migration ` and :ref:`edgedb +migrate ` commands again: .. code-block:: bash - $ edgedb -I chatapp create-migration --schema-dir app_schema + $ gel -I chatapp create-migration --schema-dir app_schema did you create object type 'default::Channel'? [y,n,l,c,b,s,q,?] y did you create link 'channel' of object type 'default::Message'? @@ -123,18 +123,18 @@ migrate ` commands again: y Created app_schema/migrations/00002.edgeql, id: m1grkbj7z3fwvj6qe7ib72xdc6urj6ih5aynx3ammlrunh6tfefnaa - $ edgedb -I chatapp migrate --schema-dir app_schema + $ gel -I chatapp migrate --schema-dir app_schema Applied m1grkbj7z3fwvj6qe7ib72xdc6urj6ih5aynx3ammlrunh6tfefnaa (00002.edgeql) At this point we may want to actually create a default channel "Main" and make the ``channel`` link required. So we alter the schema to make the link required and run :ref:`edgedb create-migration -` again: +` again: .. code-block:: bash - $ edgedb -I chatapp create-migration --schema-dir app_schema + $ gel -I chatapp create-migration --schema-dir app_schema did you make link 'channel' of object type 'default::Message' required? [y,n,l,c,b,s,q,?] y @@ -151,7 +151,7 @@ Now we can actually apply the changes: .. code-block:: bash - $ edgedb -I chatapp migrate --schema-dir app_schema + $ gel -I chatapp migrate --schema-dir app_schema edgedb error: could not read migrations in app_schema/migrations: could not read migration file app_schema/migrations/00003.edgeql: migration name should be ` @@ -172,7 +172,7 @@ can now apply it: .. code-block:: bash - $ edgedb -I chatapp migrate --schema-dir app_schema + $ gel -I chatapp migrate --schema-dir app_schema Applied m1jmrmawu4uty53clhbat7nvzjbogexyarh2zue6w6ind2kpfalwva (00003.edgeql) @@ -182,20 +182,20 @@ apply the changes: .. code-block:: bash - $ edgedb -I chatapp create-migration --schema-dir app_schema + $ gel -I chatapp create-migration --schema-dir app_schema did you rename link 'friends' of object type 'default::User' to 'circle'? [y,n,l,c,b,s,q,?] y Created app_schema/migrations/00004.edgeql, id: m1lh5julmw2msveqrchwly4qrbpyiof3hevze35d3x35ydrz3fsv3a - $ edgedb -I chatapp migrate --schema-dir app_schema + $ gel -I chatapp migrate --schema-dir app_schema Applied m1lh5julmw2msveqrchwly4qrbpyiof3hevze35d3x35ydrz3fsv3a (00004.edgeql) The above example shows some of the interactions with the EdgeDB migration management tools. We will keep improving the inference engine that guides the prompts of :ref:`edgedb create-migration -`. However, if the suggestion engine +`. However, if the suggestion engine fails to provide a perfect fit, the option of adjusting the migration file is always available. diff --git a/docs/changelog/1_0_b2.rst b/docs/changelog/1_0_b2.rst index 51871a8c725..67232c9476f 100644 --- a/docs/changelog/1_0_b2.rst +++ b/docs/changelog/1_0_b2.rst @@ -7,7 +7,7 @@ ========== This changelog summarizes new features and breaking changes in -EdgeDB 1.0 beta 2 "Luyten". +|EdgeDB| 1.0 beta 2 "Luyten". Migrations @@ -59,7 +59,7 @@ EdgeQL * Drop the deprecated ``Port``. The more general :ref:`extension ` mechanism introduced in - EdgeDB 1.0 beta 1 should be used (:eql:gh:`#2262`). + |EdgeDB| 1.0 beta 1 should be used (:eql:gh:`#2262`). * Reduce the maximum length for names of databases and roles to 51 characters (:eql:gh:`#2465`). * Enable ``br`` (or ``rb``) as a valid bytes literal prefix @@ -109,7 +109,7 @@ GraphQL Command-Line Tools ================== -We've added ``edgedb project init`` command to help manage EdgeDB +We've added ``edgedb project init`` command to help manage |EdgeDB| credentials for your project. Running this in a new project directory will setup an EdgeDB instance, create a schema and migrations directory and link the credentials for that instance to the project @@ -117,7 +117,7 @@ directory. .. code-block:: bash - $ edgedb project init + $ gel project init No `edgedb.toml` found in `/home/username/dev/hw` or above Do you want to initialize a new project? [Y/n] > Y @@ -157,7 +157,7 @@ running ``edgedb project init`` in the existing project's directory: .. code-block:: bash - $ edgedb project init + $ gel project init No `edgedb.toml` found in `/home/username/dev/myproject` or above Do you want to initialize a new project? [Y/n] > Y diff --git a/docs/changelog/1_0_b3.rst b/docs/changelog/1_0_b3.rst index 3b199886396..9455c3a64ac 100644 --- a/docs/changelog/1_0_b3.rst +++ b/docs/changelog/1_0_b3.rst @@ -7,7 +7,7 @@ ========== This changelog summarizes new features and breaking changes in -EdgeDB 1.0 beta 3 "Ross". +|EdgeDB| 1.0 beta 3 "Ross". Migrations @@ -166,14 +166,14 @@ Command-Line Tools We've changed some of the CLI `commands and groupings `_. There are some top-level "frequently used" commands such as -:ref:`ref_cli_edgedb_dump`, :ref:`ref_cli_edgedb_restore`, -:ref:`ref_cli_edgedb_migrate`, :ref:`ref_cli_edgedb_query`, -:ref:`ref_cli_edgedb_info` and :ref:`ref_cli_edgedb_cli_upgrade`. Other +:ref:`ref_cli_gel_dump`, :ref:`ref_cli_gel_restore`, +:ref:`ref_cli_gel_migrate`, :ref:`ref_cli_gel_query`, +:ref:`ref_cli_gel_info` and :ref:`ref_cli_gel_cli_upgrade`. Other commands are grouped into categories: -:ref:`ref_cli_edgedb_configure`, :ref:`ref_cli_edgedb_migration`, -:ref:`ref_cli_edgedb_list`, :ref:`ref_cli_edgedb_describe`, -:ref:`ref_cli_edgedb_instance`, :ref:`ref_cli_edgedb_project` and -:ref:`ref_cli_edgedb_server`. +:ref:`ref_cli_gel_configure`, :ref:`ref_cli_gel_migration`, +:ref:`ref_cli_gel_list`, :ref:`ref_cli_gel_describe`, +:ref:`ref_cli_gel_instance`, :ref:`ref_cli_gel_project` and +:ref:`ref_cli_gel_server`. Here's a more comprehensive list of the CLI commands: diff --git a/docs/changelog/1_0_rc1.rst b/docs/changelog/1_0_rc1.rst index c4cc65449bd..08ce63d1621 100644 --- a/docs/changelog/1_0_rc1.rst +++ b/docs/changelog/1_0_rc1.rst @@ -7,7 +7,7 @@ ======== This changelog summarizes new features and breaking changes in -EdgeDB 1.0 Release Candidate 1 "Epsilon Eridani". +|EdgeDB| 1.0 Release Candidate 1 "Epsilon Eridani". Migrations @@ -139,9 +139,9 @@ EdgeQL Command-Line Tools ================== -* Add the :ref:`cli.toml ` global configuration +* Add the :ref:`cli.toml ` global configuration file for customizing the CLI and REPL behavior. The location of the - file is shown as "Config" by :ref:`ref_cli_edgedb_info`. + file is shown as "Config" by :ref:`ref_cli_gel_info`. * Make SCRAM the default auth method (:eql:gh:`#2848`). * Add a server option to specify the default authentication method diff --git a/docs/changelog/1_0_rc3.rst b/docs/changelog/1_0_rc3.rst index b9fc2a45f72..a5c0295d201 100644 --- a/docs/changelog/1_0_rc3.rst +++ b/docs/changelog/1_0_rc3.rst @@ -6,7 +6,7 @@ 1.0 RC 3 ======== -This changelog summarizes changes and bugfixes in EdgeDB 1.0 Release +This changelog summarizes changes and bugfixes in |EdgeDB| 1.0 Release Candidate 3 "Cygni". This release is focusing on fixing existing issues rather than introducing new features. @@ -23,7 +23,7 @@ to RC3. Before you start you may want to backup the instance credentials (which you can find in the "Config" directory indicated by -:ref:`ref_cli_edgedb_info`). The first step in the upgrade process +:ref:`ref_cli_gel_info`). The first step in the upgrade process will be backing up all the instance data and that will include the login credentials that the instance expects. After restoring the database dump, you may need to restore old credentials file as @@ -37,11 +37,11 @@ following steps from the project directory: .. code-block:: bash - $ edgedb dump --all --format=dir ./upgrade_backup - $ edgedb project unlink -D - $ edgedb project upgrade --to-latest - $ edgedb project init --no-migrations - $ edgedb restore --admin --all ./upgrade_backup + $ gel dump --all --format=dir ./upgrade_backup + $ gel project unlink -D + $ gel project upgrade --to-latest + $ gel project init --no-migrations + $ gel restore --admin --all ./upgrade_backup Now that the project has been re-initialized and data dump is restored, we need to restore the login credentials. Which presents a @@ -51,13 +51,13 @@ is to reset the password: .. code-block:: bash - $ edgedb instance reset-password my_instance + $ gel instance reset-password my_instance Alternatively we can restore the old credentials: .. code-block:: bash - $ edgedb instance reset-password my_instance --password + $ gel instance reset-password my_instance --password Instance upgrade @@ -68,10 +68,10 @@ upgrade it to RC3 using the following steps: .. code-block:: bash - $ edgedb dump -I my_instance --all --format=dir ./my_instance_backup - $ edgedb instance destroy my_instance - $ edgedb instance create my_instance - $ edgedb restore -I my_instance --admin --all ./my_instance_backup + $ gel dump -I my_instance --all --format=dir ./my_instance_backup + $ gel instance destroy my_instance + $ gel instance create my_instance + $ gel restore -I my_instance --admin --all ./my_instance_backup Now that the instance has been re-initialized and data dump is restored, we need to restore the login credentials. Which presents a @@ -81,13 +81,13 @@ the database, the recommended approach is to reset the password: .. code-block:: bash - $ edgedb instance reset-password my_instance + $ gel instance reset-password my_instance Alternatively we can restore the old credentials: .. code-block:: bash - $ edgedb instance reset-password my_instance --password + $ gel instance reset-password my_instance --password EdgeQL diff --git a/docs/changelog/1_0_rc4.rst b/docs/changelog/1_0_rc4.rst index 43de120710d..66988ed925a 100644 --- a/docs/changelog/1_0_rc4.rst +++ b/docs/changelog/1_0_rc4.rst @@ -6,7 +6,7 @@ 1.0 RC 4 ======== -This changelog summarizes changes and bugfixes in EdgeDB 1.0 Release +This changelog summarizes changes and bugfixes in |EdgeDB| 1.0 Release Candidate 4 "Procyon". This release is focusing on fixing existing issues rather than introducing new features. diff --git a/docs/changelog/1_0_rc5.rst b/docs/changelog/1_0_rc5.rst index a5db292dbcd..2b531b99f96 100644 --- a/docs/changelog/1_0_rc5.rst +++ b/docs/changelog/1_0_rc5.rst @@ -6,7 +6,7 @@ 1.0 RC 5 ======== -This changelog summarizes changes and bugfixes in EdgeDB 1.0 Release +This changelog summarizes changes and bugfixes in |EdgeDB| 1.0 Release Candidate 5 "Tau Ceti". Compared to other releases this is a very small one as we're closing in on the stable version. diff --git a/docs/changelog/2_x.rst b/docs/changelog/2_x.rst index 9cd0230e33f..e1f87e77c62 100644 --- a/docs/changelog/2_x.rst +++ b/docs/changelog/2_x.rst @@ -7,7 +7,7 @@ v2.0 .. image:: images/v2_sagittarius.jpg :width: 100% -EdgeDB 2.0 was released on July 28th, 2022. Read the announcement +|EdgeDB| 2.0 was released on July 28th, 2022. Read the announcement blog post `here `_. We would like to thank our community for reporting issues and contributing @@ -55,7 +55,7 @@ the DSN of the newly created instance handy. .. code-block:: bash - $ edgedb dump --dsn --all my_database.dump/ + $ gel dump --dsn --all my_database.dump/ This will dump the schema and contents of your current database to a file on your local disk called ``my_database.dump``. The file name isn't @@ -65,7 +65,7 @@ the DSN of the newly created instance handy. .. code-block:: bash - $ edgedb restore --all my_database.dump/ --dsn + $ gel restore --all my_database.dump/ --dsn Once the restore is complete, update your application to connect to the new instance. @@ -93,11 +93,11 @@ upgrade. .. list-table:: - * - :ref:`TypeScript/JS ` + * - :ref:`TypeScript/JS ` - ``edgedb@0.21.0`` - * - :ref:`Python ` + * - :ref:`Python ` - ``edgedb@0.24.0`` - * - :ref:`Golang ` + * - :ref:`Golang ` - ``edgedb@0.12.0`` * - `Rust `_ - ``edgedb-tokio@0.3.0`` diff --git a/docs/changelog/3_x.rst b/docs/changelog/3_x.rst index 361b50e896f..208359fa740 100644 --- a/docs/changelog/3_x.rst +++ b/docs/changelog/3_x.rst @@ -7,7 +7,7 @@ v3.0 .. image:: images/v3_betelgeuse.jpg :width: 100% -EdgeDB 3.0 was released on June 22nd, 2023. Read the announcement +|EdgeDB| 3.0 was released on June 22nd, 2023. Read the announcement blog post `here `_. To play with the new features, install the CLI using `our installation guide @@ -123,7 +123,7 @@ dump-and-restore process. .. code-block:: bash - $ edgedb dump --dsn --all --format dir my_database.dump/ + $ gel dump --dsn --all --format dir my_database.dump/ This will dump the schema and contents of your current database to a directory on your local disk called ``my_database.dump``. The directory name @@ -133,7 +133,7 @@ dump-and-restore process. .. code-block:: bash - $ edgedb restore --all my_database.dump/ --dsn + $ gel restore --all my_database.dump/ --dsn Once the restore is complete, update your application to connect to the new instance. @@ -278,7 +278,7 @@ clutter in your repositories. .. code-block:: bash - $ edgedb watch + $ gel watch Initialized. Monitoring "/projects/my-edgedb-project". @@ -713,7 +713,7 @@ CLI * Change the backslash command ``\d object `` to ``\d `` * Add the ``edgedb migration edit`` command (:ref:`docs - `; released in 2.1) + `; released in 2.1) * Add the ``--get`` option to the ``edgedb info`` command (released in 2.1) @@ -984,15 +984,15 @@ New release schedule Unfortunately, the 3.0 release will not include full-text search. We have many requirements for this new API (see `the FTS RFC `_ -for details), and, while we’ve made significant progress, we have unfortunately +for details), and, while we've made significant progress, we have unfortunately run out of time to be 100% sure that it is ready for prime time. -We don’t want this delay to hold back the release of EdgeDB 3.0, which includes +We don't want this delay to hold back the release of EdgeDB 3.0, which includes many other exciting features that are ready for you to start using right now. -That’s why we’ve decided to delay only the FTS feature rather than delaying the +That's why we've decided to delay only the FTS feature rather than delaying the entire 3.0 release. -That said we’re working hard to get FTS ready as soon as possible. After the +That said we're working hard to get FTS ready as soon as possible. After the release of 3.0, we'll be moving to a much more frequent release cycle so that features like FTS can be in your hands as soon as they're ready. diff --git a/docs/changelog/4_x.rst b/docs/changelog/4_x.rst index aaea6b0777e..e1f46dbf6c4 100644 --- a/docs/changelog/4_x.rst +++ b/docs/changelog/4_x.rst @@ -5,7 +5,7 @@ v4.0 :edb-alt-title: EdgeDB v4 This release cycle is much shorter than the previous ones. It reflects our new -approach at EdgeDB where the goal is to provide improvements at a steady +approach at |EdgeDB| where the goal is to provide improvements at a steady regular pace rather than in big, but infrequent batches. Going forward we expect to maintain this shorter release cadence focusing on a few features at a time. @@ -83,7 +83,7 @@ dump-and-restore process. .. code-block:: bash - $ edgedb dump --dsn --all --format dir my_database.dump/ + $ gel dump --dsn --all --format dir my_database.dump/ This will dump the schema and contents of your current database to a directory on your local disk called ``my_database.dump``. The directory name @@ -93,7 +93,7 @@ dump-and-restore process. .. code-block:: bash - $ edgedb restore --all my_database.dump/ --dsn + $ gel restore --all my_database.dump/ --dsn Once the restore is complete, update your application to connect to the new instance. diff --git a/docs/changelog/5_x.rst b/docs/changelog/5_x.rst index abfbbf5ce6d..77e2e1293e3 100644 --- a/docs/changelog/5_x.rst +++ b/docs/changelog/5_x.rst @@ -32,7 +32,7 @@ Alternatively, specify an instance name if you aren't using a project. $ edgedb instance upgrade -I my_instance -The CLI will first check to see if your schema will migrate cleanly to EdgeDB +The CLI will first check to see if your schema will migrate cleanly to |EdgeDB| 5.0. If the upgrade check finds any problems, it will report them back to you. **Hosted instances** @@ -40,14 +40,14 @@ The CLI will first check to see if your schema will migrate cleanly to EdgeDB To upgrade a remote (hosted) instance, we recommend the following dump-and-restore process. -1. EdgeDB v5.0 supports PostgreSQL 14 (or above). So check the version of +1. |EdgeDB| v5.0 supports PostgreSQL 14 (or above). So check the version of PostgreSQL you are using before upgrading EdgeDB. If you're using Postgres 13 or below, you should upgrade Postgres first. 2. Spin up an empty 5.0 instance. You can use one of our :ref:`deployment guides `. - Under Debian/Ubuntu, when adding the EdgeDB package repository, use this + Under Debian/Ubuntu, when adding the |EdgeDB| package repository, use this command instead: .. code-block:: bash @@ -78,7 +78,7 @@ dump-and-restore process. .. code-block:: bash - $ edgedb dump --dsn --all --format dir my_database.dump/ + $ gel dump --dsn --all --format dir my_database.dump/ This will dump the schema and contents of your current database to a directory on your local disk called ``my_database.dump``. The directory name @@ -88,7 +88,7 @@ dump-and-restore process. .. code-block:: bash - $ edgedb restore --all my_database.dump/ --dsn + $ gel restore --all my_database.dump/ --dsn Once the restore is complete, update your application to connect to the new instance. @@ -102,11 +102,11 @@ New features EdgeDB + AI ----------- -We've added an ``ext::ai`` extension for handling the integration of EdgeDB +We've added an ``ext::ai`` extension for handling the integration of |EdgeDB| with various AI backends such as: OpenAI, Mistral and Anthropic. There is a special ``ext::ai::index`` that can be used to delegate the search -functionality of EdgeDB objects to a specific AI search provider. +functionality of |EdgeDB| objects to a specific AI search provider. The function ``ext::ai::to_context(object: anyobject)`` evaluates the expression of the specific ``ext::ai::index`` defined on the passed object @@ -124,7 +124,7 @@ There are also two HTTP API points for interacting with the data: EdgeDB branches --------------- -EdgeDB 5.0 adds branching functionality in order to help bridge the gap between +|EdgeDB| 5.0 adds branching functionality in order to help bridge the gap between the code (and schema) managed by version control systems and the actual development database. @@ -167,7 +167,7 @@ With these new commands, here's how we envision developers using them to manage "feature" branches: 1) Create a new "feature" VCS branch (a clone of the "main" branch) and a - corresponding "feature" EdgeDB branch. + corresponding "feature" |EdgeDB| branch. 2) Work on the "feature" branch, add migrations, etc. @@ -181,7 +181,7 @@ manage "feature" branches: 5) Then we want to rebase the "feature" branch code on top of the "main" branch code. -6) After that we need to replicate the same rebase operation with the EdgeDB +6) After that we need to replicate the same rebase operation with the |EdgeDB| branch. Our CLI tools may need to first clone the "main" branch with the data into a "temp" branch. Then we can introspect the migration histories of the "temp" and "feature" branches so that we can establish where they @@ -195,8 +195,8 @@ manage "feature" branches: then merge the EdgeDB branch as well (or rename the "feature" EdgeDB branch to "main", if the old branch is no longer needed). -We've added :ref:`edgedb branch commands ` to our CLI -as well that create, copy, rename, drop, and rebase EdgeDB branches. +We've added :ref:`edgedb branch commands ` to our CLI +as well that create, copy, rename, drop, and rebase |EdgeDB| branches. Updated pgvector extension diff --git a/docs/changelog/6_x.rst b/docs/changelog/6_x.rst index 79bab33309a..2e1461723ef 100644 --- a/docs/changelog/6_x.rst +++ b/docs/changelog/6_x.rst @@ -2,7 +2,7 @@ v6.0 ==== -:edb-alt-title: EdgeDB v6 +:edb-alt-title: Gel v6 To explore the new features, ensure you specify version 6.0 when initializing your project. Pre-release versions are not considered stable and will not be @@ -10,7 +10,7 @@ automatically suggested: .. code-block:: bash - $ edgedb project init --server-version 6.0-beta.1 + $ gel project init --server-version 6.0-beta.1 Upgrading @@ -21,20 +21,20 @@ Upgrading **Local instances** To upgrade a local project, first ensure that your CLI is up to date with -``edgedb cli upgrade``. Then run the following command inside the project +:gelcmd:`cli upgrade`. Then run the following command inside the project directory. .. code-block:: bash - $ edgedb project upgrade --to-testing + $ gel project upgrade --to-testing Alternatively, specify an instance name if you aren't using a project: .. code-block:: bash - $ edgedb instance upgrade -I my_instance + $ gel instance upgrade -I my_instance -The CLI will check if your schema can migrate cleanly to EdgeDB 6.0. If any +The CLI will check if your schema can migrate cleanly to Gel 6.0. If any issues are found, they will be reported. **Hosted instances** @@ -42,32 +42,32 @@ issues are found, they will be reported. To upgrade a remote instance, we recommend the following dump-and-restore process: -1. EdgeDB v6.0 supports PostgreSQL 14 or above. Verify your PostgreSQL version - before upgrading EdgeDB. If you're using Postgres 13 or below, upgrade +1. Gel v6.0 supports PostgreSQL 14 or above. Verify your PostgreSQL version + before upgrading Gel. If you're using Postgres 13 or below, upgrade Postgres first. 2. Spin up an empty 6.0 instance. You can use one of our :ref:`deployment guides `. - For Debian/Ubuntu, when adding the EdgeDB package repository, use this + For Debian/Ubuntu, when adding the Gel package repository, use this command: .. code-block:: bash - $ echo deb [signed-by=/usr/local/share/keyrings/edgedb-keyring.gpg] \ - https://packages.edgedb.com/apt \ + $ echo deb [signed-by=/usr/local/share/keyrings/gel-keyring.gpg] \ + https://packages.geldata.com/apt \ $(grep "VERSION_CODENAME=" /etc/os-release | cut -d= -f2) main \ - | sudo tee /etc/apt/sources.list.d/edgedb.list - $ sudo apt-get update && sudo apt-get install edgedb-6 + | sudo tee /etc/apt/sources.list.d/gel.list + $ sudo apt-get update && sudo apt-get install gel-6 For CentOS/RHEL, use this installation command: .. code-block:: bash - $ sudo yum install edgedb-6 + $ sudo yum install gel-6 - In any required ``systemctl`` commands, replace ``edgedb-server-6`` with - ``edgedb-server-6``. + In any required ``systemctl`` commands, replace ``edgedb-server-5`` with + ``gel-server-6``. For Docker setups, use the ``6.0`` tag. @@ -75,7 +75,7 @@ process: .. code-block:: bash - $ edgedb dump --dsn --all --format dir my_database.dump/ + $ gel dump --dsn --all --format dir my_database.dump/ This will dump the schema and contents of your current database to a directory on your local disk called ``my_database.dump``. The directory name @@ -85,7 +85,7 @@ process: .. code-block:: bash - $ edgedb restore --all my_database.dump/ --dsn + $ gel restore --all my_database.dump/ --dsn Once the restore is complete, update your application to connect to the new instance. @@ -100,15 +100,15 @@ SQL write support ----------------- You can now use SQL DML (``insert``, ``update``, ``delete``) when connecting to -your EdgeDB instance via the PostgreSQL protocol. Our aim is to support most +your |Gel| instance via the PostgreSQL protocol. Our aim is to support most typical use cases from tools like SQL ORMs and SQL clients. -This allows more developers to use EdgeDB, leveraging our advanced data model, +This allows more developers to use Gel, leveraging our advanced data model, tooling, and high-performance connection management. Teams can migrate their -existing SQL codebases to EdgeDB without rewriting their queries. Once adopted, +existing SQL codebases to Gel without rewriting their queries. Once adopted, you can gradually take advantage of EdgeQL's powerful query capabilities. -Existing EdgeDB users who already use EdgeQL can benefit too. While some SQL +Existing Gel users who already use EdgeQL can benefit too. While some SQL features like window functions, recursive queries, and explicit locking are not yet supported, you can use these features in SQL today. We will continue to add support for more features in the future. @@ -213,7 +213,7 @@ Simpler scoping rules --------------------- We've simplified the scoping rules for queries. See `our RFC 1027 outlining the -changes `_. +changes `_. The RFC highlights two main reasons for removing path factoring: the need to simplify and enhance the language, and concerns about implementation. Path diff --git a/docs/changelog/deprecation.rst b/docs/changelog/deprecation.rst index b41dc77dea4..09fcd407cfa 100644 --- a/docs/changelog/deprecation.rst +++ b/docs/changelog/deprecation.rst @@ -4,7 +4,7 @@ Deprecation Policy ================== -* We continue to support one previous version of EdgeDB with critical bug +* We continue to support one previous version of |Gel| with critical bug fixes. * Client bindings will support the current and the previous major version. * CLI supports all versions from version 1. diff --git a/docs/changelog/index.rst b/docs/changelog/index.rst index c7bbc31d1e4..8bc112918bb 100644 --- a/docs/changelog/index.rst +++ b/docs/changelog/index.rst @@ -4,7 +4,7 @@ Changelog ========= -Changes introduced in all of the releases of EdgeDB so far: +Changes introduced in all of the releases of |Gel| so far: .. toctree:: diff --git a/docs/cheatsheets/admin.rst b/docs/cheatsheets/admin.rst index 2440a547d6f..3b998611c92 100644 --- a/docs/cheatsheets/admin.rst +++ b/docs/cheatsheets/admin.rst @@ -3,42 +3,39 @@ Administering an instance ========================= -.. versionchanged:: _default +Create a schema branch: - Create a database: - - .. code-block:: edgeql-repl - - db> create database my_new_project; - OK: CREATE DATABASE - -.. versionchanged:: 5.0 +.. code-block:: edgeql-repl - Create a schema branch: + db> create schema branch my_new_feature from main; + OK: CREATE BRANCH - .. code-block:: edgeql-repl - db> create schema branch my_new_feature from main; - OK: CREATE BRANCH +Create a data branch: +.. code-block:: edgeql-repl + db> create data branch my_new_feature from main; + OK: CREATE BRANCH - Create a data branch: - .. code-block:: edgeql-repl +Create an empty branch: - db> create data branch my_new_feature from main; - OK: CREATE BRANCH +.. code-block:: edgeql-repl + db> create empty branch my_new_feature; + OK: CREATE BRANCH - Create an empty branch: +.. note:: + Prior to |Gel| and |EdgeDB| 5.0 *branches* were called *databases*. + A command to create a new empty *database* is ``create database`` + (still supported for backwards compatibility). .. code-block:: edgeql-repl - db> create empty branch my_new_feature; - OK: CREATE BRANCH - + db> create database my_new_feature; + OK: CREATE DATABASE Create a role: @@ -103,4 +100,4 @@ Run a script from command line: .. cli:synopsis:: - cat myscript.edgeql | edgedb [...] + cat myscript.edgeql | gel [...] diff --git a/docs/cheatsheets/annotations.rst b/docs/cheatsheets/annotations.rst index 141cbd23208..4e773a71348 100644 --- a/docs/cheatsheets/annotations.rst +++ b/docs/cheatsheets/annotations.rst @@ -5,23 +5,6 @@ Declaring annotations Use annotations to add descriptions to types and links: -.. code-block:: sdl - :version-lt: 3.0 - - type Label { - annotation description := - 'Special label to stick on reviews'; - required property comments -> str; - link review -> Review { - annotation description := - 'This review needs some attention'; - }; - } - - type Review { - content -> str; - } - .. code-block:: sdl type Label { @@ -56,7 +39,7 @@ Retrieving the annotations can be done via an introspection query: name: 'default::Label', annotations: { schema::Annotation { - name: 'std::description', + name: 'std::description', @value: 'Special label to stick on reviews' }, }, diff --git a/docs/cheatsheets/cli.rst b/docs/cheatsheets/cli.rst index 65c9213c875..fb59db91339 100644 --- a/docs/cheatsheets/cli.rst +++ b/docs/cheatsheets/cli.rst @@ -7,28 +7,28 @@ To initialize a new project: .. code-block:: bash - $ edgedb project init + $ gel project init -If an :ref:`ref_reference_edgedb_toml` file exists in the current directory, it +If an :ref:`ref_reference_gel_toml` file exists in the current directory, it will initialize a new project according to the settings defined in it. -Otherwise, a new project will be initialized and an ``edgedb.toml`` file and +Otherwise, a new project will be initialized and an |gel.toml| file and ``dbschema`` directory will be generated. For details on using projects, see the :ref:`dedicated guide `. Once initialized, you can run the CLI commands below without additional connection options. If you don't set up a project, you'll need to use -:ref:`flags ` to specify the target instance for each +:ref:`flags ` to specify the target instance for each command. ---------- -Explicitly create a new EdgeDB instance ``my_instance``: +Explicitly create a new |Gel| instance ``my_instance``: .. code-block:: bash - $ edgedb instance create my_instance + $ gel instance create my_instance ---------- @@ -38,7 +38,7 @@ Create a branch: .. code-block:: bash - $ edgedb branch create feature + $ gel branch create feature OK: CREATE @@ -49,7 +49,7 @@ Configure passwordless access (such as to a local development database): .. code-block:: bash - $ edgedb configure insert Auth \ + $ gel configure insert Auth \ > --comment 'passwordless access' \ > --priority 1 \ > --method Trust @@ -63,7 +63,7 @@ Configure access that checks password (with a higher priority): .. code-block:: bash - $ edgedb configure insert Auth \ + $ gel configure insert Auth \ > --comment 'password is required' \ > --priority 0 \ > --method SCRAM @@ -77,11 +77,16 @@ Connect to the default project branch: .. code-block:: bash - $ edgedb - EdgeDB 1.0-beta.2+ga7130d5c7.cv202104290000 (repl 1.0.0-beta.2) + $ gel + β–„β–ˆβ–ˆβ–„ + β–„β–„β–„β–„β–„ β–„β–„β–„ β–ˆβ–ˆβ–ˆβ–ˆ + β–„β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–„ β–„β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–„ β–ˆβ–ˆβ–ˆβ–ˆ + β–€β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–€ β–€β–ˆβ–ˆβ–ˆβ–€β–€β–€β–€β–€ β–ˆβ–ˆβ–ˆβ–ˆ + β–€β–€β–€β–€β–€ β–€β–€β–€ β–€β–€ + β–€β–„β–„β–„β–„β–„β–€ + β–€β–€β–€ + Gel 6.0-rc.1+673117d (repl 6.2.0-dev) Type \help for help, \quit to quit. - edgedb> - ---------- @@ -90,7 +95,7 @@ Connect to some specific branch: .. code-block:: bash - $ edgedb -b feature - EdgeDB 1.0-beta.2+ga7130d5c7.cv202104290000 (repl 1.0.0-beta.2) + $ gel -b feature + Gel 6.0-rc.1+673117d (repl 6.2.0-dev) Type \help for help, \quit to quit. special_db> diff --git a/docs/cheatsheets/delete.rst b/docs/cheatsheets/delete.rst index 8d065736de3..df16f9dafd6 100644 --- a/docs/cheatsheets/delete.rst +++ b/docs/cheatsheets/delete.rst @@ -39,5 +39,3 @@ Alternative way to delete all reviews from a specific user: * - **See also** * - :ref:`EdgeQL > Delete ` * - :ref:`Reference > Commands > Delete ` - * - `Tutorial > Data Mutations > Delete - `_ diff --git a/docs/cheatsheets/functions.rst b/docs/cheatsheets/functions.rst index bda2da106f4..599b596d154 100644 --- a/docs/cheatsheets/functions.rst +++ b/docs/cheatsheets/functions.rst @@ -56,6 +56,4 @@ Define and use polymorphic function: * - :ref:`DDL > Functions ` * - :ref:`Reference > Function calls ` * - :ref:`Introspection > Functions ` - * - `Tutorial > Advanced EdgeQL > User-Defined Functions - `_ diff --git a/docs/cheatsheets/index.rst b/docs/cheatsheets/index.rst index 8ea09b617e0..1992201f521 100644 --- a/docs/cheatsheets/index.rst +++ b/docs/cheatsheets/index.rst @@ -4,7 +4,7 @@ Cheatsheets =========== -:edb-alt-title: Cheatsheets: EdgeDB by example +:edb-alt-title: Cheatsheets: Gel by example .. toctree:: :maxdepth: 3 @@ -27,10 +27,7 @@ Cheatsheets Just getting started? Keep an eye on this collection of cheatsheets with -handy examples for what you'll need to get started with EdgeDB. -After familiarizing yourself with them, feel free to dive into more EdgeDB -via our longer `interactive tutorial `_ and -**much** longer `Easy EdgeDB textbook `_. +handy examples for what you'll need to get started with |Gel|. EdgeQL ====== @@ -63,6 +60,6 @@ CLI/Admin * :ref:`CLI Usage ` -- Getting your database started. * :ref:`Interactive Shell ` -- Shortcuts for - frequently used commands in the EdgeDB Interactive Shell. + frequently used commands in the Gel Interactive Shell. * :ref:`Administration ` -- Branch and role creation, passwords, port configuration, etc. diff --git a/docs/cheatsheets/insert.rst b/docs/cheatsheets/insert.rst index 580c56c8d53..4e8eb88fa64 100644 --- a/docs/cheatsheets/insert.rst +++ b/docs/cheatsheets/insert.rst @@ -206,7 +206,3 @@ inserting nested structures: * - **See also** * - :ref:`EdgeQL > Insert ` * - :ref:`Reference > Commands > Insert ` - * - `Tutorial > Data Mutations > Insert - `_ - * - `Tutorial > Data Mutations > Upsert - `_ diff --git a/docs/cheatsheets/link_properties.rst b/docs/cheatsheets/link_properties.rst index 0214b7776b8..194fe55f4c1 100644 --- a/docs/cheatsheets/link_properties.rst +++ b/docs/cheatsheets/link_properties.rst @@ -30,17 +30,6 @@ Declaration Let's a create a ``Person.friends`` link with a ``strength`` property corresponding to the strength of the friendship. -.. code-block:: sdl - :version-lt: 3.0 - - type Person { - required property name -> str { constraint exclusive }; - - multi link friends -> Person { - property strength -> float64; - } - } - .. code-block:: sdl type Person { @@ -54,20 +43,6 @@ corresponding to the strength of the friendship. Constraints ----------- -.. code-block:: sdl - :version-lt: 3.0 - - type Person { - required property name -> str { constraint exclusive }; - - multi link friends -> Person { - property strength -> float64; - constraint expression on ( - __subject__@strength >= 0 - ); - } - } - .. code-block:: sdl type Person { @@ -86,19 +61,6 @@ Indexes To index on a link property, you must declare an abstract link and extend it. -.. code-block:: sdl - :version-lt: 3.0 - - abstract link friendship { - property strength -> float64; - index on (__subject__@strength); - } - - type Person { - required property name -> str { constraint exclusive }; - multi link friends extending friendship -> Person; - } - .. code-block:: sdl abstract link friendship { @@ -245,13 +207,13 @@ Querying .. code-block:: edgeql-repl - edgedb> select Person { - ....... name, - ....... friends: { - ....... name, - ....... @strength - ....... } - ....... }; + gel> select Person { + .... name, + .... friends: { + .... name, + .... @strength + .... } + .... }; { default::Person {name: 'Alice', friends: {}}, default::Person { @@ -311,12 +273,8 @@ Querying :eql:func:`assert_distinct` here to assure the compiler that the result set is distinct. -.. note:: - - Specifying link properties of a computed backlink in your shape is - supported as of EdgeDB 3.0. - - If you have this schema: + Specifying link properties of a computed backlink in your shape is also + supported. If you have this schema: .. code-block:: sdl @@ -330,7 +288,7 @@ Querying multi link followers := . str; - index on (.image); - } - .. code-block:: sdl abstract type HasImage { @@ -29,16 +20,6 @@ Define an abstract type: Define a type extending from the abstract: -.. code-block:: sdl - :version-lt: 3.0 - - type User extending HasImage { - required property name -> str { - # Ensure unique name for each User. - constraint exclusive; - } - } - .. code-block:: sdl type User extending HasImage { @@ -54,27 +35,6 @@ Define a type extending from the abstract: Define a type with constraints and defaults for properties: -.. code-block:: sdl - :version-lt: 3.0 - - type Review { - required property body -> str; - required property rating -> int64 { - constraint min_value(0); - constraint max_value(5); - } - required property flag -> bool { - default := False; - } - - required link author -> User; - required link movie -> Movie; - - required property creation_time -> datetime { - default := datetime_current(); - } - } - .. code-block:: sdl type Review { @@ -102,62 +62,6 @@ Define a type with constraints and defaults for properties: Define a type with a property that is computed from the combination of the other properties: -.. code-block:: sdl - :version-lt: 3.0 - - type Person extending HasImage { - required property first_name -> str { - default := ''; - } - required property middle_name -> str { - default := ''; - } - required property last_name -> str; - property full_name := - ( - ( - (.first_name ++ ' ') - if .first_name != '' else - '' - ) ++ - ( - (.middle_name ++ ' ') - if .middle_name != '' else - '' - ) ++ - .last_name - ); - property bio -> str; - } - -.. code-block:: sdl - :version-lt: 4.0 - - type Person extending HasImage { - required first_name: str { - default := ''; - } - required middle_name: str { - default := ''; - } - required last_name: str; - property full_name := - ( - ( - (.first_name ++ ' ') - if .first_name != '' else - '' - ) ++ - ( - (.middle_name ++ ' ') - if .middle_name != '' else - '' - ) ++ - .last_name - ); - bio: str; - } - .. code-block:: sdl type Person extending HasImage { @@ -192,20 +96,6 @@ the other properties: Define an abstract links: -.. code-block:: sdl - :version-lt: 3.0 - - abstract link crew { - # Provide a way to specify some "natural" - # ordering, as relevant to the movie. This - # may be order of importance, appearance, etc. - property list_order -> int64; - } - - abstract link directors extending crew; - - abstract link actors extending crew; - .. code-block:: sdl abstract link crew { @@ -230,52 +120,6 @@ Define an abstract links: Define a type using abstract links and a computed property that aggregates values from another linked type: -.. code-block:: sdl - :version-lt: 3.0 - - type Movie extending HasImage { - required property title -> str; - required property year -> int64; - - # Add an index for accessing movies by title and year, - # separately and in combination. - index on (.title); - index on (.year); - index on ((.title, .year)); - - property description -> str; - - multi link directors extending crew -> Person; - multi link actors extending crew -> Person; - - property avg_rating := math::mean(.` scalar type and an object type using it as a property: -.. code-block:: sdl - :version-lt: 3.0 - - scalar type TicketNo extending sequence; - - type Ticket { - property number -> TicketNo { - constraint exclusive; - } - } - .. code-block:: sdl scalar type TicketNo extending sequence; diff --git a/docs/cheatsheets/repl.rst b/docs/cheatsheets/repl.rst index ead562a9eb7..ae7d739a96f 100644 --- a/docs/cheatsheets/repl.rst +++ b/docs/cheatsheets/repl.rst @@ -67,10 +67,10 @@ Commands * - ``\ds, \describe schema`` - Describe the entire schema. - * - ``\list databases`` + * - ``\list branches`` ``alias: \l`` - - List databases. + - List |branches|. * - ``\list scalars [-sI] [pattern]`` ``alias: \ls`` @@ -101,10 +101,10 @@ Commands - List indexes. * - ``\dump `` - - Dump the current database to file. + - Dump the current |branch| to file. * - ``\restore `` - - Restore the database from a dump file. + - Restore the |branch| from a dump file. * - ``\s, \history`` - Show query history @@ -120,18 +120,18 @@ Commands Type ``\set`` to see all available settings. * - ``\c, \connect []`` - - Connect to a particular database. + - Connect to a particular |branch|. Sample usage ^^^^^^^^^^^^ -List databases: +List |branches|: .. code-block:: edgeql-repl db> \ls - List of databases: + List of branches: db tutorial @@ -140,7 +140,7 @@ List databases: ---------- -Connect to a database: +Connect to a |branch|: .. code-block:: edgeql-repl diff --git a/docs/cheatsheets/select.rst b/docs/cheatsheets/select.rst index 3777ed72f47..3141808957b 100644 --- a/docs/cheatsheets/select.rst +++ b/docs/cheatsheets/select.rst @@ -225,13 +225,3 @@ instead of the named tuple if no ``matches`` are found. * - **See also** * - :ref:`EdgeQL > Select ` * - :ref:`Reference > Commands > Select ` - * - `Tutorial > Basic Queries > Objects - `_ - * - `Tutorial > Basic Queries > Filters - `_ - * - `Tutorial > Basic Queries > Aggregates - `_ - * - `Tutorial > Nested Structures > Shapes - `_ - * - `Tutorial > Nested Structures > Polymorphism - `_ diff --git a/docs/cheatsheets/update.rst b/docs/cheatsheets/update.rst index aaa6a6a4c42..be4b10dde3b 100644 --- a/docs/cheatsheets/update.rst +++ b/docs/cheatsheets/update.rst @@ -153,5 +153,3 @@ Update the ``list_order`` link property for a specific link: * - **See also** * - :ref:`EdgeQL > Update ` * - :ref:`Reference > Commands > Update ` - * - `Tutorial > Data Mutations > Update - `_ diff --git a/docs/cli/edgedb_branch/edgedb_branch_drop.rst b/docs/cli/edgedb_branch/edgedb_branch_drop.rst deleted file mode 100644 index edf16747fde..00000000000 --- a/docs/cli/edgedb_branch/edgedb_branch_drop.rst +++ /dev/null @@ -1,36 +0,0 @@ -.. _ref_cli_edgedb_branch_drop: - - -================== -edgedb branch drop -================== - -Remove an existing :ref:`branch `. - -.. cli:synopsis:: - - edgedb branch drop [] - -.. note:: - - This CLI command requires CLI version 4.3.0 or later and EdgeDB version 5.0 - or later. If you are running an earlier version of EdgeDB, you will instead - use the :ref:`ref_cli_edgedb_database_drop` command to drop a database, - which branches replaced in EdgeDB 5.0. - - -Options -======= - -The ``branch drop`` command runs in the EdgeDB instance it is -connected to. For specifying the connection target see -:ref:`connection options `. - -:cli:synopsis:`` - The name of the branch to drop. - -:cli:synopsis:`--non-interactive` - Drop the branch without asking for confirmation. - -:cli:synopsis:`--force` - Close any existing connections to the branch before dropping it. diff --git a/docs/cli/edgedb_branch/edgedb_branch_list.rst b/docs/cli/edgedb_branch/edgedb_branch_list.rst deleted file mode 100644 index deb28fa6ecc..00000000000 --- a/docs/cli/edgedb_branch/edgedb_branch_list.rst +++ /dev/null @@ -1,19 +0,0 @@ -.. _ref_cli_edgedb_branch_list: - - -================== -edgedb branch list -================== - -List all :ref:`branches ` - -.. cli:synopsis:: - - edgedb branch list - -.. note:: - - This CLI command requires CLI version 4.3.0 or later and EdgeDB version 5.0 - or later. If you are running an earlier version of EdgeDB, you will instead - use the :ref:`edgedb list databases ` command to list - databases, which branches replaced in EdgeDB 5.0. diff --git a/docs/cli/edgedb_branch/edgedb_branch_merge.rst b/docs/cli/edgedb_branch/edgedb_branch_merge.rst deleted file mode 100644 index 1131139aac5..00000000000 --- a/docs/cli/edgedb_branch/edgedb_branch_merge.rst +++ /dev/null @@ -1,53 +0,0 @@ -.. _ref_cli_edgedb_branch_merge: - - -=================== -edgedb branch merge -=================== - -Merge a :ref:`branch ` into the current branch. - -.. cli:synopsis:: - - edgedb branch merge [] - -.. note:: - - This CLI command requires CLI version 4.0 or later and EdgeDB version 5.0 - or later. Earlier versions did not feature branches and instead featured - databases. Databases offered no analog to merging. See the - :ref:`ref_cli_edgedb_database` command suite to manage databases. - - -Description -=========== - -Merges the target branch with the current branch using a fast-forward strategy, -applying any new migrations from the target branch on the current branch. - -.. note:: - - This is a fast-forward merge, so no conflict resolution will be applied to - the new migrations. If you want to merge but may have conflicts, you should - first use :ref:`ref_cli_edgedb_branch_rebase` from the target branch before - merging. - -.. note:: - - When merging, the data of the current branch is preserved. This means that - if you switch to a branch ``main`` and run ``edgedb branch merge feature``, - you will end up with a branch with the schema from ``main`` and any - new migrations from ``feature`` and the data from ``main``. - - -Options -======= - -The ``branch merge`` command runs in the EdgeDB instance it is -connected to. For specifying the connection target see -:ref:`connection options `. - -:cli:synopsis:`` - The name of the branch to merge into the current branch. -:cli:synopsis:`--no-apply` - Skip applying migrations generated from the merge diff --git a/docs/cli/edgedb_branch/edgedb_branch_rebase.rst b/docs/cli/edgedb_branch/edgedb_branch_rebase.rst deleted file mode 100644 index 247ee65711b..00000000000 --- a/docs/cli/edgedb_branch/edgedb_branch_rebase.rst +++ /dev/null @@ -1,48 +0,0 @@ -.. _ref_cli_edgedb_branch_rebase: - - -==================== -edgedb branch rebase -==================== - -Create a :ref:`branch ` based on the target branch but -including new migrations on the current branch. - -.. cli:synopsis:: - - edgedb branch rebase [] - -.. note:: - - This CLI command requires CLI version 4.0 or later and EdgeDB version 5.0 - or later. Earlier versions did not feature branches and instead featured - databases. Databases offered no analog to rebasing. See the - :ref:`ref_cli_edgedb_database` command suite to manage databases. - - -Description -=========== - -Creates a new branch that is based on the target branch, but also contains any new migrations on the -current branch. - -.. note:: - - When rebasing, the data of the target branch is preserved. This means that - if you switch to a branch ``feature`` and run ``edgedb branch rebase - main``, you will end up with a branch with the schema from ``main`` and any - new migrations from ``feature`` and the data from ``main``. - -For more about how rebasing works, check out the breakdown :ref:`in our schema -migrations guide `. - - -Options -======= - -The ``branch rebase`` command runs in the EdgeDB instance it is -connected to. For specifying the connection target see -:ref:`connection options `. - -:cli:synopsis:`` - The name of the target branch. diff --git a/docs/cli/edgedb_branch/edgedb_branch_rename.rst b/docs/cli/edgedb_branch/edgedb_branch_rename.rst deleted file mode 100644 index 3ff2d1a17cd..00000000000 --- a/docs/cli/edgedb_branch/edgedb_branch_rename.rst +++ /dev/null @@ -1,40 +0,0 @@ -.. _ref_cli_edgedb_branch_rename: - - -==================== -edgedb branch rename -==================== - -Rename a :ref:`branch ` - -.. cli:synopsis:: - - edgedb branch rename [] - -.. note:: - - This CLI command requires CLI version 4.0 or later and EdgeDB version 5.0 - or later. Earlier versions did not feature branches and instead featured - databases. Databases offered no analog to the ``rename`` command. To - rename a database, you could :ref:`dump ` your - database, :ref:`create ` a new database - with the desired name, and :ref:`restore ` the dump - to that new database. See the :ref:`ref_cli_edgedb_database` command suite - for other database management commands. - - -Options -======= - -The ``branch rename`` command runs in the EdgeDB instance it is -connected to. For specifying the connection target see -:ref:`connection options `. - -:cli:synopsis:`` - The current name of the branch to rename. - -:cli:synopsis:`` - The new name of the branch. - -:cli:synopsis:`--force` - Close any existing connections to the branch before renaming it. diff --git a/docs/cli/edgedb_branch/edgedb_branch_wipe.rst b/docs/cli/edgedb_branch/edgedb_branch_wipe.rst deleted file mode 100644 index 328feb4991f..00000000000 --- a/docs/cli/edgedb_branch/edgedb_branch_wipe.rst +++ /dev/null @@ -1,43 +0,0 @@ -.. _ref_cli_edgedb_branch_wipe: - - -================== -edgedb branch wipe -================== - -Destroy the contents of a :ref:`branch ` - -.. cli:synopsis:: - - edgedb branch wipe [] - -.. note:: - - This CLI command requires CLI version 4.3.0 or later and EdgeDB version 5.0 - or later. If you are running an earlier version of EdgeDB, you will instead - use the :ref:`ref_cli_edgedb_database_wipe` command to wipe a database, - which branches replaced in EdgeDB 5.0. - - -Description -=========== - -The contents of the branch will be destroyed and the schema reset to its -state before any migrations, but the branch itself will be preserved. - -``edgedb branch wipe`` is a terminal command equivalent to -:eql:stmt:`reset schema to initial`. - - -Options -======= - -The ``branch wipe`` command runs in the EdgeDB instance it is -connected to. For specifying the connection target see -:ref:`connection options `. - -:cli:synopsis:`` - The name of the branch to wipe. - -:cli:synopsis:`--non-interactive` - Destroy the data without asking for confirmation. diff --git a/docs/cli/edgedb_branch/index.rst b/docs/cli/edgedb_branch/index.rst deleted file mode 100644 index 035e413c0ba..00000000000 --- a/docs/cli/edgedb_branch/index.rst +++ /dev/null @@ -1,49 +0,0 @@ -.. _ref_cli_edgedb_branch: - - -============= -edgedb branch -============= - -.. note:: - - These CLI commands require CLI version 4.3.0 or later and EdgeDB version - 5.0 or later. If you are running an earlier version of EdgeDB, you will - instead use the :ref:`ref_cli_edgedb_database` command suite to manage - databases, which branches replaced in EdgeDB 5.0. - -The ``edgedb branch`` group of commands contains various branch management -tools. - -.. toctree:: - :maxdepth: 3 - :hidden: - - edgedb_branch_create - edgedb_branch_drop - edgedb_branch_list - edgedb_branch_merge - edgedb_branch_rebase - edgedb_branch_rename - edgedb_branch_switch - edgedb_branch_wipe - -.. list-table:: - :class: funcoptable - - * - :ref:`ref_cli_edgedb_branch_create` - - Create a new branch - * - :ref:`ref_cli_edgedb_branch_drop` - - Drop a branch - * - :ref:`ref_cli_edgedb_branch_list` - - List all branches - * - :ref:`ref_cli_edgedb_branch_merge` - - Merge a branch into the current branch - * - :ref:`ref_cli_edgedb_branch_rebase` - - Create a branch based on a target branch - * - :ref:`ref_cli_edgedb_branch_rename` - - Rename a branch - * - :ref:`ref_cli_edgedb_branch_switch` - - Change the currently active branch - * - :ref:`ref_cli_edgedb_branch_wipe` - - Destroy the contents of a branch diff --git a/docs/cli/edgedb_cloud/edgedb_cloud_login.rst b/docs/cli/edgedb_cloud/edgedb_cloud_login.rst deleted file mode 100644 index 587b1d70774..00000000000 --- a/docs/cli/edgedb_cloud/edgedb_cloud_login.rst +++ /dev/null @@ -1,34 +0,0 @@ -.. _ref_cli_edgedb_cloud_login: - - -================== -edgedb cloud login -================== - -.. note:: - - This CLI command requires CLI version 3.0 or later. - -Authenticate to the EdgeDB Cloud and remember the secret key locally - -.. cli:synopsis:: - - edgedb cloud login - -This command will launch your browser and start the EdgeDB Cloud authentication -flow. Once authentication is successful, the CLI will log a success message: - -.. code-block:: - - Successfully logged in to EdgeDB Cloud as - -If you are unable to complete authentication in the browser, you can interrupt -the command by pressing Ctrl-C. - -.. warning:: CI users and scripters - - This command is not intended for use in scripting and CI. Instead, you - should generate a secret key in the EdgeDB Cloud UI or by running - :ref:`ref_cli_edgedb_cloud_secretkey_create` and set the - ``EDGEDB_SECRET_KEY`` environment variable to your secret key. Once this - variable is set to your secret key, logging in is no longer required. diff --git a/docs/cli/edgedb_cloud/edgedb_cloud_secretkey/edgedb_cloud_secretkey_list.rst b/docs/cli/edgedb_cloud/edgedb_cloud_secretkey/edgedb_cloud_secretkey_list.rst deleted file mode 100644 index 01b9fc35d94..00000000000 --- a/docs/cli/edgedb_cloud/edgedb_cloud_secretkey/edgedb_cloud_secretkey_list.rst +++ /dev/null @@ -1,27 +0,0 @@ -.. _ref_cli_edgedb_cloud_secretkey_list: - - -=========================== -edgedb cloud secretkey list -=========================== - -.. note:: - - This CLI command requires CLI version 3.0 or later. - -List existing secret keys - -.. cli:synopsis:: - - edgedb cloud secretkey list [] - -.. note:: - - This command works only if you have already authenticated using - :ref:`ref_cli_edgedb_cloud_login`. - -Options -======= - -:cli:synopsis:`--json` - Output results as JSON diff --git a/docs/cli/edgedb_cloud/index.rst b/docs/cli/edgedb_cloud/index.rst deleted file mode 100644 index b7c36f7bb4a..00000000000 --- a/docs/cli/edgedb_cloud/index.rst +++ /dev/null @@ -1,44 +0,0 @@ -.. _ref_cli_edgedb_cloud: - - -============ -edgedb cloud -============ - -.. note:: - - These CLI commands require CLI version 3.0 or later. - -In addition to managing your own local and remote instances, the EdgeDB CLI -offers tools to manage your instances running on our EdgeDB Cloud. - -.. toctree:: - :maxdepth: 3 - :hidden: - - edgedb_cloud_login - edgedb_cloud_logout - edgedb_cloud_secretkey/index - -.. list-table:: - :class: funcoptable - - * - :ref:`ref_cli_edgedb_cloud_login` - - Authenticate to the EdgeDB Cloud and remember the access token locally - * - :ref:`ref_cli_edgedb_cloud_logout` - - Forget the stored access token - * - :ref:`ref_cli_edgedb_cloud_secretkey` - - Manage your secret keys - -.. warning:: CI users and scripters - - The ``edgedb cloud login`` and ``edgedb cloud logout`` commands are not - intended for use in scripting and CI. Instead, you should generate a secret - key in the EdgeDB Cloud UI or by running - :ref:`ref_cli_edgedb_cloud_secretkey_create` and set the - ``EDGEDB_SECRET_KEY`` environment variable to your secret key. Once this - variable is set to your secret key, logging in and out are no longer - required. - -Follow :ref:`our EdgeDB Cloud guide ` for information on how -to use EdgeDB Cloud. diff --git a/docs/cli/edgedb_database/edgedb_database_create.rst b/docs/cli/edgedb_database/edgedb_database_create.rst deleted file mode 100644 index 2bccf65ca1f..00000000000 --- a/docs/cli/edgedb_database/edgedb_database_create.rst +++ /dev/null @@ -1,37 +0,0 @@ -.. _ref_cli_edgedb_database_create: - - -====================== -edgedb database create -====================== - -Create a new :ref:`database `. - -.. cli:synopsis:: - - edgedb database create [] - -.. note:: - - EdgeDB 5.0 introduced :ref:`branches ` to - replace databases. This command works on instances running versions - prior to EdgeDB 5.0. If you are running a newer version of - EdgeDB, you will instead use :ref:`ref_cli_edgedb_branch_create`. - - -Description -=========== - -``edgedb database create`` is a terminal command equivalent to -:eql:stmt:`create database`. - - -Options -======= - -The ``database create`` command runs in the EdgeDB instance it is -connected to. For specifying the connection target see -:ref:`connection options `. - -:cli:synopsis:`` - The name of the new database. diff --git a/docs/cli/edgedb_database/edgedb_database_drop.rst b/docs/cli/edgedb_database/edgedb_database_drop.rst deleted file mode 100644 index d610298c5a9..00000000000 --- a/docs/cli/edgedb_database/edgedb_database_drop.rst +++ /dev/null @@ -1,39 +0,0 @@ -.. _ref_cli_edgedb_database_drop: - - -==================== -edgedb database drop -==================== - -Drop a :ref:`database `. - -.. cli:synopsis:: - - edgedb database drop [] - -.. note:: - - EdgeDB 5.0 introduced :ref:`branches ` to - replace databases. This command works on instances running versions - prior to EdgeDB 5.0. If you are running a newer version of - EdgeDB, you will instead use :ref:`ref_cli_edgedb_branch_drop`. - - -Description -=========== - -``edgedb database drop`` is a terminal command equivalent to -:eql:stmt:`drop database`. - - -Options -======= - -The ``database drop`` command runs in the EdgeDB instance it is -connected to. For specifying the connection target see -:ref:`connection options `. - -:cli:synopsis:`` - The name of the database to drop. -:cli:synopsis:`--non-interactive` - Drop the database without asking for confirmation. diff --git a/docs/cli/edgedb_database/edgedb_database_wipe.rst b/docs/cli/edgedb_database/edgedb_database_wipe.rst deleted file mode 100644 index 714c441bfa8..00000000000 --- a/docs/cli/edgedb_database/edgedb_database_wipe.rst +++ /dev/null @@ -1,42 +0,0 @@ -.. _ref_cli_edgedb_database_wipe: - - -==================== -edgedb database wipe -==================== - -Destroy the contents of a :ref:`database ` - -.. cli:synopsis:: - - edgedb database wipe [] - -.. note:: - - EdgeDB 5.0 introduced :ref:`branches ` to - replace databases. This command works on instances running versions - prior to EdgeDB 5.0. If you are running a newer version of - EdgeDB, you will instead use :ref:`ref_cli_edgedb_branch_wipe`. - - -Description -=========== - -``edgedb database wipe`` is a terminal command equivalent to -:eql:stmt:`reset schema to initial`. - -The database wiped will be one of these values: the value passed for the -``--database``/``-d`` option, the value of ``EDGEDB_DATABASE``, or ``edgedb``. -The contents of the database will be destroyed and the schema reset to its -state before any migrations, but the database itself will be preserved. - - -Options -======= - -The ``database wipe`` command runs in the EdgeDB instance it is -connected to. For specifying the connection target see -:ref:`connection options `. - -:cli:synopsis:`--non-interactive` - Destroy the data without asking for confirmation. diff --git a/docs/cli/edgedb_database/index.rst b/docs/cli/edgedb_database/index.rst deleted file mode 100644 index 65f7e28efb4..00000000000 --- a/docs/cli/edgedb_database/index.rst +++ /dev/null @@ -1,35 +0,0 @@ -.. _ref_cli_edgedb_database: - - -=============== -edgedb database -=============== - -The ``edgedb database`` group of commands contains various database -manipulation tools. - -.. note:: - - EdgeDB 5.0 introduced :ref:`branches ` to - replace databases. These commands work on instances running versions - prior to EdgeDB 5.0. If you are running a newer version of - EdgeDB, you will instead use the :ref:`ref_cli_edgedb_branch` suite of - commands. - -.. toctree:: - :maxdepth: 3 - :hidden: - - edgedb_database_create - edgedb_database_drop - edgedb_database_wipe - -.. list-table:: - :class: funcoptable - - * - :ref:`ref_cli_edgedb_database_create` - - Create a new database - * - :ref:`ref_cli_edgedb_database_drop` - - Drop a database - * - :ref:`ref_cli_edgedb_database_wipe` - - Destroy the contents of a database diff --git a/docs/cli/edgedb_describe/index.rst b/docs/cli/edgedb_describe/index.rst deleted file mode 100644 index 07b800f27b6..00000000000 --- a/docs/cli/edgedb_describe/index.rst +++ /dev/null @@ -1,24 +0,0 @@ -.. _ref_cli_edgedb_describe: - - -=============== -edgedb describe -=============== - -The ``edgedb describe`` group of commands contains various schema -introspection tools. - -.. toctree:: - :maxdepth: 3 - :hidden: - - edgedb_describe_object - edgedb_describe_schema - -.. list-table:: - :class: funcoptable - - * - :ref:`ref_cli_edgedb_describe_object` - - Describe a named schema object - * - :ref:`ref_cli_edgedb_describe_schema` - - Describe schema of the current database branch (or database pre-v5) diff --git a/docs/cli/edgedb_instance/edgedb_instance_destroy.rst b/docs/cli/edgedb_instance/edgedb_instance_destroy.rst deleted file mode 100644 index 3795c020108..00000000000 --- a/docs/cli/edgedb_instance/edgedb_instance_destroy.rst +++ /dev/null @@ -1,37 +0,0 @@ -.. _ref_cli_edgedb_instance_destroy: - - -======================= -edgedb instance destroy -======================= - -Remove an EdgeDB instance. - -.. cli:synopsis:: - - edgedb instance destroy [] - - -Description -=========== - -``edgedb instance destroy`` is a terminal command for removing an EdgeDB -instance and all its data. - -.. note:: - - The ``edgedb instance destroy`` command is not intended for use with - self-hosted instances. - - -Options -======= - -:cli:synopsis:`` - The EdgeDB instance name. - -:cli:synopsis:`--force` - Destroy the instance even if it is referred to by a project. - -:cli:synopsis:`-v, --verbose` - Verbose output. diff --git a/docs/cli/edgedb_instance/edgedb_instance_list.rst b/docs/cli/edgedb_instance/edgedb_instance_list.rst deleted file mode 100644 index bb1a604882a..00000000000 --- a/docs/cli/edgedb_instance/edgedb_instance_list.rst +++ /dev/null @@ -1,30 +0,0 @@ -.. _ref_cli_edgedb_instance_list: - - -==================== -edgedb instance list -==================== - -Show all EdgeDB instances. - -.. cli:synopsis:: - - edgedb instance list [] - - -Description -=========== - -``edgedb instance list`` is a terminal command that shows all the -registered EdgeDB instances and some relevant information about them -(status, port, etc.). - - -Options -======= - -:cli:synopsis:`--extended` - Output more debug info about each instance. - -:cli:synopsis:`-j, --json` - Output in JSON format. diff --git a/docs/cli/edgedb_instance/edgedb_instance_logs.rst b/docs/cli/edgedb_instance/edgedb_instance_logs.rst deleted file mode 100644 index c60dcbb4f7e..00000000000 --- a/docs/cli/edgedb_instance/edgedb_instance_logs.rst +++ /dev/null @@ -1,37 +0,0 @@ -.. _ref_cli_edgedb_instance_logs: - - -==================== -edgedb instance logs -==================== - -Show instance logs. - -.. cli:synopsis:: - - edgedb instance logs [] - - -Description -=========== - -``edgedb instance logs`` is a terminal command for displaying the logs -for a given EdgeDB instance. - -.. note:: - - The ``edgedb instance logs`` command is not intended for use with - self-hosted instances. - - -Options -======= - -:cli:synopsis:`` - The name of the EdgeDB instance. - -:cli:synopsis:`-n, --tail=` - Number of the most recent lines to show. - -:cli:synopsis:`-f, --follow` - Show log's tail and the continue watching for the new entries. diff --git a/docs/cli/edgedb_instance/edgedb_instance_restart.rst b/docs/cli/edgedb_instance/edgedb_instance_restart.rst deleted file mode 100644 index a0d6b3621f2..00000000000 --- a/docs/cli/edgedb_instance/edgedb_instance_restart.rst +++ /dev/null @@ -1,31 +0,0 @@ -.. _ref_cli_edgedb_instance_restart: - - -======================= -edgedb instance restart -======================= - -Restart an EdgeDB instance. - -.. cli:synopsis:: - - edgedb instance restart - - -Description -=========== - -``edgedb instance restart`` is a terminal command for restarting an -EdgeDB instance. - -.. note:: - - The ``edgedb instance restart`` command is not intended for use with - self-hosted instances. - - -Options -======= - -:cli:synopsis:`` - The EdgeDB instance name. diff --git a/docs/cli/edgedb_instance/edgedb_instance_revert.rst b/docs/cli/edgedb_instance/edgedb_instance_revert.rst deleted file mode 100644 index ee47af56251..00000000000 --- a/docs/cli/edgedb_instance/edgedb_instance_revert.rst +++ /dev/null @@ -1,40 +0,0 @@ -.. _ref_cli_edgedb_instance_revert: - - -====================== -edgedb instance revert -====================== - -Revert a major instance upgrade. - -.. cli:synopsis:: - - edgedb instance revert [] - - -Description -=========== - -When :ref:`ref_cli_edgedb_instance_upgrade` performs a major version -upgrade on an instance the old instance data is kept around. The -``edgedb instance revert`` command removes the new instance version and -replaces it with the old copy. It also ensures that the previous -version of EdgeDB server is used to run it. - -.. note:: - - The ``edgedb instance revert`` command is not intended for use with - self-hosted instances. - - -Options -======= - -:cli:synopsis:`` - The name of the EdgeDB instance to revert. - -:cli:synopsis:`--ignore-pid-check` - Do not check if upgrade is in progress. - -:cli:synopsis:`-y, --no-confirm` - Do not ask for a confirmation. diff --git a/docs/cli/edgedb_instance/edgedb_instance_start.rst b/docs/cli/edgedb_instance/edgedb_instance_start.rst deleted file mode 100644 index 561b2ed84f5..00000000000 --- a/docs/cli/edgedb_instance/edgedb_instance_start.rst +++ /dev/null @@ -1,36 +0,0 @@ -.. _ref_cli_edgedb_instance_start: - - -===================== -edgedb instance start -===================== - -Start an EdgeDB instance. - -.. cli:synopsis:: - - edgedb instance start [--foreground] - - -Description -=========== - -``edgedb instance start`` is a terminal command for starting a new -EdgeDB instance. - -.. note:: - - The ``edgedb instance start`` command is not intended for use with - self-hosted instances. - - -Options -======= - -:cli:synopsis:`` - The EdgeDB instance name. - -:cli:synopsis:`--foreground` - Start the instance in the foreground rather than using systemd to - manage the process (note you might need to stop non-foreground - instance first). diff --git a/docs/cli/edgedb_instance/edgedb_instance_stop.rst b/docs/cli/edgedb_instance/edgedb_instance_stop.rst deleted file mode 100644 index 47e758d7076..00000000000 --- a/docs/cli/edgedb_instance/edgedb_instance_stop.rst +++ /dev/null @@ -1,32 +0,0 @@ -.. _ref_cli_edgedb_instance_stop: - - -==================== -edgedb instance stop -==================== - -Stop an EdgeDB instance. - -.. cli:synopsis:: - - edgedb instance stop - - -Description -=========== - -``edgedb instance stop`` is a terminal command for stopping a running -EdgeDB instance. This is a necessary step before -:ref:`destroying ` an instance. - -.. note:: - - The ``edgedb instance stop`` command is not intended for use with - self-hosted instances. - - -Options -======= - -:cli:synopsis:`` - The EdgeDB instance name. diff --git a/docs/cli/edgedb_instance/edgedb_instance_unlink.rst b/docs/cli/edgedb_instance/edgedb_instance_unlink.rst deleted file mode 100644 index 81dedc96511..00000000000 --- a/docs/cli/edgedb_instance/edgedb_instance_unlink.rst +++ /dev/null @@ -1,26 +0,0 @@ -.. _ref_cli_edgedb_instance_unlink: - -====================== -edgedb instance unlink -====================== - -Unlink from a previously linked remote EdgeDB instance. - -.. cli:synopsis:: - - edgedb instance unlink - - -Description -=========== - -``edgedb instance unlink`` is a terminal command used to unlink a -remote instance. This removes the instance name from the list of valid -instances. - - -Options -======= - -:cli:synopsis:`` - Specifies the name of the remote instance to be unlinked. diff --git a/docs/cli/edgedb_instance/index.rst b/docs/cli/edgedb_instance/index.rst deleted file mode 100644 index 565a8c98830..00000000000 --- a/docs/cli/edgedb_instance/index.rst +++ /dev/null @@ -1,64 +0,0 @@ -.. _ref_cli_edgedb_instance: - -=============== -edgedb instance -=============== - -The ``edgedb instance`` group of commands contains all sorts of tools -for managing EdgeDB instances. - -.. note:: - - Most commands in the ``edgedb instance`` command group are not intended to - manage self-hosted instances. See individual commands for more details. - -.. toctree:: - :maxdepth: 3 - :hidden: - - edgedb_instance_create - edgedb_instance_credentials - edgedb_instance_destroy - edgedb_instance_link - edgedb_instance_list - edgedb_instance_logs - edgedb_instance_start - edgedb_instance_status - edgedb_instance_stop - edgedb_instance_reset_password - edgedb_instance_restart - edgedb_instance_revert - edgedb_instance_unlink - edgedb_instance_upgrade - -.. list-table:: - :class: funcoptable - - * - :ref:`ref_cli_edgedb_instance_create` - - Initialize a new server instance - * - :ref:`ref_cli_edgedb_instance_credentials` - - Display instance credentials - * - :ref:`ref_cli_edgedb_instance_destroy` - - Destroy a server instance and remove the data stored - * - :ref:`ref_cli_edgedb_instance_link` - - Link a remote instance - * - :ref:`ref_cli_edgedb_instance_list` - - Show all instances - * - :ref:`ref_cli_edgedb_instance_logs` - - Show logs of an instance - * - :ref:`ref_cli_edgedb_instance_start` - - Start an instance - * - :ref:`ref_cli_edgedb_instance_status` - - Show statuses of all or of a matching instance - * - :ref:`ref_cli_edgedb_instance_stop` - - Stop an instance - * - :ref:`ref_cli_edgedb_instance_reset_auth` - - Reset password for a user in the instance - * - :ref:`ref_cli_edgedb_instance_restart` - - Restart an instance - * - :ref:`ref_cli_edgedb_instance_revert` - - Revert a major instance upgrade - * - :ref:`ref_cli_edgedb_instance_unlink` - - Unlink a remote instance - * - :ref:`ref_cli_edgedb_instance_upgrade` - - Upgrade installations and instances diff --git a/docs/cli/edgedb_migrate.rst b/docs/cli/edgedb_migrate.rst deleted file mode 100644 index d432ac59d31..00000000000 --- a/docs/cli/edgedb_migrate.rst +++ /dev/null @@ -1,18 +0,0 @@ -.. _ref_cli_edgedb_migrate: - -============== -edgedb migrate -============== - -This command is an alias for :ref:`ref_cli_edgedb_migration_apply`. -Once the migration scripts are in place, the changes can be applied to the -database using this command. - -.. warning:: EdgeDB Cloud CI users and scripters - - When scripting a ``migrate``/``migration apply`` for an EdgeDB Cloud - instance, do not use ``edgedb login`` to authenticate. Instead, you should - generate a secret key in the EdgeDB Cloud UI or by running - :ref:`ref_cli_edgedb_cloud_secretkey_create` and set the - ``EDGEDB_SECRET_KEY`` environment variable to your secret key. Once this - variable is set to your secret key, logging in is no longer required. diff --git a/docs/cli/edgedb_migration/index.rst b/docs/cli/edgedb_migration/index.rst deleted file mode 100644 index 638767653c0..00000000000 --- a/docs/cli/edgedb_migration/index.rst +++ /dev/null @@ -1,55 +0,0 @@ -.. _ref_cli_edgedb_migration: - - -================ -edgedb migration -================ - -EdgeDB provides schema migration tools as server-side tools. This means that, -from the point of view of the application, migrations are language- and -platform-agnostic and don't require additional libraries. - -Using the migration tools is the recommended way to make schema changes. - -.. toctree:: - :maxdepth: 3 - :hidden: - - edgedb_migration_apply - edgedb_migration_create - edgedb_migration_edit - edgedb_migration_extract - edgedb_migration_log - edgedb_migration_status - edgedb_migration_upgrade_check - -Setup -===== - -First of all, the migration tools need a place to store the schema and -migration information. By default they will look in the ``dbschema`` -directory, but it's also possible to specify any other location by -using the :cli:synopsis:`schema-dir` option. - -Inside this directory, you will find an ``.esdl`` file with an :ref:`SDL -` schema description. You may split your schema across multiple -``.esdl`` files. The migration tools will read all of them and treat them as a -single SDL document. - -.. list-table:: - :class: funcoptable - - * - :ref:`ref_cli_edgedb_migration_apply` - - Bring current branch (or database pre-v5) to the latest or a specified revision - * - :ref:`ref_cli_edgedb_migration_create` - - Create a migration script - * - :ref:`ref_cli_edgedb_migration_edit` - - Edit migration file - * - :ref:`ref_cli_edgedb_migration_extract` - - Extract migration history and write it to ``/migrations``. - * - :ref:`ref_cli_edgedb_migration_log` - - Show all migration versions - * - :ref:`ref_cli_edgedb_migration_status` - - Show current migration state - * - :ref:`ref_cli_edgedb_migration_upgrade_check` - - Checks your schema against a different EdgeDB version. diff --git a/docs/cli/edgedb_project/index.rst b/docs/cli/edgedb_project/index.rst deleted file mode 100644 index 5a10e3c57fb..00000000000 --- a/docs/cli/edgedb_project/index.rst +++ /dev/null @@ -1,32 +0,0 @@ -.. _ref_cli_edgedb_project: - - -============== -edgedb project -============== - -EdgeDB provides a way to quickly setup a project. This way the project -directory gets associated with a specific EdgeDB instance and thus -makes it the default instance to connect to. This is done by creating -an :ref:`ref_reference_edgedb_toml` file in the project directory. - -.. toctree:: - :maxdepth: 3 - :hidden: - - edgedb_project_init - edgedb_project_info - edgedb_project_unlink - edgedb_project_upgrade - -.. list-table:: - :class: funcoptable - - * - :ref:`ref_cli_edgedb_project_init` - - Initialize a new or existing project - * - :ref:`ref_cli_edgedb_project_info` - - Get various metadata about the project - * - :ref:`ref_cli_edgedb_project_unlink` - - Remove project association with an instance - * - :ref:`ref_cli_edgedb_project_upgrade` - - Upgrade EdgeDB instance used for the current project diff --git a/docs/cli/edgedb_restore.rst b/docs/cli/edgedb_restore.rst deleted file mode 100644 index ca25d111a23..00000000000 --- a/docs/cli/edgedb_restore.rst +++ /dev/null @@ -1,52 +0,0 @@ -.. _ref_cli_edgedb_restore: - - -============== -edgedb restore -============== - -Restore an EdgeDB branch (or database pre-v5) from a backup file. - -.. cli:synopsis:: - - edgedb restore [] - - -Description -=========== - -``edgedb restore`` is a terminal command used to restore an EdgeDB database -branch (or database pre-v5) from a backup file. The backup is restored to the -currently active branch (or to the currently connected database pre-v5). - -.. note:: - - The backup cannot be restored to a branch (or database pre-v5) with any - existing schema. As a result, you should restore to one of these targets: - - - a new empty branch which can be created using - :ref:`ref_cli_edgedb_branch_create` with the ``--empty`` option - - a new empty database if your instance is running EdgeDB versions prior to - 5 - - an existing branch or database that has been wiped with the appropriate - ``wipe`` command (either :ref:`ref_cli_edgedb_branch_wipe` or - :ref:`ref_cli_edgedb_database_wipe`; note that this will destroy all data - and schema currently in that branch/database) - - -Options -======= - -The ``restore`` command restores the backup file into the active branch or, in -pre-v5 instance, the currently connected database. For specifying the -connection target see :ref:`connection options `. - -:cli:synopsis:`` - The name of the backup file to restore the database branch from. - -:cli:synopsis:`--all` - Restore all branches (or databases pre-v5) and the server configuration - using the directory specified by the :cli:synopsis:``. - -:cli:synopsis:`-v, --verbose` - Verbose output. diff --git a/docs/cli/edgedb_server/index.rst b/docs/cli/edgedb_server/index.rst deleted file mode 100644 index 3afcbeb4dfd..00000000000 --- a/docs/cli/edgedb_server/index.rst +++ /dev/null @@ -1,29 +0,0 @@ -.. _ref_cli_edgedb_server: - -============= -edgedb server -============= - -The ``edgedb server`` group of commands contains all sorts of tools -for managing EdgeDB server versions. - -.. toctree:: - :maxdepth: 3 - :hidden: - - edgedb_server_info - edgedb_server_install - edgedb_server_list_versions - edgedb_server_uninstall - -.. list-table:: - :class: funcoptable - - * - :ref:`ref_cli_edgedb_server_info` - - Show server information - * - :ref:`ref_cli_edgedb_server_install` - - Install edgedb server - * - :ref:`ref_cli_edgedb_server_list_versions` - - List available and installed versions of the server - * - :ref:`ref_cli_edgedb_server_uninstall` - - Uninstall edgedb server diff --git a/docs/cli/edgedb_watch.rst b/docs/cli/edgedb_watch.rst deleted file mode 100644 index f980938b27d..00000000000 --- a/docs/cli/edgedb_watch.rst +++ /dev/null @@ -1,38 +0,0 @@ -.. _ref_cli_edgedb_watch: - - -============ -edgedb watch -============ - -.. note:: - - This CLI feature is compatible with EdgeDB server 3.0 and above. - -Start a long-running process that watches for changes in schema files in your -project's ``dbschema`` directory and applies those changes to your database in -real time. Starting it is as simple as running this command: - -.. cli:synopsis:: - - edgedb watch - -.. note:: - - If a schema change cannot be applied, you will see an error in the ``edgedb - watch`` console. You will also receive the error when you try to run a - query with any EdgeDB client binding. - -To learn about our recommended development migration workflow using ``edgedb -watch``, read our :ref:`intro to migrations `. - -.. note:: - - If you want to apply a migration in the same manner as ``watch`` but - without the long-running process, use ``edgedb migrate --dev-mode``. See - :ref:`ref_cli_edgedb_migration_apply` for more details. - -Demo -==== - -.. edb:youtube-embed:: _IUSPBm2xEA diff --git a/docs/cli/edgedb.rst b/docs/cli/gel.rst similarity index 63% rename from docs/cli/edgedb.rst rename to docs/cli/gel.rst index c0be3dacf23..0cae6c59c1b 100644 --- a/docs/cli/edgedb.rst +++ b/docs/cli/gel.rst @@ -1,36 +1,36 @@ -.. _ref_cli_edgedb: +.. _ref_cli_gel: -====== -edgedb -====== +=== +gel +=== -:edb-alt-title: edgedb β€” Interactive Shell +:edb-alt-title: gel β€” Interactive Shell -EdgeDB interactive shell: +Gel interactive shell: .. cli:synopsis:: - edgedb [...] + gel [...] It's also possible to run an EdgeQL script by piping it into the -EdgeDB shell. The shell will then run in non-interactive mode and +|Gel| shell. The shell will then run in non-interactive mode and print all the responses into the standard output: .. cli:synopsis:: - cat myscript.edgeql | edgedb [...] + cat myscript.edgeql | gel [...] The above command also works on PowerShell in Windows, while the classic Windows Command Prompt uses a different command as shown below: .. cli:synopsis:: - type myscript.edgeql | edgedb [...] + type myscript.edgeql | gel [...] Description =========== -``edgedb`` is a terminal-based front-end to EdgeDB. It allows running +|gelcmd| is a terminal-based front-end to |Gel|. It allows running queries and seeing results interactively. @@ -41,7 +41,7 @@ Options Show help about the command and exit. :cli:synopsis:`--help-connect` - Show all available :ref:`connection options ` + Show all available :ref:`connection options ` :cli:synopsis:`-V, --version` Print version. @@ -51,15 +51,15 @@ Options :cli:synopsis:`-I , --instance=` Specifies the named instance to connect to. The actual connection - parameters are stored in ``/credentials`` and are - usually created by :ref:`ref_cli_edgedb_instance_create` or similar - commands. Run ``edgedb info`` to see the location of - ```` on your machine. + parameters are stored in ``/credentials`` and are + usually created by :ref:`ref_cli_gel_instance_create` or similar + commands. Run :gelcmd:`info` to see the location of + ```` on your machine. This option overrides host and port. :cli:synopsis:`--dsn=` - Specifies the DSN for EdgeDB to connect to. + Specifies the DSN for |Gel| to connect to. This option overrides all other options except password. @@ -68,40 +68,34 @@ Options :cli:synopsis:`-H , --host=` Specifies the host name of the machine on which the server is running. - Defaults to the value of the ``EDGEDB_HOST`` environment variable. + Defaults to the value of the :gelenv:`HOST` environment variable. :cli:synopsis:`-P , --port=` Specifies the TCP port on which the server is listening for connections. - Defaults to the value of the ``EDGEDB_PORT`` environment variable or, + Defaults to the value of the :gelenv:`PORT` environment variable or, if not set, to ``5656``. :cli:synopsis:`-u , --user=` Connect to the database as the user :cli:synopsis:``. - Defaults to the value of the ``EDGEDB_USER`` environment variable, or, + Defaults to the value of the :gelenv:`USER` environment variable, or, if not set, to the login name of the current OS user. -:cli:synopsis:`-d , --database=` - Specifies the name of the database to connect to. Default to the value - of the ``EDGEDB_DATABASE`` environment variable, or, if not set, to - the calculated value of :cli:synopsis:``. - :cli:synopsis:`-b , --branch=` Specifies the name of the branch to connect to. Default to the value - of the ``EDGEDB_BRANCH`` environment variable, or, if not set, to + of the :gelenv:`BRANCH` environment variable, or, if not set, to the calculated value of :cli:synopsis:``. .. note:: - EdgeDB 5.0 introduced :ref:`branches ` to - replace databases. This option requires CLI version 4.3.0 or later and - EdgeDB version 5.0 or later. If you are running an earlier version of - EdgeDB, you will instead use the ``-d , --database=`` + |EdgeDB| 5.0 introduced :ref:`branches ` to + replace databases. If you are running an earlier version of + Gel, you will instead use the ``-d , --database=`` option above. :cli:synopsis:`--password | --no-password` - If :cli:synopsis:`--password` is specified, force ``edgedb`` to prompt + If :cli:synopsis:`--password` is specified, force |gelcmd| to prompt for a password before connecting to the database. This is usually not - necessary, since ``edgedb`` will prompt for a password automatically + necessary, since ``gel`` will prompt for a password automatically if the server requires it. Specifying :cli:synopsis:`--no-password` disables all password prompts. @@ -137,11 +131,11 @@ Options Disable all TLS security measures. :cli:synopsis:`--wait-until-available=` - In case EdgeDB connection can't be established, keep retrying up + In case |Gel| connection can't be established, keep retrying up to :cli:synopsis:`` (e.g. ``30s``). :cli:synopsis:`--connect-timeout=` - Specifies a :cli:synopsis:`` period. In case EdgeDB + Specifies a :cli:synopsis:`` period. In case |Gel| doesn't respond for this period the command will fail (or retry if :cli:synopsis:`--wait-until-available` is also specified). The :cli:synopsis:`` value must be given using time units @@ -169,25 +163,15 @@ many of the commands: Describe the entire schema. :cli:synopsis:`\\l` - List branches on EdgeDB server 5+ or databases on prior versions. - -:cli:synopsis:`\\list databases` - List databases. - - .. note:: - - EdgeDB 5.0 introduced :ref:`branches ` to replace - databases. If you are running 5.0 or later, you will instead use the - ``\list branches`` command below. + List branches on |Gel| server 5+ or databases on prior versions. :cli:synopsis:`\\list branches` List branches. .. note:: - EdgeDB 5.0 introduced :ref:`branches ` to replace - databases. This command requires CLI version 4.3.0 or later and EdgeDB - version 5.0 or later. If you are running an earlier version of EdgeDB, + |EdgeDB| 5.0 introduced :ref:`branches ` to replace + databases. If you are running an earlier version of Gel, you will instead use the ``\list databases`` command above. :cli:synopsis:`\\ls [-sc] [PATTERN], \\list scalars [-sc] [PATTERN]` @@ -211,52 +195,31 @@ many of the commands: :cli:synopsis:`\\li [-vsc] [PATTERN], \\list indexes [-vsc] [PATTERN]` List indexes. -Database --------- - -.. note:: - - EdgeDB 5.0 introduced :ref:`branches ` to replace - databases. If you are running 5.0 or later, you will instead use the - commands in the "Branch" section below. - -:cli:synopsis:`\\database create NAME` - Create a new database. - Branch ------ -.. note:: +.. versionadded:: 5.0 - EdgeDB 5.0 introduced :ref:`branches ` to replace - databases. These commands require CLI version 4.3.0 or later and EdgeDB - version 5.0 or later. If you are running an earlier version of EdgeDB, - you will instead use the database commands above. +|EdgeDB| 5.0 introduced :ref:`branches ` to replace +databases. If you are running an earlier version of Gel, +you will instead use the database commands above. :cli:synopsis:`\\branch create NAME` Create a new branch. The backslash command mirrors the options of the CLI's - :ref:`ref_cli_edgedb_branch_create`. + :ref:`ref_cli_gel_branch_create`. :cli:synopsis:`\\branch switch NAME` Switch to a different branch. The backslash command mirrors the options of - the CLI's :ref:`ref_cli_edgedb_branch_switch`. + the CLI's :ref:`ref_cli_gel_branch_switch`. Query Analysis -------------- :cli:synopsis:`\\analyze QUERY` - .. note:: - - This command is compatible with EdgeDB server 3.0 and above. - Run a query performance analysis on the given query. Most conveniently used without a backslash by just adding ``analyze`` before any query. :cli:synopsis:`\\expand` - .. note:: - - This command is compatible with EdgeDB server 3.0 and above. - Print expanded output of last ``analyze`` operation. Data Operations @@ -266,8 +229,7 @@ Data Operations Dump current database branch to a file at *FILENAME*. :cli:synopsis:`\\restore FILENAME` - Restore the database dump at *FILENAME* into the current branch (or currently - connected database for pre-v5). + Restore the database dump at *FILENAME* into the current |branch|. Editing ------- @@ -294,43 +256,36 @@ Settings Connection ---------- -:cli:synopsis:`\\c, \\connect [DBNAME]` - Connect to database *DBNAME*. - - .. note:: - - EdgeDB 5.0 introduced :ref:`branches ` to replace - databases. If you are running 5.0 or later, you will instead use the - ``\branch switch NAME`` command to switch to a different branch. +:cli:synopsis:`\\c, \\connect [NAME]` + Connect to branch *NAME*. Migrations ---------- These migration commands are also accessible directly from the command line -without first entering the EdgeDB shell. Their counterpart commands are noted +without first entering the |Gel| shell. Their counterpart commands are noted and linked in their descriptions if you want more detail. :cli:synopsis:`\\migration create` - Create a migration script based on differences between the current branch (or - database for pre-v5) and the schema file, just like running - :ref:`ref_cli_edgedb_migration_create`. + Create a migration script based on differences between the current |branch| + and the schema file, just like running :ref:`ref_cli_gel_migration_create`. :cli:synopsis:`\\migrate, \\migration apply` Apply your migration, just like running the - :ref:`ref_cli_edgedb_migrate`. + :ref:`ref_cli_gel_migrate`. :cli:synopsis:`\\migration edit` Spawn ``$EDITOR`` on the last migration file and fixes the migration ID after - the editor exits, just like :ref:`ref_cli_edgedb_migration_edit`. This is + the editor exits, just like :ref:`ref_cli_gel_migration_edit`. This is typically used only on migrations that have not yet been applied. :cli:synopsis:`\\migration log` - Show the migration history, just like :ref:`ref_cli_edgedb_migration_log`. + Show the migration history, just like :ref:`ref_cli_gel_migration_log`. :cli:synopsis:`\\migration status` - Show how the state of the schema in the EdgeDB instance compares to the + Show how the state of the schema in the |Gel| instance compares to the migration stored in the schema directory, just like - :ref:`ref_cli_edgedb_migration_status`. + :ref:`ref_cli_gel_migration_status`. Help ---- @@ -340,3 +295,16 @@ Help :cli:synopsis:`\\q, \\quit, \\exit` Quit the REPL. You can also do this by pressing Ctrl+D. + + +Database +-------- + +.. note:: + + |EdgeDB| 5.0 introduced :ref:`branches ` to replace + databases. If you are running 5.0 or later, you will instead use the + commands in the "Branch" section above. + +:cli:synopsis:`\\database create NAME` + Create a new database. diff --git a/docs/cli/edgedb_analyze.rst b/docs/cli/gel_analyze.rst similarity index 77% rename from docs/cli/edgedb_analyze.rst rename to docs/cli/gel_analyze.rst index f8ce1607d91..0af49e6df7d 100644 --- a/docs/cli/edgedb_analyze.rst +++ b/docs/cli/gel_analyze.rst @@ -1,26 +1,22 @@ -.. _ref_cli_edgedb_analyze: +.. _ref_cli_gel_analyze: -============== -edgedb analyze -============== - -.. note:: - - This CLI feature is compatible with EdgeDB server 3.0 and above. +=========== +gel analyze +=========== .. note:: Performance analysis is also available in our :ref:`CLI REPL - ` and the UI's REPL and query builder (both accessible by - running :ref:`ref_cli_edgedb_ui` to invoke your instance's UI). Use it by + ` and the UI's REPL and query builder (both accessible by + running :ref:`ref_cli_gel_ui` to invoke your instance's UI). Use it by prepending your query with ``analyze``. Run a query performance analysis on the given query. .. cli:synopsis:: - edgedb analyze [] + gel analyze [] An example of ``analyze`` output from a simple query: @@ -44,7 +40,7 @@ Options ======= The ``analyze`` command runs on the database it is connected to. For specifying -the connection target see :ref:`connection options `. +the connection target see :ref:`connection options `. :cli:synopsis:`` The query to analyze. Be sure to wrap the query in quotes. @@ -61,4 +57,4 @@ the connection target see :ref:`connection options `. Media ===== -.. edb:youtube-embed:: WoHJu0nq5z0 \ No newline at end of file +.. edb:youtube-embed:: WoHJu0nq5z0 diff --git a/docs/cli/edgedb_branch/edgedb_branch_create.rst b/docs/cli/gel_branch/gel_branch_create.rst similarity index 52% rename from docs/cli/edgedb_branch/edgedb_branch_create.rst rename to docs/cli/gel_branch/gel_branch_create.rst index 36650c6bda7..877b9e09718 100644 --- a/docs/cli/edgedb_branch/edgedb_branch_create.rst +++ b/docs/cli/gel_branch/gel_branch_create.rst @@ -1,28 +1,20 @@ -.. _ref_cli_edgedb_branch_create: +.. _ref_cli_gel_branch_create: -==================== -edgedb branch create -==================== +================= +gel branch create +================= Create a new :ref:`branch `. .. cli:synopsis:: - edgedb branch create [] - -.. note:: - - This CLI command requires CLI version 4.3.0 or later and EdgeDB version 5.0 - or later. If you are running an earlier version of EdgeDB, you will instead - use the :ref:`ref_cli_edgedb_database_create` command to create a database, - which branches replaced in EdgeDB 5.0. - + gel branch create [] Description =========== -``edgedb branch create`` creates a new branch with the same schema as the +:gelcmd:`branch create` creates a new branch with the same schema as the current branch specified in ``$CONFIG/credentials``. Without any options, it is equivalent to :eql:stmt:`create schema branch`. @@ -30,9 +22,9 @@ equivalent to :eql:stmt:`create schema branch`. Options ======= -The ``branch create`` command runs in the EdgeDB instance it is +The ``branch create`` command runs in the |Gel| instance it is connected to. For specifying the connection target see -:ref:`connection options `. +:ref:`connection options `. :cli:synopsis:`` The name of the new branch. diff --git a/docs/cli/gel_branch/gel_branch_drop.rst b/docs/cli/gel_branch/gel_branch_drop.rst new file mode 100644 index 00000000000..3c9cf80595a --- /dev/null +++ b/docs/cli/gel_branch/gel_branch_drop.rst @@ -0,0 +1,28 @@ +.. _ref_cli_gel_branch_drop: + + +=============== +gel branch drop +=============== + +Remove an existing :ref:`branch `. + +.. cli:synopsis:: + + gel branch drop [] + +Options +======= + +The ``branch drop`` command runs in the |Gel| instance it is +connected to. For specifying the connection target see +:ref:`connection options `. + +:cli:synopsis:`` + The name of the branch to drop. + +:cli:synopsis:`--non-interactive` + Drop the branch without asking for confirmation. + +:cli:synopsis:`--force` + Close any existing connections to the branch before dropping it. diff --git a/docs/cli/gel_branch/gel_branch_list.rst b/docs/cli/gel_branch/gel_branch_list.rst new file mode 100644 index 00000000000..b046347cc84 --- /dev/null +++ b/docs/cli/gel_branch/gel_branch_list.rst @@ -0,0 +1,12 @@ +.. _ref_cli_gel_branch_list: + + +=============== +gel branch list +=============== + +List all :ref:`branches ` + +.. cli:synopsis:: + + gel branch list diff --git a/docs/cli/gel_branch/gel_branch_merge.rst b/docs/cli/gel_branch/gel_branch_merge.rst new file mode 100644 index 00000000000..db655db5aa5 --- /dev/null +++ b/docs/cli/gel_branch/gel_branch_merge.rst @@ -0,0 +1,46 @@ +.. _ref_cli_gel_branch_merge: + + +================ +gel branch merge +================ + +Merge a :ref:`branch ` into the current branch. + +.. cli:synopsis:: + + gel branch merge [] + + +Description +=========== + +Merges the target branch with the current branch using a fast-forward strategy, +applying any new migrations from the target branch on the current branch. + +.. note:: + + This is a fast-forward merge, so no conflict resolution will be applied to + the new migrations. If you want to merge but may have conflicts, you should + first use :ref:`ref_cli_gel_branch_rebase` from the target branch before + merging. + +.. note:: + + When merging, the data of the current branch is preserved. This means that + if you switch to a branch |main| and run :gelcmd:`branch merge feature`, + you will end up with a branch with the schema from |main| and any + new migrations from ``feature`` and the data from |main|. + + +Options +======= + +The ``branch merge`` command runs in the |Gel| instance it is +connected to. For specifying the connection target see +:ref:`connection options `. + +:cli:synopsis:`` + The name of the branch to merge into the current branch. +:cli:synopsis:`--no-apply` + Skip applying migrations generated from the merge diff --git a/docs/cli/gel_branch/gel_branch_rebase.rst b/docs/cli/gel_branch/gel_branch_rebase.rst new file mode 100644 index 00000000000..48852e35064 --- /dev/null +++ b/docs/cli/gel_branch/gel_branch_rebase.rst @@ -0,0 +1,41 @@ +.. _ref_cli_gel_branch_rebase: + + +================= +gel branch rebase +================= + +Create a :ref:`branch ` based on the target branch but +including new migrations on the current branch. + +.. cli:synopsis:: + + gel branch rebase [] + + +Description +=========== + +Creates a new branch that is based on the target branch, but also contains any new migrations on the +current branch. + +.. note:: + + When rebasing, the data of the target branch is preserved. This means that + if you switch to a branch ``feature`` and run :gelcmd:`branch rebase + main`, you will end up with a branch with the schema from |main| and any + new migrations from ``feature`` and the data from |main|. + +For more about how rebasing works, check out the breakdown :ref:`in our schema +migrations guide `. + + +Options +======= + +The ``branch rebase`` command runs in the |Gel| instance it is +connected to. For specifying the connection target see +:ref:`connection options `. + +:cli:synopsis:`` + The name of the target branch. diff --git a/docs/cli/gel_branch/gel_branch_rename.rst b/docs/cli/gel_branch/gel_branch_rename.rst new file mode 100644 index 00000000000..a60bd69a14d --- /dev/null +++ b/docs/cli/gel_branch/gel_branch_rename.rst @@ -0,0 +1,29 @@ +.. _ref_cli_gel_branch_rename: + + +================= +gel branch rename +================= + +Rename a :ref:`branch ` + +.. cli:synopsis:: + + gel branch rename [] + + +Options +======= + +The ``branch rename`` command runs in the |Gel| instance it is +connected to. For specifying the connection target see +:ref:`connection options `. + +:cli:synopsis:`` + The current name of the branch to rename. + +:cli:synopsis:`` + The new name of the branch. + +:cli:synopsis:`--force` + Close any existing connections to the branch before renaming it. diff --git a/docs/cli/edgedb_branch/edgedb_branch_switch.rst b/docs/cli/gel_branch/gel_branch_switch.rst similarity index 55% rename from docs/cli/edgedb_branch/edgedb_branch_switch.rst rename to docs/cli/gel_branch/gel_branch_switch.rst index ac5c317a7e6..0da095349f2 100644 --- a/docs/cli/edgedb_branch/edgedb_branch_switch.rst +++ b/docs/cli/gel_branch/gel_branch_switch.rst @@ -1,49 +1,49 @@ -.. _ref_cli_edgedb_branch_switch: +.. _ref_cli_gel_branch_switch: -==================== -edgedb branch switch -==================== +================= +gel branch switch +================= Change the currently active :ref:`branch ` .. cli:synopsis:: - edgedb branch switch [] + gel branch switch [] .. note:: - This CLI command requires CLI version 4.0 or later and EdgeDB version 5.0 - or later. Earlier versions did not feature branches and instead featured - databases. + This CLI command requires |Gel| (or |EdgeDB| version 5.0 or later.) + Earlier versions did not feature branches and instead featured + **databases**. Databases offered no direct analog to switching. - - To run a single command on a different database, use the ``-d `` + - To run a single command on a different |branch|, use the ``-d `` or ``--database=`` options described in - :ref:`ref_cli_edgedb_connopts` - - To change the database for *all* commands, set the ``EDGEDB_DATABASE`` - environment variable described in :ref:`ref_cli_edgedb_connopts` + :ref:`ref_cli_gel_connopts` + - To change the database for *all* commands, set the :gelenv:`DATABASE` + environment variable described in :ref:`ref_cli_gel_connopts` - To change the database for all commands in a project, you may update the ``credentials.json`` file's ``database`` value. To find that file for - your project, run :ref:`ref_cli_edgedb_info` to get the config path and + your project, run :ref:`ref_cli_gel_info` to get the config path and navigate to ``//credentials``. - You may use ``\connect `` or ``\c `` to change the connected database while in a REPL session. - See the :ref:`ref_cli_edgedb_database` command suite for other database + See the :ref:`ref_cli_gel_database` command suite for other database management commands. Options ======= -The ``branch switch`` command runs in the EdgeDB instance it is +The ``branch switch`` command runs in the |Gel| instance it is connected to. For specifying the connection target see -:ref:`connection options `. +:ref:`connection options `. :cli:synopsis:`` - The name of the new branch. + The name of the new |branch|. :cli:synopsis:`-c, --create` Create the branch if it doesn't exist. diff --git a/docs/cli/gel_branch/gel_branch_wipe.rst b/docs/cli/gel_branch/gel_branch_wipe.rst new file mode 100644 index 00000000000..dc5f6a54820 --- /dev/null +++ b/docs/cli/gel_branch/gel_branch_wipe.rst @@ -0,0 +1,35 @@ +.. _ref_cli_gel_branch_wipe: + + +=============== +gel branch wipe +=============== + +Destroy the contents of a :ref:`branch ` + +.. cli:synopsis:: + + gel branch wipe [] + +Description +=========== + +The contents of the branch will be destroyed and the schema reset to its +state before any migrations, but the branch itself will be preserved. + +:gelcmd:`branch wipe` is a terminal command equivalent to +:eql:stmt:`reset schema to initial`. + + +Options +======= + +The ``branch wipe`` command runs in the |Gel| instance it is +connected to. For specifying the connection target see +:ref:`connection options `. + +:cli:synopsis:`` + The name of the branch to wipe. + +:cli:synopsis:`--non-interactive` + Destroy the data without asking for confirmation. diff --git a/docs/cli/gel_branch/index.rst b/docs/cli/gel_branch/index.rst new file mode 100644 index 00000000000..4dd3640c415 --- /dev/null +++ b/docs/cli/gel_branch/index.rst @@ -0,0 +1,42 @@ +.. _ref_cli_gel_branch: + + +========== +gel branch +========== + +The :gelcmd:`branch` group of commands contains various branch management +tools. + +.. toctree:: + :maxdepth: 3 + :hidden: + + gel_branch_create + gel_branch_drop + gel_branch_list + gel_branch_merge + gel_branch_rebase + gel_branch_rename + gel_branch_switch + gel_branch_wipe + +.. list-table:: + :class: funcoptable + + * - :ref:`ref_cli_gel_branch_create` + - Create a new branch + * - :ref:`ref_cli_gel_branch_drop` + - Drop a branch + * - :ref:`ref_cli_gel_branch_list` + - List all branches + * - :ref:`ref_cli_gel_branch_merge` + - Merge a branch into the current branch + * - :ref:`ref_cli_gel_branch_rebase` + - Create a branch based on a target branch + * - :ref:`ref_cli_gel_branch_rename` + - Rename a branch + * - :ref:`ref_cli_gel_branch_switch` + - Change the currently active branch + * - :ref:`ref_cli_gel_branch_wipe` + - Destroy the contents of a branch diff --git a/docs/cli/edgedb_cli_upgrade.rst b/docs/cli/gel_cli_upgrade.rst similarity index 62% rename from docs/cli/edgedb_cli_upgrade.rst rename to docs/cli/gel_cli_upgrade.rst index e7cece318a3..75c3709fc22 100644 --- a/docs/cli/edgedb_cli_upgrade.rst +++ b/docs/cli/gel_cli_upgrade.rst @@ -1,21 +1,21 @@ -.. _ref_cli_edgedb_cli_upgrade: +.. _ref_cli_gel_cli_upgrade: -================== -edgedb cli upgrade -================== +=============== +gel cli upgrade +=============== Upgrade the CLI binary. .. cli:synopsis:: - edgedb cli upgrade [] + gel cli upgrade [] Description =========== -``edgedb cli upgrade`` is a terminal command used to upgrade the CLI +:gelcmd:`cli upgrade` is a terminal command used to upgrade the CLI tools to keep them up-to-date. diff --git a/docs/cli/gel_cloud/gel_cloud_login.rst b/docs/cli/gel_cloud/gel_cloud_login.rst new file mode 100644 index 00000000000..df3734adebb --- /dev/null +++ b/docs/cli/gel_cloud/gel_cloud_login.rst @@ -0,0 +1,30 @@ +.. _ref_cli_gel_cloud_login: + + +=============== +gel cloud login +=============== + +Authenticate to the |Gel| Cloud and remember the secret key locally + +.. cli:synopsis:: + + gel cloud login + +This command will launch your browser and start the |Gel| Cloud authentication +flow. Once authentication is successful, the CLI will log a success message: + +.. code-block:: + + Successfully logged in to |Gel| Cloud as + +If you are unable to complete authentication in the browser, you can interrupt +the command by pressing Ctrl-C. + +.. warning:: CI users and scripters + + This command is not intended for use in scripting and CI. Instead, you + should generate a secret key in the |Gel| Cloud UI or by running + :ref:`ref_cli_gel_cloud_secretkey_create` and set the + :gelenv:`SECRET_KEY` environment variable to your secret key. Once this + variable is set to your secret key, logging in is no longer required. diff --git a/docs/cli/edgedb_cloud/edgedb_cloud_logout.rst b/docs/cli/gel_cloud/gel_cloud_logout.rst similarity index 51% rename from docs/cli/edgedb_cloud/edgedb_cloud_logout.rst rename to docs/cli/gel_cloud/gel_cloud_logout.rst index 23844122ea1..02c8cd228ef 100644 --- a/docs/cli/edgedb_cloud/edgedb_cloud_logout.rst +++ b/docs/cli/gel_cloud/gel_cloud_logout.rst @@ -1,27 +1,23 @@ -.. _ref_cli_edgedb_cloud_logout: +.. _ref_cli_gel_cloud_logout: -=================== -edgedb cloud logout -=================== - -.. note:: - - This CLI command requires CLI version 3.0 or later. +================ +gel cloud logout +================ Forget the stored access token .. cli:synopsis:: - edgedb cloud logout [] + gel cloud logout [] .. warning:: CI users and scripters This command is not intended for use in scripting and CI. Instead, to - authenticate to your EdgeDB Cloud account, you should generate a secret key - in the EdgeDB Cloud UI or by running - :ref:`ref_cli_edgedb_cloud_secretkey_create` and set the - ``EDGEDB_SECRET_KEY`` environment variable to your secret key. Logging out + authenticate to your |Gel| Cloud account, you should generate a secret key + in the Gel Cloud UI or by running + :ref:`ref_cli_gel_cloud_secretkey_create` and set the + :gelenv:`SECRET_KEY` environment variable to your secret key. Logging out is not necessary. Options diff --git a/docs/cli/edgedb_cloud/edgedb_cloud_secretkey/edgedb_cloud_secretkey_create.rst b/docs/cli/gel_cloud/gel_cloud_secretkey/edgedb_cloud_secretkey_create.rst similarity index 77% rename from docs/cli/edgedb_cloud/edgedb_cloud_secretkey/edgedb_cloud_secretkey_create.rst rename to docs/cli/gel_cloud/gel_cloud_secretkey/edgedb_cloud_secretkey_create.rst index c2872a27331..9cc75138e85 100644 --- a/docs/cli/edgedb_cloud/edgedb_cloud_secretkey/edgedb_cloud_secretkey_create.rst +++ b/docs/cli/gel_cloud/gel_cloud_secretkey/edgedb_cloud_secretkey_create.rst @@ -1,24 +1,20 @@ -.. _ref_cli_edgedb_cloud_secretkey_create: +.. _ref_cli_gel_cloud_secretkey_create: -============================= -edgedb cloud secretkey create -============================= - -.. note:: - - This CLI command requires CLI version 3.0 or later. +========================== +gel cloud secretkey create +========================== Create a new secret key .. cli:synopsis:: - edgedb cloud secretkey create [] + gel cloud secretkey create [] .. note:: This command works only if you have already authenticated using - :ref:`ref_cli_edgedb_cloud_login`. + :ref:`ref_cli_gel_cloud_login`. Options ======= diff --git a/docs/cli/gel_cloud/gel_cloud_secretkey/edgedb_cloud_secretkey_list.rst b/docs/cli/gel_cloud/gel_cloud_secretkey/edgedb_cloud_secretkey_list.rst new file mode 100644 index 00000000000..d8deaa88a0e --- /dev/null +++ b/docs/cli/gel_cloud/gel_cloud_secretkey/edgedb_cloud_secretkey_list.rst @@ -0,0 +1,24 @@ +.. _ref_cli_gel_cloud_secretkey_list: + + +======================== +gel cloud secretkey list +======================== + + +List existing secret keys + +.. cli:synopsis:: + + gel cloud secretkey list [] + +.. note:: + + This command works only if you have already authenticated using + :ref:`ref_cli_gel_cloud_login`. + +Options +======= + +:cli:synopsis:`--json` + Output results as JSON diff --git a/docs/cli/edgedb_cloud/edgedb_cloud_secretkey/edgedb_cloud_secretkey_revoke.rst b/docs/cli/gel_cloud/gel_cloud_secretkey/edgedb_cloud_secretkey_revoke.rst similarity index 53% rename from docs/cli/edgedb_cloud/edgedb_cloud_secretkey/edgedb_cloud_secretkey_revoke.rst rename to docs/cli/gel_cloud/gel_cloud_secretkey/edgedb_cloud_secretkey_revoke.rst index 23a86f23000..4d681a78ebd 100644 --- a/docs/cli/edgedb_cloud/edgedb_cloud_secretkey/edgedb_cloud_secretkey_revoke.rst +++ b/docs/cli/gel_cloud/gel_cloud_secretkey/edgedb_cloud_secretkey_revoke.rst @@ -1,24 +1,20 @@ -.. _ref_cli_edgedb_cloud_secretkey_revoke: +.. _ref_cli_gel_cloud_secretkey_revoke: -============================= -edgedb cloud secretkey revoke -============================= - -.. note:: - - This CLI command requires CLI version 3.0 or later. +========================== +gel cloud secretkey revoke +========================== Revoke a secret key .. cli:synopsis:: - edgedb cloud secretkey revoke [] --secret-key-id + gel cloud secretkey revoke [] --secret-key-id .. note:: This command works only if you have already authenticated using - :ref:`ref_cli_edgedb_cloud_login`. + :ref:`ref_cli_gel_cloud_login`. Options ======= diff --git a/docs/cli/edgedb_cloud/edgedb_cloud_secretkey/index.rst b/docs/cli/gel_cloud/gel_cloud_secretkey/index.rst similarity index 51% rename from docs/cli/edgedb_cloud/edgedb_cloud_secretkey/index.rst rename to docs/cli/gel_cloud/gel_cloud_secretkey/index.rst index a2f36852385..6ca3fdd47f0 100644 --- a/docs/cli/edgedb_cloud/edgedb_cloud_secretkey/index.rst +++ b/docs/cli/gel_cloud/gel_cloud_secretkey/index.rst @@ -1,13 +1,9 @@ -.. _ref_cli_edgedb_cloud_secretkey: +.. _ref_cli_gel_cloud_secretkey: -====================== -edgedb cloud secretkey -====================== - -.. note:: - - These CLI commands require CLI version 3.0 or later. +=================== +gel cloud secretkey +=================== Manage your secret keys @@ -22,14 +18,14 @@ Manage your secret keys .. list-table:: :class: funcoptable - * - :ref:`ref_cli_edgedb_cloud_secretkey_create` + * - :ref:`ref_cli_gel_cloud_secretkey_create` - Create a new secret key - * - :ref:`ref_cli_edgedb_cloud_secretkey_list` + * - :ref:`ref_cli_gel_cloud_secretkey_list` - List existing secret keys - * - :ref:`ref_cli_edgedb_cloud_secretkey_revoke` + * - :ref:`ref_cli_gel_cloud_secretkey_revoke` - Revoke a secret key .. note:: These commands work only if you have already authenticated using - :ref:`ref_cli_edgedb_cloud_login`. + :ref:`ref_cli_gel_cloud_login`. diff --git a/docs/cli/gel_cloud/index.rst b/docs/cli/gel_cloud/index.rst new file mode 100644 index 00000000000..f8fd8d7708b --- /dev/null +++ b/docs/cli/gel_cloud/index.rst @@ -0,0 +1,41 @@ +.. _ref_cli_gel_cloud: + + +========= +gel cloud +========= + + +In addition to managing your own local and remote instances, the |Gel| CLI +offers tools to manage your instances running on our Gel Cloud. + +.. toctree:: + :maxdepth: 3 + :hidden: + + gel_cloud_login + gel_cloud_logout + gel_cloud_secretkey/index + +.. list-table:: + :class: funcoptable + + * - :ref:`ref_cli_gel_cloud_login` + - Authenticate to the |Gel| Cloud and remember the access token locally + * - :ref:`ref_cli_gel_cloud_logout` + - Forget the stored access token + * - :ref:`ref_cli_gel_cloud_secretkey` + - Manage your secret keys + +.. warning:: CI users and scripters + + The :gelcmd:`cloud login` and :gelcmd:`cloud logout` commands are not + intended for use in scripting and CI. Instead, you should generate a secret + key in the |Gel| Cloud UI or by running + :ref:`ref_cli_gel_cloud_secretkey_create` and set the + :gelenv:`SECRET_KEY` environment variable to your secret key. Once this + variable is set to your secret key, logging in and out are no longer + required. + +Follow :ref:`our Gel Cloud guide ` for information on how +to use Gel Cloud. diff --git a/docs/cli/edgedb_configure.rst b/docs/cli/gel_configure.rst similarity index 72% rename from docs/cli/edgedb_configure.rst rename to docs/cli/gel_configure.rst index 5663f1457e0..f73358b114f 100644 --- a/docs/cli/edgedb_configure.rst +++ b/docs/cli/gel_configure.rst @@ -1,35 +1,35 @@ -.. _ref_cli_edgedb_configure: +.. _ref_cli_gel_configure: -================ -edgedb configure -================ +============= +gel configure +============= -Configure the EdgeDB server. +Configure the |Gel| server. .. cli:synopsis:: - edgedb configure [] \ + gel configure [] \ [ ] \ [ --= ...] Description =========== -``edgedb configure`` is a terminal command used to alter the -configuration of an EdgeDB instance. There are three types of +:gelcmd:`configure` is a terminal command used to alter the +configuration of a |Gel| instance. There are three types of configuration actions that can be performed. Actions ======= -:cli:synopsis:`edgedb configure insert` +:cli:synopsis:`gel configure insert` Insert a new configuration entry for a setting that supports multiple configuration objects (e.g. Auth or Port). -:cli:synopsis:`edgedb configure set` +:cli:synopsis:`gel configure set` Set a scalar configuration value. -:cli:synopsis:`edgedb configure reset` +:cli:synopsis:`gel configure reset` Reset an existing configuration entry or remove all values for an entry that supports multiple configuration objects. @@ -41,7 +41,7 @@ Most of the options are the same across all of the different configuration actions. :cli:synopsis:`` - See :ref:`connection options `. + See :ref:`connection options `. :cli:synopsis:`` The name of a primitive configuration parameter. Available diff --git a/docs/cli/edgedb_connopts.rst b/docs/cli/gel_connopts.rst similarity index 65% rename from docs/cli/edgedb_connopts.rst rename to docs/cli/gel_connopts.rst index af0b0c9a5ec..715569c9e23 100644 --- a/docs/cli/edgedb_connopts.rst +++ b/docs/cli/gel_connopts.rst @@ -1,10 +1,10 @@ -.. _ref_cli_edgedb_connopts: +.. _ref_cli_gel_connopts: ================ Connection flags ================ -The ``edgedb`` CLI supports a standard set of connection flags used to specify +The |gelcmd| CLI supports a standard set of connection flags used to specify the *target* of a given command. The CLI always respects any connection parameters passed explicitly using flags. @@ -24,17 +24,18 @@ Connection flags :cli:synopsis:`-I , --instance=` Specifies the named instance to connect to. The actual connection parameters for local and self-hosted instances are stored in - ``/credentials`` and are usually created by - :ref:`ref_cli_edgedb_instance_create` or similar commands. Run ``edgedb - info`` to see the location of ```` on your machine. + ``/credentials`` and are usually created by + :ref:`ref_cli_gel_instance_create` or similar commands. Run + :gelcmd:`info` to see the location of ```` on your + machine. - EdgeDB Cloud instance names are in the format + |Gel| Cloud instance names are in the format ``/``. This option overrides host and port. :cli:synopsis:`--dsn=` - Specifies the DSN for EdgeDB to connect to. + Specifies the DSN for |Gel| to connect to. This option overrides all other options except password. @@ -43,15 +44,15 @@ Connection flags :cli:synopsis:`-H , --host=` Specifies the host name of the machine on which the server is running. - Defaults to the value of the ``EDGEDB_HOST`` environment variable. + Defaults to the value of the :gelenv:`HOST` environment variable. :cli:synopsis:`-P , --port=` Specifies the TCP port on which the server is listening for connections. - Defaults to the value of the ``EDGEDB_PORT`` environment variable or, + Defaults to the value of the :gelenv:`PORT` environment variable or, if not set, to ``5656``. :cli:synopsis:`--unix-path /path/to/socket` - Specifies a path to a Unix socket for an EdgeDB connection. If the path is + Specifies a path to a Unix socket for a |Gel| connection. If the path is a directory, the actual path will be computed using the ``port`` and ``admin`` parameters. @@ -61,33 +62,32 @@ Connection flags :cli:synopsis:`-u , --user=` Connect to the database as the user :cli:synopsis:``. - Defaults to the value of the ``EDGEDB_USER`` environment variable, or, - if not set, ``edgedb``. + Defaults to the value of the :gelenv:`USER` environment variable, or, + if not set, |admin|. -:cli:synopsis:`-d , --database=` - Specifies the name of the database to connect to. Defaults to the value of - the ``EDGEDB_DATABASE`` environment variable. If that variable isn't set, - local instances will default to ``edgedb`` while remote instances will - default to the name provided when the link was created. This also includes - EdgeDB Cloud instance links created via :ref:`ref_cli_edgedb_project_init`. +:cli:synopsis:`-b , --branch=` + Specifies the name of the branch to connect to. Defaults to the value of + the :gelenv:`BRANCH` environment variable. If that variable isn't set, + local instances will default to the most recently switched branch or the + |main| branch, while remote instances will default to the name provided + when the link was created. This also includes |Gel| Cloud instance links + created via :ref:`ref_cli_gel_project_init`. .. note:: + Prior to |EdgeDB| 5, branches were called databases. - With EdgeDB 5, databases were refactored as branches. If you're using - EdgeDB 5+, use the option below instead of this one. + The name of the database could be specified using either: + + * flags ``-d , --database=``, + * or the :gelenv:`DATABASE` environment variable. + + Gel supports those options for backwards compatibility. -:cli:synopsis:`-b , --branch=` - Specifies the name of the branch to connect to. Defaults to the value of - the ``EDGEDB_BRANCH`` environment variable. If that variable isn't set, - local instances will default to the most recently switched branch or the - ``main`` branch, while remote instances will default to the name provided - when the link was created. This also includes EdgeDB Cloud instance links - created via :ref:`ref_cli_edgedb_project_init`. :cli:synopsis:`--password | --no-password` - If :cli:synopsis:`--password` is specified, force ``edgedb`` to prompt + If :cli:synopsis:`--password` is specified, force |gelcmd| to prompt for a password before connecting to the database. This is usually not - necessary, since ``edgedb`` will prompt for a password automatically + necessary, since |gelcmd| will prompt for a password automatically if the server requires it. Specifying :cli:synopsis:`--no-password` disables all password prompts. @@ -123,18 +123,18 @@ Connection flags Disable all TLS security measures. :cli:synopsis:`--secret-key ` - Specifies the secret key to use for authentication with EdgeDB Cloud - instances. This is not required when connecting to your own EdgeDB Cloud - instance if you have logged in with :ref:`ref_cli_edgedb_cloud_login`. + Specifies the secret key to use for authentication with |Gel| Cloud + instances. This is not required when connecting to your own Gel Cloud + instance if you have logged in with :ref:`ref_cli_gel_cloud_login`. :cli:synopsis:`--wait-until-available=` - In case EdgeDB connection can't be established, keep retrying up + In case |Gel| connection can't be established, keep retrying up to :cli:synopsis:`` (e.g. ``30s``). The :cli:synopsis:`` value must be given using time units (e.g. ``hr``, ``min``, ``sec``, ``ms``, etc.). :cli:synopsis:`--connect-timeout=` - Specifies a :cli:synopsis:`` period. In the event EdgeDB doesn't + Specifies a :cli:synopsis:`` period. In the event |Gel| doesn't respond in this period, the command will fail (or retry if :cli:synopsis:`--wait-until-available` is also specified). The :cli:synopsis:`` value must be given using time units (e.g. diff --git a/docs/cli/gel_database/gel_database_create.rst b/docs/cli/gel_database/gel_database_create.rst new file mode 100644 index 00000000000..c796f39490b --- /dev/null +++ b/docs/cli/gel_database/gel_database_create.rst @@ -0,0 +1,42 @@ +.. _ref_cli_gel_database_create: + + +=================== +gel database create +=================== + +.. warning:: + + This command is deprecated in |Gel|. + Use :ref:`ref_cli_gel_branch_create` instead. + +Create a new :ref:`database `. + +.. cli:synopsis:: + + gel database create [] + +.. note:: + + |EdgeDB| 5.0 introduced :ref:`branches ` to + replace databases. This command works on instances running versions + prior to |EdgeDB| 5.0. If you are running a newer version of + Gel, you will instead use :ref:`ref_cli_gel_branch_create`. + + +Description +=========== + +:gelcmd:`database create` is a terminal command equivalent to +:eql:stmt:`create database`. + + +Options +======= + +The ``database create`` command runs in the |Gel| instance it is +connected to. For specifying the connection target see +:ref:`connection options `. + +:cli:synopsis:`` + The name of the new database. diff --git a/docs/cli/gel_database/gel_database_drop.rst b/docs/cli/gel_database/gel_database_drop.rst new file mode 100644 index 00000000000..edde6e8b0f2 --- /dev/null +++ b/docs/cli/gel_database/gel_database_drop.rst @@ -0,0 +1,44 @@ +.. _ref_cli_gel_database_drop: + + +================= +gel database drop +================= + +.. warning:: + + This command is deprecated in |Gel|. + Use :ref:`ref_cli_gel_branch_drop` instead. + +Drop a :ref:`database `. + +.. cli:synopsis:: + + gel database drop [] + +.. note:: + + |EdgeDB| 5.0 introduced :ref:`branches ` to + replace databases. This command works on instances running versions + prior to |EdgeDB| 5.0. If you are running a newer version of + Gel, you will instead use :ref:`ref_cli_gel_branch_drop`. + + +Description +=========== + +:gelcmd:`database drop` is a terminal command equivalent to +:eql:stmt:`drop database`. + + +Options +======= + +The ``database drop`` command runs in the Gel instance it is +connected to. For specifying the connection target see +:ref:`connection options `. + +:cli:synopsis:`` + The name of the database to drop. +:cli:synopsis:`--non-interactive` + Drop the database without asking for confirmation. diff --git a/docs/cli/gel_database/gel_database_wipe.rst b/docs/cli/gel_database/gel_database_wipe.rst new file mode 100644 index 00000000000..d532bc4d654 --- /dev/null +++ b/docs/cli/gel_database/gel_database_wipe.rst @@ -0,0 +1,47 @@ +.. _ref_cli_gel_database_wipe: + + +================= +gel database wipe +================= + +.. warning:: + + This command is deprecated in |Gel|. + Use :ref:`ref_cli_gel_branch_wipe` instead. + +Destroy the contents of a :ref:`database ` + +.. cli:synopsis:: + + gel database wipe [] + +.. note:: + + |EdgeDB| 5.0 introduced :ref:`branches ` to + replace databases. This command works on instances running versions + prior to |EdgeDB| 5.0. If you are running a newer version of + |EdgeDB| or Gel, you will instead use :ref:`ref_cli_gel_branch_wipe`. + + +Description +=========== + +:gelcmd:`database wipe` is a terminal command equivalent to +:eql:stmt:`reset schema to initial`. + +The database wiped will be one of these values: the value passed for the +``--database``/``-d`` option, the value of :gelenv:`DATABASE`, or |main|. +The contents of the database will be destroyed and the schema reset to its +state before any migrations, but the database itself will be preserved. + + +Options +======= + +The ``database wipe`` command runs in the |Gel| instance it is +connected to. For specifying the connection target see +:ref:`connection options `. + +:cli:synopsis:`--non-interactive` + Destroy the data without asking for confirmation. diff --git a/docs/cli/gel_database/index.rst b/docs/cli/gel_database/index.rst new file mode 100644 index 00000000000..71bd295816c --- /dev/null +++ b/docs/cli/gel_database/index.rst @@ -0,0 +1,35 @@ +.. _ref_cli_gel_database: + + +============ +gel database +============ + +The :gelcmd:`database` group of commands contains various database +manipulation tools. + +.. note:: + + |EdgeDB| 5.0 introduced :ref:`branches ` to + replace databases. These commands work on instances running versions + prior to |EdgeDB| 5.0. If you are running a newer version of + Gel, you will instead use the :ref:`ref_cli_gel_branch` suite of + commands. + +.. toctree:: + :maxdepth: 3 + :hidden: + + gel_database_create + gel_database_drop + gel_database_wipe + +.. list-table:: + :class: funcoptable + + * - :ref:`ref_cli_gel_database_create` + - Create a new database + * - :ref:`ref_cli_gel_database_drop` + - Drop a database + * - :ref:`ref_cli_gel_database_wipe` + - Destroy the contents of a database diff --git a/docs/cli/edgedb_describe/edgedb_describe_object.rst b/docs/cli/gel_describe/gel_describe_object.rst similarity index 72% rename from docs/cli/edgedb_describe/edgedb_describe_object.rst rename to docs/cli/gel_describe/gel_describe_object.rst index 4c7c11621bd..888ab657209 100644 --- a/docs/cli/edgedb_describe/edgedb_describe_object.rst +++ b/docs/cli/gel_describe/gel_describe_object.rst @@ -1,21 +1,21 @@ -.. _ref_cli_edgedb_describe_object: +.. _ref_cli_gel_describe_object: -====================== -edgedb describe object -====================== +=================== +gel describe object +=================== Describe a named schema object. .. cli:synopsis:: - edgedb describe object [] + gel describe object [] Description =========== -``edgedb describe`` is a terminal command equivalent to +:gelcmd:`describe` is a terminal command equivalent to :eql:stmt:`describe object ` introspection command. @@ -24,7 +24,7 @@ Options The ``describe`` command runs in the database it is connected to. For specifying the connection target see :ref:`connection options -`. +`. :cli:synopsis:`--verbose` This is equivalent to running :eql:stmt:`describe object ... as diff --git a/docs/cli/edgedb_describe/edgedb_describe_schema.rst b/docs/cli/gel_describe/gel_describe_schema.rst similarity index 61% rename from docs/cli/edgedb_describe/edgedb_describe_schema.rst rename to docs/cli/gel_describe/gel_describe_schema.rst index 37f2aa9d1b1..cde9032a914 100644 --- a/docs/cli/edgedb_describe/edgedb_describe_schema.rst +++ b/docs/cli/gel_describe/gel_describe_schema.rst @@ -1,22 +1,22 @@ -.. _ref_cli_edgedb_describe_schema: +.. _ref_cli_gel_describe_schema: -====================== -edgedb describe schema -====================== +=================== +gel describe schema +=================== Give an :ref:`SDL ` description of the schema of the database specified by the connection options. .. cli:synopsis:: - edgedb describe schema [] + gel describe schema [] Description =========== -``edgedb describe schema`` is a terminal command equivalent to +:gelcmd:`describe schema` is a terminal command equivalent to :eql:stmt:`describe schema as sdl ` introspection command. @@ -25,4 +25,4 @@ Options The ``describe`` command runs in the database it is connected to. For specifying the connection target see :ref:`connection options -`. +`. diff --git a/docs/cli/gel_describe/index.rst b/docs/cli/gel_describe/index.rst new file mode 100644 index 00000000000..1ad9f459ca2 --- /dev/null +++ b/docs/cli/gel_describe/index.rst @@ -0,0 +1,24 @@ +.. _ref_cli_gel_describe: + + +============ +gel describe +============ + +The :gelcmd:`describe` group of commands contains various schema +introspection tools. + +.. toctree:: + :maxdepth: 3 + :hidden: + + gel_describe_object + gel_describe_schema + +.. list-table:: + :class: funcoptable + + * - :ref:`ref_cli_gel_describe_object` + - Describe a named schema object + * - :ref:`ref_cli_gel_describe_schema` + - Describe schema of the current database |branch| diff --git a/docs/cli/edgedb_dump.rst b/docs/cli/gel_dump.rst similarity index 61% rename from docs/cli/edgedb_dump.rst rename to docs/cli/gel_dump.rst index e1e1d2e894f..5199e2fdcfc 100644 --- a/docs/cli/edgedb_dump.rst +++ b/docs/cli/gel_dump.rst @@ -1,30 +1,29 @@ -.. _ref_cli_edgedb_dump: +.. _ref_cli_gel_dump: -=========== -edgedb dump -=========== +======== +gel dump +======== -Backup an EdgeDB branch (or database pre-v5) to a file. +Backup a |Gel| |branch| to a file. .. cli:synopsis:: - edgedb dump [] + gel dump [] Options ======= -The ``dump`` command creates a backup of the currently active database branch -or, in pre-v5 instances, the currently connected database. +The ``dump`` command creates a backup of the currently active database |branch|. For specifying the connection target see :ref:`connection options -`. +`. :cli:synopsis:`` The name of the file to backup the database branch into. :cli:synopsis:`--all` - Dump all branches (databases pre-v5) and the server configuration using the + Dump all |branches| and the server configuration using the directory specified by the :cli:synopsis:``. :cli:synopsis:`--format=` diff --git a/docs/cli/edgedb_info.rst b/docs/cli/gel_info.rst similarity index 53% rename from docs/cli/edgedb_info.rst rename to docs/cli/gel_info.rst index 06387d68204..055e2074f20 100644 --- a/docs/cli/edgedb_info.rst +++ b/docs/cli/gel_info.rst @@ -1,31 +1,31 @@ -.. _ref_cli_edgedb_info: +.. _ref_cli_gel_info: -=========== -edgedb info -=========== +======== +gel info +======== -Display information about the EdgeDB installation. Currently this command -displays the filesystem paths used by EdgeDB. +Display information about the |Gel| installation. Currently this command +displays the filesystem paths used by Gel. .. cli:synopsis:: - edgedb info [] + gel info [] -.. _ref_cli_edgedb_paths: +.. _ref_cli_gel_paths: Paths ----- -EdgeDB uses several directories, each storing different kinds of information. +|Gel| uses several directories, each storing different kinds of information. The exact path to these directories is determined by your operating system. -Throughout the documentation, these paths are referred to as "EdgeDB config -directory", "EdgeDB data directory", etc. +Throughout the documentation, these paths are referred to as "Gel config +directory", "Gel data directory", etc. - **Config**: contains auto-generated credentials for all local instances and project metadata. -- **Data**: contains the *contents* of all local EdgeDB instances. +- **Data**: contains the *contents* of all local Gel instances. - **CLI Binary**: contains the CLI binary, if installed. - **Service**: the home for running processes/daemons. - **Cache**: a catchall for logs and various caches. diff --git a/docs/cli/edgedb_instance/edgedb_instance_create.rst b/docs/cli/gel_instance/gel_instance_create.rst similarity index 60% rename from docs/cli/edgedb_instance/edgedb_instance_create.rst rename to docs/cli/gel_instance/gel_instance_create.rst index 9929c432e58..a82c6d77ff6 100644 --- a/docs/cli/edgedb_instance/edgedb_instance_create.rst +++ b/docs/cli/gel_instance/gel_instance_create.rst @@ -1,42 +1,38 @@ -.. _ref_cli_edgedb_instance_create: +.. _ref_cli_gel_instance_create: -====================== -edgedb instance create -====================== +=================== +gel instance create +=================== -Initialize a new EdgeDB instance. +Initialize a new |Gel| instance. .. cli:synopsis:: - edgedb instance create [] [] [] + gel instance create [] [] [] Description =========== -``edgedb instance create`` is a terminal command for making a new EdgeDB +:gelcmd:`instance create` is a terminal command for making a new Gel instance and creating a corresponding credentials file in -``/credentials``. Run ``edgedb info`` to see the path to -```` on your machine. +``/credentials``. Run :gelcmd:`info` to see the path to +```` on your machine. .. note:: - The ``edgedb instance create`` command is not intended for use with + The :gelcmd:`instance create` command is not intended for use with self-hosted instances. You can follow one of our :ref:`deployment guides ` for information on how to create one of these instances. -EdgeDB Cloud ------------- +Gel Cloud +--------- -.. note:: - - Creating a Cloud instance requires CLI version 3.0 or later. - -EdgeDB Cloud users may use this command to create a Cloud instance after -logging in using :ref:`ref_cli_edgedb_cloud_login`. +Gel Cloud users may use this command to create a Cloud instance after +logging in using :ref:`ref_cli_gel_cloud_login`. To create a Cloud instance, your instance name should be in the format ``/``. Cloud instance names may contain alphanumeric @@ -44,7 +40,7 @@ characters and hyphens (i.e., ``-``). .. note:: - Please be aware of the following restrictions on EdgeDB Cloud instance + Please be aware of the following restrictions on |Gel| Cloud instance names: * can contain only Latin alpha-numeric characters or ``-`` @@ -58,18 +54,19 @@ Options ======= :cli:synopsis:`` - The new EdgeDB instance name. Asked interactively if not specified. + The new |Gel| instance name. Asked interactively if not specified. :cli:synopsis:`` - The default branch (or database pre-v5) name on the new instance. Defaults - to ``main`` or, when creating a pre-v5 instance, ``edgedb``. + The default |branch| name on the new instance. Defaults + to |main| or, when creating a pre-v5 instance, ``edgedb``. :cli:synopsis:`--nightly` Use the nightly server for this instance. :cli:synopsis:`--default-user=` Specifies the default user name (created during initialization, - and saved in credentials file). Defaults to: ``edgedb``. + and saved in credentials file). Defaults to: ``admin``, + or, when creating a pre-v6 instance, ``edgedb``. :cli:synopsis:`--port=` Specifies which port should the instance be configured on. By @@ -80,7 +77,7 @@ Options Configures how the new instance should start: ``auto`` for automatic start with the system or user session, ``manual`` to turn that off so that the instance can be manually started with - :ref:`ref_cli_edgedb_instance_start` on demand. Defaults to: + :ref:`ref_cli_gel_instance_start` on demand. Defaults to: ``auto``. :cli:synopsis:`--channel=` @@ -88,35 +85,35 @@ Options ``testing``, or ``nightly``. :cli:synopsis:`--version=` - Specifies the version of the EdgeDB server to be used to run the + Specifies the version of the |Gel| server to be used to run the new instance. To list the currently available options use - :ref:`ref_cli_edgedb_server_list_versions`. + :ref:`ref_cli_gel_server_list_versions`. By default, when you specify a version, the CLI will use the latest release in the major version specified. This command, for example, will install the - latest 2.x release: + latest X.Y release: .. code-block:: bash - $ edgedb instance create --version 2.6 demo26 + $ gel instance create --version X.0 demoxy You may pin to a specific version by prepending the version number with an - equals sign. This command will install version 2.6: + equals sign. This command will install version X.Y: .. code-block:: bash - $ edgedb instance create --version =2.6 demo26 + $ gel instance create --version =X.Y demoxy .. note:: Some shells like ZSH may require you to escape the equals sign (e.g., - ``\=2.6``) or quote the version string (e.g., ``"=2.6"``). + ``\=X.Y``) or quote the version string (e.g., ``"=X.Y"``). -EdgeDB Cloud options --------------------- +Gel Cloud options +----------------- :cli:synopsis:`--region=` - The region in which to create the instance (for EdgeDB Cloud instances). + The region in which to create the instance (for |Gel| Cloud instances). Possible values are ``aws-us-west-2``, ``aws-us-east-2``, and ``aws-eu-west-1``. @@ -125,7 +122,7 @@ EdgeDB Cloud options ``pro`` and ``free``. :cli:synopsis:`--compute-size=` - The size of compute to be allocated for the EdgeDB Cloud instance (in + The size of compute to be allocated for the Gel Cloud instance (in Compute Units) :cli:synopsis:`--storage-size=` diff --git a/docs/cli/edgedb_instance/edgedb_instance_credentials.rst b/docs/cli/gel_instance/gel_instance_credentials.rst similarity index 51% rename from docs/cli/edgedb_instance/edgedb_instance_credentials.rst rename to docs/cli/gel_instance/gel_instance_credentials.rst index 99698423215..a69133db0a2 100644 --- a/docs/cli/edgedb_instance/edgedb_instance_credentials.rst +++ b/docs/cli/gel_instance/gel_instance_credentials.rst @@ -1,22 +1,22 @@ -.. _ref_cli_edgedb_instance_credentials: +.. _ref_cli_gel_instance_credentials: -=========================== -edgedb instance credentials -=========================== +======================== +gel instance credentials +======================== Display instance credentials. .. cli:synopsis:: - edgedb instance credentials [options] [connection-options] + gel instance credentials [options] [connection-options] Description =========== -``edgedb instance credentials`` is a terminal command for displaying the -credentials of an EdgeDB instance. +:gelcmd:`instance credentials` is a terminal command for displaying the +credentials of a |Gel| instance. Options @@ -33,7 +33,7 @@ Options Connection Options ================== -By default, the ``edgedb.toml`` connection is used. +By default, the |gel.toml| connection is used. :cli:synopsis:`` - See :ref:`connection options `. + See :ref:`connection options `. diff --git a/docs/cli/gel_instance/gel_instance_destroy.rst b/docs/cli/gel_instance/gel_instance_destroy.rst new file mode 100644 index 00000000000..e02a773d43b --- /dev/null +++ b/docs/cli/gel_instance/gel_instance_destroy.rst @@ -0,0 +1,37 @@ +.. _ref_cli_gel_instance_destroy: + + +==================== +gel instance destroy +==================== + +Remove a |Gel| instance. + +.. cli:synopsis:: + + gel instance destroy [] + + +Description +=========== + +:gelcmd:`instance destroy` is a terminal command for removing an (or |gel.toml|) +instance and all its data. + +.. note:: + + The :gelcmd:`instance destroy` command is not intended for use with + self-hosted instances. + + +Options +======= + +:cli:synopsis:`` + The |Gel| instance name. + +:cli:synopsis:`--force` + Destroy the instance even if it is referred to by a project. + +:cli:synopsis:`-v, --verbose` + Verbose output. diff --git a/docs/cli/edgedb_instance/edgedb_instance_link.rst b/docs/cli/gel_instance/gel_instance_link.rst similarity index 61% rename from docs/cli/edgedb_instance/edgedb_instance_link.rst rename to docs/cli/gel_instance/gel_instance_link.rst index 20e8456b370..10fd188b655 100644 --- a/docs/cli/edgedb_instance/edgedb_instance_link.rst +++ b/docs/cli/gel_instance/gel_instance_link.rst @@ -1,41 +1,41 @@ -.. _ref_cli_edgedb_instance_link: +.. _ref_cli_gel_instance_link: -==================== -edgedb instance link -==================== +================= +gel instance link +================= -Authenticate a connection to a remote EdgeDB instance and assign an +Authenticate a connection to a remote |Gel| instance and assign an instance name to simplify future connections. .. cli:synopsis:: - edgedb instance link [] + gel instance link [] Description =========== -``edgedb instance link`` is a terminal command used to bind a set of +:gelcmd:`instance link` is a terminal command used to bind a set of connection credentials to an instance name. This is typically used as -a way to simplify connecting to remote EdgeDB database instances. +a way to simplify connecting to remote |Gel| database instances. Usually there's no need to do this for local instances as -:ref:`ref_cli_edgedb_project_init` will already set up a named +:ref:`ref_cli_gel_project_init` will already set up a named instance. .. note:: - Unlike other ``edgedb instance`` sub-commands, ``edgedb instance link`` is + Unlike other :gelcmd:`instance` sub-commands, :gelcmd:`instance link` is recommended to link self-hosted instances. This can make other operations like migrations, dumps, and restores more convenient. - Linking is not required for EdgeDB Cloud instances. They can always be + Linking is not required for |Gel| Cloud instances. They can always be accessed via CLI using ``/``. Options ======= The ``instance link`` command uses the standard :ref:`connection -options ` for specifying the instance to be +options ` for specifying the instance to be linked. :cli:synopsis:`` diff --git a/docs/cli/gel_instance/gel_instance_list.rst b/docs/cli/gel_instance/gel_instance_list.rst new file mode 100644 index 00000000000..f5985ad40c2 --- /dev/null +++ b/docs/cli/gel_instance/gel_instance_list.rst @@ -0,0 +1,30 @@ +.. _ref_cli_gel_instance_list: + + +================= +gel instance list +================= + +Show all |Gel| instances. + +.. cli:synopsis:: + + gel instance list [] + + +Description +=========== + +:gelcmd:`instance list` is a terminal command that shows all the +registered |Gel| instances and some relevant information about them +(status, port, etc.). + + +Options +======= + +:cli:synopsis:`--extended` + Output more debug info about each instance. + +:cli:synopsis:`-j, --json` + Output in JSON format. diff --git a/docs/cli/gel_instance/gel_instance_logs.rst b/docs/cli/gel_instance/gel_instance_logs.rst new file mode 100644 index 00000000000..8252cf28d01 --- /dev/null +++ b/docs/cli/gel_instance/gel_instance_logs.rst @@ -0,0 +1,37 @@ +.. _ref_cli_gel_instance_logs: + + +================= +gel instance logs +================= + +Show instance logs. + +.. cli:synopsis:: + + gel instance logs [] + + +Description +=========== + +:gelcmd:`instance logs` is a terminal command for displaying the logs +for a given |Gel| instance. + +.. note:: + + The :gelcmd:`instance logs` command is not intended for use with + self-hosted instances. + + +Options +======= + +:cli:synopsis:`` + The name of the |Gel| instance. + +:cli:synopsis:`-n, --tail=` + Number of the most recent lines to show. + +:cli:synopsis:`-f, --follow` + Show log's tail and the continue watching for the new entries. diff --git a/docs/cli/edgedb_instance/edgedb_instance_reset_password.rst b/docs/cli/gel_instance/gel_instance_reset_password.rst similarity index 63% rename from docs/cli/edgedb_instance/edgedb_instance_reset_password.rst rename to docs/cli/gel_instance/gel_instance_reset_password.rst index d9562b5ebc0..7efe1ff5827 100644 --- a/docs/cli/edgedb_instance/edgedb_instance_reset_password.rst +++ b/docs/cli/gel_instance/gel_instance_reset_password.rst @@ -1,26 +1,26 @@ -.. _ref_cli_edgedb_instance_reset_auth: +.. _ref_cli_gel_instance_reset_auth: -============================== -edgedb instance reset-password -============================== +=========================== +gel instance reset-password +=========================== -Reset password for a user in the EdgeDB instance. +Reset password for a user in the |Gel| instance. .. cli:synopsis:: - edgedb instance reset-password [] + gel instance reset-password [] Description =========== -``edgedb instance reset-password`` is a terminal command for resetting -or updating the password for a user of an EdgeDB instance. +:gelcmd:`instance reset-password` is a terminal command for resetting +or updating the password for a user of a |Gel| instance. .. note:: - The ``edgedb instance reset-password`` command is not intended for use with + The :gelcmd:`instance reset-password` command is not intended for use with self-hosted instances. @@ -28,7 +28,7 @@ Options ======= :cli:synopsis:`` - The name of the EdgeDB instance. + The name of the |Gel| instance. :cli:synopsis:`--user=` User to change password for. Defaults to the user in the diff --git a/docs/cli/gel_instance/gel_instance_restart.rst b/docs/cli/gel_instance/gel_instance_restart.rst new file mode 100644 index 00000000000..d9062e72e7c --- /dev/null +++ b/docs/cli/gel_instance/gel_instance_restart.rst @@ -0,0 +1,31 @@ +.. _ref_cli_gel_instance_restart: + + +==================== +gel instance restart +==================== + +Restart a |Gel| instance. + +.. cli:synopsis:: + + gel instance restart + + +Description +=========== + +:gelcmd:`instance restart` is a terminal command for restarting an +|Gel| instance. + +.. note:: + + The :gelcmd:`instance restart` command is not intended for use with + self-hosted instances. + + +Options +======= + +:cli:synopsis:`` + The |Gel| instance name. diff --git a/docs/cli/gel_instance/gel_instance_revert.rst b/docs/cli/gel_instance/gel_instance_revert.rst new file mode 100644 index 00000000000..26aa936cc1b --- /dev/null +++ b/docs/cli/gel_instance/gel_instance_revert.rst @@ -0,0 +1,40 @@ +.. _ref_cli_gel_instance_revert: + + +=================== +gel instance revert +=================== + +Revert a major instance upgrade. + +.. cli:synopsis:: + + gel instance revert [] + + +Description +=========== + +When :ref:`ref_cli_gel_instance_upgrade` performs a major version +upgrade on an instance the old instance data is kept around. The +:gelcmd:`instance revert` command removes the new instance version and +replaces it with the old copy. It also ensures that the previous +version of |Gel| server is used to run it. + +.. note:: + + The :gelcmd:`instance revert` command is not intended for use with + self-hosted instances. + + +Options +======= + +:cli:synopsis:`` + The name of the |Gel| instance to revert. + +:cli:synopsis:`--ignore-pid-check` + Do not check if upgrade is in progress. + +:cli:synopsis:`-y, --no-confirm` + Do not ask for a confirmation. diff --git a/docs/cli/gel_instance/gel_instance_start.rst b/docs/cli/gel_instance/gel_instance_start.rst new file mode 100644 index 00000000000..c0420474bb3 --- /dev/null +++ b/docs/cli/gel_instance/gel_instance_start.rst @@ -0,0 +1,36 @@ +.. _ref_cli_gel_instance_start: + + +================== +gel instance start +================== + +Start a |Gel| instance. + +.. cli:synopsis:: + + gel instance start [--foreground] + + +Description +=========== + +:gelcmd:`instance start` is a terminal command for starting a new +|Gel| instance. + +.. note:: + + The :gelcmd:`instance start` command is not intended for use with + self-hosted instances. + + +Options +======= + +:cli:synopsis:`` + The |Gel| instance name. + +:cli:synopsis:`--foreground` + Start the instance in the foreground rather than using systemd to + manage the process (note you might need to stop non-foreground + instance first). diff --git a/docs/cli/edgedb_instance/edgedb_instance_status.rst b/docs/cli/gel_instance/gel_instance_status.rst similarity index 50% rename from docs/cli/edgedb_instance/edgedb_instance_status.rst rename to docs/cli/gel_instance/gel_instance_status.rst index 28ecd8b4513..3751f2e82c3 100644 --- a/docs/cli/edgedb_instance/edgedb_instance_status.rst +++ b/docs/cli/gel_instance/gel_instance_status.rst @@ -1,29 +1,29 @@ -.. _ref_cli_edgedb_instance_status: +.. _ref_cli_gel_instance_status: -====================== -edgedb instance status -====================== +=================== +gel instance status +=================== Show instance information. .. cli:synopsis:: - edgedb instance status [] [] + gel instance status [] [] Description =========== -``edgedb instance status`` is a terminal command for displaying the -information about EdgeDB instances. +:gelcmd:`instance status` is a terminal command for displaying the +information about |Gel| instances. Options ======= :cli:synopsis:`` - Show only the status of the specific EdgeDB instance. + Show only the status of the specific |Gel| instance. :cli:synopsis:`--json` Format output as JSON. diff --git a/docs/cli/gel_instance/gel_instance_stop.rst b/docs/cli/gel_instance/gel_instance_stop.rst new file mode 100644 index 00000000000..c93f0ec0884 --- /dev/null +++ b/docs/cli/gel_instance/gel_instance_stop.rst @@ -0,0 +1,32 @@ +.. _ref_cli_gel_instance_stop: + + +================= +gel instance stop +================= + +Stop a |Gel| instance. + +.. cli:synopsis:: + + gel instance stop + + +Description +=========== + +:gelcmd:`instance stop` is a terminal command for stopping a running +|Gel| instance. This is a necessary step before +:ref:`destroying ` an instance. + +.. note:: + + The :gelcmd:`instance stop` command is not intended for use with + self-hosted instances. + + +Options +======= + +:cli:synopsis:`` + The |Gel| instance name. diff --git a/docs/cli/gel_instance/gel_instance_unlink.rst b/docs/cli/gel_instance/gel_instance_unlink.rst new file mode 100644 index 00000000000..5143d0acb41 --- /dev/null +++ b/docs/cli/gel_instance/gel_instance_unlink.rst @@ -0,0 +1,26 @@ +.. _ref_cli_gel_instance_unlink: + +=================== +gel instance unlink +=================== + +Unlink from a previously linked remote Gel instance. + +.. cli:synopsis:: + + gel instance unlink + + +Description +=========== + +:gelcmd:`instance unlink` is a terminal command used to unlink a +remote instance. This removes the instance name from the list of valid +instances. + + +Options +======= + +:cli:synopsis:`` + Specifies the name of the remote instance to be unlinked. diff --git a/docs/cli/edgedb_instance/edgedb_instance_upgrade.rst b/docs/cli/gel_instance/gel_instance_upgrade.rst similarity index 62% rename from docs/cli/edgedb_instance/edgedb_instance_upgrade.rst rename to docs/cli/gel_instance/gel_instance_upgrade.rst index 7b94497a1ab..d44cd6b00df 100644 --- a/docs/cli/edgedb_instance/edgedb_instance_upgrade.rst +++ b/docs/cli/gel_instance/gel_instance_upgrade.rst @@ -1,26 +1,26 @@ -.. _ref_cli_edgedb_instance_upgrade: +.. _ref_cli_gel_instance_upgrade: -======================= -edgedb instance upgrade -======================= +==================== +gel instance upgrade +==================== -Upgrade EdgeDB instance or installation. +Upgrade |Gel| instance or installation. .. cli:synopsis:: - edgedb instance upgrade [] [] + gel instance upgrade [] [] Description =========== -This command is used to upgrade EdgeDB instances individually or in +This command is used to upgrade |Gel| instances individually or in bulk. .. note:: - The ``edgedb instance upgrade`` command is not intended for use with + The :gelcmd:`instance upgrade` command is not intended for use with self-hosted instances. @@ -28,7 +28,7 @@ Options ======= :cli:synopsis:`` - The EdgeDB instance name to upgrade. + The |Gel| instance name to upgrade. :cli:synopsis:`--force` Force upgrade process even if there is no new version. diff --git a/docs/cli/gel_instance/index.rst b/docs/cli/gel_instance/index.rst new file mode 100644 index 00000000000..f3c55b40726 --- /dev/null +++ b/docs/cli/gel_instance/index.rst @@ -0,0 +1,64 @@ +.. _ref_cli_gel_instance: + +============ +gel instance +============ + +The :gelcmd:`instance` group of commands contains all sorts of tools +for managing |Gel| instances. + +.. note:: + + Most commands in the :gelcmd:`instance` command group are not intended to + manage self-hosted instances. See individual commands for more details. + +.. toctree:: + :maxdepth: 3 + :hidden: + + gel_instance_create + gel_instance_credentials + gel_instance_destroy + gel_instance_link + gel_instance_list + gel_instance_logs + gel_instance_start + gel_instance_status + gel_instance_stop + gel_instance_reset_password + gel_instance_restart + gel_instance_revert + gel_instance_unlink + gel_instance_upgrade + +.. list-table:: + :class: funcoptable + + * - :ref:`ref_cli_gel_instance_create` + - Initialize a new server instance + * - :ref:`ref_cli_gel_instance_credentials` + - Display instance credentials + * - :ref:`ref_cli_gel_instance_destroy` + - Destroy a server instance and remove the data stored + * - :ref:`ref_cli_gel_instance_link` + - Link a remote instance + * - :ref:`ref_cli_gel_instance_list` + - Show all instances + * - :ref:`ref_cli_gel_instance_logs` + - Show logs of an instance + * - :ref:`ref_cli_gel_instance_start` + - Start an instance + * - :ref:`ref_cli_gel_instance_status` + - Show statuses of all or of a matching instance + * - :ref:`ref_cli_gel_instance_stop` + - Stop an instance + * - :ref:`ref_cli_gel_instance_reset_auth` + - Reset password for a user in the instance + * - :ref:`ref_cli_gel_instance_restart` + - Restart an instance + * - :ref:`ref_cli_gel_instance_revert` + - Revert a major instance upgrade + * - :ref:`ref_cli_gel_instance_unlink` + - Unlink a remote instance + * - :ref:`ref_cli_gel_instance_upgrade` + - Upgrade installations and instances diff --git a/docs/cli/edgedb_list.rst b/docs/cli/gel_list.rst similarity index 60% rename from docs/cli/edgedb_list.rst rename to docs/cli/gel_list.rst index 1313f30252b..63c6339a0c3 100644 --- a/docs/cli/edgedb_list.rst +++ b/docs/cli/gel_list.rst @@ -1,59 +1,57 @@ -.. _ref_cli_edgedb_list: +.. _ref_cli_gel_list: -=========== -edgedb list -=========== +======== +gel list +======== List matching database objects by name and type. .. cli:synopsis:: - edgedb list [] + gel list [] Description =========== -The ``edgedb list`` group of commands contains tools for listing +The :gelcmd:`list` group of commands contains tools for listing database objects by matching name or type. The sub-commands are organized by the type of the objects listed. Types ===== -:cli:synopsis:`edgedb list aliases` +:cli:synopsis:`gel list aliases` Display list of aliases defined in the schema. -:cli:synopsis:`edgedb list casts` +:cli:synopsis:`gel list casts` Display list of casts defined in the schema. -.. TODO: Add `edgedb list branches` once the command is added. https://github.com/edgedb/edgedb-cli/issues/1275 - -:cli:synopsis:`edgedb list databases` - Display list of databases in the server instance. +:cli:synopsis:`gel list branches` + Display list of branches. -:cli:synopsis:`edgedb list indexes` +:cli:synopsis:`gel list indexes` Display list of indexes defined in the schema. -:cli:synopsis:`edgedb list modules` +:cli:synopsis:`gel list modules` Display list of modules defined in the schema. -:cli:synopsis:`edgedb list roles` +:cli:synopsis:`gel list roles` Display list of roles in the server instance. -:cli:synopsis:`edgedb list scalars` +:cli:synopsis:`gel list scalars` Display list of scalar types defined in the schema. -:cli:synopsis:`edgedb list types` +:cli:synopsis:`gel list types` Display list of object types defined in the schema. Options ======= -The ``list`` command runs in the database it is connected to. For +The ``list`` command runs in the |branch| it is connected to. For specifying the connection target see :ref:`connection options -`. +`. :cli:synopsis:`-c, --case-sensitive` Indicates that the pattern should be treated in a case-sensitive diff --git a/docs/cli/gel_migrate.rst b/docs/cli/gel_migrate.rst new file mode 100644 index 00000000000..b8c7822816c --- /dev/null +++ b/docs/cli/gel_migrate.rst @@ -0,0 +1,18 @@ +.. _ref_cli_gel_migrate: + +=========== +gel migrate +=========== + +This command is an alias for :ref:`ref_cli_gel_migration_apply`. +Once the migration scripts are in place, the changes can be applied to the +database using this command. + +.. warning:: Gel Cloud CI users and scripters + + When scripting a ``migrate``/``migration apply`` for a |Gel| Cloud + instance, do not use :gelcmd:`login` to authenticate. Instead, you should + generate a secret key in the Gel Cloud UI or by running + :ref:`ref_cli_gel_cloud_secretkey_create` and set the + :gelenv:`SECRET_KEY` environment variable to your secret key. Once this + variable is set to your secret key, logging in is no longer required. diff --git a/docs/cli/edgedb_migration/edgedb_migration_apply.rst b/docs/cli/gel_migration/gel_migration_apply.rst similarity index 62% rename from docs/cli/edgedb_migration/edgedb_migration_apply.rst rename to docs/cli/gel_migration/gel_migration_apply.rst index 0b6a879365e..8fa1e98fd68 100644 --- a/docs/cli/edgedb_migration/edgedb_migration_apply.rst +++ b/docs/cli/gel_migration/gel_migration_apply.rst @@ -1,28 +1,28 @@ -.. _ref_cli_edgedb_migration_apply: +.. _ref_cli_gel_migration_apply: -====================== -edgedb migration apply -====================== +=================== +gel migration apply +=================== Once the migration scripts are in place the changes can be applied to the database by this command: .. cli:synopsis:: - edgedb migration apply [] + gel migration apply [] The tool will find all the unapplied migrations in ``dbschema/migrations/`` directory and sequentially run them on the target instance. -.. warning:: EdgeDB Cloud CI users and scripters +.. warning:: Gel Cloud CI users and scripters - When scripting a ``migrate``/``migration apply`` for an EdgeDB Cloud - instance, do not use ``edgedb login`` to authenticate. Instead, you should - generate a secret key in the EdgeDB Cloud UI or by running - :ref:`ref_cli_edgedb_cloud_secretkey_create` and set the - ``EDGEDB_SECRET_KEY`` environment variable to your secret key. Once this + When scripting a ``migrate``/``migration apply`` for a |Gel| Cloud + instance, do not use :gelcmd:`login` to authenticate. Instead, you should + generate a secret key in the Gel Cloud UI or by running + :ref:`ref_cli_gel_cloud_secretkey_create` and set the + :gelenv:`SECRET_KEY` environment variable to your secret key. Once this variable is set to your secret key, logging in is no longer required. Options @@ -30,7 +30,7 @@ Options The ``migration apply`` command runs on the database it is connected to. For specifying the connection target see :ref:`connection options -`. +`. :cli:synopsis:`--quiet` Do not print any messages, only indicate success by exit status. @@ -50,12 +50,7 @@ to. For specifying the connection target see :ref:`connection options revisions are applied on top. :cli:synopsis:`--dev-mode` - .. note:: - - The ``--dev-mod`` option is compatible with EdgeDB server 3.0 and - above. - Apply the current schema changes on top of the current migration history, without having created a new migration. This works the same way as - :ref:`ref_cli_edgedb_watch` but without starting a long-running watch + :ref:`ref_cli_gel_watch` but without starting a long-running watch task. diff --git a/docs/cli/edgedb_migration/edgedb_migration_create.rst b/docs/cli/gel_migration/gel_migration_create.rst similarity index 78% rename from docs/cli/edgedb_migration/edgedb_migration_create.rst rename to docs/cli/gel_migration/gel_migration_create.rst index b39440ff9db..34f0efa0c2c 100644 --- a/docs/cli/edgedb_migration/edgedb_migration_create.rst +++ b/docs/cli/gel_migration/gel_migration_create.rst @@ -1,20 +1,20 @@ -.. _ref_cli_edgedb_migration_create: +.. _ref_cli_gel_migration_create: -======================= -edgedb migration create -======================= +==================== +gel migration create +==================== The next step after setting up the desired target schema is creating a migration script. This is done by invoking the following command: .. cli:synopsis:: - edgedb migration create [] + gel migration create [] This will start an interactive tool that will provide the user with -suggestions based on the differences between the current branch (or database -for pre-v5) and the schema file. The prompts will look something like this: +suggestions based on the differences between the current |branch| +and the schema file. The prompts will look something like this: .. code-block:: @@ -35,7 +35,7 @@ Options The ``migration create`` command runs on the database it is connected to. For specifying the connection target see :ref:`connection options -`. +`. :cli:synopsis:`--non-interactive` Do not prompt user for input. By default this works only if all @@ -55,8 +55,4 @@ to. For specifying the connection target see :ref:`connection options ``./dbschema``. :cli:synopsis:`--squash` - .. note:: - - This CLI feature is compatible with EdgeDB server 3.0 and above. - Squashes all your migrations into a single migration. diff --git a/docs/cli/edgedb_migration/edgedb_migration_edit.rst b/docs/cli/gel_migration/gel_migration_edit.rst similarity index 79% rename from docs/cli/edgedb_migration/edgedb_migration_edit.rst rename to docs/cli/gel_migration/gel_migration_edit.rst index 33f9a5312a2..84ce661fc19 100644 --- a/docs/cli/edgedb_migration/edgedb_migration_edit.rst +++ b/docs/cli/gel_migration/gel_migration_edit.rst @@ -1,15 +1,15 @@ -.. _ref_cli_edgedb_migration_edit: +.. _ref_cli_gel_migration_edit: -======================= -edgedb migration edit -======================= +================== +gel migration edit +================== Edit migration file. .. cli:synopsis:: - edgedb migration edit [] + gel migration edit [] Invokes ``$EDITOR`` on the last migration file, and then fixes migration id after editor exits. Usually should be used for migrations that haven't been @@ -20,7 +20,7 @@ Options The ``migration edit`` command runs on the database it is connected to. For specifying the connection target see :ref:`connection options -`. +`. :cli:synopsis:`--schema-dir=` Directory where the schema files are located. Defaults to diff --git a/docs/cli/edgedb_migration/edgedb_migration_extract.rst b/docs/cli/gel_migration/gel_migration_extract.rst similarity index 83% rename from docs/cli/edgedb_migration/edgedb_migration_extract.rst rename to docs/cli/gel_migration/gel_migration_extract.rst index 963908e853f..2724bcbd087 100644 --- a/docs/cli/edgedb_migration/edgedb_migration_extract.rst +++ b/docs/cli/gel_migration/gel_migration_extract.rst @@ -1,13 +1,13 @@ -.. _ref_cli_edgedb_migration_extract: +.. _ref_cli_gel_migration_extract: -======================== -edgedb migration extract -======================== +===================== +gel migration extract +===================== Extract migration history from the database and write it to ``/dbschema/migrations``. Useful when a direct DDL command has been used to -change the schema and now ``edgedb migrate`` will not comply because the +change the schema and now :gelcmd:`migrate` will not comply because the database migration history is ahead of the migration history inside ``/dbschema/migrations``. @@ -19,7 +19,7 @@ Options The ``migration extract`` command runs on the database it is connected to. For specifying the connection target see :ref:`connection options -`. +`. :cli:synopsis:`--tls-server-name ` diff --git a/docs/cli/edgedb_migration/edgedb_migration_log.rst b/docs/cli/gel_migration/gel_migration_log.rst similarity index 83% rename from docs/cli/edgedb_migration/edgedb_migration_log.rst rename to docs/cli/gel_migration/gel_migration_log.rst index 92010f7640a..e48f4bac533 100644 --- a/docs/cli/edgedb_migration/edgedb_migration_log.rst +++ b/docs/cli/gel_migration/gel_migration_log.rst @@ -1,25 +1,25 @@ -.. _ref_cli_edgedb_migration_log: +.. _ref_cli_gel_migration_log: -==================== -edgedb migration log -==================== +================= +gel migration log +================= Show all migration versions. .. cli:synopsis:: - edgedb migration log [] + gel migration log [] The tool will display the migration history either by reading it from -the EdgeDB instance or from the schema directory. +the |Gel| instance or from the schema directory. Options ======= The ``migration log`` command runs on the database it is connected to. For specifying the connection target see :ref:`connection options -`. +`. :cli:synopsis:`--from-fs` Print revisions from the schema directory (no database connection diff --git a/docs/cli/edgedb_migration/edgedb_migration_status.rst b/docs/cli/gel_migration/gel_migration_status.rst similarity index 66% rename from docs/cli/edgedb_migration/edgedb_migration_status.rst rename to docs/cli/gel_migration/gel_migration_status.rst index fc3af516a3f..f736213c814 100644 --- a/docs/cli/edgedb_migration/edgedb_migration_status.rst +++ b/docs/cli/gel_migration/gel_migration_status.rst @@ -1,17 +1,17 @@ -.. _ref_cli_edgedb_migration_status: +.. _ref_cli_gel_migration_status: -======================= -edgedb migration status -======================= +==================== +gel migration status +==================== Show current migration state. .. cli:synopsis:: - edgedb migration status [] + gel migration status [] -The tool will show how the state of the schema in the EdgeDB instance +The tool will show how the state of the schema in the |Gel| instance compares to the migrations stored in the schema directory. Options @@ -19,7 +19,7 @@ Options The ``migration status`` command runs on the database it is connected to. For specifying the connection target see :ref:`connection options -`. +`. :cli:synopsis:`--quiet` Do not print any messages, only indicate success by exit status. diff --git a/docs/cli/edgedb_migration/edgedb_migration_upgrade_check.rst b/docs/cli/gel_migration/gel_migration_upgrade_check.rst similarity index 75% rename from docs/cli/edgedb_migration/edgedb_migration_upgrade_check.rst rename to docs/cli/gel_migration/gel_migration_upgrade_check.rst index 3306ff7a5c9..1c7fc686827 100644 --- a/docs/cli/edgedb_migration/edgedb_migration_upgrade_check.rst +++ b/docs/cli/gel_migration/gel_migration_upgrade_check.rst @@ -1,15 +1,15 @@ -.. _ref_cli_edgedb_migration_upgrade_check: +.. _ref_cli_gel_migration_upgrade_check: -============================== -edgedb migration upgrade-check -============================== +=========================== +gel migration upgrade-check +=========================== -Checks your schema against a different EdgeDB version. +Checks your schema against a different |Gel| version. .. cli:synopsis:: - edgedb migration upgrade-check [] + gel migration upgrade-check [] .. note:: @@ -19,7 +19,7 @@ Description =========== By default, ``upgrade-check`` checks your schema against the latest stable -release of EdgeDB. You can add ``--to-version ``, ``--to-testing``, +release of |Gel|. You can add ``--to-version ``, ``--to-testing``, ``--to-nightly``, or ``--to-channel `` to check against a specific version. @@ -28,7 +28,7 @@ Options The ``migration upgrade-check`` command runs on the database it is connected to. For specifying the connection target see :ref:`connection options -`. +`. :cli:synopsis:`--schema-dir=` diff --git a/docs/cli/gel_migration/index.rst b/docs/cli/gel_migration/index.rst new file mode 100644 index 00000000000..5a21efafd98 --- /dev/null +++ b/docs/cli/gel_migration/index.rst @@ -0,0 +1,55 @@ +.. _ref_cli_gel_migration: + + +============= +gel migration +============= + +|Gel| provides schema migration tools as server-side tools. This means that, +from the point of view of the application, migrations are language- and +platform-agnostic and don't require additional libraries. + +Using the migration tools is the recommended way to make schema changes. + +.. toctree:: + :maxdepth: 3 + :hidden: + + gel_migration_apply + gel_migration_create + gel_migration_edit + gel_migration_extract + gel_migration_log + gel_migration_status + gel_migration_upgrade_check + +Setup +===== + +First of all, the migration tools need a place to store the schema and +migration information. By default they will look in the ``dbschema`` +directory, but it's also possible to specify any other location by +using the :cli:synopsis:`schema-dir` option. + +Inside this directory, you will find an |.gel| file with an :ref:`SDL +` schema description. You may split your schema across multiple +|.gel| files. The migration tools will read all of them and treat them as a +single SDL document. + +.. list-table:: + :class: funcoptable + + * - :ref:`ref_cli_gel_migration_apply` + - Bring current |branch| to the latest or a specified revision + * - :ref:`ref_cli_gel_migration_create` + - Create a migration script + * - :ref:`ref_cli_gel_migration_edit` + - Edit migration file + * - :ref:`ref_cli_gel_migration_extract` + - Extract migration history and write it to ``/migrations``. + * - :ref:`ref_cli_gel_migration_log` + - Show all migration versions + * - :ref:`ref_cli_gel_migration_status` + - Show current migration state + * - :ref:`ref_cli_gel_migration_upgrade_check` + - Checks your schema against a different |Gel| version. diff --git a/docs/cli/edgedb_project/edgedb_project_info.rst b/docs/cli/gel_project/gel_project_info.rst similarity index 78% rename from docs/cli/edgedb_project/edgedb_project_info.rst rename to docs/cli/gel_project/gel_project_info.rst index 52deb036b68..6b34ce31825 100644 --- a/docs/cli/edgedb_project/edgedb_project_info.rst +++ b/docs/cli/gel_project/gel_project_info.rst @@ -1,15 +1,15 @@ -.. _ref_cli_edgedb_project_info: +.. _ref_cli_gel_project_info: -=================== -edgedb project info -=================== +================ +gel project info +================ Display various metadata about the project. .. cli:synopsis:: - edgedb project info [OPTIONS] + gel project info [OPTIONS] Description diff --git a/docs/cli/edgedb_project/edgedb_project_init.rst b/docs/cli/gel_project/gel_project_init.rst similarity index 68% rename from docs/cli/edgedb_project/edgedb_project_init.rst rename to docs/cli/gel_project/gel_project_init.rst index 3093ffcb6c8..5c9dacf19e7 100644 --- a/docs/cli/edgedb_project/edgedb_project_init.rst +++ b/docs/cli/gel_project/gel_project_init.rst @@ -1,46 +1,42 @@ -.. _ref_cli_edgedb_project_init: +.. _ref_cli_gel_project_init: -=================== -edgedb project init -=================== +================ +gel project init +================ Setup a new project. .. cli:synopsis:: - edgedb project init [] + gel project init [] Description =========== This command sets up a new project, creating an instance, a schema directory, -and an :ref:`edgedb.toml ` file. It can also be used +and an :ref:`gel.toml ` file. It can also be used to convert an existing directory to a project directory, connecting the existing instance to the project. Typically this tool will prompt for specific details about how the project should be setup. -EdgeDB Cloud ------------- +Gel Cloud +--------- -.. note:: - - Creating a Cloud instance requires CLI version 3.0 or later. - -EdgeDB Cloud users may use this command to create a Cloud instance after -logging in using :ref:`ref_cli_edgedb_cloud_login`. +|Gel| Cloud users may use this command to create a Cloud instance after +logging in using :ref:`ref_cli_gel_cloud_login`. To create a Cloud instance, your instance name should be in the format ``/``. Cloud instance names may contain alphanumeric characters and hyphens (i.e., ``-``). You can provide this Cloud instance name -through the interactive project initiation by running ``edgedb project init`` +through the interactive project initiation by running :gelcmd:`project init` or by providing it via the ``--server-instance`` option. .. note:: - Please be aware of the following restrictions on EdgeDB Cloud instance + Please be aware of the following restrictions on |Gel| Cloud instance names: * can contain only Latin alpha-numeric characters or ``-`` @@ -54,7 +50,7 @@ Options ======= :cli:synopsis:`--link` - Specifies whether the existing EdgeDB server instance should be + Specifies whether the existing |Gel| server instance should be linked with the project. This option is useful for initializing a copy of a project freshly @@ -77,29 +73,29 @@ Options current directory. :cli:synopsis:`--server-instance=` - Specifies the EdgeDB server instance to be associated with the + Specifies the |Gel| server instance to be associated with the project. :cli:synopsis:`--server-version=` - Specifies the EdgeDB server instance to be associated with the + Specifies the Gel server instance to be associated with the project. By default, when you specify a version, the CLI will use the latest release in the major version specified. This command, for example, will install the - latest 2.x release: + latest 6.x release: .. code-block:: bash - $ edgedb project init --server-version 2.6 + $ gel project init --server-version 6.1 You may pin to a specific version by prepending the version number with an - equals sign. This command will install version 2.6: + equals sign. This command will install version 6.1: .. code-block:: bash - $ edgedb project init --server-version =2.6 + $ gel project init --server-version =6.1 .. note:: Some shells like ZSH may require you to escape the equals sign (e.g., - ``\=2.6``) or quote the version string (e.g., ``"=2.6"``). + ``\=6.1``) or quote the version string (e.g., ``"=6.1"``). diff --git a/docs/cli/edgedb_project/edgedb_project_unlink.rst b/docs/cli/gel_project/gel_project_unlink.rst similarity index 52% rename from docs/cli/edgedb_project/edgedb_project_unlink.rst rename to docs/cli/gel_project/gel_project_unlink.rst index 8808f41d84a..229c3346919 100644 --- a/docs/cli/edgedb_project/edgedb_project_unlink.rst +++ b/docs/cli/gel_project/gel_project_unlink.rst @@ -1,23 +1,23 @@ -.. _ref_cli_edgedb_project_unlink: +.. _ref_cli_gel_project_unlink: -===================== -edgedb project unlink -===================== +================== +gel project unlink +================== -Remove association with and optionally destroy the linked EdgeDB +Remove association with and optionally destroy the linked |Gel| instance. .. cli:synopsis:: - edgedb project unlink [] + gel project unlink [] Description =========== This command unlinks the project directory from the instance. By -default the EdgeDB instance remains untouched, but it can also be +default the |Gel| instance remains untouched, but it can also be destroyed with an explicit option. @@ -25,8 +25,8 @@ Options ======= :cli:synopsis:`-D, --destroy-server-instance` - If specified, the associated EdgeDB instance is destroyed by - running :ref:`ref_cli_edgedb_instance_destroy`. + If specified, the associated |Gel| instance is destroyed by + running :ref:`ref_cli_gel_instance_destroy`. :cli:synopsis:`--non-interactive` Do not prompts user for input. diff --git a/docs/cli/edgedb_project/edgedb_project_upgrade.rst b/docs/cli/gel_project/gel_project_upgrade.rst similarity index 75% rename from docs/cli/edgedb_project/edgedb_project_upgrade.rst rename to docs/cli/gel_project/gel_project_upgrade.rst index b1c5249f983..da243a1f773 100644 --- a/docs/cli/edgedb_project/edgedb_project_upgrade.rst +++ b/docs/cli/gel_project/gel_project_upgrade.rst @@ -1,15 +1,15 @@ -.. _ref_cli_edgedb_project_upgrade: +.. _ref_cli_gel_project_upgrade: -====================== -edgedb project upgrade -====================== +=================== +gel project upgrade +=================== -Upgrade EdgeDB instance used for the current project +Upgrade |Gel| instance used for the current project .. cli:synopsis:: - edgedb project upgrade [] + gel project upgrade [] Description @@ -17,10 +17,10 @@ Description This command has two modes of operation. -1) Upgrade instance to a version specified in :ref:`ref_reference_edgedb_toml`. +1) Upgrade instance to a version specified in :ref:`ref_reference_gel_toml`. This happens when the command is invoked without any explicit target version. -2) Update ``edgedb.toml`` to a new version and upgrade the instance. +2) Update |gel.toml| to a new version and upgrade the instance. Which happens when one of the options for providing the target version is used. @@ -30,7 +30,7 @@ if upgrading from nightly to the stable version). .. note:: - The ``edgedb project upgrade`` command is not intended for use with + The :gelcmd:`project upgrade` command is not intended for use with self-hosted instances. diff --git a/docs/cli/gel_project/index.rst b/docs/cli/gel_project/index.rst new file mode 100644 index 00000000000..0c52fc2ea6f --- /dev/null +++ b/docs/cli/gel_project/index.rst @@ -0,0 +1,32 @@ +.. _ref_cli_gel_project: + + +=========== +gel project +=========== + +|Gel| provides a way to quickly setup a project. This way the project +directory gets associated with a specific Gel instance and thus +makes it the default instance to connect to. This is done by creating +an :ref:`ref_reference_gel_toml` file in the project directory. + +.. toctree:: + :maxdepth: 3 + :hidden: + + gel_project_init + gel_project_info + gel_project_unlink + gel_project_upgrade + +.. list-table:: + :class: funcoptable + + * - :ref:`ref_cli_gel_project_init` + - Initialize a new or existing project + * - :ref:`ref_cli_gel_project_info` + - Get various metadata about the project + * - :ref:`ref_cli_gel_project_unlink` + - Remove project association with an instance + * - :ref:`ref_cli_gel_project_upgrade` + - Upgrade |Gel| instance used for the current project diff --git a/docs/cli/edgedb_query.rst b/docs/cli/gel_query.rst similarity index 75% rename from docs/cli/edgedb_query.rst rename to docs/cli/gel_query.rst index cdb6ae82401..6aec383052b 100644 --- a/docs/cli/edgedb_query.rst +++ b/docs/cli/gel_query.rst @@ -1,21 +1,21 @@ -.. _ref_cli_edgedb_query: +.. _ref_cli_gel_query: -============ -edgedb query -============ +========= +gel query +========= Execute one or more EdgeQL queries. .. cli:synopsis:: - edgedb query [] ... + gel query [] ... Description =========== -``edgedb query`` is a terminal command used to execute EdgeQL queries +:gelcmd:`query` is a terminal command used to execute EdgeQL queries provided as space-separated strings. @@ -24,7 +24,7 @@ Options The ``query`` command runs on the database it is connected to. For specifying the connection target see :ref:`connection options -`. +`. :cli:synopsis:`-F, --output-format=` Output format: ``json``, ``json-pretty``, ``json-lines``, diff --git a/docs/cli/gel_restore.rst b/docs/cli/gel_restore.rst new file mode 100644 index 00000000000..97eec08ed56 --- /dev/null +++ b/docs/cli/gel_restore.rst @@ -0,0 +1,52 @@ +.. _ref_cli_gel_restore: + + +=========== +gel restore +=========== + +Restore a |Gel| |branch| from a backup file. + +.. cli:synopsis:: + + gel restore [] + + +Description +=========== + +:gelcmd:`restore` is a terminal command used to restore an Gel |branch| +|branch| from a backup file. The backup is restored to the +currently active branch. + +.. note:: + + The backup cannot be restored to a |branch| with any + existing schema. As a result, you should restore to one of these targets: + + - a new empty |branch| which can be created using + :ref:`ref_cli_gel_branch_create` with the ``--empty`` option + - a new empty |branch| if your instance is running |EdgeDB| versions + prior to 5 + - an existing |branch| that has been wiped with the appropriate + ``wipe`` command (either :ref:`ref_cli_gel_branch_wipe` or + :ref:`ref_cli_gel_database_wipe`; note that this will destroy all data + and schema currently in that branch/database) + + +Options +======= + +The ``restore`` command restores the backup file into the active |branch|. +For specifying the connection target see :ref:`connection options +`. + +:cli:synopsis:`` + The name of the backup file to restore the |branch| from. + +:cli:synopsis:`--all` + Restore all |branches| and the server configuration + using the directory specified by the :cli:synopsis:``. + +:cli:synopsis:`-v, --verbose` + Verbose output. diff --git a/docs/cli/edgedb_server/edgedb_server_info.rst b/docs/cli/gel_server/gel_server_info.rst similarity index 68% rename from docs/cli/edgedb_server/edgedb_server_info.rst rename to docs/cli/gel_server/gel_server_info.rst index 31103f96a8b..1171113f193 100644 --- a/docs/cli/edgedb_server/edgedb_server_info.rst +++ b/docs/cli/gel_server/gel_server_info.rst @@ -1,22 +1,22 @@ -.. _ref_cli_edgedb_server_info: +.. _ref_cli_gel_server_info: -================== -edgedb server info -================== +=============== +gel server info +=============== Show server information. .. cli:synopsis:: - edgedb server info [] + gel server info [] Description =========== -``edgedb server info`` is a terminal command for displaying the -information about installed EdgeDB servers. +:gelcmd:`server info` is a terminal command for displaying the +information about installed |Gel| servers. Options diff --git a/docs/cli/edgedb_server/edgedb_server_install.rst b/docs/cli/gel_server/gel_server_install.rst similarity index 52% rename from docs/cli/edgedb_server/edgedb_server_install.rst rename to docs/cli/gel_server/gel_server_install.rst index 7af813f9ad8..5b40e07cf14 100644 --- a/docs/cli/edgedb_server/edgedb_server_install.rst +++ b/docs/cli/gel_server/gel_server_install.rst @@ -1,22 +1,22 @@ -.. _ref_cli_edgedb_server_install: +.. _ref_cli_gel_server_install: -===================== -edgedb server install -===================== +================== +gel server install +================== -Install EdgeDB server. +Install |Gel| server. .. cli:synopsis:: - edgedb server install [] + gel server install [] Description =========== -``edgedb server install`` is a terminal command for installing a -specific EdgeDB server version. +:gelcmd:`server install` is a terminal command for installing a +specific |Gel| server version. Options @@ -24,7 +24,7 @@ Options :cli:synopsis:`-i, --interactive` Performs the installation in interactive mode, similar to how - :ref:`downloading and installing ` works. + :ref:`downloading and installing ` works. :cli:synopsis:`--nightly` Installs the nightly server version. diff --git a/docs/cli/edgedb_server/edgedb_server_list_versions.rst b/docs/cli/gel_server/gel_server_list_versions.rst similarity index 52% rename from docs/cli/edgedb_server/edgedb_server_list_versions.rst rename to docs/cli/gel_server/gel_server_list_versions.rst index 40a17f1c5ba..79824d65658 100644 --- a/docs/cli/edgedb_server/edgedb_server_list_versions.rst +++ b/docs/cli/gel_server/gel_server_list_versions.rst @@ -1,22 +1,22 @@ -.. _ref_cli_edgedb_server_list_versions: +.. _ref_cli_gel_server_list_versions: -=========================== -edgedb server list-versions -=========================== +======================== +gel server list-versions +======================== -List available and installed versions of the EdgeDB server. +List available and installed versions of the |Gel| server. .. cli:synopsis:: - edgedb server list-versions [] + gel server list-versions [] Description =========== -``edgedb server list-versions`` is a terminal command for displaying -all the available EdgeDB server versions along with indicating whether +:gelcmd:`server list-versions` is a terminal command for displaying +all the available |Gel| server versions along with indicating whether or not and how they are currently installed. diff --git a/docs/cli/edgedb_server/edgedb_server_uninstall.rst b/docs/cli/gel_server/gel_server_uninstall.rst similarity index 61% rename from docs/cli/edgedb_server/edgedb_server_uninstall.rst rename to docs/cli/gel_server/gel_server_uninstall.rst index 4571e3814f2..9b33f02d3ba 100644 --- a/docs/cli/edgedb_server/edgedb_server_uninstall.rst +++ b/docs/cli/gel_server/gel_server_uninstall.rst @@ -1,22 +1,22 @@ -.. _ref_cli_edgedb_server_uninstall: +.. _ref_cli_gel_server_uninstall: -======================= -edgedb server uninstall -======================= +==================== +gel server uninstall +==================== -Uninstall EdgeDB server. +Uninstall |Gel| server. .. cli:synopsis:: - edgedb server uninstall [] + gel server uninstall [] Description =========== -``edgedb server uninstall`` is a terminal command for removing a -specific EdgeDB server version from your system. +:gelcmd:`server uninstall` is a terminal command for removing a +specific |Gel| server version from your system. Options diff --git a/docs/cli/gel_server/index.rst b/docs/cli/gel_server/index.rst new file mode 100644 index 00000000000..74544411e80 --- /dev/null +++ b/docs/cli/gel_server/index.rst @@ -0,0 +1,29 @@ +.. _ref_cli_gel_server: + +========== +gel server +========== + +The :gelcmd:`server` group of commands contains all sorts of tools +for managing |Gel| server versions. + +.. toctree:: + :maxdepth: 3 + :hidden: + + gel_server_info + gel_server_install + gel_server_list_versions + gel_server_uninstall + +.. list-table:: + :class: funcoptable + + * - :ref:`ref_cli_gel_server_info` + - Show server information + * - :ref:`ref_cli_gel_server_install` + - Install |Gel| server + * - :ref:`ref_cli_gel_server_list_versions` + - List available and installed versions of the server + * - :ref:`ref_cli_gel_server_uninstall` + - Uninstall |Gel| server diff --git a/docs/cli/edgedb_ui.rst b/docs/cli/gel_ui.rst similarity index 50% rename from docs/cli/edgedb_ui.rst rename to docs/cli/gel_ui.rst index d063244f42c..2bd80fcab06 100644 --- a/docs/cli/edgedb_ui.rst +++ b/docs/cli/gel_ui.rst @@ -1,46 +1,46 @@ -.. _ref_cli_edgedb_ui: +.. _ref_cli_gel_ui: -========= -edgedb ui -========= +====== +gel ui +====== -Open the EdgeDB UI of the current instance in your default browser. +Open the |Gel| UI of the current instance in your default browser. .. cli:synopsis:: - edgedb ui [] + gel ui [] Description =========== -``edgedb ui`` is a terminal command used to open the EdgeDB UI in your default +:gelcmd:`ui` is a terminal command used to open the |Gel| UI in your default browser. Alternatively, it can be used to print the UI URL with the ``--print-url`` option. -The EdgeDB UI is a tool that allows you to graphically manage and query your -EdgeDB databases. It contains a REPL, a textual and graphical view of your +The Gel UI is a tool that allows you to graphically manage and query your +Gel database. It contains a REPL, a textual and graphical view of your database schemas, and a data explorer which allows for viewing your data as a table. .. note:: The UI is served by default by development instances. To enable the UI on a - production instance, use the ``--admin-ui`` option with ``edgedb-server`` - or set the ``EDGEDB_SERVER_ADMIN_UI`` :ref:`environment variable + production instance, use the ``--admin-ui`` option with |gel-server| + or set the :gelenv:`SERVER_ADMIN_UI` :ref:`environment variable ` to ``enabled``. Options ======= -The ``ui`` command runs on the database it is connected to. For specifying the -connection target see :ref:`connection options `. +The ``ui`` command runs on the |branch| it is connected to. For specifying the +connection target see :ref:`connection options `. :cli:synopsis:`--print-url` Print URL in console instead of opening in the browser. This is useful if - you prefer to open the EdgeDB UI in a browser other than your default + you prefer to open the Gel UI in a browser other than your default browser. :cli:synopsis:`--no-server-check` @@ -51,4 +51,4 @@ connection target see :ref:`connection options `. Media ===== -.. edb:youtube-embed:: iwnP_6tkKgc \ No newline at end of file +.. edb:youtube-embed:: iwnP_6tkKgc diff --git a/docs/cli/gel_watch.rst b/docs/cli/gel_watch.rst new file mode 100644 index 00000000000..afc372c7998 --- /dev/null +++ b/docs/cli/gel_watch.rst @@ -0,0 +1,34 @@ +.. _ref_cli_gel_watch: + + +========= +gel watch +========= + +Start a long-running process that watches for changes in schema files in your +project's ``dbschema`` directory and applies those changes to your current +|branch| in real time. Starting it is as simple as running this command: + +.. cli:synopsis:: + + gel watch + +.. note:: + + If a schema change cannot be applied, you will see an error in the + :gelcmd:`watch` console. You will also receive the error when you + try to run a query with any |Gel| client binding. + +To learn about our recommended development migration workflow using +:gelcmd:`watch`, read our :ref:`intro to migrations `. + +.. note:: + + If you want to apply a migration in the same manner as ``watch`` but + without the long-running process, use :gelcmd:`migrate --dev-mode`. See + :ref:`ref_cli_gel_migration_apply` for more details. + +Demo +==== + +.. edb:youtube-embed:: _IUSPBm2xEA diff --git a/docs/cli/index.rst b/docs/cli/index.rst index e442bbdda9b..5749776e08d 100644 --- a/docs/cli/index.rst +++ b/docs/cli/index.rst @@ -6,15 +6,15 @@ CLI === -:edb-alt-title: The EdgeDB CLI +:edb-alt-title: The Gel CLI -The ``edgedb`` command-line interface (CLI) provides an idiomatic way to -install EdgeDB, spin up local instances, open a REPL, execute queries, +The |gelcmd| command-line interface (CLI) provides an idiomatic way to +install |Gel|, spin up local instances, open a REPL, execute queries, manage auth roles, introspect schema, create migrations, and more. You can install it with one shell command. -.. _ref_cli_edgedb_install: +.. _ref_cli_gel_install: .. rubric:: Installation @@ -23,47 +23,47 @@ on-screen instructions: .. code-block:: bash - $ curl --proto '=https' --tlsv1.2 -sSf https://sh.edgedb.com | sh + $ curl --proto '=https' --tlsv1.2 -sSf https://geldata.com/sh | sh For Windows, the installation script is: .. code-block:: powershell - PS> iwr https://ps1.edgedb.com -useb | iex + PS> iwr https://geldata.com/ps1 -useb | iex -* The `script `_, inspired by ``rustup``, will - detect the OS and download the appropriate build of the EdgeDB CLI - tool, ``edgedb``. -* The ``edgedb`` command is a single executable (it's `open source! - `_) -* Once installed, the ``edgedb`` command can be used to install, - uninstall, upgrade, and interact with EdgeDB server instances. -* You can uninstall EdgeDB server or remove the ``edgedb`` command at +* The `script `_, inspired by ``rustup``, will + detect the OS and download the appropriate build of the Gel CLI + tool, ``gel``. +* The |gelcmd| command is a single executable (it's `open source! + `_) +* Once installed, the ``gel`` command can be used to install, + uninstall, upgrade, and interact with |Gel| server instances. +* You can uninstall Gel server or remove the ``gel`` command at any time. .. rubric:: Connection options All commands respect a common set of -:ref:`connection options `, which let you specify +:ref:`connection options `, which let you specify a target instance. This instance can be local to your machine or hosted remotely. -.. _ref_cli_edgedb_nightly: +.. _ref_cli_gel_nightly: .. rubric:: Nightly version To install the nightly version of the CLI (not to be confused with the nightly -version of EdgeDB itself!) use this command: +version of |Gel| itself!) use this command: .. code-block:: bash - $ curl --proto '=https' --tlsv1.2 -sSf https://sh.edgedb.com | \ + $ curl --proto '=https' --tlsv1.2 -sSf https://geldata.com/sh | \ sh -s -- --nightly -.. _ref_cli_edgedb_uninstall: +.. _ref_cli_gel_uninstall: .. rubric:: Uninstallation @@ -72,41 +72,41 @@ macOS run: .. code-block:: bash - $ rm "$(which edgedb)" + $ rm "$(which gel)" -To remove all configuration files, run ``edgedb info`` to list the directories -where EdgeDB stores data, then use ``rm -rf `` to delete those +To remove all configuration files, run :gelcmd:`info` to list the directories +where |Gel| stores data, then use ``rm -rf `` to delete those directories. If the command-line tool was installed by the user (recommended) then it will also remove the binary. -If you've used ``edgedb`` commands you can also delete -:ref:`instances ` and :ref:`server -` packages, prior to removing the +If you've used ``gel`` commands you can also delete +:ref:`instances ` and :ref:`server +` packages, prior to removing the tool: .. code-block:: bash - $ edgedb instance destroy + $ gel instance destroy To list instances and server versions use the following commands respectively: .. code-block:: bash - $ edgedb instance status - $ edgedb server list-versions --installed-only + $ gel instance status + $ gel server list-versions --installed-only -.. _ref_cli_edgedb_config: +.. _ref_cli_gel_config: .. rubric:: Configure CLI and REPL -You can customize the behavior of the ``edgedb`` CLI and REPL with a +You can customize the behavior of the |gelcmd| CLI and REPL with a global configuration file. The file is called ``cli.toml`` and its location differs between operating systems. Use -:ref:`ref_cli_edgedb_info` to find the "Config" directory on your +:ref:`ref_cli_gel_info` to find the "Config" directory on your system. The ``cli.toml`` has the following structure. All fields are optional: @@ -128,32 +128,32 @@ The ``cli.toml`` has the following structure. All fields are optional: verbose-errors = false # Print all errors with maximum verbosity -:ref:`Notes on network usage ` +:ref:`Notes on network usage ` .. toctree:: :maxdepth: 3 :hidden: - edgedb_connopts + gel_connopts network - edgedb - edgedb_analyze - edgedb_branch/index - edgedb_configure - edgedb_cli_upgrade - edgedb_cloud/index - edgedb_database/index - edgedb_describe/index - edgedb_dump - edgedb_info - edgedb_instance/index - edgedb_list - edgedb_migrate - edgedb_migration/index - edgedb_project/index - edgedb_query - edgedb_restore - edgedb_server/index - edgedb_ui - edgedb_watch + gel + gel_project/index + gel_ui + gel_watch + gel_migrate + gel_migration/index + gel_cloud/index + gel_branch/index + gel_dump + gel_restore + gel_configure + gel_query + gel_analyze + gel_list + gel_info + gel_cli_upgrade + gel_server/index + gel_describe/index + gel_instance/index + gel_database/index diff --git a/docs/cli/network.rst b/docs/cli/network.rst index 18e0932da20..6cfb7c41a34 100644 --- a/docs/cli/network.rst +++ b/docs/cli/network.rst @@ -1,4 +1,4 @@ -.. _ref_cli_edgedb_network: +.. _ref_cli_gel_network: ============= Network usage @@ -8,33 +8,33 @@ Generally command-line tools connect only to the database host with a few exceptions: 1. When the command-line tool starts, it checks if its version is up to - date. :ref:`Details ` -2. The :ref:`ref_cli_edgedb_server` family of commands and - :ref:`ref_cli_edgedb_cli_upgrade` discover package versions and + date. :ref:`Details ` +2. The :ref:`ref_cli_gel_server` family of commands and + :ref:`ref_cli_gel_cli_upgrade` discover package versions and docker images and also invoke package managers and the docker engine to do :ref:`index updates and related data. - ` -3. The CLI communicates with the EdgeDB Cloud API to provide easy access to - your EdgeDB Cloud instances. + ` +3. The CLI communicates with the |Gel| Cloud API to provide easy access to + your Gel Cloud instances. -.. _ref_cli_edgedb_version_check: +.. _ref_cli_gel_version_check: Version Check ============= Version check checks the current version of command-line tool by fetching -``https://packages.edgedb.com/.jsonindexes/*.json``. +``https://packages.geldata.com/.jsonindexes/*.json``. Here is how such a request looks like:: GET /archive/.jsonindexes/linux-x86_64.json HTTP/1.1 - host: packages.edgedb.com + host: packages.geldata.com content-length: 0 - user-agent: edgedb + user-agent: gel The ``User-Agent`` header only specifies that request is done by -``edgedb`` command-line tool (without version number). The platform, +``gel`` command-line tool (without version number). The platform, architecture and whether nightly is used can be devised from the URL of the query. @@ -51,46 +51,48 @@ To disable version check do one of two things: 1. Use ``--no-cli-update-check`` command-line parameter to disable just for this invocation -2. Export ``EDGEDB_RUN_VERSION_CHECK=never`` in the environment. +2. Export :gelenv:`RUN_VERSION_CHECK=never` in the environment. + +.. XXX: edgedb::version_check=debug To verify that check is skipped and no network access is being done logging facility can be used:: $ export RUST_LOG=edgedb::version_check=debug - $ edgedb --no-cli-update-check + $ gel --no-cli-update-check [..snip..] Skipping version check due to --no-cli-update-check - edgedb> - $ EDGEDB_RUN_VERSION_CHECK=never edgedb - [..snip..] Skipping version check due to EDGEDB_RUN_VERSION_CHECK=never - edgedb> + gel> + $ GEL_RUN_VERSION_CHECK=never gel + [..snip..] Skipping version check due to GEL_RUN_VERSION_CHECK=never + gel> -.. _ref_cli_edgedb_net_server: +.. _ref_cli_gel_net_server: -``edgedb server`` and ``edgedb self upgrade`` -============================================= +"gel server" and "gel self upgrade" +=================================== Generally these commands do requests with exactly the headers -like :ref:`version check `. +like :ref:`version check `. Data sources for the commands directly: -1. Package indexes and packages at ``https://packages.edgedb.com`` +1. Package indexes and packages at ``https://packages.geldata.com`` 2. Docker image index at ``https://registry.hub.docker.com`` Data sources that can be used indirectly: 1. Docker engine may fetch indexes and images. Currently the only images used are at Docker Hub. More specifically - are ``edgedb/*`` and ``busybox`` (Docker's official image). + are ``gel/*`` and ``busybox`` (Docker's official image). 2. Package managers (currently ``apt-get``, ``yum``) can fetch indexes - and install packages from ``https://packages.edgedb.com``. And + and install packages from ``https://packages.geldata.com``. And as we use generic commands (e.g. ``apt-get update``) and system dependencies, package manager can fetch package indexes and package data from any sources listed in repositories configured in the system. -To avoid reaching these hosts, avoid using: ``edgedb server`` and -``edgedb self upgrade`` subcommands. These commands only simplify -installation and maintenance of the installations. All EdgeDB features +To avoid reaching these hosts, avoid using: :gelcmd:`server` and +:gelcmd:`self upgrade` subcommands. These commands only simplify +installation and maintenance of the installations. All |Gel| features are available without using them. diff --git a/docs/clients/connection.rst b/docs/clients/connection.rst index 570abea0bd8..04944ff600f 100644 --- a/docs/clients/connection.rst +++ b/docs/clients/connection.rst @@ -1,4 +1,4 @@ -.. _edgedb_client_connection: +.. _gel_client_connection: ========== Connection @@ -14,28 +14,28 @@ library. Follow the :ref:`Using projects ` guide to get started. -- Set the ``EDGEDB_DSN`` environment variable to a valid DSN (connection +- Set the :gelenv:`DSN` environment variable to a valid DSN (connection string). This is the recommended approach in *production*. A DSN is a - connection URL of the form ``edgedb://user:pass@host:port/branch``. For a + connection URL of the form :geluri:`user:pass@host:port/branch`. For a guide to DSNs, see the :ref:`DSN Specification `. -- Set the ``EDGEDB_INSTANCE`` environment variable to a :ref:`name +- Set the :gelenv:`INSTANCE` environment variable to a :ref:`name ` of a local instance, remote linked - instance, or an EdgeDB Cloud instance. (:ref:`More info on EdgeDB Cloud - connection details below. `) You can create - new instances manually with the :ref:`edgedb instance create - ` command. + instance, or a |Gel| Cloud instance. (:ref:`More info on |Gel| Cloud + connection details below. `) You can create + new instances manually with the :ref:`gel instance create + ` command. - Explicitly pass a DSN or :ref:`instance name ` into the client creation function: - ``edgedb.createClient`` in JS, ``edgedb.create_client()`` in Python, and - ``edgedb.CreateClient`` in Go. + ``gel.createClient`` in JS, ``gel.create_client()`` in Python, and + ``gel.CreateClient`` in Go. .. code-block:: typescript - const client = edgedb.createClient({ - dsn: "edgedb://..." + const client = gel.createClient({ + dsn: "gel://..." }); Only use this approach in development; it isn't recommended to include @@ -44,19 +44,19 @@ library. providers, and container-based workflows each provide various mechanisms for setting environment variables. -These are the most common ways to connect to an instance, however EdgeDB +These are the most common ways to connect to an instance, however |Gel| supports several other options for advanced use cases. For a complete reference on connection configuration, see :ref:`Reference > Connection Parameters `. -.. _edgedb_client_connection_cloud: +.. _gel_client_connection_cloud: -EdgeDB Cloud -============ +Gel Cloud +========= -To provide client connection information for an EdgeDB Cloud instance, set the -``EDGEDB_INSTANCE`` variable to the instance name +To provide client connection information for a |Gel| Cloud instance, set the +:gelenv:`INSTANCE` variable to the instance name (``/`` where ```` is the name you set -when you created the EdgeDB Cloud instance) and the ``EDGEDB_SECRET_KEY`` -variable to your secret key which can be created in the EdgeDB Cloud UI or by -running :ref:`ref_cli_edgedb_cloud_secretkey_create` via the CLI. +when you created the Gel Cloud instance) and the :gelenv:`SECRET_KEY` +variable to your secret key which can be created in the Gel Cloud UI or by +running :ref:`ref_cli_gel_cloud_secretkey_create` via the CLI. diff --git a/docs/clients/dart/index.rst b/docs/clients/dart/index.rst deleted file mode 100644 index 073632aca15..00000000000 --- a/docs/clients/dart/index.rst +++ /dev/null @@ -1,9 +0,0 @@ -.. _edgedb-dart-intro: - -==== -Dart -==== - -The documentation for the Dart client is automatically generated -from https://github.com/edgedb/edgedb-dart by the build -pipeline of the edgedb.com website. diff --git a/docs/clients/dotnet/index.rst b/docs/clients/dotnet/index.rst deleted file mode 100644 index d5818190afe..00000000000 --- a/docs/clients/dotnet/index.rst +++ /dev/null @@ -1,9 +0,0 @@ -.. _edgedb-dotnet-intro: - -==== -.NET -==== - -The documentation for the .NET client is automatically generated -from https://github.com/edgedb/edgedb-net/tree/dev/docs by the build -pipeline of the edgedb.com website. diff --git a/docs/clients/elixir/index.rst b/docs/clients/elixir/index.rst deleted file mode 100644 index 0d85a0f4778..00000000000 --- a/docs/clients/elixir/index.rst +++ /dev/null @@ -1,9 +0,0 @@ -.. _edgedb-elixir-intro: - -====== -Elixir -====== - -The documentation for the Elixir client is automatically pulled -from https://github.com/edgedb/edgedb-elixir by the -build pipeline of the edgedb.com website. diff --git a/docs/clients/go/api.rst b/docs/clients/go/api.rst new file mode 100644 index 00000000000..dc7c46b6d2b --- /dev/null +++ b/docs/clients/go/api.rst @@ -0,0 +1,211 @@ + +API +=== + + +*type* Client +------------- + +Client is a connection pool and is safe for concurrent use. + + +.. code-block:: go + + type Client = gel.Client + + +*type* Error +------------ + +Error is the error type returned from gel. + + +.. code-block:: go + + type Error = gel.Error + + +*type* ErrorCategory +-------------------- + +ErrorCategory values represent Gel's error types. + + +.. code-block:: go + + type ErrorCategory = gel.ErrorCategory + + +*type* ErrorTag +--------------- + +ErrorTag is the argument type to Error.HasTag(). + + +.. code-block:: go + + type ErrorTag = gel.ErrorTag + + +*type* Executor +--------------- + +Executor is a common interface between \*Client and \*Tx, +that can run queries on an Gel database. + + +.. code-block:: go + + type Executor = gel.Executor + + +*type* IsolationLevel +--------------------- + +IsolationLevel documentation can be found here +`docs/reference/edgeql/tx_start#parameters `_ + + +.. code-block:: go + + type IsolationLevel = gel.IsolationLevel + + +*type* ModuleAlias +------------------ + +ModuleAlias is an alias name and module name pair. + + +.. code-block:: go + + type ModuleAlias = gel.ModuleAlias + + +*type* Options +-------------- + +Options for connecting to a |Gel| server + + +.. code-block:: go + + type Options = gel.Options + + +*type* RetryBackoff +------------------- + +RetryBackoff returns the duration to wait after the nth attempt +before making the next attempt when retrying a transaction. + + +.. code-block:: go + + type RetryBackoff = gel.RetryBackoff + + +*type* RetryCondition +--------------------- + +RetryCondition represents scenarios that can cause a transaction +run in Tx() methods to be retried. + + +.. code-block:: go + + type RetryCondition = gel.RetryCondition + + +*type* RetryOptions +------------------- + +RetryOptions configures how Tx() retries failed transactions. Use +NewRetryOptions to get a default RetryOptions value instead of creating one +yourself. + + +.. code-block:: go + + type RetryOptions = gel.RetryOptions + + +*type* RetryRule +---------------- + +RetryRule determines how transactions should be retried when run in Tx() +methods. See Client.Tx() for details. + + +.. code-block:: go + + type RetryRule = gel.RetryRule + + +*type* TLSOptions +----------------- + +TLSOptions contains the parameters needed to configure TLS on |Gel| +server connections. + + +.. code-block:: go + + type TLSOptions = gel.TLSOptions + + +*type* TLSSecurityMode +---------------------- + +TLSSecurityMode specifies how strict TLS validation is. + + +.. code-block:: go + + type TLSSecurityMode = gel.TLSSecurityMode + + +*type* Tx +--------- + +Tx is a transaction. Use Client.Tx() to get a transaction. + + +.. code-block:: go + + type Tx = gel.Tx + + +*type* TxBlock +-------------- + +TxBlock is work to be done in a transaction. + + +.. code-block:: go + + type TxBlock = gel.TxBlock + + +*type* TxOptions +---------------- + +TxOptions configures how transactions behave. + + +.. code-block:: go + + type TxOptions = gel.TxOptions + + +*type* WarningHandler +--------------------- + +WarningHandler takes a slice of gel.Error that represent warnings and +optionally returns an error. This can be used to log warnings, increment +metrics, promote warnings to errors by returning them etc. + + +.. code-block:: go + + type WarningHandler = gel.WarningHandler diff --git a/docs/clients/go/codegen.rst b/docs/clients/go/codegen.rst new file mode 100644 index 00000000000..23b693f4d1d --- /dev/null +++ b/docs/clients/go/codegen.rst @@ -0,0 +1,35 @@ +Codegen +======= + +edgeql-go is a tool to generate go functions from edgeql queries. When run +in a |Gel| project directory (or subdirectory) a \*_edgeql.go source file +will be generated for each \*.edgeql file. The generated go will have an +edgeqlFileName and edgeqlFileNameJSON function with typed arguments and +return value matching the query's arguments and result shape. + + +Install +------- + +.. code-block:: go + + go install github.com/geldata/gel-go/cmd/edgeql-go@latest + +See also `pinning tool dependencies `_. + + +Usage +----- + +Typically this process would be run using `go generate `_ like this: + +.. code-block:: go + + //go:generate edgeql-go -pubfuncs -pubtypes -mixedcaps + +For a complete list of options: + +.. code-block:: go + + edgeql-go -help + diff --git a/docs/clients/go/index.rst b/docs/clients/go/index.rst index fbc70705e0f..506353d647b 100644 --- a/docs/clients/go/index.rst +++ b/docs/clients/go/index.rst @@ -1,9 +1,262 @@ -.. _edgedb-go-intro: +.. _gel-go-intro: -== -Go -== +============= +Gel Go Driver +============= + + +.. toctree:: + :maxdepth: 3 + :hidden: + + api + types + codegen + + +Typical client usage looks like this: + +.. code-block:: go + + package main + + import ( + "context" + "log" + + "github.com/geldata/gel-go" + ) + + func main() { + ctx := context.Background() + client, err := gel.CreateClient(ctx, gel.Options{}) + if err != nil { + log.Fatal(err) + } + defer client.Close() + + var ( + age int64 = 21 + users []struct { + ID gel.UUID `gel:"id"` + Name string `gel:"name"` + } + ) + + query := "SELECT User{name} FILTER .age = $0" + err = client.Query(ctx, query, &users, age) + ... + } + +We recommend using environment variables for connection parameters. See the +`client connection docs `_ for more information. + +You may also connect to a database using a DSN: + +.. code-block:: go + + url := "gel://admin@localhost/gel" + client, err := gel.CreateClientDSN(ctx, url, opts) + +Or you can use Option fields. + +.. code-block:: go + + opts := gel.Options{ + Database: "gel", + User: "gel", + Concurrency: 4, + } + + client, err := gel.CreateClient(ctx, opts) + + +Errors +------ + +``gel`` never returns underlying errors directly. +If you are checking for things like context expiration +use errors.Is() or errors.As(). + +.. code-block:: go + + err := client.Query(...) + if errors.Is(err, context.Canceled) { ... } + +Most errors returned by the gel package will satisfy the gel.Error +interface which has methods for introspecting. + +.. code-block:: go + + err := client.Query(...) + + var edbErr gel.Error + if errors.As(err, &edbErr) && edbErr.Category(gel.NoDataError){ + ... + } + + +Datatypes +--------- + +The following list shows the marshal/unmarshal +mapping between |Gel| types and go types: + +.. code-block:: go + + Gel Go + --------- --------- + Set []anytype + array []anytype + tuple struct + named tuple struct + Object struct + bool bool, gel.OptionalBool + bytes []byte, gel.OptionalBytes + str string, gel.OptionalStr + anyenum string, gel.OptionalStr + datetime time.Time, gel.OptionalDateTime + cal::local_datetime gel.LocalDateTime, + gel.OptionalLocalDateTime + cal::local_date gel.LocalDate, gel.OptionalLocalDate + cal::local_time gel.LocalTime, gel.OptionalLocalTime + duration gel.Duration, gel.OptionalDuration + cal::relative_duration gel.RelativeDuration, + gel.OptionalRelativeDuration + float32 float32, gel.OptionalFloat32 + float64 float64, gel.OptionalFloat64 + int16 int16, gel.OptionalFloat16 + int32 int32, gel.OptionalInt16 + int64 int64, gel.OptionalInt64 + uuid gel.UUID, gel.OptionalUUID + json []byte, gel.OptionalBytes + bigint *big.Int, gel.OptionalBigInt + + decimal user defined (see Custom Marshalers) + +Note that Gel's std::duration type is represented in int64 microseconds +while go's time.Duration type is int64 nanoseconds. It is incorrect to cast +one directly to the other. + +Shape fields that are not required must use optional types for receiving +query results. The gel.Optional struct can be embedded to make structs +optional. + +.. code-block:: go + + type User struct { + gel.Optional + Email string `gel:"email"` + } + + var result User + err := client.QuerySingle(ctx, `SELECT User { email } LIMIT 0`, $result) + fmt.Println(result.Missing()) + // Output: true + + err := client.QuerySingle(ctx, `SELECT User { email } LIMIT 1`, $result) + fmt.Println(result.Missing()) + // Output: false + +Not all types listed above are valid query parameters. To pass a slice of +scalar values use array in your query. |Gel| doesn't currently support +using sets as parameters. + +.. code-block:: go + + query := `select User filter .id in array_unpack(>$1)` + client.QuerySingle(ctx, query, $user, []gel.UUID{...}) + +Nested structures are also not directly allowed but you can use `json `_ +instead. + +By default |Gel| will ignore embedded structs when marshaling/unmarshaling. +To treat an embedded struct's fields as part of the parent struct's fields, +tag the embedded struct with \`gel:"$inline"\`. + +.. code-block:: go + + type Object struct { + ID gel.UUID + } + + type User struct { + Object `gel:"$inline"` + Name string + } + + +Custom Marshalers +----------------- + +Interfaces for user defined marshaler/unmarshalers are documented in the +internal/marshal package. + + + +Usage Example +------------- + +.. code-block:: go + + package gel_test + + import ( + "context" + "fmt" + "log" + "time" + + gel "github.com/gel/gel-go" + ) + + type User struct { + ID gel.UUID `gel:"id"` + Name string `gel:"name"` + DOB time.Time `gel:"dob"` + } + + func Example() { + opts := gel.Options{Concurrency: 4} + ctx := context.Background() + db, err := gel.CreateClientDSN(ctx, "gel://gel@localhost/test", opts) + if err != nil { + log.Fatal(err) + } + defer db.Close() + + // create a user object type. + err = db.Execute(ctx, ` + CREATE TYPE User { + CREATE REQUIRED PROPERTY name -> str; + CREATE PROPERTY dob -> datetime; + } + `) + if err != nil { + log.Fatal(err) + } + + // Insert a new user. + var inserted struct{ id gel.UUID } + err = db.QuerySingle(ctx, ` + INSERT User { + name := $0, + dob := $1 + } + `, &inserted, "Bob", time.Date(1984, 3, 1, 0, 0, 0, 0, time.UTC)) + if err != nil { + log.Fatal(err) + } + + // Select users. + var users []User + args := map[string]interface{}{"name": "Bob"} + query := "SELECT User {name, dob} FILTER .name = $name" + err = db.Query(ctx, query, &users, args) + if err != nil { + log.Fatal(err) + } + + fmt.Println(users) + } -The documentation for the Go client is automatically generated -from https://github.com/edgedb/edgedb-go by the build pipeline of -the edgedb.com website. diff --git a/docs/clients/go/types.rst b/docs/clients/go/types.rst new file mode 100644 index 00000000000..9b9281defc2 --- /dev/null +++ b/docs/clients/go/types.rst @@ -0,0 +1,3569 @@ +Datatypes +========= + + +*type* DateDuration +------------------- + +DateDuration represents the elapsed time between two dates in a fuzzy human +way. + + +.. code-block:: go + + type DateDuration struct { + // contains filtered or unexported fields + } + + +*function* NewDateDuration +.......................... + +.. code-block:: go + + func NewDateDuration(months int32, days int32) DateDuration + +NewDateDuration returns a new DateDuration + + + + +*method* MarshalText +.................... + +.. code-block:: go + + func (dd DateDuration) MarshalText() ([]byte, error) + +MarshalText returns dd marshaled as text. + + + + +*method* String +............... + +.. code-block:: go + + func (dd DateDuration) String() string + + + + +*method* UnmarshalText +...................... + +.. code-block:: go + + func (dd *DateDuration) UnmarshalText(b []byte) error + +UnmarshalText unmarshals bytes into \*dd. + + + + +*type* Duration +--------------- + +Duration represents the elapsed time between two instants +as an int64 microsecond count. + + +.. code-block:: go + + type Duration int64 + + +*function* DurationFromNanoseconds +.................................. + +.. code-block:: go + + func DurationFromNanoseconds(d time.Duration) Duration + +DurationFromNanoseconds creates a Duration represented as microseconds +from a `time.Duration `_ represented as nanoseconds. + + + + +*function* ParseDuration +........................ + +.. code-block:: go + + func ParseDuration(s string) (Duration, error) + +ParseDuration parses a |Gel| duration string. + + + + +*method* AsNanoseconds +...................... + +.. code-block:: go + + func (d Duration) AsNanoseconds() (time.Duration, error) + +AsNanoseconds returns `time.Duration `_ represented as nanoseconds, +after transforming from Duration microsecond representation. +Returns an error if the Duration is too long and would cause an overflow of +the internal int64 representation. + + + + +*method* String +............... + +.. code-block:: go + + func (d Duration) String() string + + + + +*type* LocalDate +---------------- + +LocalDate is a date without a time zone. +`docs/stdlib/datetime#type::cal::local_date `_ + + +.. code-block:: go + + type LocalDate struct { + // contains filtered or unexported fields + } + + +*function* NewLocalDate +....................... + +.. code-block:: go + + func NewLocalDate(year int, month time.Month, day int) LocalDate + +NewLocalDate returns a new LocalDate + + + + +*method* MarshalText +.................... + +.. code-block:: go + + func (d LocalDate) MarshalText() ([]byte, error) + +MarshalText returns d marshaled as text. + + + + +*method* String +............... + +.. code-block:: go + + func (d LocalDate) String() string + + + + +*method* UnmarshalText +...................... + +.. code-block:: go + + func (d *LocalDate) UnmarshalText(b []byte) error + +UnmarshalText unmarshals bytes into \*d. + + + + +*type* LocalDateTime +-------------------- + +LocalDateTime is a date and time without timezone. +`docs/stdlib/datetime#type::cal::local_datetime `_ + + +.. code-block:: go + + type LocalDateTime struct { + // contains filtered or unexported fields + } + + +*function* NewLocalDateTime +........................... + +.. code-block:: go + + func NewLocalDateTime( + year int, month time.Month, day, hour, minute, second, microsecond int, + ) LocalDateTime + +NewLocalDateTime returns a new LocalDateTime + + + + +*method* MarshalText +.................... + +.. code-block:: go + + func (dt LocalDateTime) MarshalText() ([]byte, error) + +MarshalText returns dt marshaled as text. + + + + +*method* String +............... + +.. code-block:: go + + func (dt LocalDateTime) String() string + + + + +*method* UnmarshalText +...................... + +.. code-block:: go + + func (dt *LocalDateTime) UnmarshalText(b []byte) error + +UnmarshalText unmarshals bytes into \*dt. + + + + +*type* LocalTime +---------------- + +LocalTime is a time without a time zone. +`docs/stdlib/datetime#type::cal::local_time `_ + + +.. code-block:: go + + type LocalTime struct { + // contains filtered or unexported fields + } + + +*function* NewLocalTime +....................... + +.. code-block:: go + + func NewLocalTime(hour, minute, second, microsecond int) LocalTime + +NewLocalTime returns a new LocalTime + + + + +*method* MarshalText +.................... + +.. code-block:: go + + func (t LocalTime) MarshalText() ([]byte, error) + +MarshalText returns t marshaled as text. + + + + +*method* String +............... + +.. code-block:: go + + func (t LocalTime) String() string + + + + +*method* UnmarshalText +...................... + +.. code-block:: go + + func (t *LocalTime) UnmarshalText(b []byte) error + +UnmarshalText unmarshals bytes into \*t. + + + + +*type* Memory +------------- + +Memory represents memory in bytes. + + +.. code-block:: go + + type Memory int64 + + +*method* MarshalText +.................... + +.. code-block:: go + + func (m Memory) MarshalText() ([]byte, error) + +MarshalText returns m marshaled as text. + + + + +*method* String +............... + +.. code-block:: go + + func (m Memory) String() string + + + + +*method* UnmarshalText +...................... + +.. code-block:: go + + func (m *Memory) UnmarshalText(b []byte) error + +UnmarshalText unmarshals bytes into \*m. + + + + +*type* MultiRangeDateTime +------------------------- + +MultiRangeDateTime is a type alias for a slice of RangeDateTime values. + + +.. code-block:: go + + type MultiRangeDateTime = []RangeDateTime + + +*type* MultiRangeFloat32 +------------------------ + +MultiRangeFloat32 is a type alias for a slice of RangeFloat32 values. + + +.. code-block:: go + + type MultiRangeFloat32 = []RangeFloat32 + + +*type* MultiRangeFloat64 +------------------------ + +MultiRangeFloat64 is a type alias for a slice of RangeFloat64 values. + + +.. code-block:: go + + type MultiRangeFloat64 = []RangeFloat64 + + +*type* MultiRangeInt32 +---------------------- + +MultiRangeInt32 is a type alias for a slice of RangeInt32 values. + + +.. code-block:: go + + type MultiRangeInt32 = []RangeInt32 + + +*type* MultiRangeInt64 +---------------------- + +MultiRangeInt64 is a type alias for a slice of RangeInt64 values. + + +.. code-block:: go + + type MultiRangeInt64 = []RangeInt64 + + +*type* MultiRangeLocalDate +-------------------------- + +MultiRangeLocalDate is a type alias for a slice of +RangeLocalDate values. + + +.. code-block:: go + + type MultiRangeLocalDate = []RangeLocalDate + + +*type* MultiRangeLocalDateTime +------------------------------ + +MultiRangeLocalDateTime is a type alias for a slice of +RangeLocalDateTime values. + + +.. code-block:: go + + type MultiRangeLocalDateTime = []RangeLocalDateTime + + +*type* Optional +--------------- + +Optional represents a shape field that is not required. +Optional is embedded in structs to make them optional. For example: + +.. code-block:: go + + type User struct { + gel.Optional + Name string `gel:"name"` + } + + +.. code-block:: go + + type Optional struct { + // contains filtered or unexported fields + } + + +*method* Missing +................ + +.. code-block:: go + + func (o *Optional) Missing() bool + +Missing returns true if the value is missing. + + + + +*method* SetMissing +................... + +.. code-block:: go + + func (o *Optional) SetMissing(missing bool) + +SetMissing sets the structs missing status. true means missing and false +means present. + + + + +*method* Unset +.............. + +.. code-block:: go + + func (o *Optional) Unset() + +Unset marks the value as missing + + + + +*type* OptionalBigInt +--------------------- + +OptionalBigInt is an optional \*big.Int. Optional types must be used for out +parameters when a shape field is not required. + + +.. code-block:: go + + type OptionalBigInt struct { + // contains filtered or unexported fields + } + + +*function* NewOptionalBigInt +............................ + +.. code-block:: go + + func NewOptionalBigInt(v *big.Int) OptionalBigInt + +NewOptionalBigInt is a convenience function for creating an OptionalBigInt +with its value set to v. + + + + +*method* Get +............ + +.. code-block:: go + + func (o OptionalBigInt) Get() (*big.Int, bool) + +Get returns the value and a boolean indicating if the value is present. + + + + +*method* MarshalJSON +.................... + +.. code-block:: go + + func (o OptionalBigInt) MarshalJSON() ([]byte, error) + +MarshalJSON returns o marshaled as json. + + + + +*method* Set +............ + +.. code-block:: go + + func (o *OptionalBigInt) Set(val *big.Int) + +Set sets the value. + + + + +*method* UnmarshalJSON +...................... + +.. code-block:: go + + func (o *OptionalBigInt) UnmarshalJSON(bytes []byte) error + +UnmarshalJSON unmarshals bytes into \*o. + + + + +*method* Unset +.............. + +.. code-block:: go + + func (o *OptionalBigInt) Unset() + +Unset marks the value as missing. + + + + +*type* OptionalBool +------------------- + +OptionalBool is an optional bool. Optional types must be used for out +parameters when a shape field is not required. + + +.. code-block:: go + + type OptionalBool struct { + // contains filtered or unexported fields + } + + +*function* NewOptionalBool +.......................... + +.. code-block:: go + + func NewOptionalBool(v bool) OptionalBool + +NewOptionalBool is a convenience function for creating an OptionalBool with +its value set to v. + + + + +*method* Get +............ + +.. code-block:: go + + func (o OptionalBool) Get() (bool, bool) + +Get returns the value and a boolean indicating if the value is present. + + + + +*method* MarshalJSON +.................... + +.. code-block:: go + + func (o OptionalBool) MarshalJSON() ([]byte, error) + +MarshalJSON returns o marshaled as json. + + + + +*method* Set +............ + +.. code-block:: go + + func (o *OptionalBool) Set(val bool) + +Set sets the value. + + + + +*method* UnmarshalJSON +...................... + +.. code-block:: go + + func (o *OptionalBool) UnmarshalJSON(bytes []byte) error + +UnmarshalJSON unmarshals bytes into \*o. + + + + +*method* Unset +.............. + +.. code-block:: go + + func (o *OptionalBool) Unset() + +Unset marks the value as missing. + + + + +*type* OptionalBytes +-------------------- + +OptionalBytes is an optional []byte. Optional types must be used for out +parameters when a shape field is not required. + + +.. code-block:: go + + type OptionalBytes struct { + // contains filtered or unexported fields + } + + +*function* NewOptionalBytes +........................... + +.. code-block:: go + + func NewOptionalBytes(v []byte) OptionalBytes + +NewOptionalBytes is a convenience function for creating an OptionalBytes +with its value set to v. + + + + +*method* Get +............ + +.. code-block:: go + + func (o OptionalBytes) Get() ([]byte, bool) + +Get returns the value and a boolean indicating if the value is present. + + + + +*method* MarshalJSON +.................... + +.. code-block:: go + + func (o OptionalBytes) MarshalJSON() ([]byte, error) + +MarshalJSON returns o marshaled as json. + + + + +*method* Set +............ + +.. code-block:: go + + func (o *OptionalBytes) Set(val []byte) + +Set sets the value. + + + + +*method* UnmarshalJSON +...................... + +.. code-block:: go + + func (o *OptionalBytes) UnmarshalJSON(bytes []byte) error + +UnmarshalJSON unmarshals bytes into \*o. + + + + +*method* Unset +.............. + +.. code-block:: go + + func (o *OptionalBytes) Unset() + +Unset marks the value as missing. + + + + +*type* OptionalDateDuration +--------------------------- + +OptionalDateDuration is an optional DateDuration. Optional types +must be used for out parameters when a shape field is not required. + + +.. code-block:: go + + type OptionalDateDuration struct { + // contains filtered or unexported fields + } + + +*function* NewOptionalDateDuration +.................................. + +.. code-block:: go + + func NewOptionalDateDuration(v DateDuration) OptionalDateDuration + +NewOptionalDateDuration is a convenience function for creating an +OptionalDateDuration with its value set to v. + + + + +*method* Get +............ + +.. code-block:: go + + func (o *OptionalDateDuration) Get() (DateDuration, bool) + +Get returns the value and a boolean indicating if the value is present. + + + + +*method* MarshalJSON +.................... + +.. code-block:: go + + func (o OptionalDateDuration) MarshalJSON() ([]byte, error) + +MarshalJSON returns o marshaled as json. + + + + +*method* Set +............ + +.. code-block:: go + + func (o *OptionalDateDuration) Set(val DateDuration) + +Set sets the value. + + + + +*method* UnmarshalJSON +...................... + +.. code-block:: go + + func (o *OptionalDateDuration) UnmarshalJSON(bytes []byte) error + +UnmarshalJSON unmarshals bytes into \*o. + + + + +*method* Unset +.............. + +.. code-block:: go + + func (o *OptionalDateDuration) Unset() + +Unset marks the value as missing. + + + + +*type* OptionalDateTime +----------------------- + +OptionalDateTime is an optional time.Time. Optional types must be used for +out parameters when a shape field is not required. + + +.. code-block:: go + + type OptionalDateTime struct { + // contains filtered or unexported fields + } + + +*function* NewOptionalDateTime +.............................. + +.. code-block:: go + + func NewOptionalDateTime(v time.Time) OptionalDateTime + +NewOptionalDateTime is a convenience function for creating an +OptionalDateTime with its value set to v. + + + + +*method* Get +............ + +.. code-block:: go + + func (o OptionalDateTime) Get() (time.Time, bool) + +Get returns the value and a boolean indicating if the value is present. + + + + +*method* MarshalJSON +.................... + +.. code-block:: go + + func (o OptionalDateTime) MarshalJSON() ([]byte, error) + +MarshalJSON returns o marshaled as json. + + + + +*method* Set +............ + +.. code-block:: go + + func (o *OptionalDateTime) Set(val time.Time) + +Set sets the value. + + + + +*method* UnmarshalJSON +...................... + +.. code-block:: go + + func (o *OptionalDateTime) UnmarshalJSON(bytes []byte) error + +UnmarshalJSON unmarshals bytes into \*o. + + + + +*method* Unset +.............. + +.. code-block:: go + + func (o *OptionalDateTime) Unset() + +Unset marks the value as missing. + + + + +*type* OptionalDuration +----------------------- + +OptionalDuration is an optional Duration. Optional types must be used for +out parameters when a shape field is not required. + + +.. code-block:: go + + type OptionalDuration struct { + // contains filtered or unexported fields + } + + +*function* NewOptionalDuration +.............................. + +.. code-block:: go + + func NewOptionalDuration(v Duration) OptionalDuration + +NewOptionalDuration is a convenience function for creating an +OptionalDuration with its value set to v. + + + + +*method* Get +............ + +.. code-block:: go + + func (o OptionalDuration) Get() (Duration, bool) + +Get returns the value and a boolean indicating if the value is present. + + + + +*method* MarshalJSON +.................... + +.. code-block:: go + + func (o OptionalDuration) MarshalJSON() ([]byte, error) + +MarshalJSON returns o marshaled as json. + + + + +*method* Set +............ + +.. code-block:: go + + func (o *OptionalDuration) Set(val Duration) + +Set sets the value. + + + + +*method* UnmarshalJSON +...................... + +.. code-block:: go + + func (o *OptionalDuration) UnmarshalJSON(bytes []byte) error + +UnmarshalJSON unmarshals bytes into \*o. + + + + +*method* Unset +.............. + +.. code-block:: go + + func (o *OptionalDuration) Unset() + +Unset marks the value as missing. + + + + +*type* OptionalFloat32 +---------------------- + +OptionalFloat32 is an optional float32. Optional types must be used for out +parameters when a shape field is not required. + + +.. code-block:: go + + type OptionalFloat32 struct { + // contains filtered or unexported fields + } + + +*function* NewOptionalFloat32 +............................. + +.. code-block:: go + + func NewOptionalFloat32(v float32) OptionalFloat32 + +NewOptionalFloat32 is a convenience function for creating an OptionalFloat32 +with its value set to v. + + + + +*method* Get +............ + +.. code-block:: go + + func (o OptionalFloat32) Get() (float32, bool) + +Get returns the value and a boolean indicating if the value is present. + + + + +*method* MarshalJSON +.................... + +.. code-block:: go + + func (o OptionalFloat32) MarshalJSON() ([]byte, error) + +MarshalJSON returns o marshaled as json. + + + + +*method* Set +............ + +.. code-block:: go + + func (o *OptionalFloat32) Set(val float32) + +Set sets the value. + + + + +*method* UnmarshalJSON +...................... + +.. code-block:: go + + func (o *OptionalFloat32) UnmarshalJSON(bytes []byte) error + +UnmarshalJSON unmarshals bytes into \*o. + + + + +*method* Unset +.............. + +.. code-block:: go + + func (o *OptionalFloat32) Unset() + +Unset marks the value as missing. + + + + +*type* OptionalFloat64 +---------------------- + +OptionalFloat64 is an optional float64. Optional types must be used for out +parameters when a shape field is not required. + + +.. code-block:: go + + type OptionalFloat64 struct { + // contains filtered or unexported fields + } + + +*function* NewOptionalFloat64 +............................. + +.. code-block:: go + + func NewOptionalFloat64(v float64) OptionalFloat64 + +NewOptionalFloat64 is a convenience function for creating an OptionalFloat64 +with its value set to v. + + + + +*method* Get +............ + +.. code-block:: go + + func (o OptionalFloat64) Get() (float64, bool) + +Get returns the value and a boolean indicating if the value is present. + + + + +*method* MarshalJSON +.................... + +.. code-block:: go + + func (o OptionalFloat64) MarshalJSON() ([]byte, error) + +MarshalJSON returns o marshaled as json. + + + + +*method* Set +............ + +.. code-block:: go + + func (o *OptionalFloat64) Set(val float64) + +Set sets the value. + + + + +*method* UnmarshalJSON +...................... + +.. code-block:: go + + func (o *OptionalFloat64) UnmarshalJSON(bytes []byte) error + +UnmarshalJSON unmarshals bytes into \*o. + + + + +*method* Unset +.............. + +.. code-block:: go + + func (o *OptionalFloat64) Unset() + +Unset marks the value as missing. + + + + +*type* OptionalInt16 +-------------------- + +OptionalInt16 is an optional int16. Optional types must be used for out +parameters when a shape field is not required. + + +.. code-block:: go + + type OptionalInt16 struct { + // contains filtered or unexported fields + } + + +*function* NewOptionalInt16 +........................... + +.. code-block:: go + + func NewOptionalInt16(v int16) OptionalInt16 + +NewOptionalInt16 is a convenience function for creating an OptionalInt16 +with its value set to v. + + + + +*method* Get +............ + +.. code-block:: go + + func (o OptionalInt16) Get() (int16, bool) + +Get returns the value and a boolean indicating if the value is present. + + + + +*method* MarshalJSON +.................... + +.. code-block:: go + + func (o OptionalInt16) MarshalJSON() ([]byte, error) + +MarshalJSON returns o marshaled as json. + + + + +*method* Set +............ + +.. code-block:: go + + func (o *OptionalInt16) Set(val int16) + +Set sets the value. + + + + +*method* UnmarshalJSON +...................... + +.. code-block:: go + + func (o *OptionalInt16) UnmarshalJSON(bytes []byte) error + +UnmarshalJSON unmarshals bytes into \*o. + + + + +*method* Unset +.............. + +.. code-block:: go + + func (o *OptionalInt16) Unset() + +Unset marks the value as missing. + + + + +*type* OptionalInt32 +-------------------- + +OptionalInt32 is an optional int32. Optional types must be used for out +parameters when a shape field is not required. + + +.. code-block:: go + + type OptionalInt32 struct { + // contains filtered or unexported fields + } + + +*function* NewOptionalInt32 +........................... + +.. code-block:: go + + func NewOptionalInt32(v int32) OptionalInt32 + +NewOptionalInt32 is a convenience function for creating an OptionalInt32 +with its value set to v. + + + + +*method* Get +............ + +.. code-block:: go + + func (o OptionalInt32) Get() (int32, bool) + +Get returns the value and a boolean indicating if the value is present. + + + + +*method* MarshalJSON +.................... + +.. code-block:: go + + func (o OptionalInt32) MarshalJSON() ([]byte, error) + +MarshalJSON returns o marshaled as json. + + + + +*method* Set +............ + +.. code-block:: go + + func (o *OptionalInt32) Set(val int32) + +Set sets the value. + + + + +*method* UnmarshalJSON +...................... + +.. code-block:: go + + func (o *OptionalInt32) UnmarshalJSON(bytes []byte) error + +UnmarshalJSON unmarshals bytes into \*o. + + + + +*method* Unset +.............. + +.. code-block:: go + + func (o *OptionalInt32) Unset() + +Unset marks the value as missing. + + + + +*type* OptionalInt64 +-------------------- + +OptionalInt64 is an optional int64. Optional types must be used for out +parameters when a shape field is not required. + + +.. code-block:: go + + type OptionalInt64 struct { + // contains filtered or unexported fields + } + + +*function* NewOptionalInt64 +........................... + +.. code-block:: go + + func NewOptionalInt64(v int64) OptionalInt64 + +NewOptionalInt64 is a convenience function for creating an OptionalInt64 +with its value set to v. + + + + +*method* Get +............ + +.. code-block:: go + + func (o OptionalInt64) Get() (int64, bool) + +Get returns the value and a boolean indicating if the value is present. + + + + +*method* MarshalJSON +.................... + +.. code-block:: go + + func (o OptionalInt64) MarshalJSON() ([]byte, error) + +MarshalJSON returns o marshaled as json. + + + + +*method* Set +............ + +.. code-block:: go + + func (o *OptionalInt64) Set(val int64) *OptionalInt64 + +Set sets the value. + + + + +*method* UnmarshalJSON +...................... + +.. code-block:: go + + func (o *OptionalInt64) UnmarshalJSON(bytes []byte) error + +UnmarshalJSON unmarshals bytes into \*o. + + + + +*method* Unset +.............. + +.. code-block:: go + + func (o *OptionalInt64) Unset() *OptionalInt64 + +Unset marks the value as missing. + + + + +*type* OptionalLocalDate +------------------------ + +OptionalLocalDate is an optional LocalDate. Optional types must be used for +out parameters when a shape field is not required. + + +.. code-block:: go + + type OptionalLocalDate struct { + // contains filtered or unexported fields + } + + +*function* NewOptionalLocalDate +............................... + +.. code-block:: go + + func NewOptionalLocalDate(v LocalDate) OptionalLocalDate + +NewOptionalLocalDate is a convenience function for creating an +OptionalLocalDate with its value set to v. + + + + +*method* Get +............ + +.. code-block:: go + + func (o OptionalLocalDate) Get() (LocalDate, bool) + +Get returns the value and a boolean indicating if the value is present. + + + + +*method* MarshalJSON +.................... + +.. code-block:: go + + func (o OptionalLocalDate) MarshalJSON() ([]byte, error) + +MarshalJSON returns o marshaled as json. + + + + +*method* Set +............ + +.. code-block:: go + + func (o *OptionalLocalDate) Set(val LocalDate) + +Set sets the value. + + + + +*method* UnmarshalJSON +...................... + +.. code-block:: go + + func (o *OptionalLocalDate) UnmarshalJSON(bytes []byte) error + +UnmarshalJSON unmarshals bytes into \*o. + + + + +*method* Unset +.............. + +.. code-block:: go + + func (o *OptionalLocalDate) Unset() + +Unset marks the value as missing. + + + + +*type* OptionalLocalDateTime +---------------------------- + +OptionalLocalDateTime is an optional LocalDateTime. Optional types must be +used for out parameters when a shape field is not required. + + +.. code-block:: go + + type OptionalLocalDateTime struct { + // contains filtered or unexported fields + } + + +*function* NewOptionalLocalDateTime +................................... + +.. code-block:: go + + func NewOptionalLocalDateTime(v LocalDateTime) OptionalLocalDateTime + +NewOptionalLocalDateTime is a convenience function for creating an +OptionalLocalDateTime with its value set to v. + + + + +*method* Get +............ + +.. code-block:: go + + func (o OptionalLocalDateTime) Get() (LocalDateTime, bool) + +Get returns the value and a boolean indicating if the value is present. + + + + +*method* MarshalJSON +.................... + +.. code-block:: go + + func (o OptionalLocalDateTime) MarshalJSON() ([]byte, error) + +MarshalJSON returns o marshaled as json. + + + + +*method* Set +............ + +.. code-block:: go + + func (o *OptionalLocalDateTime) Set(val LocalDateTime) + +Set sets the value. + + + + +*method* UnmarshalJSON +...................... + +.. code-block:: go + + func (o *OptionalLocalDateTime) UnmarshalJSON(bytes []byte) error + +UnmarshalJSON unmarshals bytes into \*o. + + + + +*method* Unset +.............. + +.. code-block:: go + + func (o *OptionalLocalDateTime) Unset() + +Unset marks the value as missing. + + + + +*type* OptionalLocalTime +------------------------ + +OptionalLocalTime is an optional LocalTime. Optional types must be used for +out parameters when a shape field is not required. + + +.. code-block:: go + + type OptionalLocalTime struct { + // contains filtered or unexported fields + } + + +*function* NewOptionalLocalTime +............................... + +.. code-block:: go + + func NewOptionalLocalTime(v LocalTime) OptionalLocalTime + +NewOptionalLocalTime is a convenience function for creating an +OptionalLocalTime with its value set to v. + + + + +*method* Get +............ + +.. code-block:: go + + func (o OptionalLocalTime) Get() (LocalTime, bool) + +Get returns the value and a boolean indicating if the value is present. + + + + +*method* MarshalJSON +.................... + +.. code-block:: go + + func (o OptionalLocalTime) MarshalJSON() ([]byte, error) + +MarshalJSON returns o marshaled as json. + + + + +*method* Set +............ + +.. code-block:: go + + func (o *OptionalLocalTime) Set(val LocalTime) + +Set sets the value. + + + + +*method* UnmarshalJSON +...................... + +.. code-block:: go + + func (o *OptionalLocalTime) UnmarshalJSON(bytes []byte) error + +UnmarshalJSON unmarshals bytes into \*o. + + + + +*method* Unset +.............. + +.. code-block:: go + + func (o *OptionalLocalTime) Unset() + +Unset marks the value as missing. + + + + +*type* OptionalMemory +--------------------- + +OptionalMemory is an optional Memory. Optional types must be used for +out parameters when a shape field is not required. + + +.. code-block:: go + + type OptionalMemory struct { + // contains filtered or unexported fields + } + + +*function* NewOptionalMemory +............................ + +.. code-block:: go + + func NewOptionalMemory(v Memory) OptionalMemory + +NewOptionalMemory is a convenience function for creating an +OptionalMemory with its value set to v. + + + + +*method* Get +............ + +.. code-block:: go + + func (o OptionalMemory) Get() (Memory, bool) + +Get returns the value and a boolean indicating if the value is present. + + + + +*method* MarshalJSON +.................... + +.. code-block:: go + + func (o OptionalMemory) MarshalJSON() ([]byte, error) + +MarshalJSON returns o marshaled as json. + + + + +*method* Set +............ + +.. code-block:: go + + func (o *OptionalMemory) Set(val Memory) + +Set sets the value. + + + + +*method* UnmarshalJSON +...................... + +.. code-block:: go + + func (o *OptionalMemory) UnmarshalJSON(bytes []byte) error + +UnmarshalJSON unmarshals bytes into \*o. + + + + +*method* Unset +.............. + +.. code-block:: go + + func (o *OptionalMemory) Unset() + +Unset marks the value as missing. + + + + +*type* OptionalRangeDateTime +---------------------------- + +OptionalRangeDateTime is an optional RangeDateTime. Optional +types must be used for out parameters when a shape field is not required. + + +.. code-block:: go + + type OptionalRangeDateTime struct { + // contains filtered or unexported fields + } + + +*function* NewOptionalRangeDateTime +................................... + +.. code-block:: go + + func NewOptionalRangeDateTime(v RangeDateTime) OptionalRangeDateTime + +NewOptionalRangeDateTime is a convenience function for creating an +OptionalRangeDateTime with its value set to v. + + + + +*method* Get +............ + +.. code-block:: go + + func (o *OptionalRangeDateTime) Get() (RangeDateTime, bool) + +Get returns the value and a boolean indicating if the value is present. + + + + +*method* MarshalJSON +.................... + +.. code-block:: go + + func (o *OptionalRangeDateTime) MarshalJSON() ([]byte, error) + +MarshalJSON returns o marshaled as json. + + + + +*method* Set +............ + +.. code-block:: go + + func (o *OptionalRangeDateTime) Set(val RangeDateTime) + +Set sets the value. + + + + +*method* UnmarshalJSON +...................... + +.. code-block:: go + + func (o *OptionalRangeDateTime) UnmarshalJSON(bytes []byte) error + +UnmarshalJSON unmarshals bytes into \*o. + + + + +*method* Unset +.............. + +.. code-block:: go + + func (o *OptionalRangeDateTime) Unset() + +Unset marks the value as missing. + + + + +*type* OptionalRangeFloat32 +--------------------------- + +OptionalRangeFloat32 is an optional RangeFloat32. Optional +types must be used for out parameters when a shape field is not required. + + +.. code-block:: go + + type OptionalRangeFloat32 struct { + // contains filtered or unexported fields + } + + +*function* NewOptionalRangeFloat32 +.................................. + +.. code-block:: go + + func NewOptionalRangeFloat32(v RangeFloat32) OptionalRangeFloat32 + +NewOptionalRangeFloat32 is a convenience function for creating an +OptionalRangeFloat32 with its value set to v. + + + + +*method* Get +............ + +.. code-block:: go + + func (o OptionalRangeFloat32) Get() (RangeFloat32, bool) + +Get returns the value and a boolean indicating if the value is present. + + + + +*method* MarshalJSON +.................... + +.. code-block:: go + + func (o OptionalRangeFloat32) MarshalJSON() ([]byte, error) + +MarshalJSON returns o marshaled as json. + + + + +*method* Set +............ + +.. code-block:: go + + func (o *OptionalRangeFloat32) Set(val RangeFloat32) + +Set sets the value. + + + + +*method* UnmarshalJSON +...................... + +.. code-block:: go + + func (o *OptionalRangeFloat32) UnmarshalJSON(bytes []byte) error + +UnmarshalJSON unmarshals bytes into \*o. + + + + +*method* Unset +.............. + +.. code-block:: go + + func (o *OptionalRangeFloat32) Unset() + +Unset marks the value as missing. + + + + +*type* OptionalRangeFloat64 +--------------------------- + +OptionalRangeFloat64 is an optional RangeFloat64. Optional +types must be used for out parameters when a shape field is not required. + + +.. code-block:: go + + type OptionalRangeFloat64 struct { + // contains filtered or unexported fields + } + + +*function* NewOptionalRangeFloat64 +.................................. + +.. code-block:: go + + func NewOptionalRangeFloat64(v RangeFloat64) OptionalRangeFloat64 + +NewOptionalRangeFloat64 is a convenience function for creating an +OptionalRangeFloat64 with its value set to v. + + + + +*method* Get +............ + +.. code-block:: go + + func (o OptionalRangeFloat64) Get() (RangeFloat64, bool) + +Get returns the value and a boolean indicating if the value is present. + + + + +*method* MarshalJSON +.................... + +.. code-block:: go + + func (o OptionalRangeFloat64) MarshalJSON() ([]byte, error) + +MarshalJSON returns o marshaled as json. + + + + +*method* Set +............ + +.. code-block:: go + + func (o *OptionalRangeFloat64) Set(val RangeFloat64) + +Set sets the value. + + + + +*method* UnmarshalJSON +...................... + +.. code-block:: go + + func (o *OptionalRangeFloat64) UnmarshalJSON(bytes []byte) error + +UnmarshalJSON unmarshals bytes into \*o. + + + + +*method* Unset +.............. + +.. code-block:: go + + func (o *OptionalRangeFloat64) Unset() + +Unset marks the value as missing. + + + + +*type* OptionalRangeInt32 +------------------------- + +OptionalRangeInt32 is an optional RangeInt32. Optional types must be used +for out parameters when a shape field is not required. + + +.. code-block:: go + + type OptionalRangeInt32 struct { + // contains filtered or unexported fields + } + + +*function* NewOptionalRangeInt32 +................................ + +.. code-block:: go + + func NewOptionalRangeInt32(v RangeInt32) OptionalRangeInt32 + +NewOptionalRangeInt32 is a convenience function for creating an +OptionalRangeInt32 with its value set to v. + + + + +*method* Get +............ + +.. code-block:: go + + func (o OptionalRangeInt32) Get() (RangeInt32, bool) + +Get returns the value and a boolean indicating if the value is present. + + + + +*method* MarshalJSON +.................... + +.. code-block:: go + + func (o OptionalRangeInt32) MarshalJSON() ([]byte, error) + +MarshalJSON returns o marshaled as json. + + + + +*method* Set +............ + +.. code-block:: go + + func (o *OptionalRangeInt32) Set(val RangeInt32) + +Set sets the value. + + + + +*method* UnmarshalJSON +...................... + +.. code-block:: go + + func (o *OptionalRangeInt32) UnmarshalJSON(bytes []byte) error + +UnmarshalJSON unmarshals bytes into \*o. + + + + +*method* Unset +.............. + +.. code-block:: go + + func (o *OptionalRangeInt32) Unset() + +Unset marks the value as missing. + + + + +*type* OptionalRangeInt64 +------------------------- + +OptionalRangeInt64 is an optional RangeInt64. Optional +types must be used for out parameters when a shape field is not required. + + +.. code-block:: go + + type OptionalRangeInt64 struct { + // contains filtered or unexported fields + } + + +*function* NewOptionalRangeInt64 +................................ + +.. code-block:: go + + func NewOptionalRangeInt64(v RangeInt64) OptionalRangeInt64 + +NewOptionalRangeInt64 is a convenience function for creating an +OptionalRangeInt64 with its value set to v. + + + + +*method* Get +............ + +.. code-block:: go + + func (o OptionalRangeInt64) Get() (RangeInt64, bool) + +Get returns the value and a boolean indicating if the value is present. + + + + +*method* MarshalJSON +.................... + +.. code-block:: go + + func (o OptionalRangeInt64) MarshalJSON() ([]byte, error) + +MarshalJSON returns o marshaled as json. + + + + +*method* Set +............ + +.. code-block:: go + + func (o *OptionalRangeInt64) Set(val RangeInt64) + +Set sets the value. + + + + +*method* UnmarshalJSON +...................... + +.. code-block:: go + + func (o *OptionalRangeInt64) UnmarshalJSON(bytes []byte) error + +UnmarshalJSON unmarshals bytes into \*o. + + + + +*method* Unset +.............. + +.. code-block:: go + + func (o *OptionalRangeInt64) Unset() + +Unset marks the value as missing. + + + + +*type* OptionalRangeLocalDate +----------------------------- + +OptionalRangeLocalDate is an optional RangeLocalDate. Optional types must be +used for out parameters when a shape field is not required. + + +.. code-block:: go + + type OptionalRangeLocalDate struct { + // contains filtered or unexported fields + } + + +*function* NewOptionalRangeLocalDate +.................................... + +.. code-block:: go + + func NewOptionalRangeLocalDate(v RangeLocalDate) OptionalRangeLocalDate + +NewOptionalRangeLocalDate is a convenience function for creating an +OptionalRangeLocalDate with its value set to v. + + + + +*method* Get +............ + +.. code-block:: go + + func (o OptionalRangeLocalDate) Get() (RangeLocalDate, bool) + +Get returns the value and a boolean indicating if the value is present. + + + + +*method* MarshalJSON +.................... + +.. code-block:: go + + func (o OptionalRangeLocalDate) MarshalJSON() ([]byte, error) + +MarshalJSON returns o marshaled as json. + + + + +*method* Set +............ + +.. code-block:: go + + func (o *OptionalRangeLocalDate) Set(val RangeLocalDate) + +Set sets the value. + + + + +*method* UnmarshalJSON +...................... + +.. code-block:: go + + func (o *OptionalRangeLocalDate) UnmarshalJSON(bytes []byte) error + +UnmarshalJSON unmarshals bytes into \*o. + + + + +*method* Unset +.............. + +.. code-block:: go + + func (o *OptionalRangeLocalDate) Unset() + +Unset marks the value as missing. + + + + +*type* OptionalRangeLocalDateTime +--------------------------------- + +OptionalRangeLocalDateTime is an optional RangeLocalDateTime. Optional +types must be used for out parameters when a shape field is not required. + + +.. code-block:: go + + type OptionalRangeLocalDateTime struct { + // contains filtered or unexported fields + } + + +*function* NewOptionalRangeLocalDateTime +........................................ + +.. code-block:: go + + func NewOptionalRangeLocalDateTime( + v RangeLocalDateTime, + ) OptionalRangeLocalDateTime + +NewOptionalRangeLocalDateTime is a convenience function for creating an +OptionalRangeLocalDateTime with its value set to v. + + + + +*method* Get +............ + +.. code-block:: go + + func (o OptionalRangeLocalDateTime) Get() (RangeLocalDateTime, bool) + +Get returns the value and a boolean indicating if the value is present. + + + + +*method* MarshalJSON +.................... + +.. code-block:: go + + func (o OptionalRangeLocalDateTime) MarshalJSON() ([]byte, error) + +MarshalJSON returns o marshaled as json. + + + + +*method* Set +............ + +.. code-block:: go + + func (o *OptionalRangeLocalDateTime) Set(val RangeLocalDateTime) + +Set sets the value. + + + + +*method* UnmarshalJSON +...................... + +.. code-block:: go + + func (o *OptionalRangeLocalDateTime) UnmarshalJSON(bytes []byte) error + +UnmarshalJSON unmarshals bytes into \*o. + + + + +*method* Unset +.............. + +.. code-block:: go + + func (o *OptionalRangeLocalDateTime) Unset() + +Unset marks the value as missing. + + + + +*type* OptionalRelativeDuration +------------------------------- + +OptionalRelativeDuration is an optional RelativeDuration. Optional types +must be used for out parameters when a shape field is not required. + + +.. code-block:: go + + type OptionalRelativeDuration struct { + // contains filtered or unexported fields + } + + +*function* NewOptionalRelativeDuration +...................................... + +.. code-block:: go + + func NewOptionalRelativeDuration(v RelativeDuration) OptionalRelativeDuration + +NewOptionalRelativeDuration is a convenience function for creating an +OptionalRelativeDuration with its value set to v. + + + + +*method* Get +............ + +.. code-block:: go + + func (o OptionalRelativeDuration) Get() (RelativeDuration, bool) + +Get returns the value and a boolean indicating if the value is present. + + + + +*method* MarshalJSON +.................... + +.. code-block:: go + + func (o OptionalRelativeDuration) MarshalJSON() ([]byte, error) + +MarshalJSON returns o marshaled as json. + + + + +*method* Set +............ + +.. code-block:: go + + func (o *OptionalRelativeDuration) Set(val RelativeDuration) + +Set sets the value. + + + + +*method* UnmarshalJSON +...................... + +.. code-block:: go + + func (o *OptionalRelativeDuration) UnmarshalJSON(bytes []byte) error + +UnmarshalJSON unmarshals bytes into \*o. + + + + +*method* Unset +.............. + +.. code-block:: go + + func (o *OptionalRelativeDuration) Unset() + +Unset marks the value as missing. + + + + +*type* OptionalStr +------------------ + +OptionalStr is an optional string. Optional types must be used for out +parameters when a shape field is not required. + + +.. code-block:: go + + type OptionalStr struct { + // contains filtered or unexported fields + } + + +*function* NewOptionalStr +......................... + +.. code-block:: go + + func NewOptionalStr(v string) OptionalStr + +NewOptionalStr is a convenience function for creating an OptionalStr with +its value set to v. + + + + +*method* Get +............ + +.. code-block:: go + + func (o OptionalStr) Get() (string, bool) + +Get returns the value and a boolean indicating if the value is present. + + + + +*method* MarshalJSON +.................... + +.. code-block:: go + + func (o OptionalStr) MarshalJSON() ([]byte, error) + +MarshalJSON returns o marshaled as json. + + + + +*method* Set +............ + +.. code-block:: go + + func (o *OptionalStr) Set(val string) + +Set sets the value. + + + + +*method* UnmarshalJSON +...................... + +.. code-block:: go + + func (o *OptionalStr) UnmarshalJSON(bytes []byte) error + +UnmarshalJSON unmarshals bytes into \*o. + + + + +*method* Unset +.............. + +.. code-block:: go + + func (o *OptionalStr) Unset() + +Unset marks the value as missing. + + + + +*type* OptionalUUID +------------------- + +OptionalUUID is an optional UUID. Optional types must be used for out +parameters when a shape field is not required. + + +.. code-block:: go + + type OptionalUUID struct { + // contains filtered or unexported fields + } + + +*function* NewOptionalUUID +.......................... + +.. code-block:: go + + func NewOptionalUUID(v UUID) OptionalUUID + +NewOptionalUUID is a convenience function for creating an OptionalUUID with +its value set to v. + + + + +*method* Get +............ + +.. code-block:: go + + func (o OptionalUUID) Get() (UUID, bool) + +Get returns the value and a boolean indicating if the value is present. + + + + +*method* MarshalJSON +.................... + +.. code-block:: go + + func (o OptionalUUID) MarshalJSON() ([]byte, error) + +MarshalJSON returns o marshaled as json. + + + + +*method* Set +............ + +.. code-block:: go + + func (o *OptionalUUID) Set(val UUID) + +Set sets the value. + + + + +*method* UnmarshalJSON +...................... + +.. code-block:: go + + func (o *OptionalUUID) UnmarshalJSON(bytes []byte) error + +UnmarshalJSON unmarshals bytes into \*o + + + + +*method* Unset +.............. + +.. code-block:: go + + func (o *OptionalUUID) Unset() + +Unset marks the value as missing. + + + + +*type* RangeDateTime +-------------------- + +RangeDateTime is an interval of time.Time values. + + +.. code-block:: go + + type RangeDateTime struct { + // contains filtered or unexported fields + } + + +*function* NewRangeDateTime +........................... + +.. code-block:: go + + func NewRangeDateTime( + lower, upper OptionalDateTime, + incLower, incUpper bool, + ) RangeDateTime + +NewRangeDateTime creates a new RangeDateTime value. + + + + +*method* Empty +.............. + +.. code-block:: go + + func (r RangeDateTime) Empty() bool + +Empty returns true if the range is empty. + + + + +*method* IncLower +................. + +.. code-block:: go + + func (r RangeDateTime) IncLower() bool + +IncLower returns true if the lower bound is inclusive. + + + + +*method* IncUpper +................. + +.. code-block:: go + + func (r RangeDateTime) IncUpper() bool + +IncUpper returns true if the upper bound is inclusive. + + + + +*method* Lower +.............. + +.. code-block:: go + + func (r RangeDateTime) Lower() OptionalDateTime + +Lower returns the lower bound. + + + + +*method* MarshalJSON +.................... + +.. code-block:: go + + func (r RangeDateTime) MarshalJSON() ([]byte, error) + +MarshalJSON returns r marshaled as json. + + + + +*method* UnmarshalJSON +...................... + +.. code-block:: go + + func (r *RangeDateTime) UnmarshalJSON(data []byte) error + +UnmarshalJSON unmarshals bytes into \*r. + + + + +*method* Upper +.............. + +.. code-block:: go + + func (r RangeDateTime) Upper() OptionalDateTime + +Upper returns the upper bound. + + + + +*type* RangeFloat32 +------------------- + +RangeFloat32 is an interval of float32 values. + + +.. code-block:: go + + type RangeFloat32 struct { + // contains filtered or unexported fields + } + + +*function* NewRangeFloat32 +.......................... + +.. code-block:: go + + func NewRangeFloat32( + lower, upper OptionalFloat32, + incLower, incUpper bool, + ) RangeFloat32 + +NewRangeFloat32 creates a new RangeFloat32 value. + + + + +*method* Empty +.............. + +.. code-block:: go + + func (r RangeFloat32) Empty() bool + +Empty returns true if the range is empty. + + + + +*method* IncLower +................. + +.. code-block:: go + + func (r RangeFloat32) IncLower() bool + +IncLower returns true if the lower bound is inclusive. + + + + +*method* IncUpper +................. + +.. code-block:: go + + func (r RangeFloat32) IncUpper() bool + +IncUpper returns true if the upper bound is inclusive. + + + + +*method* Lower +.............. + +.. code-block:: go + + func (r RangeFloat32) Lower() OptionalFloat32 + +Lower returns the lower bound. + + + + +*method* MarshalJSON +.................... + +.. code-block:: go + + func (r RangeFloat32) MarshalJSON() ([]byte, error) + +MarshalJSON returns r marshaled as json. + + + + +*method* UnmarshalJSON +...................... + +.. code-block:: go + + func (r *RangeFloat32) UnmarshalJSON(data []byte) error + +UnmarshalJSON unmarshals bytes into \*r. + + + + +*method* Upper +.............. + +.. code-block:: go + + func (r RangeFloat32) Upper() OptionalFloat32 + +Upper returns the upper bound. + + + + +*type* RangeFloat64 +------------------- + +RangeFloat64 is an interval of float64 values. + + +.. code-block:: go + + type RangeFloat64 struct { + // contains filtered or unexported fields + } + + +*function* NewRangeFloat64 +.......................... + +.. code-block:: go + + func NewRangeFloat64( + lower, upper OptionalFloat64, + incLower, incUpper bool, + ) RangeFloat64 + +NewRangeFloat64 creates a new RangeFloat64 value. + + + + +*method* Empty +.............. + +.. code-block:: go + + func (r RangeFloat64) Empty() bool + +Empty returns true if the range is empty. + + + + +*method* IncLower +................. + +.. code-block:: go + + func (r RangeFloat64) IncLower() bool + +IncLower returns true if the lower bound is inclusive. + + + + +*method* IncUpper +................. + +.. code-block:: go + + func (r RangeFloat64) IncUpper() bool + +IncUpper returns true if the upper bound is inclusive. + + + + +*method* Lower +.............. + +.. code-block:: go + + func (r RangeFloat64) Lower() OptionalFloat64 + +Lower returns the lower bound. + + + + +*method* MarshalJSON +.................... + +.. code-block:: go + + func (r RangeFloat64) MarshalJSON() ([]byte, error) + +MarshalJSON returns r marshaled as json. + + + + +*method* UnmarshalJSON +...................... + +.. code-block:: go + + func (r *RangeFloat64) UnmarshalJSON(data []byte) error + +UnmarshalJSON unmarshals bytes into \*r. + + + + +*method* Upper +.............. + +.. code-block:: go + + func (r RangeFloat64) Upper() OptionalFloat64 + +Upper returns the upper bound. + + + + +*type* RangeInt32 +----------------- + +RangeInt32 is an interval of int32 values. + + +.. code-block:: go + + type RangeInt32 struct { + // contains filtered or unexported fields + } + + +*function* NewRangeInt32 +........................ + +.. code-block:: go + + func NewRangeInt32( + lower, upper OptionalInt32, + incLower, incUpper bool, + ) RangeInt32 + +NewRangeInt32 creates a new RangeInt32 value. + + + + +*method* Empty +.............. + +.. code-block:: go + + func (r RangeInt32) Empty() bool + +Empty returns true if the range is empty. + + + + +*method* IncLower +................. + +.. code-block:: go + + func (r RangeInt32) IncLower() bool + +IncLower returns true if the lower bound is inclusive. + + + + +*method* IncUpper +................. + +.. code-block:: go + + func (r RangeInt32) IncUpper() bool + +IncUpper returns true if the upper bound is inclusive. + + + + +*method* Lower +.............. + +.. code-block:: go + + func (r RangeInt32) Lower() OptionalInt32 + +Lower returns the lower bound. + + + + +*method* MarshalJSON +.................... + +.. code-block:: go + + func (r RangeInt32) MarshalJSON() ([]byte, error) + +MarshalJSON returns r marshaled as json. + + + + +*method* UnmarshalJSON +...................... + +.. code-block:: go + + func (r *RangeInt32) UnmarshalJSON(data []byte) error + +UnmarshalJSON unmarshals bytes into \*r. + + + + +*method* Upper +.............. + +.. code-block:: go + + func (r RangeInt32) Upper() OptionalInt32 + +Upper returns the upper bound. + + + + +*type* RangeInt64 +----------------- + +RangeInt64 is an interval of int64 values. + + +.. code-block:: go + + type RangeInt64 struct { + // contains filtered or unexported fields + } + + +*function* NewRangeInt64 +........................ + +.. code-block:: go + + func NewRangeInt64( + lower, upper OptionalInt64, + incLower, incUpper bool, + ) RangeInt64 + +NewRangeInt64 creates a new RangeInt64 value. + + + + +*method* Empty +.............. + +.. code-block:: go + + func (r RangeInt64) Empty() bool + +Empty returns true if the range is empty. + + + + +*method* IncLower +................. + +.. code-block:: go + + func (r RangeInt64) IncLower() bool + +IncLower returns true if the lower bound is inclusive. + + + + +*method* IncUpper +................. + +.. code-block:: go + + func (r RangeInt64) IncUpper() bool + +IncUpper returns true if the upper bound is inclusive. + + + + +*method* Lower +.............. + +.. code-block:: go + + func (r RangeInt64) Lower() OptionalInt64 + +Lower returns the lower bound. + + + + +*method* MarshalJSON +.................... + +.. code-block:: go + + func (r RangeInt64) MarshalJSON() ([]byte, error) + +MarshalJSON returns r marshaled as json. + + + + +*method* UnmarshalJSON +...................... + +.. code-block:: go + + func (r *RangeInt64) UnmarshalJSON(data []byte) error + +UnmarshalJSON unmarshals bytes into \*r. + + + + +*method* Upper +.............. + +.. code-block:: go + + func (r RangeInt64) Upper() OptionalInt64 + +Upper returns the upper bound. + + + + +*type* RangeLocalDate +--------------------- + +RangeLocalDate is an interval of LocalDate values. + + +.. code-block:: go + + type RangeLocalDate struct { + // contains filtered or unexported fields + } + + +*function* NewRangeLocalDate +............................ + +.. code-block:: go + + func NewRangeLocalDate( + lower, upper OptionalLocalDate, + incLower, incUpper bool, + ) RangeLocalDate + +NewRangeLocalDate creates a new RangeLocalDate value. + + + + +*method* Empty +.............. + +.. code-block:: go + + func (r RangeLocalDate) Empty() bool + +Empty returns true if the range is empty. + + + + +*method* IncLower +................. + +.. code-block:: go + + func (r RangeLocalDate) IncLower() bool + +IncLower returns true if the lower bound is inclusive. + + + + +*method* IncUpper +................. + +.. code-block:: go + + func (r RangeLocalDate) IncUpper() bool + +IncUpper returns true if the upper bound is inclusive. + + + + +*method* Lower +.............. + +.. code-block:: go + + func (r RangeLocalDate) Lower() OptionalLocalDate + +Lower returns the lower bound. + + + + +*method* MarshalJSON +.................... + +.. code-block:: go + + func (r RangeLocalDate) MarshalJSON() ([]byte, error) + +MarshalJSON returns r marshaled as json. + + + + +*method* UnmarshalJSON +...................... + +.. code-block:: go + + func (r *RangeLocalDate) UnmarshalJSON(data []byte) error + +UnmarshalJSON unmarshals bytes into \*r. + + + + +*method* Upper +.............. + +.. code-block:: go + + func (r RangeLocalDate) Upper() OptionalLocalDate + +Upper returns the upper bound. + + + + +*type* RangeLocalDateTime +------------------------- + +RangeLocalDateTime is an interval of LocalDateTime values. + + +.. code-block:: go + + type RangeLocalDateTime struct { + // contains filtered or unexported fields + } + + +*function* NewRangeLocalDateTime +................................ + +.. code-block:: go + + func NewRangeLocalDateTime( + lower, upper OptionalLocalDateTime, + incLower, incUpper bool, + ) RangeLocalDateTime + +NewRangeLocalDateTime creates a new RangeLocalDateTime value. + + + + +*method* Empty +.............. + +.. code-block:: go + + func (r RangeLocalDateTime) Empty() bool + +Empty returns true if the range is empty. + + + + +*method* IncLower +................. + +.. code-block:: go + + func (r RangeLocalDateTime) IncLower() bool + +IncLower returns true if the lower bound is inclusive. + + + + +*method* IncUpper +................. + +.. code-block:: go + + func (r RangeLocalDateTime) IncUpper() bool + +IncUpper returns true if the upper bound is inclusive. + + + + +*method* Lower +.............. + +.. code-block:: go + + func (r RangeLocalDateTime) Lower() OptionalLocalDateTime + +Lower returns the lower bound. + + + + +*method* MarshalJSON +.................... + +.. code-block:: go + + func (r RangeLocalDateTime) MarshalJSON() ([]byte, error) + +MarshalJSON returns r marshaled as json. + + + + +*method* UnmarshalJSON +...................... + +.. code-block:: go + + func (r *RangeLocalDateTime) UnmarshalJSON(data []byte) error + +UnmarshalJSON unmarshals bytes into \*r. + + + + +*method* Upper +.............. + +.. code-block:: go + + func (r RangeLocalDateTime) Upper() OptionalLocalDateTime + +Upper returns the upper bound. + + + + +*type* RelativeDuration +----------------------- + +RelativeDuration represents the elapsed time between two instants in a fuzzy +human way. + + +.. code-block:: go + + type RelativeDuration struct { + // contains filtered or unexported fields + } + + +*function* NewRelativeDuration +.............................. + +.. code-block:: go + + func NewRelativeDuration( + months, days int32, + microseconds int64, + ) RelativeDuration + +NewRelativeDuration returns a new RelativeDuration + + + + +*method* MarshalText +.................... + +.. code-block:: go + + func (rd RelativeDuration) MarshalText() ([]byte, error) + +MarshalText returns rd marshaled as text. + + + + +*method* String +............... + +.. code-block:: go + + func (rd RelativeDuration) String() string + + + + +*method* UnmarshalText +...................... + +.. code-block:: go + + func (rd *RelativeDuration) UnmarshalText(b []byte) error + +UnmarshalText unmarshals bytes into \*rd. + + + + +*type* UUID +----------- + +UUID is a universally unique identifier +`docs/stdlib/uuid `_ + + +.. code-block:: go + + type UUID [16]byte + + +*function* ParseUUID +.................... + +.. code-block:: go + + func ParseUUID(s string) (UUID, error) + +ParseUUID parses s into a UUID or returns an error. + + + + +*method* MarshalText +.................... + +.. code-block:: go + + func (id UUID) MarshalText() ([]byte, error) + +MarshalText returns the id as a byte string. + + + + +*method* String +............... + +.. code-block:: go + + func (id UUID) String() string + + + + +*method* UnmarshalText +...................... + +.. code-block:: go + + func (id *UUID) UnmarshalText(b []byte) error + +UnmarshalText unmarshals the id from a string. + diff --git a/docs/clients/graphql/cheatsheet.rst b/docs/clients/graphql/cheatsheet.rst index ae2d86819a9..27b3ea2ac20 100644 --- a/docs/clients/graphql/cheatsheet.rst +++ b/docs/clients/graphql/cheatsheet.rst @@ -19,8 +19,8 @@ the schema: using extension graphql; Then create a new migration and apply it using -:ref:`ref_cli_edgedb_migration_create` and -:ref:`ref_cli_edgedb_migrate`, respectively. +:ref:`ref_cli_gel_migration_create` and +:ref:`ref_cli_gel_migrate`, respectively. Select all users in the system: diff --git a/docs/clients/graphql/graphql.rst b/docs/clients/graphql/graphql.rst index 49b0c238ea9..b6f79676d36 100644 --- a/docs/clients/graphql/graphql.rst +++ b/docs/clients/graphql/graphql.rst @@ -24,7 +24,7 @@ containing the following schema: } } -From the schema above, EdgeDB will expose to GraphQL: +From the schema above, |Gel| will expose to GraphQL: * object types ``Author`` and ``Book`` * scalars ``String`` and ``ID`` diff --git a/docs/clients/graphql/index.rst b/docs/clients/graphql/index.rst index e199b893e8a..0297f4c89b3 100644 --- a/docs/clients/graphql/index.rst +++ b/docs/clients/graphql/index.rst @@ -17,7 +17,7 @@ GraphQL cheatsheet -EdgeDB supports `GraphQL queries`__ via the built-in ``graphql`` extension. A +|Gel| supports `GraphQL queries`__ via the built-in ``graphql`` extension. A full CRUD API for all object types, their properties (both material and computed), their links, and all :ref:`aliases ` is reflected in the GraphQL schema. @@ -36,10 +36,10 @@ Then create a new migration and apply it. .. code-block:: bash - $ edgedb migration create - $ edgedb migrate + $ gel migration create + $ gel migrate -Refer to the :ref:`connection docs ` for various +Refer to the :ref:`connection docs ` for various methods of running these commands against remotely-hosted instances. Connection @@ -50,32 +50,32 @@ GraphQL queries via HTTP at the following URL. ``http:///branch//graphql`` -The default ``branch-name`` will be ``main``, and after initializing your +The default ``branch-name`` will be |main|, and after initializing your database, all queries are executed against it by default. If you want to query another branch instead, simply use that branch name in the URL. -To find the port number associated with a local instance, run ``edgedb -instance list``. +To find the port number associated with a local instance, run +:gelcmd:`instance list`. .. code-block:: bash - $ edgedb instance list + $ gel instance list β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Kind β”‚ Name β”‚ Port β”‚ Version β”‚ Status β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ - β”‚ local β”‚ inst1 β”‚ 10700 β”‚ 2.x β”‚ running β”‚ - β”‚ local β”‚ inst2 β”‚ 10702 β”‚ 2.x β”‚ running β”‚ - β”‚ local β”‚ inst3 β”‚ 10703 β”‚ 2.x β”‚ running β”‚ + β”‚ local β”‚ inst1 β”‚ 10700 β”‚ 6.x β”‚ running β”‚ + β”‚ local β”‚ inst2 β”‚ 10702 β”‚ 6.x β”‚ running β”‚ + β”‚ local β”‚ inst3 β”‚ 10703 β”‚ 6.x β”‚ running β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -To execute a GraphQL query against the branch ``main`` on the instance +To execute a GraphQL query against the |main| branch on the instance named ``inst2``, we would send an HTTP request to -``http://localhost:10702/branch/edgedb/main``. +``http://localhost:10702/branch/gel/main``. -To determine the URL of an EdgeDB Cloud instance, find the host by running -``edgedb instance credentials -I /``. Use the +To determine the URL of a |Gel| Cloud instance, find the host by running +:gelcmd:`instance credentials -I /`. Use the ``host`` and ``port`` from that table in the URL format at the top of this -section. Change the protocol to ``https`` since EdgeDB Cloud instances are +section. Change the protocol to ``https`` since Gel Cloud instances are secured with TLS. .. note:: @@ -99,7 +99,7 @@ Authentication for the GraphQL endpoint is identical to that for the The protocol ------------ -EdgeDB can recieve GraphQL queries via both ``GET`` and ``POST`` requests. +|Gel| can recieve GraphQL queries via both ``GET`` and ``POST`` requests. Requests can contain the following fields: - ``query`` - the GraphQL query string @@ -223,11 +223,11 @@ There are also some additional limitations: - :ref:`Link properties` are not reflected, as GraphQL has no such concept. -- Every non-abstract EdgeDB object type is simultaneously an interface +- Every non-abstract |Gel| object type is simultaneously an interface and an object in terms of the GraphQL type system, which means that, for every one object type name, two names are needed in reflected GraphQL. This potentially results in name clashes if the convention - of using camel-case names for user types is not followed in EdgeDB. + of using camel-case names for user types is not followed in Gel. .. __: http://graphql.org/docs/queries/ diff --git a/docs/clients/graphql/introspection.rst b/docs/clients/graphql/introspection.rst index 42ff63841d6..6a2e8f51298 100644 --- a/docs/clients/graphql/introspection.rst +++ b/docs/clients/graphql/introspection.rst @@ -4,9 +4,9 @@ Introspection ============= -GraphQL introspection can be used to explore the exposed EdgeDB types +GraphQL introspection can be used to explore the exposed |Gel| types and expresssion aliases. Note that there are certain types like -:eql:type:`tuple` that cannot be expressed in terms of the GraphQL +:eql:type:`tuple` that cannot be expressed in terms of the GraphQL type system (a ``tuple`` can be like a heterogeneous "List"). Consider the following GraphQL introspection query: diff --git a/docs/clients/graphql/mutations.rst b/docs/clients/graphql/mutations.rst index 79133092fbd..a670dc2fd96 100644 --- a/docs/clients/graphql/mutations.rst +++ b/docs/clients/graphql/mutations.rst @@ -4,7 +4,7 @@ Mutations ========= -EdgeDB provides GraphQL mutations to perform ``delete``, ``insert`` +|Gel| provides GraphQL mutations to perform ``delete``, ``insert`` and ``update`` operations. diff --git a/docs/clients/http/health-checks.rst b/docs/clients/http/health-checks.rst index 9fde911ebc3..ccb08c40769 100644 --- a/docs/clients/http/health-checks.rst +++ b/docs/clients/http/health-checks.rst @@ -4,7 +4,7 @@ Health Checks ============= -EdgeDB exposes HTTP endpoints to check for aliveness and readiness of your +|Gel| exposes HTTP endpoints to check for aliveness and readiness of your database instance. You can make GET requests to these endpoints to check the instance status. diff --git a/docs/clients/http/index.rst b/docs/clients/http/index.rst index fac728a8fc5..69cf6f05fdd 100644 --- a/docs/clients/http/index.rst +++ b/docs/clients/http/index.rst @@ -11,7 +11,7 @@ EdgeQL over HTTP protocol health-checks -EdgeDB can expose an HTTP endpoint for EdgeQL queries. Since HTTP is a +|Gel| can expose an HTTP endpoint for EdgeQL queries. Since HTTP is a stateless protocol, no :ref:`DDL `, :ref:`transaction commands `, can be executed using this endpoint. Only one query per request can be @@ -25,34 +25,34 @@ the schema: using extension edgeql_http; Then create a new migration and apply it using -:ref:`ref_cli_edgedb_migration_create` and -:ref:`ref_cli_edgedb_migrate`, respectively. +:ref:`ref_cli_gel_migration_create` and +:ref:`ref_cli_gel_migrate`, respectively. Your instance can now receive EdgeQL queries over HTTP at ``https://:/branch//edgeql``. .. note:: - Here's how to determine your local EdgeDB instance's HTTP server URL: + Here's how to determine your local |Gel| instance's HTTP server URL: - The ``hostname`` will be ``localhost`` - - Find the ``port`` by running ``edgedb instance list``. This will print a - table of all EdgeDB instances on your machine, including their associated + - Find the ``port`` by running :gelcmd:`instance list`. This will print a + table of all |Gel| instances on your machine, including their associated port number. - - The default ``branch-name`` will be ``main``, and after initializing + - The default ``branch-name`` will be |main|, and after initializing your database, all queries are executed against it by default. If you want to query another branch instead, simply use that branch name in the URL. - To determine the URL of an EdgeDB Cloud instance, find the host by running - ``edgedb instance credentials -I /``. Use the + To determine the URL of a |Gel| Cloud instance, find the host by running + :gelcmd:`instance credentials -I /`. Use the ``host`` and ``port`` from that table in the URL format above this note. - Change the protocol to ``https`` since EdgeDB Cloud instances are secured + Change the protocol to ``https`` since Gel Cloud instances are secured with TLS. To determine the URL of a self-hosted remote instance you have linked with the CLI, you can get both the hostname and port of the instance from the - "Port" column of the ``edgedb instance list`` table (formatted as + "Port" column of the :gelcmd:`instance list` table (formatted as ``:``). The same guidance on local branch names applies here. @@ -70,7 +70,7 @@ By default, the HTTP endpoint uses :eql:type:`cfg::Password` based authentication, in which `HTTP Basic Authentication `_ -is used to provide an EdgeDB username and password. +is used to provide a |Gel| username and password. .. lint-on @@ -81,7 +81,7 @@ mechanism can be configured by adjusting which If :eql:type:`cfg::JWT` is used, the requests should contain these headers: -* ``X-EdgeDB-User``: The EdgeDB username. +* ``X-EdgeDB-User``: The |Gel| username. * ``Authorization``: The JWT authorization token prefixed by ``Bearer``. @@ -96,8 +96,8 @@ behavior:: ... }; OK: CONFIGURE INSTANCE -To authenticate to your EdgeDB Cloud instance, first create a secret key using -the EdgeDB Cloud UI or :ref:`ref_cli_edgedb_cloud_secretkey_create`. Use the +To authenticate to your |Gel| Cloud instance, first create a secret key using +the Gel Cloud UI or :ref:`ref_cli_gel_cloud_secretkey_create`. Use the secret key as your token with the bearer authentication method. Here is an example showing how you might send the query ``select Person {*};`` using cURL: diff --git a/docs/clients/http/protocol.rst b/docs/clients/http/protocol.rst index 721dd497905..44e29bda9e0 100644 --- a/docs/clients/http/protocol.rst +++ b/docs/clients/http/protocol.rst @@ -4,7 +4,7 @@ Protocol ======== -EdgeDB supports GET and POST methods for handling EdgeQL over HTTP +|Gel| supports GET and POST methods for handling EdgeQL over HTTP protocol. Both GET and POST methods use the following fields: - ``query`` - contains the EdgeQL query string diff --git a/docs/clients/index.rst b/docs/clients/index.rst index df6f536da90..575fae31270 100644 --- a/docs/clients/index.rst +++ b/docs/clients/index.rst @@ -6,15 +6,11 @@ Client Libraries ================ -**Official Client Libraries** +**Client Libraries** * `Python `_ * `TypeScript/JavaScript `_ * `Go `_ -* `Rust `_ -* `.NET `_ -* `Java `_ -* `Elixir `_ **HTTP Protocols** @@ -30,10 +26,5 @@ Client Libraries js/index python/index go/index - rust/index - dart/index - dotnet/index - java/index - elixir/index http/index graphql/index diff --git a/docs/clients/java/index.rst b/docs/clients/java/index.rst deleted file mode 100644 index 7e28eb27dee..00000000000 --- a/docs/clients/java/index.rst +++ /dev/null @@ -1,9 +0,0 @@ -.. _edgedb-java-intro: - -==== -Java -==== - -The documentation for the Java client is automatically pulled -from https://github.com/edgedb/edgedb-java/tree/master/docs by the -build pipeline of the edgedb.com website. diff --git a/docs/clients/js/delete.rst b/docs/clients/js/delete.rst new file mode 100644 index 00000000000..7317839da26 --- /dev/null +++ b/docs/clients/js/delete.rst @@ -0,0 +1,19 @@ +.. _gel-js-delete: + +Delete +------ + +Delete objects with ``e.delete``. + +.. code-block:: typescript + + e.delete(e.Movie, movie => ({ + filter: e.op(movie.release_year, ">", 2000), + filter_single: { id: "abc..." }, + order_by: movie.title, + offset: 10, + limit: 10 + })); + +The only supported keys are ``filter``, ``filter_single``, ``order_by``, +``offset``, and ``limit``. diff --git a/docs/clients/js/driver.rst b/docs/clients/js/driver.rst new file mode 100644 index 00000000000..17c7000d4ee --- /dev/null +++ b/docs/clients/js/driver.rst @@ -0,0 +1,461 @@ +.. _gel-js-driver: + + +Client +====== + +The ``Client`` class implements the basic functionality required to establish a +connection to your database and execute queries. + +.. _gel-js-create-client: + +Creating clients +---------------- + +A *client* represents a connection to your database and provides methods for +executing queries. + +.. note:: + + In actuality, the client maintains a *pool* of connections under the hood. + When your server is under load, queries will be run in parallel across many + connections, instead of being bottlenecked by a single connection. + +To create a client: + +.. code-block:: javascript + + const gel = require("gel"); + + const client = gel.createClient(); + + +If you're using TypeScript or have ES modules enabled, you can use +``import`` syntax instead: + +.. code-block:: javascript + + import * as gel from "gel"; + + const client = gel.createClient(); + + +Connections +^^^^^^^^^^^ + +Notice we didn't pass any arguments into ``createClient``. That's intentional. + +**In development**, we recommend using :gelcmd:`project init` to create an +instance and link it to your project directory. As long as you're inside this +directory, ``createClient()`` with auto-detect the project and connect to the +associated instance automatically. + +**In production** you should use environment variables to provide connection +information to ``createClient``. See the :ref:`Connection parameters +` docs for details. + +Configuring clients +^^^^^^^^^^^^^^^^^^^ + +Clients can be configured using a set of *immutable* methods that start with +``with``. + +.. note:: + + These methods return a *new Client instance* that *shares a connection pool* + with the original client! This is important. Each call to ``createClient`` + instantiates a new connection pool. + +The code example below demonstrates all available configuration settings. The +value specified below is the *default value* for that setting. + +.. code-block:: typescript + + import {createClient, Duration, IsolationLevel} from "gel"; + + const baseClient = createClient(); + const client = baseClient + .withConfig({ + // 10 seconds + session_idle_transaction_timeout: Duration.from({seconds: 10}), + // 0 seconds === no timeout + query_execution_timeout: Duration.from({seconds: 0}), + allow_bare_ddl: "NeverAllow", + allow_user_specified_id: false, + apply_access_policies: true, + }) + .withRetryOptions({ + attempts: 3, + backoff: (attemptNo: number) => { + // exponential backoff + return 2 ** attemptNo * 100 + Math.random() * 100; + }, + }) + .withTransactionOptions({ + isolation: IsolationLevel.Serializable, // only supported value + deferrable: false, + readonly: false, + }); + +Running queries +--------------- + +To execute a basic query: + +.. code-block:: javascript + + const gel = require("gel"); + + const client = gel.createClient(); + + async function main() { + const result = await client.query(`select 2 + 2;`); + console.log(result); // [4] + } + + +.. _gel-js-typescript: + +In TypeScript, you can supply a type hint to receive a strongly typed result. + +.. code-block:: javascript + + const result = await client.query(`select 2 + 2;`); + // number[] + +``.query`` method +^^^^^^^^^^^^^^^^^ + +The ``.query`` method always returns an array of results. It places no +constraints on cardinality. + +.. code-block:: javascript + + await client.query(`select 2 + 2;`); // [4] + await client.query(`select [1, 2, 3];`); // [[1, 2, 3]] + await client.query(`select {};`); // [] + await client.query(`select {1, 2, 3};`); // [1, 2, 3] + +``.querySingle`` method +^^^^^^^^^^^^^^^^^^^^^^^ + +If you know your query will only return a single element, you can tell |Gel| +to expect a *singleton result* by using the ``.querySingle`` method. This is +intended for queries that return *zero or one* elements. If the query returns +a set with more than one elements, the ``Client`` will throw a runtime error. + +.. note:: + + Note that if you're selecting an array or tuple, the returned value may + still be an array. + +.. code-block:: javascript + + await client.querySingle(`select 2 + 2;`); // 4 + await client.querySingle(`select [1, 2, 3];`); // [1, 2, 3] + await client.querySingle(`select {};`); // null + await client.querySingle(`select {1, 2, 3};`); // Error + +``.queryRequiredSingle`` method +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Use ``queryRequiredSingle`` for queries that return *exactly one* element. If +the query returns an empty set or a set with multiple elements, the ``Client`` +will throw a runtime error. + +.. code-block:: javascript + + await client.queryRequiredSingle(`select 2 + 2;`); // 4 + await client.queryRequiredSingle(`select [1, 2, 3];`); // [1, 2, 3] + await client.queryRequiredSingle(`select {};`); // Error + await client.queryRequiredSingle(`select {1, 2, 3};`); // Error + +TypeScript +^^^^^^^^^^ + +The TypeScript signatures of these methods reflects their behavior. + +.. code-block:: typescript + + await client.query(`select 2 + 2;`); + // number[] + + await client.querySingle(`select 2 + 2;`); + // number | null + + await client.queryRequiredSingle(`select 2 + 2;`); + // number + + +Type conversion +--------------- + +The client converts |Gel| types into a corresponding JavaScript data +structure. Some Gel types like ``duration`` don't have a corresponding type +in the JavaScript type system, so we've implemented classes like +:js:class:`Duration` to represent them. + +.. list-table:: + + * - **Gel type** + - **JavaScript type** + * - Sets + - ``Array`` + * - Arrays + - ``Array`` + * - Tuples ``tuple`` + - ``Array`` + * - Named tuples ``tuple`` + - ``object`` + * - Enums + - ``string`` + * - ``Object`` + - ``object`` + * - ``str`` + - ``string`` + * - ``bool`` + - ``boolean`` + * - ``float32`` ``float64`` ``int16`` ``int32`` ``int64`` + - ``number`` + * - ``json`` + - ``string`` + * - ``uuid`` + - ``string`` + * - ``bigint`` + - ``BigInt`` + * - ``decimal`` + - ``string`` + * - ``bytes`` + - ``Uint8Array`` + * - ``datetime`` + - ``Date`` + * - ``duration`` + - :js:class:`Duration` + * - ``e.cal.relative_duration`` + - :js:class:`RelativeDuration` + * - ``e.cal.date_duration`` + - :js:class:`DateDuration` + * - ``cal::local_date`` + - :js:class:`LocalDate` + * - ``cal::local_time`` + - :js:class:`LocalTime` + * - ``cal::local_datetime`` + - :js:class:`LocalDateTime` + * - ``cfg::memory`` + - :js:class:`ConfigMemory` + * - Ranges ``range`` + - :js:class:`Range` + + +To learn more about the client's built-in type classes, refer to the reference +documentation. + +- :js:class:`Duration` +- :js:class:`RelativeDuration` +- :js:class:`DateDuration` +- :js:class:`LocalDate` +- :js:class:`LocalTime` +- :js:class:`LocalDateTime` +- :js:class:`ConfigMemory` +- :js:class:`Range` + + +JSON results +------------ + +Client provide additional methods for running queries and retrieving results +as a *serialized JSON string*. This serialization happens inside the database +and is typically more performant than running ``JSON.stringify`` yourself. + +.. code-block:: javascript + + await client.queryJSON(`select {1, 2, 3};`); + // "[1, 2, 3]" + + await client.querySingleJSON(`select {};`); + // "null" + + await client.queryRequiredSingleJSON(`select 3.14;`); + // "3.14" + +Non-returning queries +--------------------- + +To execute a query without retrieving a result, use the ``.execute`` method. +This is especially useful for mutations, where there's often no need for the +query to return a value. + +.. code-block:: javascript + + await client.execute(`insert Movie { + title := "Avengers: Endgame" + };`); + +You can also execute a "script" consisting of multiple +semicolon-separated statements in a single ``.execute`` call. + +.. code-block:: javascript + + await client.execute(` + insert Person { name := "Robert Downey Jr." }; + insert Person { name := "Scarlett Johansson" }; + insert Movie { + title := $title, + actors := ( + select Person filter .name in { + "Robert Downey Jr.", + "Scarlett Johansson" + } + ) + } + `, { title: "Iron Man 2" }); + +Parameters +---------- + +If your query contains parameters (e.g. ``$foo``), you can pass in values as +the second argument. This is true for all ``query*`` methods and ``execute``. + +.. code-block:: javascript + + const INSERT_MOVIE = `insert Movie { + title := $title + }` + const result = await client.querySingle(INSERT_MOVIE, { + title: "Iron Man" + }); + console.log(result); + // {id: "047c5893..."} + +Remember that :ref:`parameters ` can only be *scalars* or +*arrays of scalars*. + +Scripts +------- + +Both ``execute`` and the ``query*`` methods support scripts (queries +containing multiple statements). The statements are run in an implicit +transaction (unless already in an explicit transaction), so the whole script +remains atomic. For the ``query*`` methods only the result of the final +statement in the script will be returned. + +.. code-block:: javascript + + const result = await client.query(` + insert Movie { + title := $title + }; + insert Person { + name := $name + }; + `, { + title: "Thor: Ragnarok", + name: "Anson Mount" + }); + // [{id: "5dd2557b..."}] + +For more fine grained control of atomic exectution of multiple statements, use +the ``transaction()`` API. + +Checking connection status +-------------------------- + +The client maintains a dynamically sized *pool* of connections under the hood. +These connections are initialized *lazily*, so no connection will be +established until the first time you execute a query. + +If you want to explicitly ensure that the client is connected without running +a query, use the ``.ensureConnected()`` method. + +.. code-block:: javascript + + const gel = require("gel"); + + const client = gel.createClient(); + + async function main() { + await client.ensureConnected(); + } + +.. _gel-js-api-transaction: + +Transactions +------------ + +The most robust way to execute transactional code is to use +the ``transaction()`` API: + +.. code-block:: javascript + + await client.transaction(tx => { + await tx.execute("insert User {name := 'Don'}"); + }); + +Note that we execute queries on the ``tx`` object in the above +example, rather than on the original ``client`` object. + +The ``transaction()`` API guarantees that: + +1. Transactions are executed atomically; +2. If a transaction fails due to retryable error (like + a network failure or a concurrent update error), the transaction + would be retried; +3. If any other, non-retryable error occurs, the transaction is rolled + back and the ``transaction()`` block throws. + +The *transaction* object exposes ``query()``, ``execute()``, ``querySQL()``, +``executeSQL()``, and other ``query*()`` methods that *clients* expose, with +the only difference that queries will run within the current transaction +and can be retried automatically. + +The key implication of retrying transactions is that the entire +nested code block can be re-run, including any non-querying +JavaScript code. Here is an example: + +.. code-block:: javascript + + const email = "timmy@example.com" + + await client.transaction(async tx => { + await tx.execute( + `insert User { email := $email }`, + { email }, + ) + + await sendWelcomeEmail(email); + + await tx.execute( + `insert LoginHistory { + user := (select User filter .email = $email), + timestamp := datetime_current() + }`, + { email }, + ) + }) + +In the above example, the welcome email may be sent multiple times if the +transaction block is retried. Generally, the code inside the transaction block +shouldn't have side effects or run for a significant amount of time. + +.. note:: + + Transactions allocate expensive server resources and having + too many concurrently running long-running transactions will + negatively impact the performance of the DB server. + +.. note:: + + * RFC1004_ + * :js:meth:`Client.transaction\` + + .. _RFC1004: https://github.com/geldata/rfcs/blob/master/text/1004-transactions-api.rst + + +Next up +------- + +If you're a TypeScript user and want autocompletion and type inference, head +over to the :ref:`Query Builder docs `. If you're using plain +JavaScript that likes writing queries with composable code-first syntax, you +should check out the query builder too! If you're content writing queries as +strings, the vanilla Client API will meet your needs. diff --git a/docs/clients/js/for.rst b/docs/clients/js/for.rst new file mode 100644 index 00000000000..2a71c09154d --- /dev/null +++ b/docs/clients/js/for.rst @@ -0,0 +1,342 @@ +.. _gel-js-for: + + +For Loops +========= + +``for`` loops let you iterate over any set of values. + +.. code-block:: typescript + + const query = e.for(e.set(1, 2, 3, 4), (number) => { + return e.op(2, '^', number); + }); + const result = query.run(client); + // [2, 4, 8, 16] + +.. _gel-js-for-bulk-inserts: + +Bulk inserts +------------ + +It's common to use ``for`` loops to perform bulk inserts. The raw data is +passed in as a ``json`` parameter, converted to a set of ``json`` objects with +``json_array_unpack``, then passed into a ``for`` loop for insertion. + +.. code-block:: typescript + + const query = e.params({ items: e.json }, (params) => { + return e.for(e.json_array_unpack(params.items), (item) => { + return e.insert(e.Movie, { + title: e.cast(e.str, item.title), + release_year: e.cast(e.int64, item.release_year), + }); + }); + }); + + const result = await query.run(client, { + items: [ + { title: "Deadpool", release_year: 2016 }, + { title: "Deadpool 2", release_year: 2018 }, + { title: "Deadpool 3", release_year: 2024 }, + { title: "Deadpool 4", release_year: null }, + ], + }); + +Note that any optional properties values must be explicitly set to ``null``. +They cannot be set to ``undefined`` or omitted; doing so will cause a runtime +error. + +.. _gel-js-for-bulk-inserts-conflicts: + +Handling conflicts in bulk inserts +---------------------------------- + +Here's a more complex example, demonstrating how to complete a nested insert +with conflicts on the inner items. First, take a look at the schema for this +database: + +.. code-block:: sdl + + module default { + type Character { + required name: str { + constraint exclusive; + } + portrayed_by: str; + multi movies: Movie; + } + + type Movie { + required title: str { + constraint exclusive; + }; + release_year: int64; + } + } + +Note that the ``Movie`` type's ``title`` property has an exclusive constraint. + +Here's the data we want to bulk insert: + +.. code-block:: javascript + + [ + { + portrayed_by: "Robert Downey Jr.", + name: "Iron Man", + movies: ["Iron Man", "Iron Man 2", "Iron Man 3"] + }, + { + portrayed_by: "Chris Evans", + name: "Captain America", + movies: [ + "Captain America: The First Avenger", + "The Avengers", + "Captain America: The Winter Soldier", + ] + }, + { + portrayed_by: "Mark Ruffalo", + name: "The Hulk", + movies: ["The Avengers", "Iron Man 3", "Avengers: Age of Ultron"] + } + ] + +This is potentially a problem because some of the characters appear in the same +movies. We can't just naively insert all the movies because we'll eventually +hit a conflict. Since we're going to write this as a single query, chaining +``.unlessConflict`` on our query won't help. It only handles conflicts with +objects that existed *before* the current query. + +Let's look at a query that can accomplish this insert, and then we'll break it +down. + +.. code-block:: typescript + + const query = e.params( + { + characters: e.array( + e.tuple({ + portrayed_by: e.str, + name: e.str, + movies: e.array(e.str), + }) + ), + }, + (params) => { + const movies = e.for( + e.op( + "distinct", + e.array_unpack(e.array_unpack(params.characters).movies) + ), + (movieTitle) => { + return e + .insert(e.Movie, { + title: movieTitle, + }) + .unlessConflict((movie) => ({ + on: movie.title, + else: movie, + })); + } + ); + return e.with( + [movies], + e.for(e.array_unpack(params.characters), (character) => { + return e.insert(e.Character, { + name: character.name, + portrayed_by: character.portrayed_by, + movies: e.assert_distinct( + e.select(movies, (movie) => ({ + filter: e.op(movie.title, "in", e.array_unpack(character.movies)), + })) + ), + }); + }) + ); + } + ); + +.. _gel-js-for-bulk-inserts-conflicts-params: + +Structured params +~~~~~~~~~~~~~~~~~ + +.. code-block:: typescript + + const query = e.params( + { + characters: e.array( + e.tuple({ + portrayed_by: e.str, + name: e.str, + movies: e.array(e.str), + }) + ), + }, + (params) => { ... + +In raw EdgeQL, you can only have scalar types as parameters. We could mirror +that here with something like this: ``e.params({characters: e.json})``, but +this would then require us to cast all the values inside the JSON like +``portrayed_by`` and ``name``. + +By doing it this way β€” typing ``characters`` with ``e.array`` and the character +objects as named tuples by passing an object to ``e.tuple`` β€” all the data in +the array will be properly cast for us. It will also better type check the data +you pass to the query's ``run`` method. + +.. _gel-js-for-bulk-inserts-conflicting-data: + +Inserting the inner conflicting data +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: typescript + + ... + (params) => { + const movies = e.for( + e.op("distinct", e.array_unpack(e.array_unpack(params.characters).movies)), + (movie) => { + return e + .insert(e.Movie, { + title: movie, + }) + .unlessConflict((movie) => ({ + on: movie.title, + else: movie, + })); + } + ); + ... + +We need to separate this movie insert query so that we can use ``distinct`` on +it. We could just nest an insert inside our character insert if movies weren't +duplicated across characters (e.g., two characters have "The Avengers" in +``movies``). Even though the query is separated from the character inserts +here, it will still be built as part of a single |Gel| query using ``with`` +which we'll get to a bit later. + +The ``distinct`` operator can only operate on sets. We use ``array_unpack`` to +make these arrays into sets. We need to call it twice because +``params.characters`` is an array and ``.movies`` is an array nested inside +each character. + +Chaining ``unlessConflict`` takes care of any movies that already exist in the +database *before* we run this query, but it won't handle conflicts that come +about over the course of this query. The ``distinct`` operator we used earlier +pro-actively eliminates any conflicts we might have had among this data. + +.. _gel-js-for-bulk-inserts-outer-data: + +Inserting the outer data +~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: typescript + + ... + return e.with( + [movies], + e.for(e.array_unpack(params.characters), (character) => { + return e.insert(e.Character, { + name: character.name, + portrayed_by: character.portrayed_by, + movies: e.assert_distinct( + e.select(movies, (movie) => ({ + filter: e.op(movie.title, "in", e.array_unpack(character.movies)), + })) + ), + }); + }) + ); + ... + +The query builder will try to automatically use EdgeQL's ``with``, but in this +instance, it doesn't know where to place the ``with``. By using ``e.with`` +explicitly, we break our movie insert out to the top-level of the query. By +default, it would be scoped *inside* the query, so our ``distinct`` operator +would be applied only to each character's movies instead of to all of the +movies. This would have caused the query to fail. + +The rest of the query is relatively straightforward. We unpack +``params.characters`` to a set so that we can pass it to ``e.for`` to iterate +over the characters. For each character, we build an ``insert`` query with +their ``name`` and ``portrayed_by`` values. + +For the character's ``movies``, we ``select`` everything in the +``movies`` insert query we wrote previously, filtering for those with titles +that match values in the ``character.movies`` array. + +All that's left is to run the query, passing the data to the query's ``run`` +method! + +.. _gel-js-for-bulk-updates: + +Bulk updates +^^^^^^^^^^^^ + +Just like with inserts, you can run bulk updates using a ``for`` loop. Pass in +your data, iterate over it, and build an ``update`` query for each item. + +In this example, we use ``name`` to filter for the character to be updated +since ``name`` has an exclusive constraint in the schema (meaning a given name +will correspond to, at most, a single object). That filtering is done using the +``filter_single`` property of the object returned from your ``update`` +callback. Then the ``last_appeared`` value is updated by including it in the +nested ``set`` object. + +.. code-block:: typescript + + const query = e.params( + { + characters: e.array( + e.tuple({ + name: e.str, + last_appeared: e.int64, + }) + ), + }, + (params) => { + return e.for(e.array_unpack(params.characters), (character) => { + return e.update(e.Character, () => ({ + filter_single: { name: character.name }, + set: { + last_appeared: character.last_appeared, + }, + })); + }); + } + ); + + await query.run(client, { + characters: [ + { name: "Iron Man", last_appeared: 2019 }, + { name: "Captain America", last_appeared: 2019 }, + { name: "The Hulk", last_appeared: 2021 }, + ], + }); + +e.for vs JS for or .forEach +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +You may be tempted to use JavaScript's ``for`` or the JavaScript array's +``.forEach`` method to avoid having to massage your data into a set for +consumption by ``e.for``. This approach comes at a cost of performance. + +If you use ``for`` or ``.forEach`` to iterate over a standard JavaScript data +structure and run separate queries for each item in your iterable, you're doing +just that: running separate queries for each item in your iterable. By +iterating inside your query using ``e.for``, you're guaranteed everything will +happen in a single query. + +In addition to the performance implications, a single query means that either +everything succeeds or everything fails. You will never end up with only some +of your data inserted. This ensures your data integrity is maintained. You +could achieve this yourself by wrapping your batch queryies with :ref:`a +transaction `, but a single query is already atomic +without any additional work on your part. + +Using ``e.for`` to run a single query is generally the best approach. When +dealing with extremely large datasets, it may become more practical to batch +queries and run them individually. diff --git a/docs/clients/js/funcops.rst b/docs/clients/js/funcops.rst new file mode 100644 index 00000000000..fe0530973dc --- /dev/null +++ b/docs/clients/js/funcops.rst @@ -0,0 +1,81 @@ +.. _gel-js-funcops: + +Functions and Operators +----------------------- + +Function syntax +^^^^^^^^^^^^^^^ + +All built-in standard library functions are reflected as functions in ``e``. + +.. code-block:: typescript + + e.str_upper(e.str("hello")); + // str_upper("hello") + + e.op(e.int64(2), '+', e.int64(2)); + // 2 + 2 + + const nums = e.set(e.int64(3), e.int64(5), e.int64(7)) + e.op(e.int64(4), 'in', nums); + // 4 in {3, 5, 7} + + e.math.mean(nums); + // math::mean({3, 5, 7}) + + +.. _gel-js-funcops-prefix: + +Prefix operators +^^^^^^^^^^^^^^^^ + +Unlike functions, operators do *not* correspond to a top-level function on the +``e`` object. Instead, they are expressed with the ``e.op`` function. + +Prefix operators operate on a single argument: ``OPERATOR ``. + +.. code-block:: typescript + + e.op('not', e.bool(true)); // not true + e.op('exists', e.set('hi')); // exists {'hi'} + e.op('distinct', e.set('hi', 'hi')); // distinct {'hi', 'hi'} + +.. list-table:: + + * - ``"exists"`` ``"distinct"`` ``"not"`` + + +.. _gel-js-funcops-infix: + +Infix operators +^^^^^^^^^^^^^^^ + +Infix operators operate on two arguments: `` OPERATOR ``. + +.. code-block:: typescript + + e.op(e.str('Hello '), '++', e.str('World!')); + // 'Hello ' ++ 'World!' + +.. list-table:: + + * - ``"="`` ``"?="`` ``"!="`` ``"?!="`` ``">="`` ``">"`` ``"<="`` ``"<"`` + ``"or"`` ``"and"`` ``"+"`` ``"-"`` ``"*"`` ``"/"`` ``"//"`` ``"%"`` + ``"^"`` ``"in"`` ``"not in"`` ``"union"`` ``"??"`` ``"++"`` ``"like"`` + ``"ilike"`` ``"not like"`` ``"not ilike"`` + + +.. _gel-js-funcops-ternary: + +Ternary operators +^^^^^^^^^^^^^^^^^ + +Ternary operators operate on three arguments: `` OPERATOR OPERATOR +``. Currently there's only one ternary operator: the ``if else`` +statement. + +.. code-block:: typescript + + e.op(e.str('πŸ˜„'), 'if', e.bool(true), 'else', e.str('😒')); + // πŸ˜„ if true else 😒 + diff --git a/docs/clients/js/generation.rst b/docs/clients/js/generation.rst new file mode 100644 index 00000000000..bcabcb444b8 --- /dev/null +++ b/docs/clients/js/generation.rst @@ -0,0 +1,122 @@ +.. _gel-js-generators: + +Generators +========== + +The ``@gel/generate`` package provides a set of code generation tools that +are useful when developing an Gel-backed applications with +TypeScript/JavaScript. + +To get started with generators, first initialize an :ref:`Gel project +` in the root of your application. Generators will +look for an |gel.toml| file to determine the root of your application. See +the :ref:`Overview ` page for details on installing. + +.. note:: + + Generators work by connecting to the database to get information about the current state of the schema. Make sure you run the generators again any time the schema changes so that the generated code is in-sync with the current state of the schema. + +Run a generator with the following command. + +.. tabs:: + + .. code-tab:: bash + :caption: npm + + $ npx @gel/generate [options] + + .. code-tab:: bash + :caption: yarn + + $ yarn run -B generate [options] + + .. code-tab:: bash + :caption: pnpm + + $ pnpm exec generate [options] + + .. code-tab:: bash + :caption: Deno + + $ deno run \ + --allow-all \ + --unstable \ + https://deno.land/x/gel/generate.ts [options] + + .. code-tab:: bash + :caption: bun + + $ bunx @gel/generate [options] + +The value of ```` should be one of the following: + +.. list-table:: + :class: funcoptable + + * - ``edgeql-js`` + - Generates the query builder which provides a **code-first** way to write + **fully-typed** EdgeQL queries with TypeScript. We recommend it for + TypeScript users, or anyone who prefers writing queries with code. + - :ref:`docs ` + + * - ``queries`` + - Scans your project for ``*.edgeql`` files and generates functions that + allow you to execute these queries in a typesafe way. + - :ref:`docs ` + + * - ``interfaces`` + - Introspects your schema and generates file containing *TypeScript + interfaces* that correspond to each object type. This is useful for + writing typesafe code to interact with |Gel|. + - :ref:`docs ` + +Connection +^^^^^^^^^^ + +The generators require a connection to an active |Gel| database. It does +**not** simply read your local |.gel| schema files. Generators rely on the +database to introspect the schema and analyze queries. Doing so without a +database connection would require implementing a full EdgeQL parser and static +analyzer in JavaScriptβ€”which we don't intend to do anytime soon. + +.. note:: + + Make sure your development database is up-to-date with your latest schema + before running a generator! + +If you're using :gelcmd:`project init`, the connection is automatically handled +for you. Otherwise, you'll need to explicitly pass connection information via +environment variables or CLI flags, just like any other CLI command. See +:ref:`Client Libraries > Connection ` for guidance. + +.. _gel_qb_target: + +Targets +^^^^^^^ + +All generators look at your environment and guess what kind of files to generate +(``.ts`` vs ``.js + .d.ts``) and what module system to use (CommonJS vs ES +modules). You can override this with the ``--target`` flag. + +.. list-table:: + + * - ``--target ts`` + - Generate TypeScript files (``.ts``) + * - ``--target mts`` + - Generate TypeScript files (``.mts``) with extensioned ESM imports + * - ``--target esm`` + - Generate ``.js`` with ESM syntax and ``.d.ts`` declaration files + * - ``--target cjs`` + - Generate JavaScript with CommonJS syntax and and ``.d.ts`` declaration + files + * - ``--target deno`` + - Generate TypeScript files with Deno-style ESM imports + +Help +^^^^ + +To see helptext for the ``@gel/generate`` command, run the following. + +.. code-block:: bash + + $ npx @gel/generate --help diff --git a/docs/clients/js/group.rst b/docs/clients/js/group.rst new file mode 100644 index 00000000000..deb9d27b8f2 --- /dev/null +++ b/docs/clients/js/group.rst @@ -0,0 +1,265 @@ +.. _gel-js-group: + +Group +===== + +The ``group`` statement provides a powerful mechanism for categorizing a set +of objects (e.g., movies) into *groups*. You can group by properties, +expressions, or combinatations thereof. + +.. note:: + + This page does not aim to describe how the ``group`` statement works, merely + the syntax for writing ``e.group`` statements with the query builder. For + full documentation, refer to :ref:`EdgeQL > Group `. + +Simple grouping +--------------- + +Sort a set of objects by a simple property. + +.. tabs:: + + .. code-tab:: typescript + + e.group(e.Movie, movie => { + return { + by: {release_year: movie.release_year} + } + }); + /* + [ + { + key: {release_year: 2008}, + grouping: ["release_year"], + elements: [{id: "..."}, {id: "..."}] + }, + { + key: { release_year: 2009 }, + grouping: ["release_year"], + elements: [{id: "..."}, {id: "..."}] + }, + // ... + ] + */ + + .. code-tab:: edgeql + + group Movie + by .release_year + +Add a shape that will be applied to ``elements``. The ``by`` key is a special +key, similar to ``filter``, etc. in ``e.select``. All other keys are +interpreted as *shape elements* and support the same functionality as +``e.select`` (nested shapes, computeds, etc.). + +.. tabs:: + + .. code-tab:: typescript + + e.group(e.Movie, movie => { + return { + title: true, + actors: {name: true}, + num_actors: e.count(movie.characters), + by: {release_year: movie.release_year} + } + }); + /* [ + { + key: {release_year: 2008}, + grouping: ["release_year"], + elements: [{ + title: "Iron Man", + actors: [...], + num_actors: 5 + }, { + title: "The Incredible Hulk", + actors: [...], + num_actors: 3 + }] + }, + // ... + ] */ + + .. code-tab:: edgeql + + group Movie { + title, + num_actors := count(.actors) + } + by .release_year + +Group by a tuple of properties. + +.. tabs:: + + .. code-tab:: typescript + + e.group(e.Movie, movie => { + const release_year = movie.release_year; + const first_letter = movie.title[0]; + return { + title: true, + by: {release_year, first_letter} + }; + }); + /* + [ + { + key: {release_year: 2008, first_letter: "I"}, + grouping: ["release_year", "first_letter"], + elements: [{title: "Iron Man"}] + }, + { + key: {release_year: 2008, first_letter: "T"}, + grouping: ["release_year", "first_letter"], + elements: [{title: "The Incredible Hulk"}] + }, + // ... + ] + */ + + .. code-tab:: edgeql + + group Movie { title } + using first_letter := .title[0] + by .release_year, first_letter + +Using grouping sets to group by several expressions simultaneously. + +.. tabs:: + + .. code-tab:: typescript + + e.group(e.Movie, movie => { + const release_year = movie.release_year; + const first_letter = movie.title[0]; + return { + title: true, + by: e.group.set({release_year, first_letter}) + }; + }); + /* [ + { + key: {release_year: 2008}, + grouping: ["release_year"], + elements: [{title: "Iron Man"}, {title: "The Incredible Hulk"}] + }, + { + key: {first_letter: "I"}, + grouping: ["first_letter"], + elements: [{title: "Iron Man"}, {title: "Iron Man 2"}, {title: "Iron Man 3"}], + }, + // ... + ] */ + + .. code-tab:: edgeql + + group Movie { title } + using first_letter := .title[0] + by {.release_year, first_letter} + + +Using a combination of tuples and grouping sets. + +.. tabs:: + + .. code-tab:: typescript + + e.group(e.Movie, movie => { + const release_year = movie.release_year; + const first_letter = movie.title[0]; + const cast_size = e.count(movie.actors); + return { + title: true, + by: e.group.tuple(release_year, e.group.set({first_letter, cast_size})) + // by .release_year, { first_letter, cast_size } + // equivalent to + // by (.release_year, first_letter), (.release_year, cast_size), + }; + }); + /* [ + { + key: {release_year: 2008, first_letter: "I"}, + grouping: ["release_year", "first_letter"], + elements: [{title: "Iron Man"}] + }, + { + key: {release_year: 2008, cast_size: 3}, + grouping: ["release_year", "cast_size"], + elements: [{title: "The Incredible Hulk"}] + }, + // ... + ] */ + + .. code-tab:: edgeql + + group Movie { title } + using + first_letter := .title[0], + cast_size := count(.actors) + by .release_year, {first_letter, cast_size} + + + +The ``group`` statement provides a syntactic sugar for defining certain common +grouping sets: ``cube`` and ``rollup``. Here's a quick primer on how they work: + +.. code-block:: + + ROLLUP (a, b, c) + is equivalent to + {(), (a), (a, b), (a, b, c)} + + CUBE (a, b) + is equivalent to + {(), (a), (b), (a, b)} + +To use these in the query builder use the ``e.group.cube`` and +``e.group.rollup`` functions. + + +.. tabs:: + + .. code-tab:: typescript + + e.group(e.Movie, movie => { + const release_year = movie.release_year; + const first_letter = movie.title[0]; + const cast_size = e.count(movie.actors); + return { + title: true, + by: e.group.rollup({release_year, first_letter, cast_size}) + }; + }); + + .. code-tab:: edgeql + + group Movie { title } + using + first_letter := .title[0], + cast_size := count(.actors) + by rollup(.release_year, first_letter, cast_size) + +.. tabs:: + + .. code-tab:: typescript + + e.group(e.Movie, movie => { + const release_year = movie.release_year; + const first_letter = movie.title[0]; + const cast_size = e.count(movie.actors); + return { + title: true, + by: e.group.cube({release_year, first_letter, cast_size}) + }; + }); + + .. code-tab:: edgeql + + group Movie { title } + using + first_letter := .title[0], + cast_size := count(.actors) + by cube(.release_year, first_letter, cast_size) diff --git a/docs/clients/js/index.rst b/docs/clients/js/index.rst index 6a6a657e1cd..80dc45f6ac2 100644 --- a/docs/clients/js/index.rst +++ b/docs/clients/js/index.rst @@ -1,9 +1,403 @@ -.. _edgedb-js-intro: +.. _gel-js-intro: +======================== +Gel TypeScript/JS Client +======================== + +.. toctree:: + :maxdepth: 3 + :hidden: + + driver + generation + queries + interfaces + querybuilder + literals + types + funcops + parameters + objects + select + insert + update + delete + with + for + group + reference + +.. _gel-js-installation: + + +Installation +============ + +You can install the published database driver and optional (but recommended!) +generators from npm using your package manager of choice. + +.. tabs:: + + .. code-tab:: bash + :caption: npm + + $ npm install --save-prod gel # database driver + $ npm install --save-dev @gel/generate # generators + + .. code-tab:: bash + :caption: yarn + + $ yarn add gel # database driver + $ yarn add --dev @gel/generate # generators + + .. code-tab:: bash + :caption: pnpm + + $ pnpm add --save-prod gel # database driver + $ pnpm add --save-dev @gel/generate # generators + + .. code-tab:: typescript + :caption: deno + + import * as gel from "http://deno.land/x/gel/mod.ts"; + + .. code-tab:: bash + :caption: bun + + $ bun add gel # database driver + $ bun add --dev @gel/generate # generators + +.. note:: Deno users + + Create these two files in your project root: + + .. code-block:: json + :caption: importMap.json + + { + "imports": { + "gel": "https://deno.land/x/gel/mod.ts", + "gel/": "https://deno.land/x/gel/" + } + } + + .. code-block:: json + :caption: deno.js + + { + "importMap": "./importMap.json" + } + + +.. _gel-js-quickstart: + +Quickstart ========== -JavaScript -========== -The documentation for the JavaScript client is automatically pulled -from https://github.com/edgedb/edgedb-js/tree/master/docs by the -build pipeline of the edgedb.com website. +Setup +^^^^^ + +This section assumes you have gone through the :ref:`Quickstart Guide +` and understand how to update schemas, run migrations, and have +a working |Gel| project. Let's update the schema to make the ``title`` property +of the ``Movie`` type exclusive. This will help with filtering by +``Movie.title`` in our queries. + +.. code-block:: sdl-diff + :caption: dbschema/default.gel + + module default { + type Person { + required name: str; + } + + type Movie { + - required title: str; + + required title: str { + + constraint exclusive; + + }; + multi actors: Person; + } + } + +Generate the new migration and apply them: + +.. code-block:: bash + + $ gel migration create + $ gel migrate + +We'll be using TypeScript and Node for this example, so let's setup a simple +app: + +.. code-block:: bash + + $ npm init -y # initialize a new npm project + $ npm i gel + $ npm i -D typescript @types/node @gel/generate tsx + $ npx tsc --init # initialize a basic TypeScript project + +Client +^^^^^^ + +The ``Client`` class implements the core functionality required to establish a +connection to your database and execute queries. If you prefer writing queries +as strings, the Client API is all you need. + +Let's create a simple Node.js script that seeds the database by running an +insert query directly with the driver: + +.. code-block:: typescript + :caption: seed.ts + + import * as gel from "gel"; + + const client = gel.createClient(); + + async function main() { + await client.execute(` + insert Person { name := "Robert Downey Jr." }; + insert Person { name := "Scarlett Johansson" }; + insert Movie { + title := $title, + actors := ( + select Person filter .name in { + "Robert Downey Jr.", + "Scarlett Johansson" + } + ) + } + `, { title: "Iron Man 2" }); + } + + main(); + +We can now seed the database by running this script with ``tsx`` + +.. code-block:: bash + + $ npx tsx seed.ts + +Feel free to explore the database in the :ref:`Gel UI `, +where you will find the new data you inserted through this script, as well as +any data you inserted when running the Quickstart. + +.. note:: A word on module systems + + Different build tools and runtimes have different specifications for how + modules are imported, and we support a wide-range of those styles. For + clarity, we will be sticking to standard TypeScript-style ESM module importing + without a file extension throughout this documentation. Please see your build + or environment tooling's guidance on how to adapt this style. + +Querying with plain strings +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Now, let's write a Node.js script that queries the database for details about +Iron Man 2: + +.. code-block:: typescript + :caption: query.ts + + import * as gel from "gel"; + + const client = gel.createClient(); + + async function main() { + const result = await client.querySingle(` + select Movie { + id, + title, + actors: { + id, + name, + } + } filter .title = "Iron Man 2" + `); + + console.log(JSON.stringify(result, null, 2)); + } + + main(); + +Interfaces +^^^^^^^^^^ + +Since we're using TypeScript, it would be nice to be able to type the return +value of this query, so let's use our first generator, the :ref:`interfaces +generator ` to tell TypeScript what the type of our result +is. + +First we run the generator: + +.. code-block:: bash + + $ npx @gel/generate interfaces + +This generator introspects your database schema and generates a set of +equivalent TypeScript interfaces. + +Now we can annotate our query since we are selecting the whole ``Movie`` type: + +.. code-block:: typescript-diff + :caption: query.ts + + import * as gel from "gel"; + import { Movie } from "./dbschema/interfaces" + + const client = gel.createClient(); + + async function main() { + // result will be inferred as Movie | null + - const result = await client.querySingle(` + + const result = await client.querySingle(` + select Movie { + id, + title, + actors: { + id, + name, + } + } filter .title = "Iron Man 2" + `); + + console.log(JSON.stringify(result, null, 2)); + } + + main(); + +You can now run the script with ``tsx``: + +.. code-block:: bash + + $ npx tsx query.ts + +Queries generator +^^^^^^^^^^^^^^^^^ + +Wouldn't it be great if we could write any arbitrary query and get a type-safe +function that we could call? Good news, that's exactly what the next generator +does! The :ref:`queries generator ` scans your project for +``*.edgeql`` files and generates a file containing a strongly-typed function. + +First, move the query into a separate file called ``getMovie.edgeql``. + +.. code-block:: edgeql + :caption: getMovie.edgeql + + select Movie { + id, + title, + actors: { + id, + name, + } + }; + + +Next, we'll run the ``queries`` generator, specifying the ``--file`` option +which will compile all the queries it finds into a single TypeScript module: + +.. code-block:: bash + + $ npx @gel/generate queries --file + +Now, let's update our query script to call the generated function, which will +provide us with type-safe querying. + +.. code-block:: typescript-diff + :caption: query.ts + + import * as gel from "gel"; + - import { Movie } from "./dbschema/interfaces" + + import { getMovie } from "./dbschema/queries" + + const client = gel.createClient(); + + async function main() { + // result will be inferred as Movie | null + - const result = await client.querySingle(` + - select Movie { + - id, + - title, + - actors: { + - id, + - name, + - } + - } filter .title = "Iron Man 2" + - `); + + const result = await getMovie(client); + + console.log(JSON.stringify(result, null, 2)); + } + + main(); + +Now, if you change the query to return different data, or take parameters, and +run the queries generator again, the type of the newly generated function will +change. It'll be completely type safe! + +Query builder +^^^^^^^^^^^^^ + +At last we've arrived at the most powerful API for querying your |Gel| +instance: the query builder. The Gel query builder provides a **code-first** +way to write **fully-typed** EdgeQL queries with TypeScript. We recommend it for +TypeScript users, or anyone who prefers writing queries with code. + +First, we'll run the query builder generator: + +.. code-block:: bash + + $ npx @gel/generate edgeql-js + +.. note:: Version control + + The first time you run the generator, you'll be prompted to add the generated + files to your ``.gitignore``. Confirm this prompt to automatically add a line + to your ``.gitignore`` that excludes the generated files. + + For consistency, we recommend omitting the generated files from version + control and re-generating them as part of your deployment process. However, + there may be circumstances where checking the generated files into version + control is desirable, e.g. if you are building Docker images that must contain + the full source code of your application. + +Now, we can import the generated query builder and express our query completely +in TypeScript, getting editor completion, type checking, and type inferrence: + +.. code-block:: typescript-diff + :caption: query.ts + + import * as gel from "gel"; + - import { getMovie } from "./dbschema/queries"; + + import e from "./dbschema/edgeql-js"; + + const client = gel.createClient(); + + async function main() { + - // result will be inferred as Movie | null + + // result will be inferred based on the query + - const result = await getMovie(client); + + const result = await e + + .select(e.Movie, () => ({ + + id: true, + + title: true, + + actors: () => ({ id: true, name: true }), + + filter_single: { title: "Iron Man 2" }, + + })) + + .run(client); + + console.log(JSON.stringify(result, null, 2)); + } + + main(); + +What's next +=========== + +We recommend reading the :ref:`client docs ` first and getting +familiar with configuring the client. You'll find important APIs like +``withGlobals`` and connection details there. After that, depending on your +preferences, look through the :ref:`query builder ` documentation +and use the other pages as a reference for writing code-first Gel queries. diff --git a/docs/clients/js/insert.rst b/docs/clients/js/insert.rst new file mode 100644 index 00000000000..37fbf7df5bb --- /dev/null +++ b/docs/clients/js/insert.rst @@ -0,0 +1,162 @@ +.. _gel-js-insert: + +Insert +------ + +Insert new data with ``e.insert``. + +.. code-block:: typescript + + e.insert(e.Movie, { + title: e.str("Spider-Man: No Way Home"), + release_year: e.int64(2021) + }); + +For convenience, the second argument of ``e.insert`` function can also accept +plain JS data or a named tuple. + +.. code-block:: typescript + + e.insert(e.Movie, { + title: "Spider-Man: No Way Home", + actors: e.select(e.Person, person => ({ + filter: e.op(person.name, "=", "Robert Downey Jr."), + '@character_name': e.str("Iron Man") + })) + }); + + +.. code-block:: typescript + + e.params({ + movie: e.tuple({ + title: e.str, + release_year: e.int64 + }) + }, $ => + e.insert(e.Movie, $.movie) + ); + + +Link properties +^^^^^^^^^^^^^^^ + +As in EdgeQL, link properties are inserted inside the shape of a subquery. + +.. code-block:: typescript + + const query = e.insert(e.Movie, { + title: "Iron Man", + actors: e.select(e.Person, person => ({ + filter_single: {name: "Robert Downey Jr."}, + "@character_name": e.str("Tony Stark") + + // link props must correspond to expressions + "@character_name": "Tony Stark" // invalid + )) + }); + + +.. note:: + + For technical reasons, link properties must correspond to query + builder expressions, not plain JS data. + +Similarly you can directly include link properties inside nested ``e.insert`` +queries: + +.. code-block:: typescript + + const query = e.insert(e.Movie, { + title: "Iron Man", + release_year: 2008, + actors: e.insert(e.Person, { + name: "Robert Downey Jr.", + "@character_name": e.str("Tony Start") + }), + }); + +Handling conflicts +^^^^^^^^^^^^^^^^^^ +:index: querybuilder unlessconflict unless conflict constraint + +In EdgeQL, "upsert" functionality is achieved by handling **conflicts** on +``insert`` statements with the ``unless conflict`` clause. In the query +builder, this is possible with the ``.unlessConflict`` method (available only +on ``insert`` expressions). + +In the simplest case, adding ``.unlessConflict`` (no arguments) will prevent +Gel from throwing an error if the insertion would violate an exclusivity +contstraint. Instead, the query returns an empty set (``null``). + +.. code-block:: typescript + + e.insert(e.Movie, { + title: "Spider-Man: No Way Home", + release_year: 2021 + }).unlessConflict(); + // => null + + +Provide an ``on`` clause to "catch" conflicts only on a specific property/link. + +.. code-block:: typescript + + e.insert(e.Movie, { + title: "Spider-Man: No Way Home", + release_year: 2021 + }).unlessConflict(movie => ({ + on: movie.title, // can be any expression + })); + + +You can also provide an ``else`` expression which will be executed and returned +in case of a conflict. You must specify an ``on`` clause in order to use ``else``. + +The following query simply returns the pre-existing (conflicting) object. + +.. code-block:: typescript + + e.insert(e.Movie, { + title: "Spider-Man: Homecoming", + release_year: 2021 + }).unlessConflict(movie => ({ + on: movie.title, + else: movie + })); + + +Or you can perform an upsert operation with an ``e.update`` in the ``else``. + +.. code-block:: typescript + + e.insert(e.Movie, { + title: "Spider-Man: Homecoming", + release_year: 2021 + }).unlessConflict(movie => ({ + on: movie.title, + else: e.update(movie, () => ({ + set: { + release_year: 2021 + } + })), + })); + + +If the constraint you're targeting is a composite constraint, wrap the +properties in a tuple. + +.. code-block:: typescript + + e.insert(e.Movie, { + title: "Spider-Man: No Way Home", + release_year: 2021 + }).unlessConflict(movie => ({ + on: e.tuple([movie.title, movie.release_year]) + })); + +Bulk inserts +^^^^^^^^^^^^ + +You can use a :ref:`for loop ` to perform :ref:`bulk inserts +`. diff --git a/docs/clients/js/interfaces.rst b/docs/clients/js/interfaces.rst new file mode 100644 index 00000000000..7bc69dc9af2 --- /dev/null +++ b/docs/clients/js/interfaces.rst @@ -0,0 +1,189 @@ +.. _gel-js-interfaces: + +==================== +Interfaces Generator +==================== + +The ``interfaces`` generator introspects your schema and generates file containing *TypeScript interfaces* that correspond to each object type. This is useful for writing typesafe code to interact with |Gel|. + +Installation +------------ + +To get started, install the following packages. (If you're using Deno, you can skip this step.) + +Install the ``gel`` package. + +.. code-block:: bash + + $ npm install gel # npm users + $ yarn add gel # yarn users + $ bun add gel # bun users + +Then install ``@gel/generate`` as a dev dependency. + +.. code-block:: bash + + $ npm install @gel/generate --save-dev # npm users + $ yarn add @gel/generate --dev # yarn users + $ bun add --dev @gel/generate # bun users + + +Generation +---------- + +Assume your database contains the following Gel schema. + +.. code-block:: sdl + + module default { + type Person { + required name: str; + } + + scalar type Genre extending enum; + + type Movie { + required title: str; + genre: Genre; + multi actors: Person; + } + } + +The following command will run the ``interfaces`` generator. + +.. tabs:: + + .. code-tab:: bash + :caption: Node.js + + $ npx @gel/generate interfaces + + .. code-tab:: bash + :caption: Deno + + $ deno run --allow-all --unstable https://deno.land/x/gel/generate.ts interfaces + + .. code-tab:: bash + :caption: Bun + + $ bunx @gel/generate interfaces + +.. note:: Deno users + + Create these two files in your project root: + + .. code-block:: json + :caption: importMap.json + + { + "imports": { + "gel": "https://deno.land/x/gel/mod.ts", + "gel/": "https://deno.land/x/gel/" + } + } + + .. code-block:: json + :caption: deno.js + + { + "importMap": "./importMap.json" + } + +This will introspect your schema and generate TypeScript interfaces that correspond to each object type. By default, these interfaces will be written to a single file called ``interfaces.ts`` into the ``dbschema`` directory in your project root. The file will contain the following contents (roughly): + +.. code-block:: typescript + + export interface Person { + id: string; + name: string; + } + + export type Genre = "Horror" | "Comedy" | "Drama"; + + export interface Movie { + id: string; + title: string; + genre?: Genre | null; + actors: Person[]; + } + +Any types declared in a non-``default`` module will be generated into an accordingly named ``namespace``. + +.. note:: + + Generators work by connecting to the database to get information about the current state of the schema. Make sure you run the generators again any time the schema changes so that the generated code is in-sync with the current state of the schema. + + +Customize file path +~~~~~~~~~~~~~~~~~~~ + +Pass a ``--file`` flag to specify the output file path. + +.. code-block:: bash + + $ npx @gel/generate interfaces --file schema.ts + +If the value passed as ``--file`` is a relative path, it will be evaluated relative to the current working directory (``process.cwd()``). If the value is an absolute path, it will be used as-is. + +.. note:: + + Because this generator is TypeScript-specific, the ``--target`` flag is not supported as in other generators. + + +Version control +~~~~~~~~~~~~~~~ + +To exclude the generated file, add the following lines to your ``.gitignore`` file. + +.. code-block:: text + + dbschema/interfaces.ts + +Usage +----- + +The generated interfaces can be imported like so. + +.. code-block:: typescript + + import {Genre, Movie} from "./dbschema/interfaces"; + +You will need to manipulate the generated interfaces to match your application's needs. For example, you may wish to strip the ``id`` property for a ``createMovie`` mutation. + +.. code-block:: typescript + + function createMovie(data: Omit) { + // ... + } + +.. note:: + + Refer to the `TypeScript docs `_ for information about built-in utility types like ``Pick``, ``Omit``, and ``Partial``. + +For convenience, the file also exports a namespace called ``helper`` containing a couple useful utilities for extracting the properties or links from an object type interface. + +.. code-block:: typescript + + import {Movie, helper} from "./dbschema/interfaces"; + + type MovieProperties = helper.Props; + // { id: string; title: string; ... } + + type MovieLinks = helper.Links; + // { actors: Person[]; } + + +Enums +~~~~~ + +Note that an ``enum`` in your schema will be represented in the generated code as a union of string literals. + +.. code-block:: typescript + + export type Genre = "Horror" | "Comedy" | "Drama"; + +We do *not* generate TypeScript enums for a number of reasons. + +- In TypeScript, enums are nominally typed. Two identically named enums are not + considered equal, even if they have the same members. +- Enums are both a runtime and static construct. Hovever, for simplicity we want the ``interfaces`` generator to produce exclusively static (type-level) code. diff --git a/docs/clients/js/literals.rst b/docs/clients/js/literals.rst new file mode 100644 index 00000000000..1e6d7272dcd --- /dev/null +++ b/docs/clients/js/literals.rst @@ -0,0 +1,417 @@ +.. _gel-js-literals: + + +Literals +-------- + +The query builder provides a set of "helper functions" that convert JavaScript +literals into *expressions* that can be used in queries. For the most part, +these helper functions correspond to the *name* of the type. + + + +Primitives +^^^^^^^^^^ + +Primitive literal expressions are created using constructor functions that +correspond to Gel datatypes. Each expression below is accompanied by the +EdgeQL it produces. + +.. code-block:: typescript + + e.str("asdf") // "asdf" + e.int64(123) // 123 + e.float64(123.456) // 123.456 + e.bool(true) // true + e.bigint(12345n) // 12345n + e.decimal("1234.1234n") // 1234.1234n + e.uuid("599236a4...") // "599236a4..." + + e.bytes(Uint8Array.from('binary data')); + // b'binary data' + +Strings +^^^^^^^ + +String expressions have some special functionality: they support indexing and +slicing, as in EdgeQL. + +.. code-block:: typescript + + const myString = e.str("hello world"); + + myString[5]; // "hello world"[5] + myString['2:5']; // "hello world"[2:5] + myString[':5']; // "hello world"[:5] + myString['2:']; // "hello world"[2:] + +There are also equivalent ``.index`` and ``.slice`` methods that can accept +integer expressions as arguments. + +.. code-block:: typescript + + const myString = e.str("hello world"); + const start = e.int64(2); + const end = e.int64(5); + + myString.index(start); // "hello world"[2] + myString.slice(start, end); // "hello world"[2:5] + myString.slice(null, end); // "hello world"[:5] + myString.slice(start, null); // "hello world"[2:] + +Enums +^^^^^ + +Enum literals are available as properties defined on the enum type. + +.. code-block:: typescript + + e.Colors.green; + // Colors.green; + + e.sys.VersionStage.beta; + // sys::VersionStage.beta + +Dates and times +^^^^^^^^^^^^^^^ + +To create an instance of ``datetime``, pass a JavaScript ``Date`` object into +``e.datetime``: + +.. code-block:: typescript + + e.datetime(new Date('1999-01-01')); + // '1999-01-01T00:00:00.000Z' + +Gel's other temporal datatypes don't have equivalents in the JavaScript +type system: ``duration``, ``cal::relative_duration``, ``cal::date_duration``, +``cal::local_date``, ``cal::local_time``, and ``cal::local_datetime``, + +To resolve this, each of these datatypes can be represented with an instance +of a corresponding class, as defined in ``gel`` module. Clients use +these classes to represent these values in query results; they are documented +on the :ref:`Client API ` docs. + +.. list-table:: + + * - ``e.duration`` + - :js:class:`Duration` + * - ``e.cal.relative_duration`` + - :js:class:`RelativeDuration` + * - ``e.cal.date_duration`` + - :js:class:`DateDuration` + * - ``e.cal.local_date`` + - :js:class:`LocalDate` + * - ``e.cal.local_time`` + - :js:class:`LocalTime` + * - ``e.cal.local_datetime`` + - :js:class:`LocalDateTime` + * - ``e.cal.local_datetime`` + - :js:class:`LocalDateTime` + * - ``e.cal.local_datetime`` + - :js:class:`LocalDateTime` + +The code below demonstrates how to declare each kind of temporal literal, +along with the equivalent EdgeQL. + +.. code-block:: typescript + + import * as gel from "gel"; + + const myDuration = new gel.Duration(0, 0, 0, 0, 1, 2, 3); + e.duration(myDuration); + + const myLocalDate = new gel.LocalDate(1776, 7, 4); + e.cal.local_date(myLocalDate); + + const myLocalTime = new gel.LocalTime(13, 15, 0); + e.cal.local_time(myLocalTime); + + const myLocalDateTime = new gel.LocalDateTime(1776, 7, 4, 13, 15, 0); + e.cal.local_datetime(myLocalDateTime); + + +You can also declare these literals by casting an appropriately formatted +``str`` expression, as in EdgeQL. Casting :ref:`is documented +` in more detail later in the docs. + +.. code-block:: typescript + + e.cast(e.duration, e.str('5 minutes')); + // '5 minutes' + + e.cast(e.cal.local_datetime, e.str('1999-03-31T15:17:00')); + // '1999-03-31T15:17:00' + + e.cast(e.cal.local_date, e.str('1999-03-31')); + // '1999-03-31' + + e.cast(e.cal.local_time, e.str('15:17:00')); + // '15:17:00' + + +JSON +^^^^ + +JSON literals are created with the ``e.json`` function. You can pass in any +Gel-compatible data structure. + + +What does "Gel-compatible" mean? It means any JavaScript data structure +with an equivalent in Gel: strings, number, booleans, ``bigint``\ s, +``Uint8Array``\ s, ``Date``\ s, and instances of Gel's built-in classes: +(``LocalDate`` ``LocalTime``, ``LocalDateTime``, ``DateDuration``, +``Duration``, and ``RelativeDuration``), and any array or object of these +types. Other JavaScript data structures like symbols, instances of custom +classes, sets, maps, and `typed arrays `_ are not supported. + +.. code-block:: typescript + + const query = e.json({ name: "Billie" }) + // to_json('{"name": "Billie"}') + + const data = e.json({ + name: "Billie", + numbers: [1,2,3], + nested: { foo: "bar"}, + duration: new gel.Duration(1, 3, 3) + }) + +JSON expressions support indexing, as in EdgeQL. The returned expression also +has a ``json`` type. + +.. code-block:: typescript + + const query = e.json({ numbers: [0,1,2] }); + + query.toEdgeQL(); // to_json((numbers := [0,1,2])) + + query.numbers[0].toEdgeQL(); + // to_json('{"numbers":[0,1,2]}')['numbers'][0] + +.. Keep in mind that JSON expressions are represented as strings when returned from a query. + +.. .. code-block:: typescript + +.. await e.json({ +.. name: "Billie", +.. numbers: [1,2,3] +.. }).run(client) +.. // => '{"name": "Billie", "numbers": [1, 2, 3]}'; + +The inferred type associated with a ``json`` expression is ``unknown``. + +.. code-block:: typescript + + const result = await query.run(client) + // unknown + +Arrays +^^^^^^ + +Declare array expressions by passing an array of expressions into ``e.array``. + +.. code-block:: typescript + + e.array([e.str("a"), e.str("b"), e.str("b")]); + // ["a", "b", "c"] + +EdgeQL semantics are enforced by TypeScript, so arrays can't contain elements +with incompatible types. + +.. code-block:: typescript + + e.array([e.int64(5), e.str("foo")]); + // TypeError! + +For convenience, the ``e.array`` can also accept arrays of plain JavaScript +data as well. + +.. code-block:: typescript + + e.array(['a', 'b', 'c']); + // ['a', 'b', 'c'] + + // you can intermixing expressions and plain data + e.array([1, 2, e.int64(3)]); + // [1, 2, 3] + +Array expressions also support indexing and slicing operations. + +.. code-block:: typescript + + const myArray = e.array(['a', 'b', 'c', 'd', 'e']); + // ['a', 'b', 'c', 'd', 'e'] + + myArray[1]; + // ['a', 'b', 'c', 'd', 'e'][1] + + myArray['1:3']; + // ['a', 'b', 'c', 'd', 'e'][1:3] + +There are also equivalent ``.index`` and ``.slice`` methods that can accept +other expressions as arguments. + +.. code-block:: typescript + + const start = e.int64(1); + const end = e.int64(3); + + myArray.index(start); + // ['a', 'b', 'c', 'd', 'e'][1] + + myArray.slice(start, end); + // ['a', 'b', 'c', 'd', 'e'][1:3] + +Tuples +^^^^^^ + +Declare tuples with ``e.tuple``. Pass in an array to declare a "regular" +(unnamed) tuple; pass in an object to declare a named tuple. + +.. code-block:: typescript + + e.tuple([e.str("Peter Parker"), e.int64(18)]); + // ("Peter Parker", 18) + + e.tuple({ + name: e.str("Peter Parker"), + age: e.int64(18) + }); + // (name := "Peter Parker", age := 18) + +Tuple expressions support indexing. + +.. code-block:: typescript + + // Unnamed tuples + const spidey = e.tuple([ + e.str("Peter Parker"), + e.int64(18) + ]); + spidey[0]; // => ("Peter Parker", 18)[0] + + // Named tuples + const spidey = e.tuple({ + name: e.str("Peter Parker"), + age: e.int64(18) + }); + spidey.name; + // (name := "Peter Parker", age := 18).name + +Set literals +^^^^^^^^^^^^ + +Declare sets with ``e.set``. + +.. code-block:: typescript + + e.set(e.str("asdf"), e.str("qwer")); + // {'asdf', 'qwer'} + +As in EdgeQL, sets can't contain elements with incompatible types. These +semantics are enforced by TypeScript. + +.. code-block:: typescript + + e.set(e.int64(1234), e.str('sup')); + // TypeError + +Empty sets +^^^^^^^^^^ + +To declare an empty set, cast an empty set to the desired type. As in EdgeQL, +empty sets are not allowed without a cast. + +.. code-block:: typescript + + e.cast(e.int64, e.set()); + // {} + + +Range literals +^^^^^^^^^^^^^^ + +As in EdgeQL, declare range literals with the built-in ``range`` function. + +.. code-block:: typescript + + const myRange = e.range(0, 8); + + myRange.toEdgeQL(); + // => std::range(0, 8); + +Ranges can be created for all numerical types, as well as ``datetime``, ``local_datetime``, and ``local_date``. + +.. code-block:: typescript + + e.range(e.decimal('100'), e.decimal('200')); + e.range(Date.parse("1970-01-01"), Date.parse("2022-01-01")); + e.range(new LocalDate(1970, 1, 1), new LocalDate(2022, 1, 1)); + +Supply named parameters as the first argument. + +.. code-block:: typescript + + e.range({inc_lower: true, inc_upper: true, empty: true}, 0, 8); + // => std::range(0, 8, true, true); + +JavaScript doesn't have a native way to represent range values. Any range value returned from a query will be encoded as an instance of the :js:class:`Range` class, which is exported from the ``gel`` package. + +.. code-block:: typescript + + const query = e.range(0, 8); + const result = await query.run(client); + // => Range; + + console.log(result.lower); // 0 + console.log(result.upper); // 8 + console.log(result.isEmpty); // false + console.log(result.incLower); // true + console.log(result.incUpper); // false + + +.. Modules +.. ------- + +.. All *types*, *functions*, and *commands* are available on the ``e`` object, properly namespaced by module. + +.. .. code-block:: typescript + +.. // commands +.. e.select; +.. e.insert; +.. e.update; +.. e.delete; + +.. // types +.. e.std.str; +.. e.std.int64; +.. e.std.bool; +.. e.cal.local_datetime; +.. e.default.User; // user-defined object type +.. e.my_module.Foo; // object type in user-defined module + +.. // functions +.. e.std.len; +.. e.std.str_upper; +.. e.math.floor; +.. e.sys.get_version; + +.. For convenience, the contents of the ``std`` and ``default`` modules are also exposed at the top-level of ``e``. + +.. .. code-block:: typescript + +.. e.str; +.. e.int64; +.. e.bool; +.. e.len; +.. e.str_upper; +.. e.User; + +.. .. note:: + +.. If there are any name conflicts (e.g. a user-defined module called ``len``), +.. ``e.len`` will point to the user-defined module; in that scenario, you must +.. explicitly use ``e.std.len`` to access the built-in ``len`` function. diff --git a/docs/clients/js/objects.rst b/docs/clients/js/objects.rst new file mode 100644 index 00000000000..9df71ed7acd --- /dev/null +++ b/docs/clients/js/objects.rst @@ -0,0 +1,124 @@ +.. _gel-js-objects: + + +Objects and Paths +================= + +All queries on this page assume the following schema. + +.. code-block:: sdl + + module default { + type Person { + required name: str; + } + + abstract type Content { + required title: str { + constraint exclusive + }; + multi actors: Person { + character_name: str; + }; + } + + type Movie extending Content { + release_year: int64; + } + + type TVShow extending Content { + num_seasons: int64; + } + } + +Object types +^^^^^^^^^^^^ + +All object types in your schema are reflected into the query builder, properly +namespaced by module. + +.. code-block:: typescript + + e.default.Person; + e.default.Movie; + e.default.TVShow; + e.my_module.SomeType; + +For convenience, the contents of the ``default`` module are also available at +the top-level of ``e``. + +.. code-block:: typescript + + e.Person; + e.Movie; + e.TVShow; + +.. As in EdgeQL, type names like ``Movie`` serve two purposes. + +.. - They can be used to represent the set of all Movie objects: ``select Movie``. +.. - They can be used to represent the Movie *type* in operations like type intersections: ``select Content[is Movie]`` + +Paths +^^^^^ + +EdgeQL-style *paths* are supported on object type references. + +.. code-block:: typescript + + e.Person.name; // Person.name + e.Movie.title; // Movie.title + e.TVShow.actors.name; // Movie.actors.name + +Paths can be constructed from any object expression, not just the root types. + +.. code-block:: typescript + + e.select(e.Person).name; + // (select Person).name + + e.op(e.Movie, 'union', e.TVShow).actors; + // (Movie union TVShow).actors + + const ironMan = e.insert(e.Movie, { + title: "Iron Man" + }); + ironMan.title; + // (insert Movie { title := "Iron Man" }).title + + +.. _gel-js-objects-type-intersections: + +Type intersections +^^^^^^^^^^^^^^^^^^ + +Use the type intersection operator to narrow the type of a set of objects. For +instance, to represent the elements of an Account's watchlist that are of type +``TVShow``: + +.. code-block:: typescript + + e.Person.acted_in.is(e.TVShow); + // Person.acted_in[is TVShow] + + +Backlinks +^^^^^^^^^ + +All possible backlinks are auto-generated and can be auto-completed by +TypeScript. They behave just like forward links. However, because they contain +special characters, you must use bracket syntax instead of simple dot notation. + +.. code-block:: typescript + + e.Person[" + e.op('Yer a wizard, ', '++', params.name) + ); + /* with name := $name + select name; + */ + + +The first argument is an object defining the parameter names and their +corresponding types. The second argument is a closure that returns an +expression; use the ``params`` argument to construct the rest of your query. + +Passing parameter data +^^^^^^^^^^^^^^^^^^^^^^ + +To executing a query with parameters, pass the parameter data as the second +argument to ``.run()``; this argument is *fully typed*! + +.. code-block:: typescript + + await helloQuery.run(client, { name: "Harry Styles" }) + // => "Yer a wizard, Harry Styles" + + await helloQuery.run(client, { name: 16 }) + // => TypeError: number is not assignable to string + +Top-level usage +^^^^^^^^^^^^^^^ + +Note that you must call ``.run`` on the result of ``e.params``; in other +words, you can only use ``e.params`` at the *top level* of your query, not as +an expression inside a larger query. + +.. code-block:: typescript + + // ❌ TypeError + const wrappedQuery = e.select(helloQuery); + wrappedQuery.run(client, {name: "Harry Styles"}); + + +.. _gel-js-optional-parameters: + +Optional parameters +^^^^^^^^^^^^^^^^^^^ + +A type can be made optional with the ``e.optional`` function. + +.. code-block:: typescript + + const query = e.params( + { + title: e.str, + duration: e.optional(e.duration), + }, + (params) => { + return e.insert(e.Movie, { + title: params.title, + duration: params.duration, + }); + } + ); + + // works with duration + const result = await query.run(client, { + title: 'The Eternals', + duration: Duration.from({hours: 2, minutes: 3}) + }); + + // or without duration + const result = await query.run(client, {title: 'The Eternals'}); + +Complex types +^^^^^^^^^^^^^ + +In EdgeQL, parameters can only be primitives or arrays of primitives. That's +not true with the query builder! Parameter types can be arbitrarily complex. +Under the hood, the query builder serializes the parameters to JSON and +deserializes them on the server. + +.. code-block:: typescript + + const insertMovie = e.params( + { + title: e.str, + release_year: e.int64, + actors: e.array( + e.tuple({ + name: e.str, + }) + ), + }, + (params) => + e.insert(e.Movie, { + title: params.title, + }) + ); + + await insertMovie.run(client, { + title: 'Dune', + release_year: 2021, + actors: [{name: 'Timmy'}, {name: 'JMo'}], + }); + diff --git a/docs/clients/js/queries.rst b/docs/clients/js/queries.rst new file mode 100644 index 00000000000..b0a0bdaf905 --- /dev/null +++ b/docs/clients/js/queries.rst @@ -0,0 +1,281 @@ +.. _gel-js-queries: + +================= +Queries Generator +================= + +The ``queries`` generator scans your project for ``*.edgeql`` files and generates functions that allow you to execute these queries in a typesafe way. + +Installation +------------ + +To get started, install the following packages. + +.. note:: + + If you're using Deno, you can skip this step. + +Install the ``gel`` package. + +.. code-block:: bash + + $ npm install gel # npm users + $ yarn add gel # yarn users + $ bun add gel # bun users + +Then install ``@gel/generate`` as a dev dependency. + +.. code-block:: bash + + $ npm install @gel/generate --save-dev # npm users + $ yarn add @gel/generate --dev # yarn users + $ bun add --dev @gel/generate # bun users + + +Generation +---------- + +Consider the following file tree. + +.. code-block:: text + + . + β”œβ”€β”€ package.json + β”œβ”€β”€ gel.toml + β”œβ”€β”€ index.ts + β”œβ”€β”€ dbschema + └── queries + └── getUser.edgeql + + +The following command will run the ``queries`` generator. + +.. tabs:: + + .. code-tab:: bash + :caption: Node.js + + $ npx @gel/generate queries + + .. code-tab:: bash + :caption: Deno + + $ deno run --allow-all --unstable https://deno.land/x/gel/generate.ts queries + + .. code-tab:: bash + :caption: Bun + + $ bunx @gel/generate queries + +.. note:: Deno users + + Create these two files in your project root: + + .. code-block:: json + :caption: importMap.json + + { + "imports": { + "gel": "https://deno.land/x/gel/mod.ts", + "gel/": "https://deno.land/x/gel/" + } + } + + .. code-block:: json + :caption: deno.js + + { + "importMap": "./importMap.json" + } + +The generator will detect the project root by looking for an ``gel.toml``, +then scan the directory for ``*.edgeql`` files. In this case, there's only one: +``queries/getUser.edgeql``. + +.. code-block:: edgeql + :caption: getUser.edgeql + + select User { name, email } filter .id = $user_id; + +For each ``.edgeql`` file, the generator will read the contents and send the +query to the database, which returns type information about its parameters and +return type. The generator uses this information to create a new file +``getUser.query.ts`` alongside the original ``getUser.edgeql`` file. + +.. code-block:: text + + . + β”œβ”€β”€ package.json + β”œβ”€β”€ gel.toml + β”œβ”€β”€ index.ts + β”œβ”€β”€ dbschema + └── queries + └── getUser.edgeql + └── getUser.query.ts <-- generated file + + +.. note:: + + This example assumes you are using TypeScript. The generator tries to + auto-detect the language you're using; you can also specify the language with + the ``--target`` flag. See the :ref:`Targets ` section for + more information. + +The generated file will look something like this: + +.. code-block:: typescript + + import type { Client } from "gel"; + + export type GetUserArgs = { + user_id: string; + }; + + export type GetUserReturns = { + name: string; + email: string; + } | null; + + export async function getUser( + client: Client, + args: GetUserArgs + ): Promise { + return await client.querySingle( + `select User { name, email } filter .id = $user_id;`, + args + ); + } + +Some things to note: + +- The first argument is a ``Client`` instance. This is the same client you would use to execute a query manually. You can use the same client for both manual and generated queries. +- The second argument is a parameter object. The keys of this object are the names of the parameters in the query. +- The code uses the ``querySingle`` method, since the query is only expected to return a single result. +- We export the type of the parameter object and the return value unwrapped from the promise. + +We can now use this function in our code. + +.. code-block:: typescript + + import { getUser } from "./queries/getUser.query"; + import { + createClient, + type GetUserArgs, + type GetUserReturns, + } from "gel"; + + const client = await createClient(); + + const newUser: GetUserArgs = { + user_id: "00000000-0000-0000-0000-000000000000" + }; + + const user = await getUser(client, newUser); // GetUserReturns + + if (user) { + user.name; // string + user.email; // string + } + +.. note:: + + Generators work by connecting to the database to get information about the current state of the schema. Make sure you run the generators again any time the schema changes so that the generated code is in-sync with the current state of the schema. + + +Single-file mode +---------------- + +Pass the ``--file`` flag to generate a single file that contains functions for all detected ``.edgeql`` files. This lets you import all your queries from a single file. + +Let's say we start with the following file tree. + +.. code-block:: text + + . + β”œβ”€β”€ package.json + β”œβ”€β”€ gel.toml + β”œβ”€β”€ index.ts + β”œβ”€β”€ dbschema + └── queries + └── getUser.edgeql + └── getMovies.edgeql + +The following command will run the generator in ``--file`` mode. + +.. code-block:: bash + + $ npx @gel/generate queries --file + +A single file will be generated that exports two functions, ``getUser`` and ``getMovies``. By default this file is generated into the ``dbschema`` directory. + +.. code-block:: text + + . + β”œβ”€β”€ package.json + β”œβ”€β”€ gel.toml + β”œβ”€β”€ index.ts + β”œβ”€β”€ dbschema + β”‚ └── queries.ts <-- generated file + └── queries + └── getUser.edgeql + └── getMovies.edgeql + + +We can now use these functions in our code. + +.. code-block:: typescript + + import * as queries from "./dbschema/queries"; + import {createClient} from "gel"; + + const client = await createClient(); + + const movies = await queries.getMovies(client); + const user = await queries.getUser(client, { + user_id: "00000000-0000-0000-0000-000000000000" + }); + +To override the file path and name, you can optionally pass a value to the ``--file`` flag. Note that you should *exclude the extension*. + +.. code-block:: bash + + $ npx @gel/generate queries --file path/to/myqueries + +The file extension is determined by the generator ``--target`` and will be automatically appended to the provided path. Extensionless "absolute" paths will work; relative paths will be resolved relative to the current working directory. + +This will result in the following file tree. + +.. code-block:: text + + . + β”œβ”€β”€ package.json + β”œβ”€β”€ gel.toml + β”œβ”€β”€ path + β”‚ └── to + β”‚ └── myqueries.ts + β”œβ”€β”€ queries + β”‚ └── getUser.edgeql + β”‚ └── getMovies.edgeql + └── index.ts + +Version control +--------------- + +To exclude the generated files, add the following lines to your ``.gitignore`` file. + +.. code-block:: text + + **/*.edgeql.ts + dbschema/queries.* + +Writing Queries with Parameters +------------------------------- + +To inject external values into your EdgeQL queries, you can use `parameters `__. + +When using the queries generator, you may be tempted to declare the same parameter in multiple places. +However, it's better practice to declare it once by assigning it to a variable in a `with block `__ +and reference that variable in the rest of your query. This way you avoid mismatched types in your declarations, +such as forgetting to mark them all as `optional `__. + +Check out the `EdgeQL docs `__ to learn more about writing queries. diff --git a/docs/clients/js/querybuilder.rst b/docs/clients/js/querybuilder.rst new file mode 100644 index 00000000000..833bd585e90 --- /dev/null +++ b/docs/clients/js/querybuilder.rst @@ -0,0 +1,625 @@ +.. _gel-js-qb: + +======================= +Query Builder Generator +======================= +:index: querybuilder generator typescript + +The |Gel| query builder provides a **code-first** way to write +**fully-typed** EdgeQL queries with TypeScript. We recommend it for TypeScript +users, or anyone who prefers writing queries with code. + +.. code-block:: typescript + + import * as gel from "gel"; + import e from "./dbschema/edgeql-js"; + + const client = gel.createClient(); + + async function run() { + const query = e.select(e.Movie, ()=>({ + id: true, + title: true, + actors: { name: true } + })); + + const result = await query.run(client) + /* + { + id: string; + title: string; + actors: { name: string; }[]; + }[] + */ + } + + run(); + +.. note:: Is it an ORM? + + Noβ€”it's better! Like any modern TypeScript ORM, the query builder gives you + full typesafety and autocompletion, but without the power and `performance + `_ + tradeoffs. You have access to the **full power** of EdgeQL and can write + EdgeQL queries of arbitrary complexity. And since |Gel| compiles each + EdgeQL query into a single, highly-optimized SQL query, your queries stay + fast, even when they're complex. + +Why use the query builder? +-------------------------- + +*Type inference!* If you're using TypeScript, the result type of *all +queries* is automatically inferred for you. For the first time, you don't +need an ORM to write strongly typed queries. + +*Auto-completion!* You can write queries full autocompletion on EdgeQL +keywords, standard library functions, and link/property names. + +*Type checking!* In the vast majority of cases, the query builder won't let +you construct invalid queries. This eliminates an entire class of bugs and +helps you write valid queries the first time. + +*Close to EdgeQL!* The goal of the query builder is to provide an API that is as +close as possible to EdgeQL itself while feeling like idiomatic TypeScript. + +Installation +------------ + +To get started, install the following packages. + +.. note:: + + If you're using Deno, you can skip this step. + +Install the ``gel`` package. + +.. code-block:: bash + + $ npm install gel # npm users + $ yarn add gel # yarn users + $ bun add gel # bun users + +Then install ``@gel/generate`` as a dev dependency. + +.. code-block:: bash + + $ npm install @gel/generate --save-dev # npm users + $ yarn add @gel/generate --dev # yarn users + $ bun add --dev @gel/generate # bun users + + +Generation +---------- + +The following command will run the ``edgeql-js`` query builder generator. + +.. tabs:: + + .. code-tab:: bash + :caption: Node.js + + $ npx @gel/generate edgeql-js + + .. code-tab:: bash + :caption: Deno + + $ deno run --allow-all --unstable https://deno.land/x/gel/generate.ts edgeql-js + + .. code-tab:: bash + :caption: Bun + + $ bunx @gel/generate edgeql-js + +.. note:: Deno users + + Create these two files in your project root: + + .. code-block:: json + :caption: importMap.json + + { + "imports": { + "gel": "https://deno.land/x/gel/mod.ts", + "gel/": "https://deno.land/x/gel/" + } + } + + .. code-block:: json + :caption: deno.js + + { + "importMap": "./importMap.json" + } + +The generation command is configurable in a number of ways. + +``--output-dir `` + Sets the output directory for the generated files. + +``--target `` + What type of files to generate. + +``--force-overwrite`` + To avoid accidental changes, you'll be prompted to confirm whenever the + ``--target`` has changed from the previous run. To avoid this prompt, pass + ``--force-overwrite``. + +The generator also supports all the :ref:`connection flags +` supported by the |Gel| CLI. These aren't +necessary when using a project or environment variables to configure a +connection. + +.. note:: + + Generators work by connecting to the database to get information about the current state of the schema. Make sure you run the generators again any time the schema changes so that the generated code is in-sync with the current state of the schema. + +.. _gel-js-execution: + +Expressions +----------- + +Throughout the documentation, we use the term "expression" a lot. This is a +catch-all term that refers to *any query or query fragment* you define with +the query builder. They all conform to an interface called ``Expression`` with +some common functionality. + +Most importantly, any expression can be executed with the ``.run()`` method, +which accepts a ``Client`` instead as the first argument. The result is +``Promise``, where ``T`` is the inferred type of the query. + +.. code-block:: typescript + + await e.str("hello world").run(client); + // => "hello world" + + await e.set(e.int64(1), e.int64(2), e.int64(3)).run(client); + // => [1, 2, 3] + + await e + .select(e.Movie, () => ({ + title: true, + actors: { name: true }, + })) + .run(client); + // => [{ title: "The Avengers", actors: [...]}] + +Note that the ``.run`` method accepts an instance of :js:class:`Client` (or +``Transaction``) as it's first argument. See :ref:`Creating a Client +` for details on creating clients. The second +argument is for passing :ref:`$parameters `, more on +that later. + +.. code-block:: typescript + + .run(client: Client | Transaction, params: Params): Promise + + +Converting to EdgeQL +-------------------- +:index: querybuilder toedgeql + +You can extract an EdgeQL representation of any expression calling the +``.toEdgeQL()`` method. Below is a number of expressions and the EdgeQL they +produce. (The actual EdgeQL the create may look slightly different, but it's +equivalent.) + +.. code-block:: typescript + + e.str("hello world").toEdgeQL(); + // => select "hello world" + + e.set(e.int64(1), e.int64(2), e.int64(3)).toEdgeQL(); + // => select {1, 2, 3} + + e.select(e.Movie, () => ({ + title: true, + actors: { name: true } + })).toEdgeQL(); + // => select Movie { title, actors: { name }} + +Extracting the inferred type +---------------------------- + +The query builder *automatically infers* the TypeScript type that best +represents the result of a given expression. This inferred type can be +extracted with the ``$infer`` type helper. + +.. code-block:: typescript + + import e, { type $infer } from "./dbschema/edgeql-js"; + + const query = e.select(e.Movie, () => ({ id: true, title: true })); + type result = $infer; + // { id: string; title: string }[] + +Cheatsheet +---------- + +Below is a set of examples to get you started with the query builder. It is +not intended to be comprehensive, but it should provide a good starting point. + +.. note:: + + Modify the examples below to fit your schema, paste them into ``script.ts``, + and execute them with the ``npx`` command from the previous section! Note + how the signature of ``result`` changes as you modify the query. + +Insert an object +^^^^^^^^^^^^^^^^ + +.. code-block:: typescript + + const query = e.insert(e.Movie, { + title: 'Doctor Strange 2', + release_year: 2022 + }); + + const result = await query.run(client); + // { id: string } + // by default INSERT only returns the id of the new object + +.. _gel-js-qb-transaction: + +Transaction +^^^^^^^^^^^ + +We can also run the same query as above, build with the query builder, in a +transaction. + +.. code-block:: typescript + + const query = e.insert(e.Movie, { + title: 'Doctor Strange 2', + release_year: 2022 + }); + + await client.transaction(async (tx) => { + const result = await query.run(tx); + // { id: string } + }); + + +Select objects +^^^^^^^^^^^^^^ + +.. code-block:: typescript + + const query = e.select(e.Movie, () => ({ + id: true, + title: true, + })); + + const result = await query.run(client); + // { id: string; title: string; }[] + +To select all properties of an object, use the spread operator with the +special ``*`` property: + +.. code-block:: typescript + + const query = e.select(e.Movie, () => ({ + ...e.Movie['*'] + })); + + const result = await query.run(client); + /* + { + id: string; + title: string; + release_year: number | null; # optional property + }[] + */ + +Nested shapes +^^^^^^^^^^^^^ + +.. code-block:: typescript + + const query = e.select(e.Movie, () => ({ + id: true, + title: true, + actors: { + name: true, + } + })); + + const result = await query.run(client); + /* + { + id: string; + title: string; + actors: { name: string; }[]; + }[] + */ + +Filtering +^^^^^^^^^ + +Pass a boolean expression as the special key ``filter`` to filter the results. + +.. code-block:: typescript + + const query = e.select(e.Movie, (movie) => ({ + id: true, + title: true, + // special "filter" key + filter: e.op(movie.release_year, ">", 1999) + })); + + const result = await query.run(client); + // { id: string; title: number }[] + +Since ``filter`` is a reserved keyword in EdgeQL, the special ``filter`` key can +live alongside your property keys without a risk of collision. + +.. note:: + + The ``e.op`` function is used to express EdgeQL operators. It is documented in + more detail below and on the :ref:`Functions and operators + ` page. + +Select a single object +^^^^^^^^^^^^^^^^^^^^^^ + +To select a particular object, use the ``filter_single`` key. This tells the +query builder to expect a singleton result. + +.. code-block:: typescript + + const query = e.select(e.Movie, (movie) => ({ + id: true, + title: true, + release_year: true, + + filter_single: e.op( + movie.id, + "=", + e.uuid("2053a8b4-49b1-437a-84c8-e1b0291ccd9f") + }, + })); + + const result = await query.run(client); + // { id: string; title: string; release_year: number | null } + +For convenience ``filter_single`` also supports a simplified syntax that +eliminates the need for ``e.op`` when used on exclusive properties: + +.. code-block:: typescript + + e.select(e.Movie, (movie) => ({ + id: true, + title: true, + release_year: true, + + filter_single: { id: "2053a8b4-49b1-437a-84c8-e1b0291ccd9f" }, + })); + +This also works if an object type has a composite exclusive constraint: + +.. code-block:: typescript + + /* + type Movie { + ... + constraint exclusive on (.title, .release_year); + } + */ + + e.select(e.Movie, (movie) => ({ + title: true, + filter_single: { + title: "The Avengers", + release_year: 2012 + }, + })); + + +Ordering and pagination +^^^^^^^^^^^^^^^^^^^^^^^ + +The special keys ``order_by``, ``limit``, and ``offset`` correspond to +equivalent EdgeQL clauses. + +.. code-block:: typescript + + const query = e.select(e.Movie, (movie) => ({ + id: true, + title: true, + + order_by: movie.title, + limit: 10, + offset: 10 + })); + + const result = await query.run(client); + // { id: true; title: true }[] + +Operators +^^^^^^^^^ + +Note that the filter expression above uses ``e.op`` function, which is how to +use *operators* like ``=``, ``>=``, ``++``, and ``and``. + +.. code-block:: typescript + + // prefix (unary) operators + e.op("not", e.bool(true)); // not true + e.op("exists", e.set("hi")); // exists {"hi"} + + // infix (binary) operators + e.op(e.int64(2), "+", e.int64(2)); // 2 + 2 + e.op(e.str("Hello "), "++", e.str("World!")); // "Hello " ++ "World!" + + // ternary operator (if/else) + e.op(e.str("πŸ˜„"), "if", e.bool(true), "else", e.str("😒")); + // "πŸ˜„" if true else "😒" + + +Update objects +^^^^^^^^^^^^^^ + +.. code-block:: typescript + + const query = e.update(e.Movie, (movie) => ({ + filter_single: { title: "Doctor Strange 2" }, + set: { + title: "Doctor Strange in the Multiverse of Madness", + }, + })); + + const result = await query.run(client); + +Delete objects +^^^^^^^^^^^^^^ + +.. code-block:: typescript + + const query = e.delete(e.Movie, (movie) => ({ + filter: e.op(movie.title, 'ilike', "the avengers%"), + })); + + const result = await query.run(client); + // { id: string }[] + +Delete multiple objects using an array of properties: + +.. code-block:: typescript + + const titles = ["The Avengers", "Doctor Strange 2"]; + const query = e.delete(e.Movie, (movie) => ({ + filter: e.op( + movie.title, + "in", + e.array_unpack(e.literal(e.array(e.str), titles)) + ) + })); + const result = await query.run(client); + // { id: string }[] + +Note that we have to use ``array_unpack`` to cast our ``array`` into a +``set`` since the ``in`` operator works on sets. And we use ``literal`` to +create a custom literal since we're inlining the titles array into our query. + +Here's an example of how to do this with params: + +.. code-block:: typescript + + const query = e.params({ titles: e.array(e.str) }, ({ titles }) => + e.delete(e.Movie, (movie) => ({ + filter: e.op(movie.title, "in", e.array_unpack(titles)), + })) + ); + + const result = await query.run(client, { + titles: ["The Avengers", "Doctor Strange 2"], + }); + // { id: string }[] + +Compose queries +^^^^^^^^^^^^^^^ + +All query expressions are fully composable; this is one of the major +differentiators between this query builder and a typical ORM. For instance, we +can ``select`` an ``insert`` query in order to fetch properties of the object we +just inserted. + + +.. code-block:: typescript + + const newMovie = e.insert(e.Movie, { + title: "Iron Man", + release_year: 2008 + }); + + const query = e.select(newMovie, () => ({ + title: true, + release_year: true, + num_actors: e.count(newMovie.actors) + })); + + const result = await query.run(client); + // { title: string; release_year: number; num_actors: number } + +Or we can use subqueries inside mutations. + +.. code-block:: typescript + + // select Doctor Strange + const drStrange = e.select(e.Movie, (movie) => ({ + filter_single: { title: "Doctor Strange" } + })); + + // select actors + const actors = e.select(e.Person, (person) => ({ + filter: e.op( + person.name, + "in", + e.set("Benedict Cumberbatch", "Rachel McAdams") + ) + })); + + // add actors to cast of drStrange + const query = e.update(drStrange, () => ({ + actors: { "+=": actors } + })); + + const result = await query.run(client); + + +Parameters +^^^^^^^^^^ + +.. code-block:: typescript + + const query = e.params({ + title: e.str, + release_year: e.int64, + }, + (params) => { + return e.insert(e.Movie, { + title: params.title, + release_year: params.release_year, + })) + }; + + const result = await query.run(client, { + title: "Thor: Love and Thunder", + release_year: 2022, + }); + // { id: string } + +.. note:: + + Continue reading for more complete documentation on how to express any + EdgeQL query with the query builder. + + +.. _ref_geljs_globals: + +Globals +^^^^^^^ + +Reference global variables. + +.. code-block:: typescript + + e.global.user_id; + e.default.global.user_id; // same as above + e.my_module.global.some_value; + +Other modules +^^^^^^^^^^^^^ + +Reference entities in modules other than ``default``. + +The ``Vampire`` type in a module named ``characters``: + +.. code-block:: typescript + + e.characters.Vampire; + +As shown in "Globals," a global ``some_value`` in a module ``my_module``: + +.. code-block:: typescript + + e.my_module.global.some_value; diff --git a/docs/clients/js/reference.rst b/docs/clients/js/reference.rst new file mode 100644 index 00000000000..b564fad678b --- /dev/null +++ b/docs/clients/js/reference.rst @@ -0,0 +1,1301 @@ +.. _gel-js-api-reference: + +######### +Reference +######### + +.. _gel-js-api-client: + +Client +====== + +.. js:function:: createClient( \ + options: string | ConnectOptions | null \ + ): Client + + Creates a new :js:class:`Client` instance. + + :param options: + This is an optional parameter. When it is not specified the client + will connect to the current |Gel| Project instance. + + If this parameter is a string it can represent either a + DSN or an instance name: + + * when the string does not start with |geluri| it is a + :ref:`name of an instance `; + + * otherwise it specifies a single string in the connection URI format: + :geluri:`user:password@host:port/database?option=value`. + + See the :ref:`Connection Parameters ` + docs for full details. + + Alternatively the parameter can be a ``ConnectOptions`` config; + see the documentation of valid options below. + + :param string options.dsn: + Specifies the DSN of the instance. + + :param string options.credentialsFile: + Path to a file containing credentials. + + :param string options.host: + Database host address as either an IP address or a domain name. + + :param number options.port: + Port number to connect to at the server host. + + :param string options.user: + The name of the database role used for authentication. + + :param string options.database: + The name of the database to connect to. + + :param string options.password: + Password to be used for authentication, if the server requires one. + + :param string options.tlsCAFile: + Path to a file containing the root certificate of the server. + + :param boolean options.tlsSecurity: + Determines whether certificate and hostname verification is enabled. + Valid values are ``'strict'`` (certificate will be fully validated), + ``'no_host_verification'`` (certificate will be validated, but + hostname may not match), ``'insecure'`` (certificate not validated, + self-signed certificates will be trusted), or ``'default'`` (acts as + ``strict`` by default, or ``no_host_verification`` if ``tlsCAFile`` + is set). + + The above connection options can also be specified by their corresponding + environment variable. If none of ``dsn``, ``credentialsFile``, ``host`` or + ``port`` are explicitly specified, the client will connect to your + linked project instance, if it exists. For full details, see the + :ref:`Connection Parameters ` docs. + + + :param number options.timeout: + Connection timeout in milliseconds. + + :param number options.waitUntilAvailable: + If first connection fails, the number of milliseconds to keep retrying + to connect (Defaults to 30 seconds). Useful if your development + instance and app are started together, to allow the server time to + be ready. + + :param number options.concurrency: + The maximum number of connection the ``Client`` will create in it's + connection pool. If not specified the concurrency will be controlled + by the server. This is recommended as it allows the server to better + manage the number of client connections based on it's own available + resources. + + :returns: + Returns an instance of :js:class:`Client`. + + Example: + + .. code-block:: javascript + + // Use the Node.js assert library to test results. + const assert = require("assert"); + const gel = require("gel"); + + async function main() { + const client = gel.createClient(); + + const data = await client.querySingle("select 1 + 1"); + + // The result is a number 2. + assert(typeof data === "number"); + assert(data === 2); + } + + main(); + + +.. js:class:: Client + + A ``Client`` allows you to run queries on a |Gel| instance. + + Since opening connections is an expensive operation, ``Client`` also + maintains a internal pool of connections to the instance, allowing + connections to be automatically reused, and you to run multiple queries + on the client simultaneously, enhancing the performance of + database interactions. + + :js:class:`Client` is not meant to be instantiated directly; + :js:func:`createClient` should be used instead. + + + .. _gel-js-api-async-optargs: + + .. note:: + + Some methods take query arguments as an *args* parameter. The type of + the *args* parameter depends on the query: + + * If the query uses positional query arguments, the *args* parameter + must be an ``array`` of values of the types specified by each query + argument's type cast. + * If the query uses named query arguments, the *args* parameter must + be an ``object`` with property names and values corresponding to + the query argument names and type casts. + + If a query argument is defined as ``optional``, the key/value can be + either omitted from the *args* object or be a ``null`` value. + + .. js:method:: execute(query: string, args?: QueryArgs): Promise + + Execute an EdgeQL command (or commands). + + :param query: Query text. + + This method takes :ref:`optional query arguments + `. + + Example: + + .. code-block:: javascript + + await client.execute(` + CREATE TYPE MyType { + CREATE PROPERTY a -> int64 + }; + + for x in {100, 200, 300} + union (insert MyType { a := x }); + `) + + .. js:method:: query(query: string, args?: QueryArgs): Promise + + Run an EdgeQL query and return the results as an array. + This method **always** returns an array. + + This method takes :ref:`optional query arguments + `. + + .. js:method:: queryRequired( \ + query: string, \ + args?: QueryArgs \ + ): Promise<[T, ...T[]]> + + Run a query that returns at least one element and return the result as an + array. + + This method takes :ref:`optional query arguments + `. + + The *query* must return at least one element. If the query less than one + element, a ``ResultCardinalityMismatchError`` error is thrown. + + .. js:method:: querySingle( \ + query: string, \ + args?: QueryArgs \ + ): Promise + + Run an optional singleton-returning query and return the result. + + This method takes :ref:`optional query arguments + `. + + The *query* must return no more than one element. If the query returns + more than one element, a ``ResultCardinalityMismatchError`` error is + thrown. + + .. js:method:: queryRequiredSingle( \ + query: string, \ + args?: QueryArgs \ + ): Promise + + Run a singleton-returning query and return the result. + + This method takes :ref:`optional query arguments + `. + + The *query* must return exactly one element. If the query returns + more than one element, a ``ResultCardinalityMismatchError`` error is + thrown. If the query returns an empty set, a ``NoDataError`` error is + thrown. + + .. js:method:: queryJSON(query: string, args?: QueryArgs): Promise + + Run a query and return the results as a JSON-encoded string. + + This method takes :ref:`optional query arguments + `. + + .. note:: + + Caution is advised when reading ``decimal`` or ``bigint`` + values using this method. The JSON specification does not + have a limit on significant digits, so a ``decimal`` or a + ``bigint`` number can be losslessly represented in JSON. + However, JSON decoders in JavaScript will often read all + such numbers as ``number`` values, which may result in + precision loss. If such loss is unacceptable, then + consider casting the value into ``str`` and decoding it on + the client side into a more appropriate type, such as + BigInt_. + + .. js:method:: queryRequiredJSON( \ + query: string, \ + args?: QueryArgs \ + ): Promise + + Run a query that returns at least one element and return the result as a + JSON-encoded string. + + This method takes :ref:`optional query arguments + `. + + The *query* must return at least one element. If the query less than one + element, a ``ResultCardinalityMismatchError`` error is thrown. + + .. note:: + + Caution is advised when reading ``decimal`` or ``bigint`` + values using this method. The JSON specification does not + have a limit on significant digits, so a ``decimal`` or a + ``bigint`` number can be losslessly represented in JSON. + However, JSON decoders in JavaScript will often read all + such numbers as ``number`` values, which may result in + precision loss. If such loss is unacceptable, then + consider casting the value into ``str`` and decoding it on + the client side into a more appropriate type, such as + BigInt_. + + .. js:method:: querySingleJSON( \ + query: string, \ + args?: QueryArgs \ + ): Promise + + Run an optional singleton-returning query and return its element + as a JSON-encoded string. + + This method takes :ref:`optional query arguments + `. + + The *query* must return at most one element. If the query returns + more than one element, an ``ResultCardinalityMismatchError`` error + is thrown. + + .. note:: + + Caution is advised when reading ``decimal`` or ``bigint`` + values using this method. The JSON specification does not + have a limit on significant digits, so a ``decimal`` or a + ``bigint`` number can be losslessly represented in JSON. + However, JSON decoders in JavaScript will often read all + such numbers as ``number`` values, which may result in + precision loss. If such loss is unacceptable, then + consider casting the value into ``str`` and decoding it on + the client side into a more appropriate type, such as + BigInt_. + + .. js:method:: queryRequiredSingleJSON( \ + query: string, \ + args?: QueryArgs \ + ): Promise + + Run a singleton-returning query and return its element as a + JSON-encoded string. + + This method takes :ref:`optional query arguments + `. + + The *query* must return exactly one element. If the query returns + more than one element, a ``ResultCardinalityMismatchError`` error + is thrown. If the query returns an empty set, a ``NoDataError`` error + is thrown. + + .. note:: + + Caution is advised when reading ``decimal`` or ``bigint`` + values using this method. The JSON specification does not + have a limit on significant digits, so a ``decimal`` or a + ``bigint`` number can be losslessly represented in JSON. + However, JSON decoders in JavaScript will often read all + such numbers as ``number`` values, which may result in + precision loss. If such loss is unacceptable, then + consider casting the value into ``str`` and decoding it on + the client side into a more appropriate type, such as + BigInt_. + + .. js:method:: executeSQL(query: string, args?: unknown[]): Promise + + Execute a SQL command. + + :param query: SQL query text. + + This method takes optional query arguments. + + Example: + + .. code-block:: javascript + + await client.executeSQL(` + INSERT INTO "MyType"(prop) VALUES ("value"); + `) + + .. js:method:: querySQL(query: string, args?: unknown[]): Promise + + Run a SQL query and return the results as an array. + This method **always** returns an array. + + The array will contain the returned rows. By default, rows are + ``Objects`` with columns addressable by name. + + This can controlled with ``client.withSQLRowMode('array' | 'object')`` + API. + + This method takes optional query arguments. + + Example: + + .. code-block:: javascript + + let vals = await client.querySQL(`SELECT 1 as foo`) + console.log(vals); // [{'foo': 1}] + + vals = await client + .withSQLRowMode('array') + .querySQL(`SELECT 1 as foo`); + + console.log(vals); // [[1]] + + .. js:method:: transaction( \ + action: (tx: Transaction) => Promise \ + ): Promise + + Execute a retryable transaction. The ``Transaction`` object passed to + the action function has the same ``execute`` and ``query*`` methods + as ``Client``. + + This is the preferred method of initiating and running a database + transaction in a robust fashion. The ``transaction()`` method + will attempt to re-execute the transaction body if a transient error + occurs, such as a network error or a transaction serialization error. + The number of times ``transaction()`` will attempt to execute the + transaction, and the backoff timeout between retries can be + configured with :js:meth:`Client.withRetryOptions`. + + See :ref:`gel-js-api-transaction` for more details. + + Example: + + .. code-block:: javascript + + await client.transaction(async tx => { + const value = await tx.querySingle("select Counter.value") + await tx.execute( + `update Counter set { value := $value }`, + {value: value + 1}, + ) + }); + + Note that we are executing queries on the ``tx`` object rather + than on the original ``client``. + + .. js:method:: ensureConnected(): Promise + + If the client does not yet have any open connections in its pool, + attempts to open a connection, else returns immediately. + + Since the client lazily creates new connections as needed (up to the + configured ``concurrency`` limit), the first connection attempt will + only occur when the first query is run a client. ``ensureConnected`` + can be useful to catch any errors resulting from connection + mis-configuration by triggering the first connection attempt + explicitly. + + Example: + + .. code-block:: javascript + + import {createClient} from 'gel'; + + async function getClient() { + try { + return await createClient('custom_instance').ensureConnected(); + } catch (err) { + // handle connection error + } + } + + function main() { + const client = await getClient(); + + await client.query('select ...'); + } + + .. js:method:: withGlobals(globals: {[name: string]: any}): Client + + Returns a new ``Client`` instance with the specified global values. + The ``globals`` argument object is merged with any existing globals + defined on the current client instance. + + Equivalent to using the ``set global`` command. + + Example: + + .. code-block:: javascript + + const user = await client.withGlobals({ + userId: '...' + }).querySingle(` + select User {name} filter .id = global userId + `); + + .. js:method:: withModuleAliases(aliases: {[name: string]: string}): Client + + Returns a new ``Client`` instance with the specified module aliases. + The ``aliases`` argument object is merged with any existing module + aliases defined on the current client instance. + + If the alias ``name`` is ``module`` this is equivalent to using + the ``set module`` command, otherwise it is equivalent to the + ``set alias`` command. + + Example: + + .. code-block:: javascript + + const user = await client.withModuleAliases({ + module: 'sys' + }).querySingle(` + select get_version_as_str() + `); + // "2.0" + + .. js:method:: withConfig(config: {[name: string]: any}): Client + + Returns a new ``Client`` instance with the specified client session + configuration. The ``config`` argument object is merged with any + existing session config defined on the current client instance. + + Equivalent to using the ``configure session`` command. For available + configuration parameters refer to the + :ref:`Config documentation `. + + .. js:method:: withRetryOptions(opts: { \ + attempts?: number \ + backoff?: (attempt: number) => number \ + }): Client + + Returns a new ``Client`` instance with the specified retry attempts + number and backoff time function (the time that retrying methods will + wait between retry attempts, in milliseconds), where options not given + are inherited from the current client instance. + + The default number of attempts is ``3``. The default backoff + function returns a random time between 100 and 200ms multiplied by + ``2 ^ attempt number``. + + .. note:: + + The new client instance will share the same connection pool as the + client it's created from, so calling the ``ensureConnected``, + ``close`` and ``terminate`` methods will affect all clients + sharing the pool. + + Example: + + .. code-block:: javascript + + import {createClient} from 'gel'; + + function main() { + const client = createClient(); + + // By default transactions will retry if they fail + await client.transaction(async tx => { + // ... + }); + + const nonRetryingClient = client.withRetryOptions({ + attempts: 1 + }); + + // This transaction will not retry + await nonRetryingClient.transaction(async tx => { + // ... + }); + } + + .. js:method:: close(): Promise + + Close the client's open connections gracefully. When a client is + closed, all its underlying connections are awaited to complete their + pending operations, then closed. A warning is produced if the pool + takes more than 60 seconds to close. + + .. note:: + + Clients will not prevent Node.js from exiting once all of it's + open connections are idle and Node.js has no further tasks it is + awaiting on, so it is not necessary to explicitly call ``close()`` + if it is more convenient for your application. + + (This does not apply to Deno, since Deno is missing the + required API's to ``unref`` idle connections) + + .. js:method:: isClosed(): boolean + + Returns true if ``close()`` has been called on the client. + + .. js:method:: terminate(): void + + Terminate all connections in the client, closing all connections non + gracefully. If the client is already closed, return without doing + anything. + + +.. _gel-js-datatypes: + +Type conversion +=============== + +The client automatically converts |Gel| types to the corresponding JavaScript +types and vice versa. + +The table below shows the correspondence between Gel and JavaScript types. + + +.. list-table:: + + * - **Gel Type** + - **JavaScript Type** + * - ``multi`` set + - ``Array`` + * - ``array`` + - ``Array`` + * - ``anytuple`` + - ``Array`` + * - ``anyenum`` + - ``string`` + * - ``Object`` + - ``object`` + * - ``bool`` + - ``boolean`` + * - ``bytes`` + - ``Uint8Array`` + * - ``str`` + - ``string`` + * - ``float32``, ``float64``, ``int16``, ``int32``, ``int64`` + - ``number`` + * - ``bigint`` + - ``BigInt`` + * - ``decimal`` + - n/a + * - ``json`` + - ``unknown`` + * - ``uuid`` + - ``string`` + * - ``datetime`` + - ``Date`` + * - ``cal::local_date`` + - :js:class:`LocalDate` + * - ``cal::local_time`` + - :js:class:`LocalTime` + * - ``cal::local_datetime`` + - :js:class:`LocalDateTime` + * - ``duration`` + - :js:class:`Duration` + * - ``cal::relative_duration`` + - :js:class:`RelativeDuration` + * - ``cal::date_duration`` + - :js:class:`DateDuration` + * - ``range`` + - :js:class:`Range` + * - ``cfg::memory`` + - :js:class:`ConfigMemory` + + +.. note:: + + Inexact single-precision ``float`` values may have a different + representation when decoded into a JavaScript number. This is inherent + to the implementation of limited-precision floating point types. + If you need the decimal representation to match, cast the expression + to ``float64`` in your query. + +.. note:: + + Due to precision limitations the ``decimal`` type cannot be decoded to a + JavaScript number. Use an explicit cast to ``float64`` if the precision + degradation is acceptable or a cast to ``str`` for an exact decimal + representation. + + +Arrays +====== + +Gel ``array`` maps onto the JavaScript ``Array``. + +.. code-block:: javascript + + // Use the Node.js assert library to test results. + const assert = require("assert"); + const gel = require("gel"); + + async function main() { + const client = gel.createClient(); + + const data = await client.querySingle("select [1, 2, 3]"); + + // The result is an Array. + assert(data instanceof Array); + assert(typeof data[0] === "number"); + assert(data.length === 3); + assert(data[2] === 3); + } + + main(); + +.. _gel-js-types-object: + +Objects +======= + +``Object`` represents an object instance returned from a query. The value of an +object property or a link can be accessed through a corresponding object key: + +.. code-block:: javascript + + // Use the Node.js assert library to test results. + const assert = require("assert"); + const gel = require("gel"); + + async function main() { + const client = gel.createClient(); + + const data = await client.querySingle(` + select schema::Property { + name, + annotations: {name, @value} + } + filter .name = 'listen_port' + and .source.name = 'cfg::Config' + limit 1 + `); + + // The property 'name' is accessible. + assert(typeof data.name === "string"); + // The link 'annotaions' is accessible and is a Set. + assert(typeof data.annotations === "object"); + assert(data.annotations instanceof gel.Set); + // The Set of 'annotations' is array-like. + assert(data.annotations.length > 0); + assert(data.annotations[0].name === "cfg::system"); + assert(data.annotations[0]["@value"] === "true"); + } + + main(); + +Tuples +====== + +A regular |Gel| ``tuple`` becomes an ``Array`` in JavaScript. + +.. code-block:: javascript + + // Use the Node.js assert library to test results. + const assert = require("assert"); + const gel = require("gel"); + + async function main() { + const client = gel.createClient(); + + const data = await client.querySingle(` + select (1, 'a', [3]) + `); + + // The resulting tuple is an Array. + assert(data instanceof Array); + assert(data.length === 3); + assert(typeof data[0] === "number"); + assert(typeof data[1] === "string"); + assert(data[2] instanceof Array); + } + + main(); + +Named Tuples +============ + +A named |Gel| ``tuple`` becomes an ``Array``-like ``object`` in JavaScript, +where the elements are accessible either by their names or indexes. + +.. code-block:: javascript + + // Use the Node.js assert library to test results. + const assert = require("assert"); + const gel = require("gel"); + + async function main() { + const client = gel.createClient(); + + const data = await client.querySingle(` + select (a := 1, b := 'a', c := [3]) + `); + + // The resulting tuple is an Array. + assert(data instanceof Array); + assert(data.length === 3); + assert(typeof data[0] === "number"); + assert(typeof data[1] === "string"); + assert(data[2] instanceof Array); + // Elements can be accessed by their names. + assert(typeof data.a === "number"); + assert(typeof data["b"] === "string"); + assert(data.c instanceof Array); + } + + main(); + + +Local Date +========== + +.. js:class:: LocalDate(\ + year: number, \ + month: number, \ + day: number) + + A JavaScript representation of a |Gel| ``local_date`` value. Implements + a subset of the `TC39 Temporal Proposal`_ ``PlainDate`` type. + + Assumes the calendar is always `ISO 8601`_. + + .. js:attribute:: year: number + + The year value of the local date. + + .. js:attribute:: month: number + + The numerical month value of the local date. + + .. note:: + + Unlike the JS ``Date`` object, months in ``LocalDate`` start at 1. + ie. Jan = 1, Feb = 2, etc. + + .. js:attribute:: day: number + + The day of the month value of the local date (starting with 1). + + .. js:attribute:: dayOfWeek: number + + The weekday number of the local date. Returns a value between 1 and 7 + inclusive, where 1 = Monday and 7 = Sunday. + + .. js:attribute:: dayOfYear: number + + The ordinal day of the year of the local date. Returns a value between + 1 and 365 (or 366 in a leap year). + + .. js:attribute:: weekOfYear: number + + The ISO week number of the local date. Returns a value between 1 and + 53, where ISO week 1 is defined as the week containing the first + Thursday of the year. + + .. js:attribute:: daysInWeek: number + + The number of days in the week of the local date. Always returns 7. + + .. js:attribute:: daysInMonth: number + + The number of days in the month of the local date. Returns a value + between 28 and 31 inclusive. + + .. js:attribute:: daysInYear: number + + The number of days in the year of the local date. Returns either 365 or + 366 if the year is a leap year. + + .. js:attribute:: monthsInYear: number + + The number of months in the year of the local date. Always returns 12. + + .. js:attribute:: inLeapYear: boolean + + Return whether the year of the local date is a leap year. + + .. js:method:: toString(): string + + Get the string representation of the ``LocalDate`` in the + ``YYYY-MM-DD`` format. + + .. js:method:: toJSON(): number + + Same as :js:meth:`~LocalDate.toString`. + + .. js:method:: valueOf(): never + + Always throws an Error. ``LocalDate`` objects are not comparable. + + +Local Time +========== + +.. js:class:: LocalTime(\ + hour: number = 0, \ + minute: number = 0, \ + second: number = 0, \ + millisecond: number = 0, \ + microsecond: number = 0, \ + nanosecond: number = 0) + + A JavaScript representation of an Gel ``local_time`` value. Implements + a subset of the `TC39 Temporal Proposal`_ ``PlainTime`` type. + + .. note:: + + The Gel ``local_time`` type only has microsecond precision, any + nanoseconds specified in the ``LocalTime`` will be ignored when + encoding to an Gel ``local_time``. + + .. js:attribute:: hour: number + + The hours component of the local time in 0-23 range. + + .. js:attribute:: minute: number + + The minutes component of the local time in 0-59 range. + + .. js:attribute:: second: number + + The seconds component of the local time in 0-59 range. + + .. js:attribute:: millisecond: number + + The millisecond component of the local time in 0-999 range. + + .. js:attribute:: microsecond: number + + The microsecond component of the local time in 0-999 range. + + .. js:attribute:: nanosecond: number + + The nanosecond component of the local time in 0-999 range. + + .. js:method:: toString(): string + + Get the string representation of the ``local_time`` in the ``HH:MM:SS`` + 24-hour format. + + .. js:method:: toJSON(): string + + Same as :js:meth:`~LocalTime.toString`. + + .. js:method:: valueOf(): never + + Always throws an Error. ``LocalTime`` objects are not comparable. + + +Local Date and Time +=================== + +.. js:class:: LocalDateTime(\ + year: number, \ + month: number, \ + day: number, \ + hour: number = 0, \ + minute: number = 0, \ + second: number = 0, \ + millisecond: number = 0, \ + microsecond: number = 0, \ + nanosecond: number = 0) extends LocalDate, LocalTime + + A JavaScript representation of a |Gel| ``local_datetime`` value. + Implements a subset of the `TC39 Temporal Proposal`_ ``PlainDateTime`` + type. + + Inherits all properties from the :js:class:`~LocalDate` and + :js:class:`~LocalTime` types. + + .. js:method:: toString(): string + + Get the string representation of the ``local_datetime`` in the + ``YYYY-MM-DDTHH:MM:SS`` 24-hour format. + + .. js:method:: toJSON(): string + + Same as :js:meth:`~LocalDateTime.toString`. + + .. js:method:: valueOf(): never + + Always throws an Error. ``LocalDateTime`` objects are not comparable. + + +Duration +======== + +.. js:class:: Duration(\ + years: number = 0, \ + months: number = 0, \ + weeks: number = 0, \ + days: number = 0, \ + hours: number = 0, \ + minutes: number = 0, \ + seconds: number = 0, \ + milliseconds: number = 0, \ + microseconds: number = 0, \ + nanoseconds: number = 0) + + A JavaScript representation of a Gel ``duration`` value. This class + attempts to conform to the `TC39 Temporal Proposal`_ ``Duration`` type as + closely as possible. + + No arguments may be infinite and all must have the same sign. + Any non-integer arguments will be rounded towards zero. + + .. note:: + + The Temporal ``Duration`` type can contain both absolute duration + components, such as hours, minutes, seconds, etc. and relative + duration components, such as years, months, weeks, and days, where + their absolute duration changes depending on the exact date they are + relative to (eg. different months have a different number of days). + + The Gel ``duration`` type only supports absolute durations, so any + ``Duration`` with non-zero years, months, weeks, or days will throw + an error when trying to encode them. + + .. note:: + + The Gel ``duration`` type only has microsecond precision, any + nanoseconds specified in the ``Duration`` will be ignored when + encoding to an Gel ``duration``. + + .. note:: + + Temporal ``Duration`` objects can be unbalanced_, (ie. have a greater + value in any property than it would naturally have, eg. have a seconds + property greater than 59), but Gel ``duration`` objects are always + balanced. + + Therefore in a round-trip of a ``Duration`` object to Gel and back, + the returned object, while being an equivalent duration, may not + have exactly the same property values as the sent object. + + .. js:attribute:: years: number + + The number of years in the duration. + + .. js:attribute:: months: number + + The number of months in the duration. + + .. js:attribute:: weeks: number + + The number of weeks in the duration. + + .. js:attribute:: days: number + + The number of days in the duration. + + .. js:attribute:: hours: number + + The number of hours in the duration. + + .. js:attribute:: minutes: number + + The number of minutes in the duration. + + .. js:attribute:: seconds: number + + The number of seconds in the duration. + + .. js:attribute:: milliseconds: number + + The number of milliseconds in the duration. + + .. js:attribute:: microseconds: number + + The number of microseconds in the duration. + + .. js:attribute:: nanoseconds: number + + The number of nanoseconds in the duration. + + .. js:attribute:: sign: number + + Returns -1, 0, or 1 depending on whether the duration is negative, + zero or positive. + + .. js:attribute:: blank: boolean + + Returns ``true`` if the duration is zero. + + .. js:method:: toString(): string + + Get the string representation of the duration in `ISO 8601 duration`_ + format. + + .. js:method:: toJSON(): number + + Same as :js:meth:`~Duration.toString`. + + .. js:method:: valueOf(): never + + Always throws an Error. ``Duration`` objects are not comparable. + + +RelativeDuration +================ + +.. js:class:: RelativeDuration(\ + years: number = 0, \ + months: number = 0, \ + weeks: number = 0, \ + days: number = 0, \ + hours: number = 0, \ + minutes: number = 0, \ + seconds: number = 0, \ + milliseconds: number = 0, \ + microseconds: number = 0) + + A JavaScript representation of an Gel + :eql:type:`cal::relative_duration` value. This type represents a + non-definite span of time such as "2 years 3 days". This cannot be + represented as a :eql:type:`duration` because a year has no absolute + duration; for instance, leap years are longer than non-leap years. + + This class attempts to conform to the `TC39 Temporal Proposal`_ + ``Duration`` type as closely as possible. + + Internally, a ``cal::relative_duration`` value is represented as an + integer number of months, days, and seconds. During encoding, other units + will be normalized to these three. Sub-second units like ``microseconds`` + will be ignored. + + .. js:attribute:: years: number + + The number of years in the relative duration. + + .. js:attribute:: months: number + + The number of months in the relative duration. + + .. js:attribute:: weeks: number + + The number of weeks in the relative duration. + + .. js:attribute:: days: number + + The number of days in the relative duration. + + .. js:attribute:: hours: number + + The number of hours in the relative duration. + + .. js:attribute:: minutes: number + + The number of minutes in the relative duration. + + .. js:attribute:: seconds: number + + The number of seconds in the relative duration. + + .. js:attribute:: milliseconds: number + + The number of milliseconds in the relative duration. + + .. js:attribute:: microseconds: number + + The number of microseconds in the relative duration. + + .. js:method:: toString(): string + + Get the string representation of the duration in `ISO 8601 duration`_ + format. + + .. js:method:: toJSON(): string + + Same as :js:meth:`~Duration.toString`. + + .. js:method:: valueOf(): never + + Always throws an Error. ``RelativeDuration`` objects are not + comparable. + + +DateDuration +============ + +.. js:class:: DateDuration( \ + years: number = 0, \ + months: number = 0, \ + weeks: number = 0, \ + days: number = 0, \ + ) + + A JavaScript representation of an Gel + :eql:type:`cal::date_duration` value. This type represents a + non-definite span of time consisting of an integer number of *months* and + *days*. + + This type is primarily intended to simplify logic involving + :eql:type:`cal::local_date` values. + + .. code-block:: edgeql-repl + + db> select '5 days'; + {'P5D'} + db> select '2022-06-25' + '5 days'; + {'2022-06-30'} + db> select '2022-06-30' - '2022-06-25'; + {'P5D'} + + Internally, a ``cal::relative_duration`` value is represented as an + integer number of months and days. During encoding, other units will be + normalized to these two. + + .. js:attribute:: years: number + + The number of years in the relative duration. + + .. js:attribute:: months: number + + The number of months in the relative duration. + + .. js:attribute:: weeks: number + + The number of weeks in the relative duration. + + .. js:attribute:: days: number + + The number of days in the relative duration. + + .. js:method:: toString(): string + + Get the string representation of the duration in `ISO 8601 duration`_ + format. + + .. js:method:: toJSON(): string + + Same as :js:meth:`~Duration.toString`. + + .. js:method:: valueOf(): never + + Always throws an Error. ``DateDuration`` objects are not comparable. + + +Memory +====== + +.. js:class:: ConfigMemory(bytes: BigInt) + + A JavaScript representation of an Gel ``cfg::memory`` value. + + .. js:attribute:: bytes: number + + The memory value in bytes (B). + + .. note:: + + The Gel ``cfg::memory`` represents a number of bytes stored as + an ``int64``. Since JS the ``number`` type is a ``float64``, values + above ``~8191TiB`` will lose precision when represented as a JS + ``number``. To keep full precision use the ``bytesBigInt`` + property. + + .. js::attribute:: bytesBigInt: BigInt + + The memory value in bytes represented as a ``BigInt``. + + .. js:attribute:: kibibytes: number + + The memory value in kibibytes (KiB). + + .. js:attribute:: mebibytes: number + + The memory value in mebibytes (MiB). + + .. js:attribute:: gibibytes: number + + The memory value in gibibytes (GiB). + + .. js:attribute:: tebibytes: number + + The memory value in tebibytes (TiB). + + .. js:attribute:: pebibytes: number + + The memory value in pebibytes (PiB). + + .. js:method:: toString(): string + + Get the string representation of the memory value. Format is the same + as returned by string casting a ``cfg::memory`` value in Gel. + +Range +===== + +.. js:class:: Range(\ + lower: T | null, \ + upper: T | null, \ + incLower: boolean = true, \ + incUpper: boolean = false \ + ) + + A JavaScript representation of an Gel ``std::range`` value. This is a generic TypeScript class with the following type signature. + + .. code-block:: typescript + + class Range< + T extends number | Date | LocalDate | LocalDateTime | Duration + >{ + // ... + } + + .. js:attribute:: lower: T + + The lower bound of the range value. + + .. js:attribute:: upper: T + + The upper bound of the range value. + + .. js:attribute:: incLower: boolean + + Whether the lower bound is inclusive. + + .. js:attribute:: incUpper: boolean + + Whether the upper bound is inclusive. + + .. js:attribute:: empty: boolean + + Whether the range is empty. + + .. js:method:: toJSON(): { \ + lower: T | null; \ + upper: T | null; \ + inc_lower: boolean; \ + inc_upper: boolean; \ + empty?: undefined; \ + } + + Returns a JSON-encodable representation of the range. + + .. js:method:: empty(): Range + + A static method to declare an empty range (no bounds). + + .. code-block:: typescript + + Range.empty(); + + + + +.. _BigInt: + https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt +.. _TC39 Temporal Proposal: https://tc39.es/proposal-temporal/docs/ +.. _ISO 8601: https://en.wikipedia.org/wiki/ISO_8601#Dates +.. _ISO 8601 duration: https://en.wikipedia.org/wiki/ISO_8601#Durations +.. _unbalanced: https://tc39.es/proposal-temporal/docs/balancing.html diff --git a/docs/clients/js/select.rst b/docs/clients/js/select.rst new file mode 100644 index 00000000000..781d08d2061 --- /dev/null +++ b/docs/clients/js/select.rst @@ -0,0 +1,679 @@ +.. _gel-js-select: + +Select +====== + +The full power of the EdgeQL ``select`` statement is available as a top-level +``e.select`` function. All queries on this page assume the Netflix schema +described on the :ref:`Objects page `. + +Selecting scalars +----------------- + +Any scalar expression be passed into ``e.select``, though it's often +unnecessary, since expressions are ``run``\ able without being wrapped by +``e.select``. + +.. code-block:: typescript + + e.select(e.str('Hello world')); + // select 1234; + + e.select(e.op(e.int64(2), '+', e.int64(2))); + // select 2 + 2; + + +Selecting objects +----------------- + +As in EdgeQL, selecting an set of objects without a shape will return their +``id`` property only. This is reflected in the TypeScript type of the result. + +.. code-block:: typescript + + const query = e.select(e.Movie); + // select Movie; + + const result = await query.run(client); + // {id:string}[] + +Shapes +^^^^^^ + +To specify a shape, pass a function as the second argument. This function +should return an object that specifies which properties to include in the +result. This roughly corresponds to a *shape* in EdgeQL. + +.. code-block:: typescript + + const query = e.select(e.Movie, ()=>({ + id: true, + title: true, + release_year: true, + })); + /* + select Movie { + id, + title, + release_year + } + */ + +Note that the type of the query result is properly inferred from the shape. +This is true for all queries on this page. + +.. code-block:: typescript + + const result = await query.run(client); + /* { + id: string; + title: string; + release_year: number | null; + }[] */ + +As you can see, the type of ``release_year`` is ``number | null`` since +it's an optional property, whereas ``id`` and ``title`` are required. + +Passing a ``boolean`` value (as opposed to a ``true`` literal), which will +make the property optional. Passing ``false`` will exclude that property. + +.. code-block:: typescript + + e.select(e.Movie, movie => ({ + id: true, + title: Math.random() > 0.5, + release_year: false, + })); + + const result = await query.run(client); + // {id: string; title: string | undefined; release_year: never}[] + +Selecting all properties +^^^^^^^^^^^^^^^^^^^^^^^^ + +For convenience, the query builder provides a shorthand for selecting all +properties of a given object. + +.. code-block:: typescript + + e.select(e.Movie, movie => ({ + ...e.Movie['*'] + })); + + const result = await query.run(client); + // {id: string; title: string; release_year: number | null}[] + +This ``*`` property is just a strongly-typed, plain object: + +.. code-block:: typescript + + e.Movie['*']; + // => {id: true, title: true, release_year: true} + +Select a single object +^^^^^^^^^^^^^^^^^^^^^^ + +To select a particular object, use the ``filter_single`` key. This tells the query builder to expect a singleton result. + +.. code-block:: typescript + + e.select(e.Movie, (movie) => ({ + id: true, + title: true, + release_year: true, + + filter_single: {id: '2053a8b4-49b1-437a-84c8-e1b0291ccd9f'}, + })); + +This also works if an object type has a composite exclusive constraint: + +.. code-block:: typescript + + /* + type Movie { + ... + constraint exclusive on (.title, .release_year); + } + */ + + e.select(e.Movie, (movie) => ({ + title: true, + filter_single: {title: 'The Avengers', release_year: 2012}, + })); + +You can also pass an arbitrary boolean expression to ``filter_single`` if you prefer. + +.. code-block:: typescript + + const query = e.select(e.Movie, (movie) => ({ + id: true, + title: true, + release_year: true, + filter_single: e.op(movie.id, '=', '2053a8b4-49b1-437a-84c8-e1b0291ccd9f'), + })); + + const result = await query.run(client); + // {id: string; title: string; release_year: number | null} + + +Select many objects by ID +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: typescript + + const query = e.params({ ids: e.array(e.uuid) }, ({ ids }) => + e.select(e.Movie, (movie) => ({ + id: true, + title: true, + release_year: true, + filter: e.op(movie.id, 'in', e.array_unpack(ids)), + })) + + const result = await query.run(client, { + ids: [ + '2053a8b4-49b1-437a-84c8-e1b0291ccd9f', + '2053a8b4-49b1-437a-84c8-af5d3f383484', + ], + }) + // {id: string; title: string; release_year: number | null}[] + +Nesting shapes +^^^^^^^^^^^^^^ + +As in EdgeQL, shapes can be nested to fetch deeply related objects. + +.. code-block:: typescript + + const query = e.select(e.Movie, () => ({ + id: true, + title: true, + actors: { + name: true + } + })); + + const result = await query.run(client); + /* { + id: string; + title: string; + actors: { name: string }[] + }[] */ + + +Portable shapes +^^^^^^^^^^^^^^^ + +You can use ``e.shape`` to define a "portable shape" that can be defined +independently and used in multiple queries. + +.. code-block:: typescript + + const baseShape = e.shape(e.Movie, (m) => ({ + title: true, + num_actors: e.count(m) + })); + + const query = e.select(e.Movie, m => ({ + ...baseShape(m), + release_year: true, + filter_single: {title: 'The Avengers'} + })) + +.. note:: + + Note that the result of ``e.shape`` is a *function*. When you use the shape + in your final queries, be sure to pass in the *scope variable* (e.g. ``m`` + in the example above). This is required for the query builder to correctly + resolve the query. + +Why closures? +------------- + +In EdgeQL, a ``select`` statement introduces a new *scope*; within the clauses +of a select statement, you can refer to fields of the *elements being +selected* using leading dot notation. + +.. code-block:: edgeql + + select Movie { id, title } + filter .title = "The Avengers"; + +Here, ``.title`` is shorthand for the ``title`` property of the selected +``Movie`` elements. All properties/links on the ``Movie`` type can be +referenced using this shorthand anywhere in the ``select`` expression. In +other words, the ``select`` expression is *scoped* to the ``Movie`` type. + +To represent this scoping in the query builder, we use function scoping. This +is a powerful pattern that makes it painless to represent filters, ordering, +computed fields, and other expressions. Let's see it in action. + + +Filtering +--------- + +To add a filtering clause, just include a ``filter`` key in the returned +params object. This should correspond to a boolean expression. + +.. code-block:: typescript + + e.select(e.Movie, movie => ({ + id: true, + title: true, + filter: e.op(movie.title, 'ilike', "The Matrix%") + })); + /* + select Movie { + id, + title + } filter .title ilike "The Matrix%" + */ + +.. note:: + + Since ``filter`` is a :ref:`reserved keyword ` in + |Gel|, there is minimal danger of conflicting with a property or link named + ``filter``. All shapes can contain filter clauses, even nested ones. + +If you have many conditions you want to test for, your filter can start to get +difficult to read. + +.. code-block:: typescript + + e.select(e.Movie, movie => ({ + id: true, + title: true, + filter: e.op( + e.op( + e.op(movie.title, 'ilike', "The Matrix%"), + 'and', + e.op(movie.release_year, '=', 1999) + ), + 'or', + e.op(movie.title, '=', 'Iron Man') + ) + })); + +To improve readability, we recommend breaking these operations out into named +variables and composing them. + +.. code-block:: typescript + + e.select(e.Movie, movie => { + const isAMatrixMovie = e.op(movie.title, 'ilike', "The Matrix%"); + const wasReleased1999 = e.op(movie.release_year, '=', 1999); + const isIronMan = e.op(movie.title, '=', 'Iron Man'); + return { + id: true, + title: true, + filter: e.op( + e.op( + isAMatrixMovie, + 'and', + wasReleased1999 + ), + 'or', + isIronMan + ) + } + }); + +You can combine compound conditions as much or as little as makes sense for +your application. + +.. code-block:: typescript + + e.select(e.Movie, movie => { + const isAMatrixMovie = e.op(movie.title, 'ilike', "The Matrix%"); + const wasReleased1999 = e.op(movie.release_year, '=', 1999); + const isAMatrixMovieReleased1999 = e.op( + isAMatrixMovie, + 'and', + wasReleased1999 + ); + const isIronMan = e.op(movie.title, '=', 'Iron Man'); + return { + id: true, + title: true, + filter: e.op( + isAMatrixMovieReleased1999 + 'or', + isIronMan + ) + } + }); + +If you need to string together several conditions with ``or``, ``e.any`` may be +a better choice. Be sure to wrap your conditions in ``e.set`` since ``e.any`` +takes a set. + +.. code-block:: typescript + + e.select(e.Movie, movie => ({ + id: true, + title: true, + filter: e.any( + e.set( + e.op(movie.title, "=", "Iron Man"), + e.op(movie.title, "ilike", "guardians%"), + e.op(movie.title, "ilike", "captain%") + ) + ), + })); + +Similarly to ``e.any``, ``e.all`` can replace multiple conditions strung +together with ``and``. + +.. code-block:: typescript + + e.select(e.Movie, movie => ({ + id: true, + title: true, + filter: e.all( + e.set( + e.op(movie.title, "ilike", "captain%"), + e.op(movie.title, "ilike", "%america%"), + e.op(movie.title, "ilike", "%:%") + ) + ), + })); + +The conditions passed to ``e.any`` or ``e.all`` can be composed just like +before. + +.. code-block:: typescript + + e.select(e.Movie, movie => { + const isIronMan = e.op(movie.title, "=", "Iron Man"); + const startsWithGuardians = e.op(movie.title, "ilike", "guardians%"); + const startsWithCaptain = e.op(movie.title, "ilike", "captain%"); + return { + id: true, + title: true, + filter: e.any( + e.set( + isIronMan, + startsWithGuardians, + startsWithCaptain + ) + ), + } + }); + + +Filters on links +---------------- + +Links can be filtered using traditional filters. + +.. code-block:: typescript + + e.select(e.Movie, movie => ({ + title: true, + actors: actor => ({ + name: true, + filter: e.op(actor.name.slice(0, 1), '=', 'A'), + }), + filter_single: {title: 'Iron Man'} + })); + + +You can also use the :ref:`type intersection +` operator to filter a link based on its +type. For example, since ``actor.roles`` might be of type ``Movie`` or +``TVShow``, to only return ``roles`` that are ``Movie`` types, you would use +the ``.is`` type intersection operator: + +.. code-block:: typescript + + e.select(e.Actor, actor => ({ + movies: actor.roles.is(e.Movie), + })); + +This is how you would use the EdgeQL :eql:op:`[is type] ` type +intersection operator via the TypeScript query builder. + + +Filters on link properties +-------------------------- + +.. code-block:: typescript + + e.select(e.Movie, movie => ({ + title: true, + actors: actor => ({ + name: true, + filter: e.op(actor['@character_name'], 'ilike', 'Tony Stark'), + }), + filter_single: {title: 'Iron Man'} + })); + + +Ordering +-------- + +As with ``filter``, you can pass a value with the special ``order_by`` key. To +simply order by a property: + +.. code-block:: typescript + + e.select(e.Movie, movie => ({ + order_by: movie.title, + })); + +.. note:: + + Unlike ``filter``, ``order_by`` is *not* a reserved word in |Gel|. Using + ``order_by`` as a link or property name will create a naming conflict and + likely cause bugs. + +The ``order_by`` key can correspond to an arbitrary expression. + +.. code-block:: typescript + + // order by length of title + e.select(e.Movie, movie => ({ + order_by: e.len(movie.title), + })); + /* + select Movie + order by len(.title) + */ + + // order by number of actors + e.select(e.Movie, movie => ({ + order_by: e.count(movie.actors), + })); + /* + select Movie + order by count(.actors) + */ + +You can customize the sort direction and empty-handling behavior by passing an +object into ``order_by``. + +.. code-block:: typescript + + e.select(e.Movie, movie => ({ + order_by: { + expression: movie.title, + direction: e.DESC, + empty: e.EMPTY_FIRST, + }, + })); + /* + select Movie + order by .title desc empty first + */ + +.. list-table:: + + * - Order direction + - ``e.DESC`` ``e.ASC`` + * - Empty handling + - ``e.EMPTY_FIRST`` ``e.EMPTY_LAST`` + +Pass an array of objects to do multiple ordering. + +.. code-block:: typescript + + e.select(e.Movie, movie => ({ + title: true, + order_by: [ + { + expression: movie.title, + direction: e.DESC, + }, + { + expression: e.count(movie.actors), + direction: e.ASC, + empty: e.EMPTY_LAST, + }, + ], + })); + + +Pagination +---------- + +Use ``offset`` and ``limit`` to paginate queries. You can pass an expression +with an integer type or a plain JS number. + +.. code-block:: typescript + + e.select(e.Movie, movie => ({ + offset: 50, + limit: e.int64(10), + })); + /* + select Movie + offset 50 + limit 10 + */ + +Computeds +--------- + +To add a computed field, just add it to the returned shape alongside the other +elements. All reflected functions are typesafe, so the output type + +.. code-block:: typescript + + const query = e.select(e.Movie, movie => ({ + title: true, + uppercase_title: e.str_upper(movie.title), + title_length: e.len(movie.title), + })); + + const result = await query.run(client); + /* => + [ + { + title:"Iron Man", + uppercase_title: "IRON MAN", + title_length: 8 + }, + ... + ] + */ + // {name: string; uppercase_title: string, title_length: number}[] + + +Computed fields can "override" an actual link/property as long as the type +signatures agree. + +.. code-block:: typescript + + e.select(e.Movie, movie => ({ + title: e.str_upper(movie.title), // this works + release_year: e.str("2012"), // TypeError + + // you can override links too + actors: e.Person, + })); + + +.. _ref_qb_polymorphism: + +Polymorphism +------------ + +EdgeQL supports polymorphic queries using the ``[is type]`` prefix. + +.. code-block:: edgeql + + select Content { + title, + [is Movie].release_year, + [is TVShow].num_seasons + } + +In the query builder, this is represented with the ``e.is`` function. + +.. code-block:: typescript + + e.select(e.Content, content => ({ + title: true, + ...e.is(e.Movie, { release_year: true }), + ...e.is(e.TVShow, { num_seasons: true }), + })); + + const result = await query.run(client); + /* { + title: string; + release_year: number | null; + num_seasons: number | null; + }[] */ + +The ``release_year`` and ``num_seasons`` properties are nullable to reflect the +fact that they will only occur in certain objects. + +.. note:: + + In EdgeQL it is not valid to select the ``id`` property in a polymorphic + field. So for convenience when using the ``['*']`` all properties shorthand + with ``e.is``, the ``id`` property will be filtered out of the polymorphic + shape object. + + +Detached +-------- + +Sometimes you need to "detach" a set reference from the current scope. (Read the `reference docs `_ for details.) You can achieve this in the query builder with the top-level ``e.detached`` function. + +.. code-block:: typescript + + const query = e.select(e.Person, (outer) => ({ + name: true, + castmates: e.select(e.detached(e.Person), (inner) => ({ + name: true, + filter: e.op(outer.acted_in, 'in', inner.acted_in) + })), + })); + /* + with outer := Person + select Person { + name, + castmates := ( + select detached Person { name } + filter .acted_in in Person.acted_in + ) + } + */ + +Selecting free objects +---------------------- + +Select a free object by passing an object into ``e.select`` + +.. code-block:: typescript + + e.select({ + name: e.str("Name"), + number: e.int64(1234), + movies: e.Movie, + }); + /* select { + name := "Name", + number := 1234, + movies := Movie + } */ diff --git a/docs/clients/js/types.rst b/docs/clients/js/types.rst new file mode 100644 index 00000000000..136e8bfe6a9 --- /dev/null +++ b/docs/clients/js/types.rst @@ -0,0 +1,131 @@ +.. _gel-js-types-and-casting: + + +Types +----- + +The entire type system of |Gel| is reflected in the ``e`` object, including +scalar types, object types, and enums. These types are used in queries for thinks like *casting* and *declaring parameters*. + +.. code-block:: typescript + + e.str; + e.bool; + e.int16; + e.int32; + e.int64; + e.float32; + e.float64; + e.bigint; + e.decimal; + e.datetime; + e.duration; + e.bytes; + e.json; + e.cal.local_datetime; + e.cal.local_date; + e.cal.local_time; + e.cal.relative_duration; + e.cal.date_duration; + + e.Movie; // user-defined object type + e.Genre; // user-defined enum + +You can construct array and tuple types, as in EdgeQL. + +.. code-block:: typescript + + e.array(e.bool); + // array + + e.tuple([e.str, e.int64]); + // tuple + + e.tuple({ + name: e.str, + age: e.int64 + }); + // tuple + + +.. _ref_qb_casting: + +Casting +^^^^^^^ + +These types can be used to *cast* one expression to another type. + +.. code-block:: typescript + + e.cast(e.json, e.int64('123')); + // '123' + + e.cast(e.duration, e.str('127 hours')); + // '127 hours' + +.. note:: + + Scalar types like ``e.str`` serve a dual purpose. They can be used as + functions to instantiate literals (``e.str("hi")``) or used as variables + (``e.cast(e.str, e.int64(123))``). + +Custom literals +^^^^^^^^^^^^^^^ + +You can use ``e.literal`` to create literals corresponding to collection +types like tuples, arrays, and primitives. The first argument expects a type, +the second expects a *value* of that type. + +.. code-block:: typescript + + e.literal(e.str, "sup"); + // equivalent to: e.str("sup") + + e.literal(e.array(e.int16), [1, 2, 3]); + // >[1, 2, 3] + + e.literal(e.tuple([e.str, e.int64]), ['baz', 9000]); + // >("Goku", 9000) + + e.literal( + e.tuple({name: e.str, power_level: e.int64}), + {name: 'Goku', power_level: 9000} + ); + // >("asdf", false) + +Parameters +^^^^^^^^^^ + +Types are also necessary for declaring *query parameters*. + +Pass strongly-typed parameters into your query with ``e.params``. + +.. code-block:: typescript + + const query = e.params({name: e.str}, params => + e.op(e.str("Yer a wizard, "), "++", params.name) + ); + + await query.run(client, {name: "Harry"}); + // => "Yer a wizard, Harry" + + +The full documentation on using parameters is :ref:`here +`. + + +Polymorphism +^^^^^^^^^^^^ + +Types are also used to write polymorphic queries. For full documentation on +this, see :ref:`Polymorphism ` in the ``e.select`` +documentation. + +.. code-block:: typescript + + e.select(e.Content, content => ({ + title: true, + ...e.is(e.Movie, { release_year: true }), + ...e.is(e.TVShow, { num_seasons: true }), + })); + diff --git a/docs/clients/js/update.rst b/docs/clients/js/update.rst new file mode 100644 index 00000000000..04d000bf7f8 --- /dev/null +++ b/docs/clients/js/update.rst @@ -0,0 +1,171 @@ +.. _gel-js-update: + +Update +------ + +Update objects with the ``e.update`` function. + +.. code-block:: typescript + + e.update(e.Movie, () => ({ + filter_single: { title: "Avengers 4" }, + set: { + title: "Avengers: Endgame" + } + })) + + +You can reference the current value of the object's properties. + +.. code-block:: typescript + + e.update(e.Movie, (movie) => ({ + filter: e.op(movie.title[0], '=', ' '), + set: { + title: e.str_trim(movie.title) + } + })) + +You can conditionally update a property by using an :ref:`optional parameter +` and the :ref:`coalescing infix operator +`. + +.. code-block:: typescript + + e.params({ id: e.uuid, title: e.optional(e.str) }, (params) => + e.update(e.Movie, (movie) => ({ + filter_single: { id: params.id }, + set: { + title: e.op(params.title, "??", movie.title), + } + })) + ); + +Note that ``e.update`` will return just the ``{ id: true }`` of the updated object. If you want to select further properties, you can wrap the update in a ``e.select`` call. This is still just a single query to the database. + +.. code-block:: typescript + + e.params({ id: e.uuid, title: e.optional(e.str) }, (params) => { + const updated = e.update(e.Movie, (movie) => ({ + filter_single: { id: params.id }, + set: { + title: e.op(params.title, "??", movie.title), + }, + })); + return e.select(updated, (movie) => ({ + title: movie.title, + })); + }); + + + +Updating links +^^^^^^^^^^^^^^ + +EdgeQL supports some convenient syntax for appending to, subtracting from, and +overwriting links. + +.. code-block:: edgeql + + update Movie set { + # overwrite + actors := Person, + + # add to link + actors += Person, + + # subtract from link + actors -= Person + } + +In the query builder this is represented with the following syntax. + +**Overwrite a link** + +.. code-block:: typescript + + const actors = e.select(e.Person, ...); + e.update(e.Movie, movie => ({ + filter_single: {title: 'The Eternals'}, + set: { + actors: actors, + } + })) + +**Add to a link** + +.. code-block:: typescript + + const actors = e.select(e.Person, ...); + e.update(e.Movie, movie => ({ + filter_single: {title: 'The Eternals'}, + set: { + actors: { "+=": actors }, + } + })) + + +**Subtract from a link** + +.. code-block:: typescript + + const actors = e.select(e.Person, ...); + e.update(e.Movie, movie => ({ + filter_single: {title: 'The Eternals'}, + set: { + actors: { "-=": actors }, + } + })) + +**Updating a single link property** + +.. code-block:: typescript + + e.update(e.Movie, (movie) => ({ + filter_single: { title: "The Eternals" }, + set: { + actors: { + "+=": e.select(movie.actors, (actor) => ({ + "@character_name": e.str("Sersi"), + filter: e.op(actor.name, "=", "Gemma Chan") + })) + } + } + })); + +**Updating many link properties** + +.. code-block:: typescript + + const q = e.params( + { + cast: e.array(e.tuple({ name: e.str, character_name: e.str })), + }, + (params) => + e.update(e.Movie, (movie) => ({ + filter_single: { title: "The Eternals" }, + set: { + actors: { + "+=": e.for(e.array_unpack(params.cast), (cast) => + e.select(movie.characters, (character) => ({ + "@character_name": cast.character_name, + filter: e.op(cast.name, "=", character.name), + })), + ), + }, + }, + })), + ).run(client, { + cast: [ + { name: "Gemma Chan", character_name: "Sersi" }, + { name: "Richard Madden", character_name: "Ikaris" }, + { name: "Angelina Jolie", character_name: "Thena" }, + { name: "Salma Hayek", character_name: "Ajak" }, + ], + }); + +Bulk updates +^^^^^^^^^^^^ + +You can use a :ref:`for loop ` to perform :ref:`bulk updates +`. diff --git a/docs/clients/js/with.rst b/docs/clients/js/with.rst new file mode 100644 index 00000000000..28d3977c699 --- /dev/null +++ b/docs/clients/js/with.rst @@ -0,0 +1,100 @@ +.. _gel-js-with: + +With Blocks +----------- + +During the query rendering step, the number of occurrences of each expression +are tracked. If an expression occurs more than once it is automatically +extracted into a ``with`` block. + +.. code-block:: typescript + + const x = e.int64(3); + const y = e.select(e.op(x, '^', x)); + + y.toEdgeQL(); + // with x := 3 + // select x ^ x + + const result = await y.run(client); + // => 27 + +This hold for expressions of arbitrary complexity. + +.. code-block:: typescript + + const robert = e.insert(e.Person, { + name: "Robert Pattinson" + }); + const colin = e.insert(e.Person, { + name: "Colin Farrell" + }); + const newMovie = e.insert(e.Movie, { + title: "The Batman", + actors: e.set(colin, robert) + }); + + /* + with + robert := (insert Person { name := "Robert Pattinson"}), + colin := (insert Person { name := "Colin Farrell"}), + insert Movie { + title := "The Batman", + actors := {robert, colin} + } + */ + +Note that ``robert`` and ``colin`` were pulled out into a top-level with +block. To force these variables to occur in an internal ``with`` block, you +can short-circuit this logic with ``e.with``. + + +.. code-block:: typescript + + const robert = e.insert(e.Person, { + name: "Robert Pattinson" + }); + const colin = e.insert(e.Person, { + name: "Colin Farrell" + }); + const newMovie = e.insert(e.Movie, { + actors: e.with([robert, colin], // list "dependencies" + e.select(e.set(robert, colin)) + ) + }) + + /* + insert Movie { + title := "The Batman", + actors := ( + with + robert := (insert Person { name := "Robert Pattinson"}), + colin := (insert Person { name := "Colin Farrell"}) + select {robert, colin} + ) + } + */ + + +.. note:: + + It's an error to pass an expression into multiple + ``e.with``\ s, or use an expression passed to ``e.with`` outside of that + block. + +To explicitly create a detached "alias" of another expression, use ``e.alias``. + +.. code-block:: typescript + + const a = e.set(1, 2, 3); + const b = e.alias(a); + + const query = e.select(e.op(a, '*', b)) + // WITH + // a := {1, 2, 3}, + // b := a + // SELECT a + b + + const result = await query.run(client); + // => [1, 2, 3, 2, 4, 6, 3, 6, 9] + diff --git a/docs/clients/python/api/advanced.rst b/docs/clients/python/api/advanced.rst new file mode 100644 index 00000000000..aaedeff530d --- /dev/null +++ b/docs/clients/python/api/advanced.rst @@ -0,0 +1,288 @@ +.. _gel-python-advanced: + +============== +Advanced Usage +============== + +.. py:currentmodule:: gel + + +.. _gel-python-transaction-options: + +Transaction Options +=================== + +Transactions can be customized with different options: + +.. py:class:: TransactionOptions(isolation=IsolationLevel.Serializable, readonly=False, deferrable=False) + + :param IsolationLevel isolation: transaction isolation level + :param bool readonly: if true the transaction will be readonly + :param bool deferrable: if true the transaction will be deferrable + + .. py:method:: defaults() + :classmethod: + + Returns the default :py:class:`TransactionOptions`. + +.. py:class:: IsolationLevel + + Isolation level for transaction + + .. py:attribute:: Serializable + + Serializable isolation level + + .. py:attribute:: RepeatableRead + + Repeatable read isolation level (supported in read-only transactions) + +:py:class:`TransactionOptions` can be set on :py:class:`~gel.Client` or +:py:class:`~gel.AsyncIOClient` using one of these methods: + +* :py:meth:`gel.Client.with_transaction_options` +* :py:meth:`gel.AsyncIOClient.with_transaction_options` + +These methods return a "shallow copy" of the current client object with modified +transaction options. Both ``self`` and the returned object can be used, but +different transaction options will applied respectively. + +Transaction options are used by the future calls to the method +:py:meth:`gel.Client.transaction` or :py:meth:`gel.AsyncIOClient.transaction`. + + +.. _gel-python-retry-options: + +Retry Options +============= + +Individual EdgeQL commands or whole transaction blocks are automatically retried on +retryable errors. By default, gel-python will try at most 3 times, with an +exponential backoff time interval starting from 100ms, plus a random hash under 100ms. + +Retry rules can be granularly customized with different retry options: + +.. py:class:: RetryOptions(attempts, backoff=default_backoff) + + :param int attempts: the default number of attempts + :param Callable[[int], Union[float, int]] backoff: the default backoff function + + .. py:method:: with_rule(condition, attempts=None, backoff=None) + + Adds a backoff rule for a particular condition + + :param RetryCondition condition: condition that will trigger this rule + :param int attempts: number of times to retry + :param Callable[[int], Union[float, int]] backoff: + function taking the current attempt number and returning the number + of seconds to wait before the next attempt + + .. py:method:: defaults() + :classmethod: + + Returns the default :py:class:`RetryOptions`. + +.. py:class:: RetryCondition + + Specific condition to retry on for fine-grained control + + .. py:attribute:: TransactionConflict + + Triggered when a TransactionConflictError occurs. + + .. py:attribute:: NetworkError + + Triggered when a ClientError occurs. + +:py:class:`RetryOptions` can be set on :py:class:`~gel.Client` or +:py:class:`~gel.AsyncIOClient` using one of these methods: + +* :py:meth:`gel.Client.with_retry_options` +* :py:meth:`gel.AsyncIOClient.with_retry_options` + +These methods return a "shallow copy" of the current client object with modified +retry options. Both ``self`` and the returned object can be used, but different +retry options will applied respectively. + + +.. _gel-python-state: + +State +===== + +State is an execution context that affects the execution of EdgeQL commands in +different ways: default module, module aliases, session config and global values. + +.. py:class:: State(default_module=None, module_aliases={}, config={}, globals_={}) + + :type default_module: str or None + :param default_module: + The *default module* that the future commands will be executed with. + ``None`` means the default *default module* on the server-side, + which is usually just ``default``. + + :param dict[str, str] module_aliases: + Module aliases mapping of alias -> target module. + + :param dict[str, object] config: + Non system-level config settings mapping of config name -> config value. + + For available configuration parameters refer to the + :ref:`Config documentation `. + + :param dict[str, object] globals_: + Global values mapping of global name -> global value. + + .. note:: + The global name can be either a qualified name like + ``my_mod::glob2``, or a simple name under the default module. + Simple names will be prefixed with the default module, while module + aliases in qualified names - if any - will be resolved into actual + module names. + + .. py:method:: with_default_module(module=None) + + Returns a new :py:class:`State` copy with adjusted default module. + + .. note:: + This will not affect the globals that are already stored in this + state using simple names, because their names were resolved before + this call to ``with_default_module()``, which affects only the + future calls to the :py:meth:`with_globals` method. + + This is equivalent to using the ``set module`` command, or using the + ``reset module`` command when giving ``None``. + + :type module: str or None + :param module: + Adjust the *default module*. If ``module`` is ``None``, the + *default module* will be reset to default. + + .. py:method:: with_module_aliases(aliases_dict=None, /, **aliases) + + Returns a new :py:class:`State` copy with adjusted module aliases. + + .. note:: + This will not affect the globals that are already stored in this + state using module aliases, because their names were resolved + before this call to ``with_module_aliases()``, which affects only + the future calls to the :py:meth:`with_globals` method. + + This is equivalent to using the ``set alias`` command. + + :type aliases_dict: dict[str, str] or None + :param aliases_dict: + Adjust the module aliases by merging with the given alias -> target + module mapping. This is an optional positional-only argument. + + :param dict[str, str] aliases: + Adjust the module aliases by merging with the given alias -> target + module mapping, after applying ``aliases_dict`` if set. + + .. py:method:: without_module_aliases(*aliases) + + Returns a new :py:class:`State` copy without specified module aliases. + + .. note:: + This will not affect the globals that are already stored in this + state using module aliases, because their names were resolved + before this call to ``without_module_aliases()``, which affects + only the future calls to the :py:meth:`with_globals` method. + + This is equivalent to using the ``reset alias`` command. + + :param tuple[str] aliases: + Adjust the module aliases by dropping the specified aliases if they + were set, no errors will be raised if they weren't. + + If no aliases were given, all module aliases will be dropped. + + .. py:method:: with_config(config_dict=None, /, **config) + + Returns a new :py:class:`State` copy with adjusted session config. + + This is equivalent to using the ``configure session set`` command. + + :type config_dict: dict[str, object] or None + :param config_dict: + Adjust the config settings by merging with the given config name -> + config value mapping. This is an optional positional-only argument. + + :param dict[str, object] config: + Adjust the config settings by merging with the given config name -> + config value mapping, after applying ``config_dict`` if set. + + .. py:method:: without_config(*config_names) + + Returns a new :py:class:`State` copy without specified session config. + + This is equivalent to using the ``configure session reset`` command. + + :param tuple[str] config_names: + Adjust the config settings by resetting the specified config to + default if they were set, no errors will be raised if they weren't. + + If no names were given, all session config will be reset. + + .. py:method:: with_globals(globals_dict=None, /, **globals_) + + Returns a new :py:class:`State` copy with adjusted global values. + + .. note:: + The globals are stored with their names resolved into the actual + fully-qualified names using the current default module and module + aliases set on this state. + + This is equivalent to using the ``set global`` command. + + :type globals_dict: dict[str, object] or None + :param globals_dict: + Adjust the global values by merging with the given global name -> + global value mapping. This is an optional positional-only argument. + + :param dict[str, object] globals_: + Adjust the global values by merging with the given global name -> + global value mapping, after applying ``globals_dict`` if set. + + .. py:method:: without_globals(*global_names) + + Returns a new :py:class:`State` copy without specified globals. + + This is equivalent to using the ``reset global`` command. + + :param tuple[str] global_names: + Adjust the globals by resetting the specified globals to default if + they were set, no errors will be raised if they weren't. + + If no names were given, all globals will be reset. + +:py:class:`State` can be set on :py:class:`~gel.Client` or +:py:class:`~gel.AsyncIOClient` using one of these methods: + +* :py:meth:`gel.Client.with_state` +* :py:meth:`gel.AsyncIOClient.with_state` + +These methods return a "shallow copy" of the current client object with +modified state, affecting all future commands executed using the returned copy. +Both ``self`` and the returned object can be used, but different state will +applied respectively. + +Alternatively, shortcuts are available on client objects: + +* :py:meth:`gel.Client.with_default_module` +* :py:meth:`gel.Client.with_module_aliases` +* :py:meth:`gel.Client.without_module_aliases` +* :py:meth:`gel.Client.with_config` +* :py:meth:`gel.Client.without_config` +* :py:meth:`gel.Client.with_globals` +* :py:meth:`gel.Client.without_globals` +* :py:meth:`gel.AsyncIOClient.with_default_module` +* :py:meth:`gel.AsyncIOClient.with_module_aliases` +* :py:meth:`gel.AsyncIOClient.without_module_aliases` +* :py:meth:`gel.AsyncIOClient.with_config` +* :py:meth:`gel.AsyncIOClient.without_config` +* :py:meth:`gel.AsyncIOClient.with_globals` +* :py:meth:`gel.AsyncIOClient.without_globals` + +They work the same way as ``with_state``, and adjusts the corresponding state +values. diff --git a/docs/clients/python/api/asyncio_client.rst b/docs/clients/python/api/asyncio_client.rst new file mode 100644 index 00000000000..0a75e0b8cdc --- /dev/null +++ b/docs/clients/python/api/asyncio_client.rst @@ -0,0 +1,683 @@ +.. _gel-python-asyncio-api-reference: + +=========== +AsyncIO API +=========== + +.. py:currentmodule:: gel + + +.. _gel-python-async-api-client: + +Client +====== + +.. py:function:: create_async_client(dsn=None, *, \ + host=None, port=None, \ + user=None, password=None, \ + secret_key=None, \ + database=None, \ + timeout=60, \ + concurrency=None) + + Create an asynchronous client with a lazy connection pool. + + The connection parameters may be specified either as a connection + URI in *dsn*, or as specific keyword arguments, or both. + If both *dsn* and keyword arguments are specified, the latter + override the corresponding values parsed from the connection URI. + + If no connection parameter is specified, the client will try to search in + environment variables and then the current project, see :ref:`Client + Library Connection ` docs for more information. + + Returns a new :py:class:`AsyncIOClient` object. + + :param str dsn: + If this parameter does not start with |geluri| then this is + interpreted as the :ref:`name of a local instance + `. + + Otherwise it specifies a single string in the following format: + :geluri:`user:password@host:port/database?option=value`. + The following options are recognized: host, port, + user, database, password. For a complete reference on DSN, see + the :ref:`DSN Specification `. + + :param host: + Database host address as an IP address or a domain name; + + If not specified, the following will be tried, in order: + + - host address(es) parsed from the *dsn* argument, + - the value of the :gelenv:`HOST` environment variable, + - ``"localhost"``. + + :param port: + Port number to connect to at the server host. If multiple host + addresses were specified, this parameter may specify a + sequence of port numbers of the same length as the host sequence, + or it may specify a single port number to be used for all host + addresses. + + If not specified, the value parsed from the *dsn* argument is used, + or the value of the :gelenv:`PORT` environment variable, or ``5656`` + if neither is specified. + + :param user: + The name of the database role used for authentication. + + If not specified, the value parsed from the *dsn* argument is used, + or the value of the :gelenv:`USER` environment variable, or the + operating system name of the user running the application. + + :param database: + The name of the database to connect to. + + If not specified, the value parsed from the *dsn* argument is used, + or the value of the :gelenv:`DATABASE` environment variable, or the + operating system name of the user running the application. + + :param password: + Password to be used for authentication, if the server requires + one. If not specified, the value parsed from the *dsn* argument + is used, or the value of the :gelenv:`PASSWORD` environment variable. + Note that the use of the environment variable is discouraged as + other users and applications may be able to read it without needing + specific privileges. + + :param secret_key: + Secret key to be used for authentication, if the server requires one. + If not specified, the value parsed from the *dsn* argument is used, + or the value of the :gelenv:`SECRET_KEY` environment variable. + Note that the use of the environment variable is discouraged as + other users and applications may be able to read it without needing + specific privileges. + + :param float timeout: + Connection timeout in seconds. + + :param int concurrency: + Max number of connections in the pool. If not set, the suggested + concurrency value provided by the server is used. + + :return: An instance of :py:class:`AsyncIOClient`. + + The APIs on the returned client instance can be safely used by different + :py:class:`asyncio.Task`/coroutines, because under the hood they are + checking out different connections from the pool to run the queries: + + * :py:meth:`AsyncIOClient.query()` + * :py:meth:`AsyncIOClient.query_single()` + * :py:meth:`AsyncIOClient.query_required_single()` + * :py:meth:`AsyncIOClient.query_json()` + * :py:meth:`AsyncIOClient.query_single_json()` + * :py:meth:`AsyncIOClient.query_required_single_json()` + * :py:meth:`AsyncIOClient.execute()` + * :py:meth:`AsyncIOClient.transaction()` + + .. code-block:: python + + client = gel.create_async_client() + await client.query('SELECT {1, 2, 3}') + + The same for transactions: + + .. code-block:: python + + client = gel.create_async_client() + async for tx in client.transaction(): + async with tx: + await tx.query('SELECT {1, 2, 3}') + + + +.. py:class:: AsyncIOClient() + + An asynchronous client with a connection pool, safe for concurrent use. + + Async clients are created by calling + :py:func:`~gel.create_async_client`. + + .. py:coroutinemethod:: query(query, *args, **kwargs) + + Acquire a connection and use it to run a query and return the results + as an :py:class:`gel.Set` instance. The temporary + connection is automatically returned back to the pool. + + :param str query: Query text. + :param args: Positional query arguments. + :param kwargs: Named query arguments. + + :return: + An instance of :py:class:`gel.Set` containing + the query result. + + Note that positional and named query arguments cannot be mixed. + + + .. py:coroutinemethod:: query_single(query, *args, **kwargs) + + Acquire a connection and use it to run an optional singleton-returning + query and return its element. The temporary connection is automatically + returned back to the pool. + + :param str query: Query text. + :param args: Positional query arguments. + :param kwargs: Named query arguments. + + :return: + Query result. + + The *query* must return no more than one element. If the query returns + more than one element, an ``gel.ResultCardinalityMismatchError`` + is raised, if it returns an empty set, ``None`` is returned. + + Note, that positional and named query arguments cannot be mixed. + + + .. py:coroutinemethod:: query_required_single(query, *args, **kwargs) + + Acquire a connection and use it to run a singleton-returning query + and return its element. The temporary connection is automatically + returned back to the pool. + + :param str query: Query text. + :param args: Positional query arguments. + :param kwargs: Named query arguments. + + :return: + Query result. + + The *query* must return exactly one element. If the query returns + more than one element, an ``gel.ResultCardinalityMismatchError`` + is raised, if it returns an empty set, an ``gel.NoDataError`` + is raised. + + Note, that positional and named query arguments cannot be mixed. + + + .. py:coroutinemethod:: query_json(query, *args, **kwargs) + + Acquire a connection and use it to run a query and + return the results as JSON. The temporary connection is automatically + returned back to the pool. + + :param str query: Query text. + :param args: Positional query arguments. + :param kwargs: Named query arguments. + + :return: + A JSON string containing an array of query results. + + Note, that positional and named query arguments cannot be mixed. + + .. note:: + + Caution is advised when reading ``decimal`` values using + this method. The JSON specification does not have a limit + on significant digits, so a ``decimal`` number can be + losslessly represented in JSON. However, the default JSON + decoder in Python will read all such numbers as ``float`` + values, which may result in errors or precision loss. If + such loss is unacceptable, then consider casting the value + into ``str`` and decoding it on the client side into a + more appropriate type, such as ``Decimal``. + + + .. py:coroutinemethod:: query_single_json(query, *args, **kwargs) + + Acquire a connection and use it to run an optional singleton-returning + query and return its element in JSON. The temporary connection is + automatically returned back to the pool. + + :param str query: Query text. + :param args: Positional query arguments. + :param kwargs: Named query arguments. + + :return: + Query result encoded in JSON. + + The *query* must return no more than one element. If the query returns + more than one element, an ``gel.ResultCardinalityMismatchError`` + is raised, if it returns an empty set, ``"null"`` is returned. + + Note, that positional and named query arguments cannot be mixed. + + .. note:: + + Caution is advised when reading ``decimal`` values using + this method. The JSON specification does not have a limit + on significant digits, so a ``decimal`` number can be + losslessly represented in JSON. However, the default JSON + decoder in Python will read all such numbers as ``float`` + values, which may result in errors or precision loss. If + such loss is unacceptable, then consider casting the value + into ``str`` and decoding it on the client side into a + more appropriate type, such as ``Decimal``. + + + .. py:coroutinemethod:: query_required_single_json(query, *args, **kwargs) + + Acquire a connection and use it to run a singleton-returning + query and return its element in JSON. The temporary connection is + automatically returned back to the pool. + + :param str query: Query text. + :param args: Positional query arguments. + :param kwargs: Named query arguments. + + :return: + Query result encoded in JSON. + + The *query* must return exactly one element. If the query returns + more than one element, an ``gel.ResultCardinalityMismatchError`` + is raised, if it returns an empty set, an ``gel.NoDataError`` + is raised. + + Note, that positional and named query arguments cannot be mixed. + + .. note:: + + Caution is advised when reading ``decimal`` values using + this method. The JSON specification does not have a limit + on significant digits, so a ``decimal`` number can be + losslessly represented in JSON. However, the default JSON + decoder in Python will read all such numbers as ``float`` + values, which may result in errors or precision loss. If + such loss is unacceptable, then consider casting the value + into ``str`` and decoding it on the client side into a + more appropriate type, such as ``Decimal``. + + + .. py:coroutinemethod:: execute(query) + + Acquire a connection and use it to execute an EdgeQL command + (or commands). The temporary connection is automatically + returned back to the pool. + + :param str query: Query text. + + The commands must take no arguments. + + Example: + + .. code-block:: pycon + + >>> await con.execute(''' + ... CREATE TYPE MyType { + ... CREATE PROPERTY a -> int64 + ... }; + ... FOR x IN {100, 200, 300} + ... UNION INSERT MyType { a := x }; + ... ''') + + .. note:: + If the results of *query* are desired, :py:meth:`query`, + :py:meth:`query_single` or :py:meth:`query_required_single` + should be used instead. + + .. py:method:: transaction() + + Open a retryable transaction loop. + + This is the preferred method of initiating and running a database + transaction in a robust fashion. The ``transaction()`` + transaction loop will attempt to re-execute the transaction loop body + if a transient error occurs, such as a network error or a transaction + serialization error. + + Returns an instance of :py:class:`AsyncIORetry`. + + See :ref:`gel-python-asyncio-api-transaction` for more details. + + Example: + + .. code-block:: python + + async for tx in con.transaction(): + async with tx: + value = await tx.query_single("SELECT Counter.value") + await tx.execute( + "UPDATE Counter SET { value := $value }", + value=value + 1, + ) + + Note that we are executing queries on the ``tx`` object rather + than on the original connection. + + .. note:: + The transaction starts lazily. A connection is only acquired from + the pool when the first query is issued on the transaction instance. + + + .. py:coroutinemethod:: aclose() + + Attempt to gracefully close all connections in the pool. + + Wait until all pool connections are released, close them and + shut down the pool. If any error (including cancellation) occurs + in ``aclose()`` the pool will terminate by calling + :py:meth:`~gel.AsyncIOClient.terminate`. + + It is advisable to use :py:func:`python:asyncio.wait_for` to set + a timeout. + + .. py:method:: terminate() + + Terminate all connections in the pool. + + + .. py:coroutinemethod:: ensure_connected() + + If the client does not yet have any open connections in its pool, + attempts to open a connection, else returns immediately. + + Since the client lazily creates new connections as needed (up to the + configured ``concurrency`` limit), the first connection attempt will + only occur when the first query is run on a client. ``ensureConnected`` + can be useful to catch any errors resulting from connection + mis-configuration by triggering the first connection attempt + explicitly. + + .. py:method:: with_transaction_options(options=None) + + Returns a shallow copy of the client with adjusted transaction options. + + :param TransactionOptions options: + Object that encapsulates transaction options. + + See :ref:`gel-python-transaction-options` for details. + + .. py:method:: with_retry_options(options=None) + + Returns a shallow copy of the client with adjusted retry options. + + :param RetryOptions options: Object that encapsulates retry options. + + See :ref:`gel-python-retry-options` for details. + + .. py:method:: with_state(state) + + Returns a shallow copy of the client with adjusted state. + + :param State state: Object that encapsulates state. + + See :ref:`gel-python-state` for details. + + .. py:method:: with_default_module(module=None) + + Returns a shallow copy of the client with adjusted default module. + + This is equivalent to using the ``set module`` command, or using the + ``reset module`` command when giving ``None``. + + :type module: str or None + :param module: Adjust the *default module*. + + See :py:meth:`State.with_default_module` for details. + + .. py:method:: with_module_aliases(aliases_dict=None, /, **aliases) + + Returns a shallow copy of the client with adjusted module aliases. + + This is equivalent to using the ``set alias`` command. + + :type aliases_dict: dict[str, str] or None + :param aliases_dict: This is an optional positional-only argument. + + :param dict[str, str] aliases: + Adjust the module aliases after applying ``aliases_dict`` if set. + + See :py:meth:`State.with_module_aliases` for details. + + .. py:method:: without_module_aliases(*aliases) + + Returns a shallow copy of the client without specified module aliases. + + This is equivalent to using the ``reset alias`` command. + + :param tuple[str] aliases: Module aliases to reset. + + See :py:meth:`State.without_module_aliases` for details. + + .. py:method:: with_config(config_dict=None, /, **config) + + Returns a shallow copy of the client with adjusted session config. + + This is equivalent to using the ``configure session set`` command. + + :type config_dict: dict[str, object] or None + :param config_dict: This is an optional positional-only argument. + + :param dict[str, object] config: + Adjust the config settings after applying ``config_dict`` if set. + + See :py:meth:`State.with_config` for details. + + .. py:method:: without_config(*config_names) + + Returns a shallow copy of the client without specified session config. + + This is equivalent to using the ``configure session reset`` command. + + :param tuple[str] config_names: Config to reset. + + See :py:meth:`State.without_config` for details. + + .. py:method:: with_globals(globals_dict=None, /, **globals_) + + Returns a shallow copy of the client with adjusted global values. + + This is equivalent to using the ``set global`` command. + + :type globals_dict: dict[str, object] or None + :param globals_dict: This is an optional positional-only argument. + + :param dict[str, object] globals_: + Adjust the global values after applying ``globals_dict`` if set. + + See :py:meth:`State.with_globals` for details. + + .. py:method:: without_globals(*global_names) + + Returns a shallow copy of the client without specified globals. + + This is equivalent to using the ``reset global`` command. + + :param tuple[str] global_names: Globals to reset. + + See :py:meth:`State.without_globals` for details. + + +.. _gel-python-asyncio-api-transaction: + +Transactions +============ + +The most robust way to execute transactional code is to use +the ``transaction()`` loop API: + +.. code-block:: python + + async for tx in client.transaction(): + async with tx: + await tx.execute("INSERT User { name := 'Don' }") + +Note that we execute queries on the ``tx`` object in the above +example, rather than on the original ``client`` object. + +The ``tx`` object stores a connection acquired from the pool, so that all +queries can be executed on the same connection in the same transaction. +Transaction start is lazy. ``async for tx`` or ``async with tx`` won't acquire +the connection and start the transaction. It's only done when executing the +first query on the ``tx`` object. That connection is pinned to the ``tx`` +object even when a reconnection is needed, until leaving the final +``async with`` transaction block. + +The ``transaction()`` API guarantees that: + +1. Transactions are executed atomically; +2. If a transaction is failed for any of the number of transient errors (i.e. + a network failure or a concurrent update error), the transaction would + be retried; +3. If any other, non-retryable exception occurs, the transaction is rolled + back, and the exception is propagated, immediately aborting the + ``transaction()`` block. + +The key implication of retrying transactions is that the entire +nested code block can be re-run, including any non-querying +Python code. Here is an example: + +.. code-block:: python + + async for tx in client.transaction(): + async with tx: + user = await tx.query_single( + "SELECT User { email } FILTER .login = $login", + login=login, + ) + data = await httpclient.get( + 'https://service.local/email_info', + params=dict(email=user.email), + ) + user = await tx.query_single(''' + UPDATE User FILTER .login = $login + SET { email_info := $data} + ''', + login=login, + data=data, + ) + +In the above example, the execution of the HTTP request would be retried +too. The core of the issue is that whenever a transaction is interrupted +the user's email might have been changed (as the result of a concurrent +transaction), so we have to redo all the work done. + +Generally it's recommended to not execute any long running +code within the transaction unless absolutely necessary. + +Transactions allocate expensive server resources, and having +too many concurrent long-running transactions will +negatively impact the performance of the DB server. + +To rollback a transaction that is in progress raise an exception. + +.. code-block:: python + + class RollBack(Exception): + "A user defined exception." + + try: + async for tx in client.transaction(): + async with tx: + raise RollBack + except RollBack: + pass + +See also: + +* RFC1004_ +* :py:meth:`AsyncIOClient.transaction()` + + + +.. py:class:: AsyncIORetry + + Represents a wrapper that yields :py:class:`AsyncIOTransaction` + object when iterating. + + See :py:meth:`AsyncIOClient.transaction()` + method for an example. + + .. py:coroutinemethod:: __anext__() + + Yields :py:class:`AsyncIOTransaction` object every time transaction + has to be repeated. + +.. py:class:: AsyncIOTransaction + + Represents a transaction. + + Instances of this type are yielded by a :py:class:`AsyncIORetry` iterator. + + .. describe:: async with c: + + Start and commit/rollback the transaction + automatically when entering and exiting the code inside the + context manager block. + + .. py:coroutinemethod:: query(query, *args, **kwargs) + + Acquire a connection if the current transaction doesn't have one yet, + and use it to run a query and return the results + as an :py:class:`gel.Set` instance. The temporary + connection is automatically returned back to the pool when exiting the + transaction block. + + See :py:meth:`AsyncIOClient.query() + ` for details. + + .. py:coroutinemethod:: query_single(query, *args, **kwargs) + + Acquire a connection if the current transaction doesn't have one yet, + and use it to run an optional singleton-returning + query and return its element. The temporary connection is automatically + returned back to the pool when exiting the transaction block. + + See :py:meth:`AsyncIOClient.query_single() + ` for details. + + .. py:coroutinemethod:: query_required_single(query, *args, **kwargs) + + Acquire a connection if the current transaction doesn't have one yet, + and use it to run a singleton-returning query + and return its element. The temporary connection is automatically + returned back to the pool when exiting the transaction block. + + See :py:meth:`AsyncIOClient.query_required_single() + ` for details. + + .. py:coroutinemethod:: query_json(query, *args, **kwargs) + + Acquire a connection if the current transaction doesn't have one yet, + and use it to run a query and + return the results as JSON. The temporary connection is automatically + returned back to the pool when exiting the transaction block. + + See :py:meth:`AsyncIOClient.query_json() + ` for details. + + .. py:coroutinemethod:: query_single_json(query, *args, **kwargs) + + Acquire a connection if the current transaction doesn't have one yet, + and use it to run an optional singleton-returning + query and return its element in JSON. The temporary connection is + automatically returned back to the pool when exiting the transaction + block. + + See :py:meth:`AsyncIOClient.query_single_json() + ` for details. + + .. py:coroutinemethod:: query_required_single_json(query, *args, **kwargs) + + Acquire a connection if the current transaction doesn't have one yet, + and use it to run a singleton-returning + query and return its element in JSON. The temporary connection is + automatically returned back to the pool when exiting the transaction + block. + + See :py:meth:`AsyncIOClient.query_requried_single_json() + ` for details. + + .. py:coroutinemethod:: execute(query) + + Acquire a connection if the current transaction doesn't have one yet, + and use it to execute an EdgeQL command + (or commands). The temporary connection is automatically + returned back to the pool when exiting the transaction block. + + See :py:meth:`AsyncIOClient.execute() + ` for details. + +.. _RFC1004: https://github.com/gel/rfcs/blob/master/text/1004-transactions-api.rst diff --git a/docs/clients/python/api/blocking_client.rst b/docs/clients/python/api/blocking_client.rst new file mode 100644 index 00000000000..801541df41f --- /dev/null +++ b/docs/clients/python/api/blocking_client.rst @@ -0,0 +1,679 @@ +.. _gel-python-blocking-api-reference: + +============ +Blocking API +============ + +.. py:currentmodule:: gel + + +.. _gel-python-blocking-api-client: + +Client +====== + +.. py:function:: create_client(dsn=None, *, \ + host=None, port=None, \ + user=None, password=None, \ + secret_key=None, \ + database=None, \ + timeout=60, \ + concurrency=None) + + Create a blocking client with a lazy connection pool. + + The connection parameters may be specified either as a connection + URI in *dsn*, or as specific keyword arguments, or both. + If both *dsn* and keyword arguments are specified, the latter + override the corresponding values parsed from the connection URI. + + If no connection parameter is specified, the client will try to search in + environment variables and then the current project, see :ref:`Client + Library Connection ` docs for more information. + + Returns a new :py:class:`Client` object. + + :param dsn: + If this parameter does not start with |geluri| then this is + interpreted as the :ref:`name of a local instance + `. + + Otherwise it specifies a single string in the following format: + :geluri:`user:password@host:port/database?option=value`. + The following options are recognized: host, port, + user, database, password. For a complete reference on DSN, see + the :ref:`DSN Specification `. + + :param host: + Database host address as an IP address or a domain name; + + If not specified, the following will be tried, in order: + + - host address(es) parsed from the *dsn* argument, + - the value of the :gelenv:`HOST` environment variable, + - ``"localhost"``. + + :param port: + Port number to connect to at the server host. If multiple host + addresses were specified, this parameter may specify a + sequence of port numbers of the same length as the host sequence, + or it may specify a single port number to be used for all host + addresses. + + If not specified, the value parsed from the *dsn* argument is used, + or the value of the :gelenv:`PORT` environment variable, or ``5656`` + if neither is specified. + + :param user: + The name of the database role used for authentication. + + If not specified, the value parsed from the *dsn* argument is used, + or the value of the :gelenv:`USER` environment variable, or the + operating system name of the user running the application. + + :param database: + The name of the database to connect to. + + If not specified, the value parsed from the *dsn* argument is used, + or the value of the :gelenv:`DATABASE` environment variable, or the + operating system name of the user running the application. + + :param password: + Password to be used for authentication, if the server requires + one. If not specified, the value parsed from the *dsn* argument + is used, or the value of the :gelenv:`PASSWORD` environment variable. + Note that the use of the environment variable is discouraged as + other users and applications may be able to read it without needing + specific privileges. + + :param secret_key: + Secret key to be used for authentication, if the server requires one. + If not specified, the value parsed from the *dsn* argument is used, + or the value of the :gelenv:`SECRET_KEY` environment variable. + Note that the use of the environment variable is discouraged as + other users and applications may be able to read it without needing + specific privileges. + + :param float timeout: + Connection timeout in seconds. + + :return: An instance of :py:class:`Client`. + + The APIs on the returned client instance can be safely used by different + threads, because under the hood they are + checking out different connections from the pool to run the queries: + + * :py:meth:`Client.query()` + * :py:meth:`Client.query_single()` + * :py:meth:`Client.query_required_single()` + * :py:meth:`Client.query_json()` + * :py:meth:`Client.query_single_json()` + * :py:meth:`Client.query_required_single_json()` + * :py:meth:`Client.execute()` + * :py:meth:`Client.transaction()` + + .. code-block:: python + + client = gel.create_client() + client.query('SELECT {1, 2, 3}') + + The same for transactions: + + .. code-block:: python + + client = gel.create_client() + for tx in client.transaction(): + with tx: + tx.query('SELECT {1, 2, 3}') + + + +.. py:class:: Client + + A thread-safe blocking client with a connection pool. + + Blocking clients are created by calling :py:func:`create_client`. + + + .. py:method:: query(query, *args, **kwargs) + + Acquire a connection and use it to run a query and return the results + as an :py:class:`gel.Set` instance. The temporary + connection is automatically returned back to the pool. + + :param str query: Query text. + :param args: Positional query arguments. + :param kwargs: Named query arguments. + + :return: + An instance of :py:class:`gel.Set` containing + the query result. + + Note that positional and named query arguments cannot be mixed. + + + .. py:method:: query_single(query, *args, **kwargs) + + Acquire a connection and use it to run an optional singleton-returning + query and return its element. The temporary connection is automatically + returned back to the pool. + + :param str query: Query text. + :param args: Positional query arguments. + :param kwargs: Named query arguments. + + :return: + Query result. + + The *query* must return no more than one element. If the query returns + more than one element, an ``gel.ResultCardinalityMismatchError`` + is raised, if it returns an empty set, ``None`` is returned. + + Note, that positional and named query arguments cannot be mixed. + + + .. py:method:: query_required_single(query, *args, **kwargs) + + Acquire a connection and use it to run a singleton-returning query + and return its element. The temporary connection is automatically + returned back to the pool. + + :param str query: Query text. + :param args: Positional query arguments. + :param kwargs: Named query arguments. + + :return: + Query result. + + The *query* must return exactly one element. If the query returns + more than one element, an ``gel.ResultCardinalityMismatchError`` + is raised, if it returns an empty set, an ``gel.NoDataError`` + is raised. + + Note, that positional and named query arguments cannot be mixed. + + + .. py:method:: query_json(query, *args, **kwargs) + + Acquire a connection and use it to run a query and + return the results as JSON. The temporary connection is automatically + returned back to the pool. + + :param str query: Query text. + :param args: Positional query arguments. + :param kwargs: Named query arguments. + + :return: + A JSON string containing an array of query results. + + Note, that positional and named query arguments cannot be mixed. + + .. note:: + + Caution is advised when reading ``decimal`` values using + this method. The JSON specification does not have a limit + on significant digits, so a ``decimal`` number can be + losslessly represented in JSON. However, the default JSON + decoder in Python will read all such numbers as ``float`` + values, which may result in errors or precision loss. If + such loss is unacceptable, then consider casting the value + into ``str`` and decoding it on the client side into a + more appropriate type, such as ``Decimal``. + + + .. py:method:: query_single_json(query, *args, **kwargs) + + Acquire a connection and use it to run an optional singleton-returning + query and return its element in JSON. The temporary connection is + automatically returned back to the pool. + + :param str query: Query text. + :param args: Positional query arguments. + :param kwargs: Named query arguments. + + :return: + Query result encoded in JSON. + + The *query* must return no more than one element. If the query returns + more than one element, an ``gel.ResultCardinalityMismatchError`` + is raised, if it returns an empty set, ``"null"`` is returned. + + Note, that positional and named query arguments cannot be mixed. + + .. note:: + + Caution is advised when reading ``decimal`` values using + this method. The JSON specification does not have a limit + on significant digits, so a ``decimal`` number can be + losslessly represented in JSON. However, the default JSON + decoder in Python will read all such numbers as ``float`` + values, which may result in errors or precision loss. If + such loss is unacceptable, then consider casting the value + into ``str`` and decoding it on the client side into a + more appropriate type, such as ``Decimal``. + + + .. py:method:: query_required_single_json(query, *args, **kwargs) + + Acquire a connection and use it to run a singleton-returning + query and return its element in JSON. The temporary connection is + automatically returned back to the pool. + + :param str query: Query text. + :param args: Positional query arguments. + :param kwargs: Named query arguments. + + :return: + Query result encoded in JSON. + + The *query* must return exactly one element. If the query returns + more than one element, an ``gel.ResultCardinalityMismatchError`` + is raised, if it returns an empty set, an ``gel.NoDataError`` + is raised. + + Note, that positional and named query arguments cannot be mixed. + + .. note:: + + Caution is advised when reading ``decimal`` values using + this method. The JSON specification does not have a limit + on significant digits, so a ``decimal`` number can be + losslessly represented in JSON. However, the default JSON + decoder in Python will read all such numbers as ``float`` + values, which may result in errors or precision loss. If + such loss is unacceptable, then consider casting the value + into ``str`` and decoding it on the client side into a + more appropriate type, such as ``Decimal``. + + + .. py:method:: execute(query) + + Acquire a connection and use it to execute an EdgeQL command + (or commands). The temporary connection is automatically + returned back to the pool. + + :param str query: Query text. + + The commands must take no arguments. + + Example: + + .. code-block:: pycon + + >>> client.execute(''' + ... CREATE TYPE MyType { + ... CREATE PROPERTY a -> int64 + ... }; + ... FOR x IN {100, 200, 300} + ... UNION INSERT MyType { a := x }; + ... ''') + + .. note:: + If the results of *query* are desired, :py:meth:`query`, + :py:meth:`query_single` or :py:meth:`query_required_single` + should be used instead. + + .. py:method:: transaction() + + Open a retryable transaction loop. + + This is the preferred method of initiating and running a database + transaction in a robust fashion. The ``transaction()`` + transaction loop will attempt to re-execute the transaction loop body + if a transient error occurs, such as a network error or a transaction + serialization error. + + Returns an instance of :py:class:`Retry`. + + See :ref:`gel-python-blocking-api-transaction` for more details. + + Example: + + .. code-block:: python + + for tx in client.transaction(): + with tx: + value = tx.query_single("SELECT Counter.value") + tx.execute( + "UPDATE Counter SET { value := $value }", + value=value + 1, + ) + + Note that we are executing queries on the ``tx`` object rather + than on the original connection. + + .. note:: + The transaction starts lazily. A connection is only acquired from + the pool when the first query is issued on the transaction instance. + + + .. py:method:: close(timeout=None) + + Attempt to gracefully close all connections in the pool. + + Wait until all pool connections are released, close them and + shut down the pool. If any error (including timeout) occurs + in ``close()`` the pool will terminate by calling + :py:meth:`~gel.Client.terminate`. + + :param float timeout: Seconds to wait, ``None`` for wait forever. + + + .. py:method:: terminate() + + Terminate all connections in the pool. + + + .. py:method:: ensure_connected() + + If the client does not yet have any open connections in its pool, + attempts to open a connection, else returns immediately. + + Since the client lazily creates new connections as needed (up to the + configured ``concurrency`` limit), the first connection attempt will + only occur when the first query is run on a client. ``ensureConnected`` + can be useful to catch any errors resulting from connection + mis-configuration by triggering the first connection attempt + explicitly. + + .. py:method:: with_transaction_options(options=None) + + Returns a shallow copy of the client with adjusted transaction options. + + :param TransactionOptions options: + Object that encapsulates transaction options. + + See :ref:`gel-python-transaction-options` for details. + + .. py:method:: with_retry_options(options=None) + + Returns a shallow copy of the client with adjusted retry options. + + :param RetryOptions options: Object that encapsulates retry options. + + See :ref:`gel-python-retry-options` for details. + + .. py:method:: with_state(state) + + Returns a shallow copy of the client with adjusted state. + + :param State state: Object that encapsulates state. + + See :ref:`gel-python-state` for details. + + .. py:method:: with_default_module(module=None) + + Returns a shallow copy of the client with adjusted default module. + + This is equivalent to using the ``set module`` command, or using the + ``reset module`` command when giving ``None``. + + :type module: str or None + :param module: Adjust the *default module*. + + See :py:meth:`State.with_default_module` for details. + + .. py:method:: with_module_aliases(aliases_dict=None, /, **aliases) + + Returns a shallow copy of the client with adjusted module aliases. + + This is equivalent to using the ``set alias`` command. + + :type aliases_dict: dict[str, str] or None + :param aliases_dict: This is an optional positional-only argument. + + :param dict[str, str] aliases: + Adjust the module aliases after applying ``aliases_dict`` if set. + + See :py:meth:`State.with_module_aliases` for details. + + .. py:method:: without_module_aliases(*aliases) + + Returns a shallow copy of the client without specified module aliases. + + This is equivalent to using the ``reset alias`` command. + + :param tuple[str] aliases: Module aliases to reset. + + See :py:meth:`State.without_module_aliases` for details. + + .. py:method:: with_config(config_dict=None, /, **config) + + Returns a shallow copy of the client with adjusted session config. + + This is equivalent to using the ``configure session set`` command. + + :type config_dict: dict[str, object] or None + :param config_dict: This is an optional positional-only argument. + + :param dict[str, object] config: + Adjust the config settings after applying ``config_dict`` if set. + + See :py:meth:`State.with_config` for details. + + .. py:method:: without_config(*config_names) + + Returns a shallow copy of the client without specified session config. + + This is equivalent to using the ``configure session reset`` command. + + :param tuple[str] config_names: Config to reset. + + See :py:meth:`State.without_config` for details. + + .. py:method:: with_globals(globals_dict=None, /, **globals_) + + Returns a shallow copy of the client with adjusted global values. + + This is equivalent to using the ``set global`` command. + + :type globals_dict: dict[str, object] or None + :param globals_dict: This is an optional positional-only argument. + + :param dict[str, object] globals_: + Adjust the global values after applying ``globals_dict`` if set. + + See :py:meth:`State.with_globals` for details. + + .. py:method:: without_globals(*global_names) + + Returns a shallow copy of the client without specified globals. + + This is equivalent to using the ``reset global`` command. + + :param tuple[str] global_names: Globals to reset. + + See :py:meth:`State.without_globals` for details. + + +.. _gel-python-blocking-api-transaction: + +Transactions +============ + +The most robust way to execute transactional code is to use the +``transaction()`` loop API: + +.. code-block:: python + + for tx in client.transaction(): + with tx: + tx.execute("INSERT User { name := 'Don' }") + +Note that we execute queries on the ``tx`` object in the above +example, rather than on the original ``client`` object. + +The ``tx`` object stores a connection acquired from the pool, so that all +queries can be executed on the same connection in the same transaction. +Transaction start is lazy. ``for tx`` or ``with tx`` won't acquire +the connection and start the transaction. It's only done when executing the +first query on the ``tx`` object. That connection is pinned to the ``tx`` +object even when a reconnection is needed, until leaving the final +``with`` transaction block. + +The ``transaction()`` API guarantees that: + +1. Transactions are executed atomically; +2. If a transaction is failed for any of the number of transient errors + (i.e. a network failure or a concurrent update error), the transaction + would be retried; +3. If any other, non-retryable exception occurs, the transaction is + rolled back, and the exception is propagated, immediately aborting the + ``transaction()`` block. + +The key implication of retrying transactions is that the entire +nested code block can be re-run, including any non-querying +Python code. Here is an example: + +.. code-block:: python + + for tx in client.transaction(): + with tx: + user = tx.query_single( + "SELECT User { email } FILTER .login = $login", + login=login, + ) + data = httpclient.get( + 'https://service.local/email_info', + params=dict(email=user.email), + ) + user = tx.query_single(''' + UPDATE User FILTER .login = $login + SET { email_info := $data} + ''', + login=login, + data=data, + ) + +In the above example, the execution of the HTTP request would be retried +too. The core of the issue is that whenever a transaction is interrupted +the user's email might have been changed (as the result of a concurrent +transaction), so we have to redo all the work done. + +Generally it's recommended to not execute any long running +code within the transaction unless absolutely necessary. + +Transactions allocate expensive server resources and having +too many concurrently running long-running transactions will +negatively impact the performance of the DB server. + +To rollback a transaction that is in progress raise an exception. + +.. code-block:: python + + class RollBack(Exception): + "A user defined exception." + + try: + for tx in client.transaction(): + with tx: + raise RollBack + except RollBack: + pass + +See also: + +* RFC1004_ +* :py:meth:`Client.transaction()` + + +.. py:class:: Transaction() + + Represents a transaction. + + Instances of this type are yielded by a :py:class:`Retry` iterator. + + .. describe:: with c: + + start and commit/rollback the transaction + automatically when entering and exiting the code inside the + context manager block. + + .. py:method:: query(query, *args, **kwargs) + + Acquire a connection if the current transaction doesn't have one yet, + and use it to run a query and return the results + as an :py:class:`gel.Set` instance. The temporary + connection is automatically returned back to the pool when exiting the + transaction block. + + See :py:meth:`Client.query() + ` for details. + + .. py:method:: query_single(query, *args, **kwargs) + + Acquire a connection if the current transaction doesn't have one yet, + and use it to run an optional singleton-returning + query and return its element. The temporary connection is automatically + returned back to the pool when exiting the transaction block. + + See :py:meth:`Client.query_single() + ` for details. + + .. py:method:: query_required_single(query, *args, **kwargs) + + Acquire a connection if the current transaction doesn't have one yet, + and use it to run a singleton-returning query + and return its element. The temporary connection is automatically + returned back to the pool when exiting the transaction block. + + See :py:meth:`Client.query_required_single() + ` for details. + + .. py:method:: query_json(query, *args, **kwargs) + + Acquire a connection if the current transaction doesn't have one yet, + and use it to run a query and + return the results as JSON. The temporary connection is automatically + returned back to the pool when exiting the transaction block. + + See :py:meth:`Client.query_json() + ` for details. + + .. py:method:: query_single_json(query, *args, **kwargs) + + Acquire a connection if the current transaction doesn't have one yet, + and use it to run an optional singleton-returning + query and return its element in JSON. The temporary connection is + automatically returned back to the pool when exiting the transaction + block. + + See :py:meth:`Client.query_single_json() + ` for details. + + .. py:method:: query_required_single_json(query, *args, **kwargs) + + Acquire a connection if the current transaction doesn't have one yet, + and use it to run a singleton-returning + query and return its element in JSON. The temporary connection is + automatically returned back to the pool when exiting the transaction + block. + + See :py:meth:`Client.query_requried_single_json() + ` for details. + + .. py:method:: execute(query) + + Acquire a connection if the current transaction doesn't have one yet, + and use it to execute an EdgeQL command + (or commands). The temporary connection is automatically + returned back to the pool when exiting the transaction block. + + See :py:meth:`Client.execute() + ` for details. + +.. py:class:: Retry + + Represents a wrapper that yields :py:class:`Transaction` + object when iterating. + + See :py:meth:`Client.transaction()` method for + an example. + + .. py:method:: __next__() + + Yields :py:class:`Transaction` object every time transaction has to + be repeated. + + +.. _RFC1004: https://github.com/gel/rfcs/blob/master/text/1004-transactions-api.rst diff --git a/docs/clients/python/api/codegen.rst b/docs/clients/python/api/codegen.rst new file mode 100644 index 00000000000..bca973455f8 --- /dev/null +++ b/docs/clients/python/api/codegen.rst @@ -0,0 +1,96 @@ +.. _gel-python-codegen: + +=============== +Code Generation +=============== + +.. py:currentmodule:: gel + +The ``gel-python`` package exposes a command-line tool to generate +typesafe functions from ``*.edgeql`` files, using :py:mod:`dataclasses` for +objects primarily. + +.. code-block:: bash + + $ gel-py + +Or alternatively: + +.. code-block:: bash + + $ python -m gel.codegen + +Consider a simple query that lives in a file called ``get_number.edgeql``: + +.. code-block:: edgeql + + select $arg; + +Running the code generator will generate a new file called +``get_number_async_edgeql.py`` containing the following code (roughly): + +.. code-block:: python + + from __future__ import annotations + import gel + + + async def get_number( + client: gel.AsyncIOClient, + *, + arg: int, + ) -> int: + return await client.query_single( + """\ + select $arg\ + """, + arg=arg, + ) + +Target +~~~~~~ + +By default, the generated code uses an ``async`` API. The generator supports +additional targets via the ``--target`` flag. + +.. code-block:: bash + + $ gel-py --target async # generate async function (default) + $ gel-py --target blocking # generate blocking code + +The names of the generated files will differ accordingly: +``{query_filename}_{target}_edgeql.py``. + +Single-file mode +~~~~~~~~~~~~~~~~ + +It may be preferable to generate a single file containing all the generated +functions. This can be done by passing the ``--file`` flag. + +.. code-block:: bash + + $ gel-py --file + +This generates a single file called ``generated_{target}_edgeql.py`` in the +root of your project. + +Connection +~~~~~~~~~~ + +The ``gel-py`` command supports the same set of :ref:`connection options +` as the ``gel`` CLI. + +.. code-block:: + + -I, --instance + --dsn + --credentials-file + -H, --host + -P, --port + -d, --database + -u, --user + --password + --password-from-stdin + --tls-ca-file + --tls-security + diff --git a/docs/clients/python/api/types.rst b/docs/clients/python/api/types.rst new file mode 100644 index 00000000000..848d5dda09b --- /dev/null +++ b/docs/clients/python/api/types.rst @@ -0,0 +1,296 @@ +.. _gel-python-datatypes: + +========= +Datatypes +========= + +.. py:currentmodule:: gel + + +gel-python automatically converts |Gel| types to the corresponding Python +types and vice versa. + +The table below shows the correspondence between Gel and Python types. + ++----------------------------+-----------------------------------------------------+ +| Gel Type | Python Type | ++============================+=====================================================+ +| ``Set`` | :py:class:`gel.Set` | ++----------------------------+-----------------------------------------------------+ +| ``array`` | :py:class:`gel.Array` | ++----------------------------+-----------------------------------------------------+ +| ``anytuple`` | :py:class:`gel.Tuple` or | +| | :py:class:`gel.NamedTuple` | ++----------------------------+-----------------------------------------------------+ +| ``anyenum`` | :py:class:`gel.EnumValue` | ++----------------------------+-----------------------------------------------------+ +| ``Object`` | :py:class:`gel.Object` | ++----------------------------+-----------------------------------------------------+ +| ``bool`` | :py:class:`bool ` | ++----------------------------+-----------------------------------------------------+ +| ``bytes`` | :py:class:`bytes ` | ++----------------------------+-----------------------------------------------------+ +| ``str`` | :py:class:`str ` | ++----------------------------+-----------------------------------------------------+ +| ``cal::local_date`` | :py:class:`datetime.date ` | ++----------------------------+-----------------------------------------------------+ +| ``cal::local_time`` | offset-naive :py:class:`datetime.time \ | +| | ` | ++----------------------------+-----------------------------------------------------+ +| ``cal::local_datetime`` | offset-naive :py:class:`datetime.datetime \ | +| | ` | ++----------------------------+-----------------------------------------------------+ +| ``cal::relative_duration`` | :py:class:`gel.RelativeDuration` | ++----------------------------+-----------------------------------------------------+ +| ``cal::date_duration`` | :py:class:`gel.DateDuration` | ++----------------------------+-----------------------------------------------------+ +| ``datetime`` | offset-aware :py:class:`datetime.datetime \ | +| | ` | ++----------------------------+-----------------------------------------------------+ +| ``duration`` | :py:class:`datetime.timedelta \ | +| | ` | ++----------------------------+-----------------------------------------------------+ +| ``float32``, | :py:class:`float ` | +| ``float64`` | | ++----------------------------+-----------------------------------------------------+ +| ``int16``, | :py:class:`int ` | +| ``int32``, | | +| ``int64``, | | +| ``bigint`` | | ++----------------------------+-----------------------------------------------------+ +| ``decimal`` | :py:class:`Decimal ` | ++----------------------------+-----------------------------------------------------+ +| ``json`` | :py:class:`str ` | ++----------------------------+-----------------------------------------------------+ +| ``uuid`` | :py:class:`uuid.UUID ` | ++----------------------------+-----------------------------------------------------+ + +.. note:: + + Inexact single-precision ``float`` values may have a different + representation when decoded into a Python float. This is inherent + to the implementation of limited-precision floating point types. + If you need the decimal representation to match, cast the expression + to ``float64`` or ``decimal`` in your query. + + +.. _gel-python-types-set: + +Sets +==== + +.. py:class:: Set() + + This is :py:class:`list ` since version 1.0. + + +.. _gel-python-types-object: + +Objects +======= + +.. py:class:: Object() + + An immutable representation of an object instance returned from a query. + + .. versionchanged:: 1.0 + + ``gel.Object`` instances are dataclass-compatible since version 1.0, + for example, ``dataclasses.is_dataclass()`` will return ``True``, and + ``dataclasses.asdict()`` will work on ``gel.Object`` instances. + + .. versionchanged:: 1.0 + + ``gel.Object.__hash__`` is just ``object.__hash__`` in version 1.0. + Similarly, ``==`` is equivalent to the ``is`` operator comparing + ``gel.Object`` instances, and ``<``, ``<=``, ``>``, ``>=`` are not + allowed on ``gel.Object`` instances. + + The value of an object property or a link can be accessed through + a corresponding attribute: + + .. code-block:: pycon + + >>> import gel + >>> client = gel.create_client() + >>> r = client.query_single(''' + ... SELECT schema::ObjectType {name} + ... FILTER .name = 'std::Object' + ... LIMIT 1''') + >>> r + Object{name := 'std::Object'} + >>> r.name + 'std::Object' + + .. describe:: obj[linkname] + + Return a :py:class:`gel.Link` or a :py:class:`gel.LinkSet` instance + representing the instance(s) of link *linkname* associated with + *obj*. + + Example: + + .. code-block:: pycon + + >>> import gel + >>> client = gel.create_client() + >>> r = client.query_single(''' + ... SELECT schema::Property {name, annotations: {name, @value}} + ... FILTER .name = 'listen_port' + ... AND .source.name = 'cfg::Config' + ... LIMIT 1''') + >>> r + Object { + name: 'listen_port', + annotations: { + Object { + name: 'cfg::system', + @value: 'true' + } + } + } + >>> r['annotations'] + LinkSet(name='annotations') + >>> l = list(r['annotations])[0] + >>> l.value + 'true' + + +Links +===== + +.. py:class:: Link + + An immutable representation of an object link. + + Links are created when :py:class:`gel.Object` is accessed via + a ``[]`` operator. Using Link objects explicitly is useful for + accessing link properties. + + +.. py:class:: LinkSet + + An immutable representation of a set of Links. + + LinkSets are created when a multi link on :py:class:`gel.Object` + is accessed via a ``[]`` operator. + + +Tuples +====== + +.. py:class:: Tuple() + + This is :py:class:`tuple ` since version 1.0. + + +Named Tuples +============ + +.. py:class:: NamedTuple() + + An immutable value representing an Gel named tuple value. + + .. versionchanged:: 1.0 + + ``gel.NamedTuple`` is a subclass of :py:class:`tuple ` + and is duck-type compatible with ``collections.namedtuple`` since + version 1.0. + + Instances of ``gel.NamedTuple`` generally behave similarly to + :py:func:`namedtuple `: + + .. code-block:: pycon + + >>> import gel + >>> client = gel.create_client() + >>> r = client.query_single('''SELECT (a := 1, b := 'a', c := [3])''') + >>> r + (a := 1, b := 'a', c := [3]) + >>> r.b + 'a' + >>> r[0] + 1 + >>> r == (1, 'a', [3]) + True + >>> r._fields + ('a', 'b', 'c') + + +Arrays +====== + +.. py:class:: Array() + + This is :py:class:`list ` since version 1.0. + + +RelativeDuration +================ + +.. py:class:: RelativeDuration() + + An immutable value representing an Gel ``cal::relative_duration`` value. + + .. code-block:: pycon + + >>> import gel + >>> client = gel.create_client() + >>> r = client.query_single('''SELECT "1 year 2 days 3 seconds"''') + >>> r + + >>> r.months + 12 + >>> r.days + 2 + >>> r.microseconds + 3000000 + + +DateDuration +============ + +.. py:class:: DateDuration() + + An immutable value representing an Gel ``cal::date_duration`` value. + + .. code-block:: pycon + + >>> import gel + >>> client = gel.create_client() + >>> r = client.query_single('''SELECT "1 year 2 days"''') + >>> r + + >>> r.months + 12 + >>> r.days + 2 + + +EnumValue +========= + +.. py:class:: EnumValue() + + An immutable value representing an Gel enum value. + + .. versionchanged:: 1.0 + + Since version 1.0, ``gel.EnumValue`` is a subclass of + :py:class:`enum.Enum `. Actual enum values are + instances of ad-hoc enum classes created by the codecs to represent + the actual members defined in your Gel schema. + + .. code-block:: pycon + + >>> import gel + >>> client = gel.create_client() + >>> r = client.query_single("""SELECT 'red'""") + >>> r + + >>> str(r) + 'red' + >>> r.value # added in 1.0 + 'red' + >>> r.name # added in 1.0, simply str.upper() of r.value + 'RED' diff --git a/docs/clients/python/index.rst b/docs/clients/python/index.rst index 51537be37d0..c4c54079ad1 100644 --- a/docs/clients/python/index.rst +++ b/docs/clients/python/index.rst @@ -1,9 +1,54 @@ -.. _edgedb-python-intro: +.. _gel-python-intro: -====== -Python -====== +================= +Gel Python Driver +================= -The documentation for the Python client is automatically pulled -from https://github.com/edgedb/edgedb-python/tree/master/docs by the -build pipeline of the edgedb.com website. +**gel-python** is the official |Gel| driver for Python. +It provides both :ref:`blocking IO ` +and :ref:`asyncio ` implementations. + +.. rubric:: Contents + +* :ref:`gel-python-installation` + + gel-python is installable via ``$ pip install gel``. Read + the section for more information on how to install the library. + +* :ref:`gel-python-examples` + + High-level examples on how to use blocking and asyncio connections, + as well as on how to work with transactions. + +* :ref:`gel-python-asyncio-api-reference` + + Asynchronous API reference. + +* :ref:`gel-python-blocking-api-reference` + + Synchronous API reference. + +* :ref:`gel-python-datatypes` + + Gel Python types documentation. + +* :ref:`gel-python-codegen` + + Python code generation command-line tool documentation. + +* :ref:`gel-python-advanced` + + Advanced usages of the state and optional customization. + + +.. toctree:: + :maxdepth: 3 + :hidden: + + installation + usage + api/asyncio_client + api/blocking_client + api/types + api/codegen + api/advanced diff --git a/docs/clients/python/installation.rst b/docs/clients/python/installation.rst new file mode 100644 index 00000000000..2ad30f48086 --- /dev/null +++ b/docs/clients/python/installation.rst @@ -0,0 +1,48 @@ +.. _gel-python-installation: + + +Installation +============ + +The recommended way to install the |Gel| driver is to use **pip**: + +.. code-block:: bash + + $ pip install gel + + +.. note:: + + It is recommended to use **pip** version **8.1** or later to take + advantage of the precompiled wheel packages. Older versions of pip + will ignore the wheel packages and install from the source + package. In that case a working C compiler is required. + + +Building from source +-------------------- + +If you want to build the |Gel| driver from a Git checkout you will need: + +* A working C compiler. +* CPython header files. These can usually be obtained by installing + the relevant Python development package: **python3-dev** on Debian/Ubuntu, + **python3-devel** on RHEL/Fedora. + +Once the above requirements are satisfied, run the following command +in the root of the source checkout: + +.. code-block:: bash + + $ pip install -e . + + +Running tests +------------- + +The testsuite requires a working local installation of the Gel server. +To execute the testsuite run: + +.. code-block:: bash + + $ python setup.py test diff --git a/docs/clients/python/usage.rst b/docs/clients/python/usage.rst new file mode 100644 index 00000000000..39377e5c12e --- /dev/null +++ b/docs/clients/python/usage.rst @@ -0,0 +1,176 @@ +.. _gel-python-examples: + +Basic Usage +=========== + +To start using Gel in Python, create an :py:class:`gel.Client` instance +using :py:func:`gel.create_client`: + +.. code-block:: python + + import datetime + import gel + + client = gel.create_client() + + client.query(""" + INSERT User { + name := $name, + dob := $dob + } + """, name="Bob", dob=datetime.date(1984, 3, 1)) + + user_set = client.query( + "SELECT User {name, dob} FILTER .name = $name", name="Bob") + # *user_set* now contains + # Set{Object{name := 'Bob', dob := datetime.date(1984, 3, 1)}} + + client.close() + +When used with asyncio, this should be replaced with +:py:func:`gel.create_async_client` which creates an instance of the +:py:class:`~gel.AsyncIOClient`: + +.. code-block:: python + + import asyncio + import datetime + import gel + + client = gel.create_async_client() + + async def main(): + await client.query(""" + INSERT User { + name := $name, + dob := $dob + } + """, name="Bob", dob=datetime.date(1984, 3, 1)) + + user_set = await client.query( + "SELECT User {name, dob} FILTER .name = $name", name="Bob") + # *user_set* now contains + # Set{Object{name := 'Bob', dob := datetime.date(1984, 3, 1)}} + + await client.aclose() + + asyncio.run(main()) + + +Connect to Gel +-------------- + +The examples above only work under an :ref:`Gel project +`. You could also provide your own connection +parameters, refer to the :ref:`Client Library Connection +` docs for details. + + +Type conversion +--------------- + +gel-python automatically converts Gel types to the corresponding Python +types and vice versa. See :ref:`gel-python-datatypes` for details. + + +.. _gel-python-connection-pool: + +Client connection pools +----------------------- + +For server-type applications that handle frequent requests and need +the database connection for a short period of time while handling a request, +the use of a connection pool is recommended. Both :py:class:`gel.Client` +and :py:class:`gel.AsyncIOClient` come with such a pool. + +For :py:class:`gel.Client`, all methods are thread-safe. You can share the +same client instance safely across multiple threads, and run queries +concurrently. Likewise, :py:class:`~gel.AsyncIOClient` is designed to be +shared among different :py:class:`asyncio.Task`/coroutines for concurrency. + +Below is an example of a web API server running `aiohttp +`_: + +.. code-block:: python + + import asyncio + import gel + from aiohttp import web + + + async def handle(request): + """Handle incoming requests.""" + client = request.app['client'] + username = request.match_info.get('name') + + # Execute the query on any pool connection + result = await client.query_single_json( + ''' + SELECT User {first_name, email, bio} + FILTER .name = $username + ''', username=username) + return web.Response( + text=result, + content_type='application/json') + + + def init_app(): + """Initialize the application server.""" + app = web.Application() + # Create a database client + app['client'] = gel.create_async_client( + database='my_service', + user='my_service') + # Configure service routes + app.router.add_route('GET', '/user/{name}', handle) + return app + + + loop = asyncio.get_event_loop() + app = init_app() + web.run_app(app) + +Note that the client is created synchronously. Pool connections are created +lazily as they are needed. If you want to explicitly connect to the +database in ``init_app()``, use the ``ensure_connected()`` method on the client. + +For more information, see API documentation of :ref:`the blocking client +` and :ref:`the asynchronous client +`. + + +Transactions +------------ + +The most robust way to create a +:ref:`transaction ` is the +``transaction()`` method: + +* :py:meth:`AsyncIOClient.transaction() ` +* :py:meth:`Client.transaction() ` + + +Example: + +.. code-block:: python + + for tx in client.transaction(): + with tx: + tx.execute("INSERT User {name := 'Don'}") + +or, if using the async API: + +.. code-block:: python + + async for tx in client.transaction(): + async with tx: + await tx.execute("INSERT User {name := 'Don'}") + +.. note:: + + When not in an explicit transaction block, any changes to the database + will be applied immediately. + +For more information, see API documentation of transactions for :ref:`the +blocking client ` and :ref:`the +asynchronous client `. diff --git a/docs/clients/rust/arguments.rst b/docs/clients/rust/arguments.rst deleted file mode 100644 index 529e809f175..00000000000 --- a/docs/clients/rust/arguments.rst +++ /dev/null @@ -1,81 +0,0 @@ -.. _ref_rust_arguments: - -Passing in arguments --------------------- - -A regular EdgeQL query without arguments looks like this: - -.. code-block:: edgeql - - with - message1 := 'Hello there', - message2 := 'General Kenobi', - select message1 ++ ' ' ++ message2; - -And the same query with arguments: - -.. code-block:: edgeql - - with - message1 := $0, - message2 := $1, - select message1 ++ ' ' ++ message2; - -In the EdgeQL REPL you are prompted to enter arguments: - -.. code-block:: edgeql-repl - - db> with - ... message1 := $0, - ... message2 := $1, - ... select message1 ++ ' ' ++ message2; - Parameter $0: Hello there - Parameter $1: General Kenobi - {'Hello there General Kenobi'} - -But when using the Rust client, there is no prompt to do so. At present, -arguments also have to be in the order ``$0``, ``$1``, and so on, while in -the REPL they can be named (e.g. ``$message`` and ``$person`` instead of -``$0`` and ``$1``). The arguments in the client are then passed to the -appropriate query method as a tuple: - -.. code-block:: rust - - let args = ("Nice movie", 2023); - let query = "with - movie := (insert Movie { - title := $0, - release_year := $1 - }) - select { - title, - release_year, - id - }"; - let query_res: Value = client.query_required_single(query, &(args)).await?; - -A note on the casting syntax: EdgeDB requires arguments to have a cast in the -same way that Rust requires a type declaration in function signatures. -As such, arguments in queries are used as type specification for the EdgeDB -compiler, not to cast from queries from the Rust side. Take this query -as an example: - -.. code-block:: rust - - let query = "select $0"; - -This simply means "select an argument that must be an ``int32``", not -"take the received argument and cast it into an ``int32``". - -As such, this will return an error: - -.. code-block:: rust - - let query = "select $0"; - let arg = 9i16; // Rust client will expect an int16 - let query_res: Result = - client.query_required_single(query, &(arg,)).await; - assert!(query_res - .unwrap_err() - .to_string() - .contains("expected std::int16")); \ No newline at end of file diff --git a/docs/clients/rust/client.rst b/docs/clients/rust/client.rst deleted file mode 100644 index 98c2f52c4ec..00000000000 --- a/docs/clients/rust/client.rst +++ /dev/null @@ -1,113 +0,0 @@ -.. _ref_rust_client: - -Using the client ----------------- - -Creating a new EdgeDB client can be done in a single line: - -.. code-block:: rust - - let client = edgedb_tokio::create_client().await?; - -Under the hood, this will create a ``Builder``, look for environment variables -and/or an ``edgedb.toml`` file, and return an ``Ok(Self)`` if successful. -This ``Builder`` can be used on its own instead of ``create_client()`` -if you need a more customized setup. - -Queries with the client ------------------------ - -Here are the simplified signatures of the client methods used for querying: - -.. note:: - ``R`` here means a type that implements ``QueryResult``. - (See more on ``QueryResult`` and ``QueryArgs`` on the - `edgedb-protocol documentation`_.) - -.. code-block:: rust - - fn query -> Result, Error> - fn query_json -> Result - - fn query_single -> Result, Error> - fn query_single_json -> Result> - - fn query_required_single -> Result - fn query_required_single_json -> Result - - fn execute -> Result<(), Error> - -Note the difference between the ``_single`` and the -``_required_single`` methods: - -- The ``_required_single`` methods return empty results as a ``NoDataError`` - which allows propagating errors normally through an application. -- The ``_single`` methods will simply give you an ``Ok(None)`` in this case. - -These methods all take a *query* (a ``&str``) and *arguments* (something that -implements the ``QueryArgs`` trait). - -The ``()`` unit type implements ``QueryArgs`` and is used when no arguments -are present so ``&()`` is a pretty common sight when using the Rust client. - -.. code-block:: rust - - // Without arguments: just add &() after the query - let query_res: String = - client.query_required_single("select 'Just a string'", &()).await?; - - // With arguments, same output as the previous example - let a = " a "; - let b = "string"; - let query_res: String = client - .query_required_single("select 'Just' ++ $0 ++ $1", &(a, b)) - .await?; - -For more, see the section on :ref:`passing in arguments `. - -These methods take two generic parameters which can be specified with the -turbofish syntax: - -.. code-block:: rust - - let query_res = client - .query_required_single::("select 'Just a string'", &()) - .await?; - // or - let query_res = client - .query_required_single::("select 'Just a string'", &()) - .await?; - -But declaring the final expected type upfront tends to look neater. - -.. code-block:: rust - - let query_res: String = client - .query_required_single("select 'Just a string'", &()) - .await?; - -When cardinality is guaranteed to be 1 --------------------------------------- - -Using the ``.query()`` method works fine for any cardinality, but returns a -``Vec`` of results. This query with a cardinality of 1 returns a -``Result>`` which becomes a ``Vec`` after the error -is handled: - -.. code-block:: rust - - let query = "select 'Just a string'"; - let query_res: Vec = client.query(query, &()).await?; - -But if you know that only a single result will be returned, using -``.query_required_single()`` or ``.query_single()`` will be more ergonomic: - -.. code-block:: rust - - let query = "select 'Just a string'"; - let query_res: String = client - .query_required_single(query, &()).await?; - let query_res_opt: Option = client - .query_single(query, &()).await?; - -.. _`edgedb-protocol documentation`: https://docs.rs/edgedb-protocol/ \ No newline at end of file diff --git a/docs/clients/rust/client_config.rst b/docs/clients/rust/client_config.rst deleted file mode 100644 index d31d5a7cbab..00000000000 --- a/docs/clients/rust/client_config.rst +++ /dev/null @@ -1,51 +0,0 @@ -.. _ref_rust_client_config: - -Client configuration --------------------- - -The client can be configured after initialization via the ``with_*`` methods -(``with_retry_options``, ``with_transaction_options``, etc.) that create a -shallow copy of the client with adjusted options. - -.. code-block:: rust - - // Take a schema with matching Rust structs: - // - // module default { - // type User { - // required name: str; - // } - // } - - // module test { - // type User { - // required name: str; - // } - // }; - - // The regular client will query from module 'default' by default - let client = edgedb_tokio::create_client().await?; - - // This client will query from module 'test' by default - // The original client is unaffected - let test_client = client.with_default_module(Some("test")); - - // Each client queries separately with different behavior - let query = "select User {name};"; - let users: Vec = client.query(query, &()).await?; - let test_users: Vec = test_client.query(query, &()).await?; - - // Many other clients can be created with different options, - // all independent of the main client: - let transaction_opts = TransactionOptions::default().read_only(true); - let _read_only_client = client - .with_transaction_options(transaction_opts); - - let retry_opts = RetryOptions::default().with_rule( - RetryCondition::TransactionConflict, - // No. of retries - 1, - // Retry immediately, instead of default with increasing backoff - |_| std::time::Duration::from_millis(0), - ); - let _one_immediate_retry_client = client.with_retry_options(retry_opts); diff --git a/docs/clients/rust/execute.rst b/docs/clients/rust/execute.rst deleted file mode 100644 index ed685cf6c30..00000000000 --- a/docs/clients/rust/execute.rst +++ /dev/null @@ -1,22 +0,0 @@ -.. _ref_rust_execute: - -Execute -------- - -The ``execute`` method doesn't return anything β€” a successful execute returns -an ``Ok(())`` β€” which is convenient for things like updates or commands where -we don't care about getting output if it works: - -.. code-block:: rust - - client.execute("update Account set {username := .username ++ '!'};", &()) - .await?; - client.execute("create superuser role project;", &()) - .await?; - client.execute("alter role project set password := 'GOODpassword';", &()) - .await?; - - // Returns Ok(()) upon success but error info will be returned - let command = client.execute("create type MyType {};", &()).await; - let command_string = command.unwrap_err().to_string(); - assert!(command_string.contains("bare DDL statements are not allowed")); \ No newline at end of file diff --git a/docs/clients/rust/getting_started.rst b/docs/clients/rust/getting_started.rst deleted file mode 100644 index b73a1f78476..00000000000 --- a/docs/clients/rust/getting_started.rst +++ /dev/null @@ -1,141 +0,0 @@ -.. _ref_rust_getting_started: - -=============== -Getting started -=============== - -From examples repo -================== - -If you just want a working repo to get started, clone the Rust client -`examples repo`_, type ``edgedb project init`` to start an EdgeDB -project, and then ``cargo run`` to run the samples. - -This tutorial contains a lot of similar examples to those found in the -``main.rs`` file inside that repo. - -From scratch -============ - -The minimum to add to your Cargo.toml to use the client is `edgedb-tokio`_: - -.. code-block:: toml - - edgedb-tokio = "0.5.0" - -The next most common dependency is `edgedb-protocol`_, which includes the -EdgeDB types used for data modeling: - -.. code-block:: toml - - edgedb-protocol = "0.6.0" - -A third crate called `edgedb-derive`_ contains the ``#[derive(Queryable)]`` -derive macro which is the main way to unpack EdgeDB output into Rust types: - -.. code-block:: toml - - edgedb-derive = "0.5.1" - -The Rust client uses tokio so add this to Cargo.toml as well: - -.. code-block:: toml - - tokio = { version = "1.29.1", features = ["macros", "rt-multi-thread"] } - -If you are avoiding async code and want to emulate a blocking client, you will -still need to use tokio as a dependency but can bridge with async using one of -the `bridging methods`_ recommended by tokio. This won't require any -added features: - -.. code-block:: toml - - tokio = "1.29.1" - -Then you can start a runtime. Block and wait for futures to resolve by calling -the runtime's ``.block_on()`` method: - -.. code-block:: rust - - let rt = tokio::runtime::Builder::new_current_thread() - .enable_all() - .build()?; - let just_a_string: String = - rt.block_on(client.query_required_single("select 'A string'", &()))?; - -Edgedb project setup -==================== - -The EdgeDB CLI initializes an EdgeDB project with a single command in the same -way that Cargo initializes a Rust project, except it does not create a -new directory. So to start a project: - -- Use ``cargo new `` as usual, then: -- Go into the directory and type ``edgedb project init``. - -The CLI will prompt you for the instance name and version of EdgeDB to use. -It will look something like this: - -.. code-block:: powershell - - PS> edgedb project init - No `edgedb.toml` found in `\\?\C:\rust\my_db` or above - Do you want to initialize a new project? [Y/n] - > Y - Specify the name of EdgeDB instance to use - with this project [default: my_db]: - > my_db - Checking EdgeDB versions... - Specify the version of EdgeDB to use with this project [default: 3.0]: - > 3.0 - β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” - β”‚ Project directory β”‚ \\?\C:\rust\my_db β”‚ - β”‚ Project config β”‚ \\?\C:\rust\my_db\edgedb.toml β”‚ - β”‚ Schema dir (empty) β”‚ \\?\C:\rust\my_db\dbschema β”‚ - β”‚ Installation method β”‚ WSL β”‚ - β”‚ Version β”‚ 3.0+e7d38e9 β”‚ - β”‚ Instance name β”‚ my_db β”‚ - β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - Version 3.0+e7d38e9 is already installed - Initializing EdgeDB instance... - Applying migrations... - Everything is up to date. Revision initial - Project initialized. - To connect to my_db, run `edgedb` - -Inside your project directory you'll notice some new items: - -- ``edgedb.toml``, which is used to mark the directory as an EdgeDB project. - -The file itself doesn't contain much β€” just the version of EdgeDB being -used β€” but is used by the CLI to run commands without connection flags. -(E.g., ``edgedb -I my_project migrate`` becomes simply ``edgedb migrate``). -See more in our :ref:`edgedb.toml reference ` or on -the `blog post introducing the EdgeDB projects CLI`_. - -- A ``/dbschema`` folder, inside which you'll see: - - - a ``default.esdl`` file which holds your schema. You can change the schema - by directly modifying this file followed by ``edgedb migration create`` - and ``edgedb migrate``. - - - a ``/migrations`` folder with ``.edgeql`` files named starting at - ``00001``. These hold the :ref:`ddl ` commands that were used - to migrate your schema. A new file shows up in this directory every time - your schema is migrated. - -If you are running EdgeDB 3.0 and above, you also have the option of using -the :ref:`edgedb watch ` command. Doing so starts a -long-running process that keeps an eye on changes in ``/dbschema``, -automatically applying these changes in real time. - -Now that you have the right dependencies and an EdgeDB instance, -you can create a client. - -.. _`blog post introducing the EdgeDB projects CLI`: - https://www.edgedb.com/blog/introducing-edgedb-projects -.. _`bridging methods`: https://tokio.rs/tokio/topics/bridging -.. _`edgedb-derive`: https://docs.rs/edgedb-derive/latest/edgedb_derive/ -.. _`edgedb-protocol`: https://docs.rs/edgedb-protocol/latest/edgedb_protocol -.. _`edgedb-tokio`: https://docs.rs/edgedb-tokio/latest/edgedb_tokio -.. _`examples repo`: https://github.com/Dhghomon/edgedb_rust_client_examples \ No newline at end of file diff --git a/docs/clients/rust/index.rst b/docs/clients/rust/index.rst deleted file mode 100644 index b88a4486628..00000000000 --- a/docs/clients/rust/index.rst +++ /dev/null @@ -1,41 +0,0 @@ -.. _ref_rust_index: - -==== -Rust -==== - -:edb-alt-title: EdgeDB Rust Client - -EdgeDB maintains a client library for Rust. View the `full documentation`_. - -The "hello world" of the Rust EdgeDB client is as follows: - -.. code-block:: rust - - #[tokio::main] - async fn main() { - let conn = edgedb_tokio::create_client() - .await - .expect("Client should have initiated"); - let val: i64 = conn - .query_required_single("select 7*8", &()) - .await - .expect("Query should have worked"); - println!("7*8 is: {val}"); - } - -.. _`full documentation`: https://docs.rs/edgedb-tokio/latest/edgedb_tokio/ - -.. toctree:: - :maxdepth: 2 - :hidden: - - getting_started - client - queryable - arguments - queryable_alternatives - execute - transactions - client_config - diff --git a/docs/clients/rust/queryable.rst b/docs/clients/rust/queryable.rst deleted file mode 100644 index f58c543a28c..00000000000 --- a/docs/clients/rust/queryable.rst +++ /dev/null @@ -1,150 +0,0 @@ -.. _ref_rust_queryable: - -Using the ``Queryable`` macro ------------------------------ - -The easiest way to unpack an EdgeDB query result is the built-in -``Queryable`` macro from the ``edgedb-derive`` crate. This turns queries -directly into Rust types without having to match on a ``Value`` (more in -the section on the ``Value`` enum), cast to JSON, etc. - -.. code-block:: rust - - #[derive(Debug, Deserialize, Queryable)] - pub struct QueryableAccount { - pub username: String, - pub id: Uuid, - } - - let query = "select account { - username, - id - };"; - let as_queryable_account: QueryableAccount = client - .query_required_single(query, &()) - .await?; - -.. note:: - - Field order within the shape of the query matters when using the - ``Queryable`` macro. In the example below, we run a query with the order - ``id, username`` instead of ``username, id`` as defined in the struct: - -.. code-block:: rust - - let query = "select account { - id, - username - };"; - let wrong_order: Result = client - .query_required_single(query, &()) - .await; - assert!( - format!("{wrong_order:?}") - .contains(r#"WrongField { unexpected: "id", expected: "username""#); - ); - -You can use `cargo expand`_ with the nightly compiler to see the code -generated by the ``Queryable`` macro, but the minimal example repo also -contains a somewhat cleaned up version of the generated ``Queryable`` code: - -.. code-block:: rust - - use edgedb_protocol::{ - descriptors::{Descriptor, TypePos}, - errors::DecodeError, - queryable::{Decoder, DescriptorContext, DescriptorMismatch, Queryable}, - serialization::decode::DecodeTupleLike, - }; - - // The code below shows the code generated from the Queryable macro in a - // more readable form (with macro-generated qualified paths replaced with - // use statements). - - #[derive(Debug)] - pub struct IsAStruct { - pub name: String, - pub number: i16, - pub is_ok: bool, - } - - impl Queryable for IsAStruct { - fn decode(decoder: &Decoder, buf: &[u8]) -> Result { - let nfields = 3usize - + if decoder.has_implicit_id { 1 } else { 0 } - + if decoder.has_implicit_tid { 1 } else { 0 } - + if decoder.has_implicit_tname { 1 } else { 0 }; - let mut elements = DecodeTupleLike::new_object(buf, nfields)?; - if decoder.has_implicit_tid { - elements.skip_element()?; - } - if decoder.has_implicit_tname { - elements.skip_element()?; - } - if decoder.has_implicit_id { - elements.skip_element()?; - } - let name = Queryable::decode_optional(decoder, elements.read()?)?; - let number = Queryable::decode_optional(decoder, elements.read()?)?; - let is_ok = Queryable::decode_optional(decoder, elements.read()?)?; - Ok(IsAStruct { - name, - number, - is_ok, - }) - } - - fn check_descriptor( - ctx: &DescriptorContext, - type_pos: TypePos, - ) -> Result<(), DescriptorMismatch> { - let desc = ctx.get(type_pos)?; - let shape = match desc { - Descriptor::ObjectShape(shape) => shape, - _ => return Err(ctx.wrong_type(desc, "str")), - }; - let mut idx = 0; - if ctx.has_implicit_tid { - if !shape.elements[idx].flag_implicit { - return Err(ctx.expected("implicit __tid__")); - } - idx += 1; - } - if ctx.has_implicit_tname { - if !shape.elements[idx].flag_implicit { - return Err(ctx.expected("implicit __tname__")); - } - idx += 1; - } - if ctx.has_implicit_id { - if !shape.elements[idx].flag_implicit { - return Err(ctx.expected("implicit id")); - } - idx += 1; - } - let el = &shape.elements[idx]; - if el.name != "name" { - return Err(ctx.wrong_field("name", &el.name)); - } - idx += 1; - ::check_descriptor(ctx, el.type_pos)?; - let el = &shape.elements[idx]; - if el.name != "number" { - return Err(ctx.wrong_field("number", &el.name)); - } - idx += 1; - ::check_descriptor(ctx, el.type_pos)?; - let el = &shape.elements[idx]; - if el.name != "is_ok" { - return Err(ctx.wrong_field("is_ok", &el.name)); - } - idx += 1; - ::check_descriptor(ctx, el.type_pos)?; - if shape.elements.len() != idx { - return Err(ctx.field_number(shape.elements.len(), idx)); - } - Ok(()) - } - } - -.. _`cargo expand`: https://github.com/dtolnay/cargo-expand \ No newline at end of file diff --git a/docs/clients/rust/queryable_alternatives.rst b/docs/clients/rust/queryable_alternatives.rst deleted file mode 100644 index f2a66f1da3b..00000000000 --- a/docs/clients/rust/queryable_alternatives.rst +++ /dev/null @@ -1,101 +0,0 @@ -.. _ref_rust_queryable_alternatives: - -Alternatives to the Queryable macro ------------------------------------ - -The ``Queryable`` macro is the recommended way to make EdgeDB queries in -Rust, but some alternatives exist. - -The ``Value`` enum ------------------- - -The ``Value`` enum can be found in the `edgedb-protocol`_ crate. A ``Value`` -represents anything returned from EdgeDB. This means you can always return -a ``Value`` from any of the query methods without needing to deserialize -into a Rust type, and the enum can be instructive in getting to know -the protocol. On the other hand, returning a ``Value`` leads to -pattern matching to get to the inner value and is not the most ergonomic way -to work with results from EdgeDB. - -.. code-block:: rust - - pub enum Value { - Nothing, - Uuid(Uuid), - Str(String), - Bytes(Vec), - Int16(i16), - Int32(i32), - Int64(i64), - Float32(f32), - Float64(f64), - BigInt(BigInt), - // ... and so on - } - -Most variants of the ``Value`` enum correspond to a Rust type from the Rust -standard library, while some are from the ``edgedb-protocol`` crate and must -be constructed. For example, this query expecting an EdgeDB ``bigint`` will -return an error as it receives a ``20``, which is an ``i32``: - -.. code-block:: rust - - let query = "select $0"; - let arg = 20; - let query_res: Result = - client.query_required_single(query, &(arg,)).await; - assert!(format!("{query_res:?}").contains("expected std::int32")); - -Instead, first construct a ``BigInt`` from the ``i32`` and pass that in -as an argument: - -.. code-block:: rust - - use edgedb_protocol::model::BigInt; - - let query = "select $0"; - let arg = BigInt::from(20); - let query_res: Result = - client.query_required_single(query, &(arg,)).await; - assert_eq!( - format!("{query_res:?}"), - "Ok(BigInt(BigInt { negative: false, weight: 0, digits: [20] }))" - ); - -Using JSON ----------- - -EdgeDB can cast any type to JSON with ````, but the ``*_json`` methods -don't require this cast in the query. This result can be turned into a -``String`` and used to respond to some JSON API request directly, unpacked -into a struct using ``serde`` and ``serde_json``, etc. - -.. code-block:: rust - - #[derive(Debug, Deserialize)] - pub struct Account { - pub username: String, - pub id: Uuid, - } - - // No need for cast here - let query = "select Account { - username, - id - } filter .username = $0;"; - - // Can use query_single_json if we know there will only be one result; - // otherwise query_json which returns a map of json - let json_res = client - .query_single_json(query, &("SomeUserName",)) - .await? - .unwrap(); - - // Format: - // {"username" : "SomeUser1", - // "id" : "7093944a-fd3a-11ed-a013-c7de12ffe7a9"} - let as_string = json_res.to_string(); - let as_account: Account = serde_json::from_str(&json_res)?; - - -.. _`edgedb-protocol`: https://docs.rs/edgedb-protocol \ No newline at end of file diff --git a/docs/clients/rust/transactions.rst b/docs/clients/rust/transactions.rst deleted file mode 100644 index 6924b761f60..00000000000 --- a/docs/clients/rust/transactions.rst +++ /dev/null @@ -1,71 +0,0 @@ -.. _ref_rust_transactions: - -Transactions ------------- - -The client also has a ``.transaction()`` method that -allows for atomic :ref:`transactions `. - -Wikipedia has a good example of a scenario requiring a transaction which we -can then implement: - -*An example of an atomic transaction is a monetary transfer from bank account A -to account B. It consists of two operations, withdrawing the money from account -A and saving it to account B. Performing these operations in an atomic -transaction ensures that the database remains in a consistent state, that is, -money is neither lost nor created if either of those two operations fails.* - -A transaction removing 10 cents from one customer's account and placing it in -another's would look like this: - -.. code-block:: rust - - #[derive(Debug, Deserialize, Queryable)] - pub struct BankCustomer { - pub name: String, - pub bank_balance: i32, - } - // Customer1 has an account with 110 cents in it. - // Customer2 has an account with 90 cents in it. - // Customer1 is going to send 10 cents to Customer 2. This will be a - // transaction as we don't want the case to ever occur - even for a - // split second - where one account has sent money while the other - // has not received it yet. - - // After the transaction is over, each customer should have 100 cents. - - let sender_name = "Customer1"; - let receiver_name = "Customer2"; - let balance_check = "select BankCustomer { name, bank_balance } - filter .name = $0"; - let balance_change = "update BankCustomer - filter .name = $0 - set { bank_balance := .bank_balance + $1 }"; - let send_amount = 10; - - client - .transaction(|mut conn| async move { - let sender: BankCustomer = conn - .query_required_single(balance_check, &(sender_name,)) - .await?; - if sender.bank_balance < send_amount { - println!("Not enough money, bailing from transaction"); - return Ok(()); - }; - conn.execute(balance_change, &(sender_name, send_amount.neg())) - .await?; - conn.execute(balance_change, &(receiver_name, send_amount)) - .await?; - Ok(()) - }) - .await?; - -.. note:: - - What often may seem to require an atomic transaction can instead be - achieved with links and :ref:`backlinks ` which - are both idiomatic and easy to use in EdgeDB. - For example, if one object holds a ``required link`` to two - other objects and each of these two objects has a single backlink to the - first one, simply updating the first object will effectively change the - state of the other two instantaneously. diff --git a/docs/cloud/cli.rst b/docs/cloud/cli.rst new file mode 100644 index 00000000000..36fcd6eab8c --- /dev/null +++ b/docs/cloud/cli.rst @@ -0,0 +1,72 @@ +.. _ref_guide_cloud_cli: + +=== +CLI +=== + +:edb-alt-title: Using Gel Cloud via the CLI + +To use |Gel| Cloud via the CLI, first log in using +:ref:`ref_cli_gel_cloud_login`. + +.. note:: + + This is the way you'll log in interactively on your development machine, + but when interacting with Gel Cloud via a script or in CI, you'll + instead set the :gelenv:`SECRET_KEY` environment variable to your secret + key. Generate a secret key in the Gel Cloud UI or by running + :ref:`ref_cli_gel_cloud_secretkey_create`. The :gelcmd:`cloud + login` and :gelcmd:`cloud logout` commands are not intended for use + in this context. + +Once your login is successful, you will be able to create an instance using +either :ref:`ref_cli_gel_instance_create` or +:ref:`ref_cli_gel_project_init`, depending on whether you also want to +create a local project linked to your instance. + +* :ref:`ref_cli_gel_instance_create` with an instance name of + ``/``. + + .. code-block:: bash + + $ gel instance create / + +* :ref:`ref_cli_gel_project_init` with the ``--server-instance`` option. Set + the server instance name to ``/``. + + .. code-block:: bash + + $ gel project init \ + --server-instance / + + Alternatively, you can run :gelcmd:`project init` *without* the + ``--server-instance`` option and enter an instance name in the + ``/`` format when prompted interactively. + +.. note:: + + Please be aware of the following restrictions on |Gel| Cloud instance + names: + + * can contain only Latin alpha-numeric characters or ``-`` + * cannot start with a dash (``-``) or contain double dashes (``--``) + * maximum instance name length is 61 characters minus the length of your + organization name (i.e., length of organization name + length of instance + name must be fewer than 62 characters) + +To use :gelcmd:`instance create`: + +.. code-block:: bash + + $ gel instance create / + +To use :gelcmd:`project init`: + +.. code-block:: bash + + $ gel project init \ + --server-instance / + +Alternatively, you can run :gelcmd:`project init` *without* the +``--server-instance`` option and enter an instance name in the +``/`` format when prompted interactively. diff --git a/docs/guides/cloud/deploy/fly.rst b/docs/cloud/deploy/fly.rst similarity index 57% rename from docs/guides/cloud/deploy/fly.rst rename to docs/cloud/deploy/fly.rst index 99efd0bd827..b4445227286 100644 --- a/docs/guides/cloud/deploy/fly.rst +++ b/docs/cloud/deploy/fly.rst @@ -4,41 +4,41 @@ Fly.io ====== -:edb-alt-title: Deploying applications built on EdgeDB Cloud to Fly.io +:edb-alt-title: Deploying applications built on Gel Cloud to Fly.io 1. Install the `Fly.io CLI `_ 2. Log in to Fly.io with ``flyctl auth login`` 3. Run ``flyctl launch`` to create a new app on Fly.io and configure it. - It will ask you to select a region and a name for your app. When done it will + It will ask you to select a region and a name for your app. When done it will create a ``fly.toml`` file and a ``Dockerfile`` in your project directory. -4. Set ``EDGEDB_INSTANCE`` and ``EDGEDB_SECRET_KEY`` as secrets in your Fly.io - app. - +4. Set :gelenv:`INSTANCE` and :gelenv:`SECRET_KEY` as secrets in your Fly.io + app. + For **runtime secrets**, you can do this by running the following commands: .. code-block:: bash - $ flyctl secrets set EDGEDB_INSTANCE - $ flyctl secrets set EDGEDB_SECRET_KEY + $ flyctl secrets set GEL_INSTANCE + $ flyctl secrets set GEL_SECRET_KEY - `Read more about Fly.io runtime secrets + `Read more about Fly.io runtime secrets `_. - For **build secrets**, you can do this by modifying the ``Dockerfile`` to + For **build secrets**, you can do this by modifying the ``Dockerfile`` to mount the secrets as environment variables. .. code-block:: dockerfile-diff :caption: Dockerfile - + # Build application - RUN pnpm run build - + RUN --mount=type=secret,id=EDGEDB_INSTANCE \ - + --mount=type=secret,id=EDGEDB_SECRET_KEY \ - + EDGEDB_INSTANCE="$(cat /run/secrets/EDGEDB_INSTANCE)" \ - + EDGEDB_SECRET_KEY="$(cat /run/secrets/EDGEDB_SECRET_KEY)" \ + + RUN --mount=type=secret,id=GEL_INSTANCE \ + + --mount=type=secret,id=GEL_SECRET_KEY \ + + GEL_INSTANCE="$(cat /run/secrets/GEL_INSTANCE)" \ + + GEL_SECRET_KEY="$(cat /run/secrets/GEL_SECRET_KEY)" \ + pnpm run build - `Read more about Fly.io build secrets + `Read more about Fly.io build secrets `_. 5. Deploy your app to Fly.io @@ -47,10 +47,10 @@ Fly.io $ flyctl deploy - If your app requires build secrets, you can pass them as arguments + If your app requires build secrets, you can pass them as arguments to the ``deploy`` command: .. code-block:: bash - $ flyctl deploy --build-secret EDGEDB_INSTANCE="" \ - --build-secret EDGEDB_SECRET_KEY="" + $ flyctl deploy --build-secret GEL_INSTANCE="" \ + --build-secret GEL_SECRET_KEY="" diff --git a/docs/guides/cloud/deploy/images/cloud-netlify-config.png b/docs/cloud/deploy/images/cloud-netlify-config.png similarity index 100% rename from docs/guides/cloud/deploy/images/cloud-netlify-config.png rename to docs/cloud/deploy/images/cloud-netlify-config.png diff --git a/docs/guides/cloud/deploy/images/cloud-railway-config.png b/docs/cloud/deploy/images/cloud-railway-config.png similarity index 100% rename from docs/guides/cloud/deploy/images/cloud-railway-config.png rename to docs/cloud/deploy/images/cloud-railway-config.png diff --git a/docs/guides/cloud/deploy/images/cloud-render-config.png b/docs/cloud/deploy/images/cloud-render-config.png similarity index 100% rename from docs/guides/cloud/deploy/images/cloud-render-config.png rename to docs/cloud/deploy/images/cloud-render-config.png diff --git a/docs/guides/cloud/deploy/images/cloud-vercel-config.png b/docs/cloud/deploy/images/cloud-vercel-config.png similarity index 100% rename from docs/guides/cloud/deploy/images/cloud-vercel-config.png rename to docs/cloud/deploy/images/cloud-vercel-config.png diff --git a/docs/guides/cloud/deploy/index.rst b/docs/cloud/deploy/index.rst similarity index 64% rename from docs/guides/cloud/deploy/index.rst rename to docs/cloud/deploy/index.rst index b3c0b29bc80..ebb282e9ae4 100644 --- a/docs/guides/cloud/deploy/index.rst +++ b/docs/cloud/deploy/index.rst @@ -4,15 +4,15 @@ Deploy an app ============= -:edb-alt-title: Deploying applications built on EdgeDB Cloud +:edb-alt-title: Deploying applications built on Gel Cloud For your production deployment, generate a dedicated secret key for your -instance with :ref:`ref_cli_edgedb_cloud_secretkey_create` or via the web UI's +instance with :ref:`ref_cli_gel_cloud_secretkey_create` or via the web UI's "Secret Keys" pane in your instance dashboard. Create two environment variables accessible to your production application: -* ``EDGEDB_SECRET_KEY``- contains the secret key you generated -* ``EDGEDB_INSTANCE``- the name of your EdgeDB Cloud instance +* :gelenv:`SECRET_KEY`- contains the secret key you generated +* :gelenv:`INSTANCE`- the name of your Gel Cloud instance (``/``) If you use one of these platforms, try the platform's guide for diff --git a/docs/guides/cloud/deploy/netlify.rst b/docs/cloud/deploy/netlify.rst similarity index 66% rename from docs/guides/cloud/deploy/netlify.rst rename to docs/cloud/deploy/netlify.rst index 1c5a5951ea6..4dea1ca9fbc 100644 --- a/docs/guides/cloud/deploy/netlify.rst +++ b/docs/cloud/deploy/netlify.rst @@ -4,26 +4,26 @@ Netlify ======= -:edb-alt-title: Deploying applications built on EdgeDB Cloud to Netlify +:edb-alt-title: Deploying applications built on |Gel| Cloud to Netlify .. note:: This guide assumes the Git deployment method on Netlify, but you may also - deploy your site using other methods. Just make sure the EdgeDB Cloud + deploy your site using other methods. Just make sure the Gel Cloud environment variables are set, and your app should have connectivity to your instance. 1. Push project to GitHub or some other Git remote repository -2. Create and make note of a secret key for your EdgeDB Cloud instance +2. Create and make note of a secret key for your Gel Cloud instance 3. On your Netlify Team Overview view under Sites, click Import from Git 4. Import your project's repository 5. Configure the build settings appropriately for your app 6. Click the Add environment variable button 7. Use the New variable button to add two variables: - - ``EDGEDB_INSTANCE`` containing your EdgeDB Cloud instance name (in + - :gelenv:`INSTANCE` containing your Gel Cloud instance name (in ``/`` format) - - ``EDGEDB_SECRET_KEY`` containing the secret key you created and noted + - :gelenv:`SECRET_KEY` containing the secret key you created and noted previously. 8. Click Deploy @@ -32,5 +32,5 @@ Netlify :width: 100% :alt: A screenshot of the Netlify deployment configuration view highlighting the environment variables section where a user will - need to set the necessary variables for EdgeDB Cloud instance + need to set the necessary variables for Gel Cloud instance connection. diff --git a/docs/guides/cloud/deploy/railway.rst b/docs/cloud/deploy/railway.rst similarity index 61% rename from docs/guides/cloud/deploy/railway.rst rename to docs/cloud/deploy/railway.rst index 13f17055f68..41dd28bc891 100644 --- a/docs/guides/cloud/deploy/railway.rst +++ b/docs/cloud/deploy/railway.rst @@ -4,24 +4,24 @@ Railway ======= -:edb-alt-title: Deploying applications built on EdgeDB Cloud to Railway +:edb-alt-title: Deploying applications built on |Gel| Cloud to Railway 1. Push project to GitHub or some other Git remote repository -2. Create and make note of a secret key for your EdgeDB Cloud instance +2. Create and make note of a secret key for your Gel Cloud instance 3. From Railway's dashboard, click the "New Project" button 4. Select the repository you want to deploy 5. Click the "Add variables" button to add the following environment variables: - - ``EDGEDB_INSTANCE`` containing your EdgeDB Cloud instance name (in + - :gelenv:`INSTANCE` containing your Gel Cloud instance name (in ``/`` format) - - ``EDGEDB_SECRET_KEY`` containing the secret key you created and noted + - :gelenv:`SECRET_KEY` containing the secret key you created and noted previously. 6. Click "Deploy" .. image:: images/cloud-railway-config.png :width: 100% - :alt: A screenshot of the Railway deployment configuration view - highlighting the environment variables section where a user will - need to set the necessary variables for EdgeDB Cloud instance + :alt: A screenshot of the Railway deployment configuration view + highlighting the environment variables section where a user will + need to set the necessary variables for Gel Cloud instance connection. diff --git a/docs/guides/cloud/deploy/render.rst b/docs/cloud/deploy/render.rst similarity index 60% rename from docs/guides/cloud/deploy/render.rst rename to docs/cloud/deploy/render.rst index 016c82a9e32..f46f5c048a0 100644 --- a/docs/guides/cloud/deploy/render.rst +++ b/docs/cloud/deploy/render.rst @@ -4,25 +4,25 @@ Render ====== -:edb-alt-title: Deploying applications built on EdgeDB Cloud to Render +:edb-alt-title: Deploying applications built on |Gel| Cloud to Render 1. Push project to GitHub or some other Git remote repository -2. Create and make note of a secret key for your EdgeDB Cloud instance +2. Create and make note of a secret key for your Gel Cloud instance 3. From Render's dashboard, click "New > Web Service" 4. Import your project's repository -5. In the setup page, scroll down to the "Environment Variables" section and +5. In the setup page, scroll down to the "Environment Variables" section and add the following environment variables: - - ``EDGEDB_INSTANCE`` containing your EdgeDB Cloud instance name (in + - :gelenv:`INSTANCE` containing your Gel Cloud instance name (in ``/`` format) - - ``EDGEDB_SECRET_KEY`` containing the secret key you created and noted + - :gelenv:`SECRET_KEY` containing the secret key you created and noted previously. 6. Click Deploy .. image:: images/cloud-render-config.png :width: 100% - :alt: A screenshot of the Render deployment configuration view - highlighting the environment variables section where a user - will need to set the necessary variables for EdgeDB Cloud instance + :alt: A screenshot of the Render deployment configuration view + highlighting the environment variables section where a user + will need to set the necessary variables for Gel Cloud instance connection. diff --git a/docs/guides/cloud/deploy/vercel.rst b/docs/cloud/deploy/vercel.rst similarity index 62% rename from docs/guides/cloud/deploy/vercel.rst rename to docs/cloud/deploy/vercel.rst index bb81a667d0f..4361ee58fc3 100644 --- a/docs/guides/cloud/deploy/vercel.rst +++ b/docs/cloud/deploy/vercel.rst @@ -4,17 +4,17 @@ Vercel ====== -:edb-alt-title: Deploying applications built on EdgeDB Cloud to Vercel +:edb-alt-title: Deploying applications built on Gel Cloud to Vercel 1. Push project to GitHub or some other Git remote repository -2. Create and make note of a secret key for your EdgeDB Cloud instance +2. Create and make note of a secret key for your Gel Cloud instance 3. From Vercel's Overview tab, click Add New > Project 4. Import your project's repository 5. In "Configure Project," expand "Environment Variables" to add two variables: - - ``EDGEDB_INSTANCE`` containing your EdgeDB Cloud instance name (in + - :gelenv:`INSTANCE` containing your Gel Cloud instance name (in ``/`` format) - - ``EDGEDB_SECRET_KEY`` containing the secret key you created and noted + - :gelenv:`SECRET_KEY` containing the secret key you created and noted previously. 6. Click Deploy @@ -23,4 +23,4 @@ Vercel :width: 100% :alt: A screenshot of the Vercel deployment configuration view highlighting the environment variables section where a user will need to set the - necessary variables for EdgeDB Cloud instance connection. + necessary variables for |Gel| Cloud instance connection. diff --git a/docs/guides/cloud/http_gql.rst b/docs/cloud/http_gql.rst similarity index 67% rename from docs/guides/cloud/http_gql.rst rename to docs/cloud/http_gql.rst index 389cd25c74f..48b3b5a07e3 100644 --- a/docs/guides/cloud/http_gql.rst +++ b/docs/cloud/http_gql.rst @@ -4,17 +4,17 @@ HTTP & GraphQL APIs =================== -:edb-alt-title: Querying EdgeDB Cloud over HTTP and GraphQL +:edb-alt-title: Querying Gel Cloud over HTTP and GraphQL -Using EdgeDB Cloud via HTTP and GraphQL works the same as :ref:`using any other -EdgeDB instance `. The two differences are in **how to +Using |Gel| Cloud via HTTP and GraphQL works the same as :ref:`using any other +|Gel| instance `. The two differences are in **how to discover your instance's URL** and **authentication**. Enabling ======== -EdgeDB Cloud can expose an HTTP endpoint for EdgeQL queries. Since HTTP is a +|Gel| Cloud can expose an HTTP endpoint for EdgeQL queries. Since HTTP is a stateless protocol, no :ref:`DDL ` or :ref:`transaction commands `, can be executed using this endpoint. Only one query per request can be executed. @@ -27,8 +27,8 @@ the schema: using extension edgeql_http; Then create a new migration and apply it using -:ref:`ref_cli_edgedb_migration_create` and -:ref:`ref_cli_edgedb_migrate`, respectively. +:ref:`ref_cli_gel_migration_create` and +:ref:`ref_cli_gel_migrate`, respectively. Your instance can now receive EdgeQL queries over HTTP at ``https://:/branch//edgeql``. @@ -37,10 +37,10 @@ Your instance can now receive EdgeQL queries over HTTP at Instance URL ============ -To determine the URL of an EdgeDB Cloud instance, find the host by running -``edgedb instance credentials -I /``. Use the +To determine the URL of a |Gel| Cloud instance, find the host by running +:gelcmd:`instance credentials -I /`. Use the ``host`` and ``port`` from that table in the URL format above this note. -Change the protocol to ``https`` since EdgeDB Cloud instances are secured +Change the protocol to ``https`` since Gel Cloud instances are secured with TLS. Your instance can now receive EdgeQL queries over HTTP at @@ -51,8 +51,8 @@ Authentication ============== -To authenticate to your EdgeDB Cloud instance, first create a secret key using -the EdgeDB Cloud UI or :ref:`ref_cli_edgedb_cloud_secretkey_create`. Use the +To authenticate to your |Gel| Cloud instance, first create a secret key using +the Gel Cloud UI or :ref:`ref_cli_gel_cloud_secretkey_create`. Use the secret key as your token with the bearer authentication method. Here is an example showing how you might send the query ``select Person {*};`` using cURL: @@ -70,7 +70,7 @@ example showing how you might send the query ``select Person {*};`` using cURL: Usage ===== -Usage of the HTTP and GraphQL APIs is identical on an EdgeDB Cloud instance. +Usage of the HTTP and GraphQL APIs is identical on a |Gel| Cloud instance. Reference the HTTP and GraphQL documentation for more information. diff --git a/docs/guides/cloud/index.rst b/docs/cloud/index.rst similarity index 61% rename from docs/guides/cloud/index.rst rename to docs/cloud/index.rst index 3fad39fcc8c..fab2d84cc05 100644 --- a/docs/guides/cloud/index.rst +++ b/docs/cloud/index.rst @@ -4,11 +4,11 @@ Cloud ===== -:edb-alt-title: Using EdgeDB Cloud +:edb-alt-title: Using Gel Cloud -EdgeDB Cloud is the easiest way to host your EdgeDB instance. We offer two ways -to interact with EdgeDB Cloud: via our CLI or through a graphical web -interface nearly identical to the :ref:`EdgeDB UI `. +|Gel| Cloud is the easiest way to host your Gel instance. We offer two ways +to interact with Gel Cloud: via our CLI or through a graphical web +interface nearly identical to the :ref:`Gel UI `. .. edb:youtube-embed:: IG1MggUzzH4 @@ -31,16 +31,16 @@ interface nearly identical to the :ref:`EdgeDB UI `. Questions? Problems? Bugs? ========================== -Thank you for helping us make the best way to host your EdgeDB instances even +Thank you for helping us make the best way to host your Gel instances even better! * Please join us on `our Discord `_ to ask questions. * If you're experiencing a service interruption, check `our status page - `_ for information on what may be + `_ for information on what may be causing it. * Report any bugs you find by `submitting a support ticket - `_. Note: when using EdgeDB Cloud + `_. Note: when using |Gel| Cloud through the CLI, setting the ``RUST_LOG`` environment variable to ``info``, ``debug``, or ``trace`` may provide additional debugging information which will be useful to include with your ticket. diff --git a/docs/guides/cloud/web.rst b/docs/cloud/web.rst similarity index 74% rename from docs/guides/cloud/web.rst rename to docs/cloud/web.rst index 59e3a95f8c1..144ef8bec89 100644 --- a/docs/guides/cloud/web.rst +++ b/docs/cloud/web.rst @@ -4,10 +4,10 @@ Web GUI ======= -:edb-alt-title: Using EdgeDB Cloud via the web GUI +:edb-alt-title: Using Gel Cloud via the web GUI -If you'd prefer, you can also manage your account via `the EdgeDB Cloud -web-based GUI `_. +If you'd prefer, you can also manage your account via `the |Gel| Cloud +web-based GUI `_. The first time you access the web UI, you will be prompted to log in. Once you log in with your account, you'll be on the "Instances" tab of the front page @@ -17,19 +17,19 @@ organization settings and billing. Instances --------- -If this is your first time accessing EdgeDB Cloud, this list will be empty. To +If this is your first time accessing Gel Cloud, this list will be empty. To create an instance, click "Create new instance." This will pop up a modal -allowing you to name your instance and specify the version of EdgeDB and the +allowing you to name your instance and specify the version of Gel and the region for the instance. Once the instance has been created, you'll see the instance dashboard which allows you to monitor your instance, navigate to the management page for its branches, and create secret keys. -You'll also see instructions in the bottom-right for linking your EdgeDB CLI to -your EdgeDB Cloud account. You do this by running the CLI command ``edgedb -cloud login``. This will make all of your EdgeDB Cloud instances accessible via -the CLI. You can manage them just as you would other remote EdgeDB instances. +You'll also see instructions in the bottom-right for linking your |Gel| CLI to +your Gel Cloud account. You do this by running the CLI command +:gelcmd:`cloud login`. This will make all of your Gel Cloud instances accessible via +the CLI. You can manage them just as you would other remote Gel instances. If you want to manage a branch of your database, click through on the instance's name from the top right of the instance dashboard. If you just @@ -46,7 +46,7 @@ Org Settings This tab allows you to add GitHub organizations for which you are an admin. If you don't see your organization's name here, you may need to update your -`org settings`_ in GitHub to allow EdgeDB Cloud to read your list of +`org settings`_ in GitHub to allow |Gel| Cloud to read your list of organizations, and then refresh the org list. .. lint-off diff --git a/docs/datamodel/access_policies.rst b/docs/datamodel/access_policies.rst index 2e155ca645d..e94e14013ea 100644 --- a/docs/datamodel/access_policies.rst +++ b/docs/datamodel/access_policies.rst @@ -1,29 +1,29 @@ -.. versionadded:: 2.0 - .. _ref_datamodel_access_policies: =============== Access Policies =============== -Object types can contain security policies that restrict the set of objects -that can be selected, inserted, updated, or deleted by a particular query. -This is known as *object-level security* and it is similar in function to SQL's -row-level security. +.. index:: access policy, object-level security, row-level security, RLS, + allow, deny, using -Let's start with a simple schema for a blog without any access policies. +Object types in |Gel| can contain security policies that restrict the set of +objects that can be selected, inserted, updated, or deleted by a particular +query. This is known as *object-level security* and is similar in function +to SQL's row-level security. -.. code-block:: sdl - :version-lt: 3.0 +When no access policies are defined, object-level security is not activated: +any properly authenticated client can carry out any operation on any object +in the database. Access policies allow you to ensure that the database itself +handles access control logic rather than having to implement it in every +application or service that connects to your database. - type User { - required property email -> str { constraint exclusive; } - } +Access policies can greatly simplify your backend code, centralizing access +control logic in a single place. They can also be extremely useful for +implementing AI agentic flows, where you want to have guardrails around +your data that agents can't break. - type BlogPost { - required property title -> str; - required link author -> User; - } +We'll illustrate access policies in this document with this simple schema: .. code-block:: sdl @@ -36,55 +36,43 @@ Let's start with a simple schema for a blog without any access policies. required author: User; } -When no access policies are defined, object-level security is not activated. -Any properly authenticated client can carry out any operation on any object -in the database. At the moment, we would need to ensure that the app handles -the logic to restrict users from accessing other users' posts. Access -policies allow us to ensure that the database itself handles this logic, -thereby freeing us up from implementing access control in each and every -piece of software that accesses the data. .. warning:: - Once a policy is added to a particular object type, **all operations** - (``select``, ``insert``, ``delete``, ``update``, etc.) on any object of - that type are now *disallowed by default* unless specifically allowed by an - access policy! See the subsection on resolution order below for details. - -Defining a global -^^^^^^^^^^^^^^^^^ - -Global variables are the a convenient way to provide the context needed to -determine what sort of access should be allowed for a given object, as they -can be set and reset by the application as needed. - -To start, we'll add two global variables to our schema. We'll use one global -``uuid`` to represent the identity of the user executing the query, and an -enum for the other to represent the type of country that the user is currently -in. The enum represents three types of countries: those where the service has -not been rolled out, those with read-only access, and those with full access. -A global makes sense in this case because a user's current country is -context-specific: the same user who can access certain content in one country -might not be able to in another country due to different legal frameworks -(such as copyright length). - -.. code-block:: sdl-diff - :version-lt: 3.0 - - + scalar type Country extending enum; - + global current_user -> uuid; - + required global current_country -> Country { - + default := Country.None - + } - - type User { - required property email -> str { constraint exclusive; } - } - - type BlogPost { - required property title -> str; - required link author -> User; - } + Once a policy is added to a particular object type, **all operations** + (``select``, ``insert``, ``delete``, ``update``, etc.) on any object of + that type are now *disallowed by default* unless specifically allowed by + an access policy! See :ref:`resolution order ` + below for details. + +Global variables +================ + +Global variables are a convenient way to set up the context for your access +policies. Gel's global variables are tightly integrated with the Gel's +data model, client APIs, EdgeQL and SQL, and the tooling around them. + +Global variables in Gel are not pre-defined. Users are free to define +as many globals in their schema as they want to represent the business +logic of their application. + +A common scenario is storing a ``current_user`` global representing +the user executing queries. We'd like to have a slightly more complex example +showing that you can use more than one global variable. Let's do that: + +* We'll use one *global* ``uuid`` to represent the identity of the user + executing the query. +* We'll have the ``Country`` *enum* to represent the type of country + that the user is currently in. The enum represents three types of + countries: those where the service has not been rolled out, those with + read-only access, and those with full access. +* We'll use the ``current_country`` *global* to represent the user's + current country. In our *example schema*, we want *country* to be + context-specific: the same user who can access certain content in one + country might not be able to in another country (let's imagine that's + due to different country-specific legal frameworks). + +Here is an illustration: .. code-block:: sdl-diff @@ -103,24 +91,29 @@ might not be able to in another country due to different legal frameworks required author: User; } -The value of these global variables is attached to the *client* you use to -execute queries. The exact API depends on which client library you're using: +You can set and reset these globals in Gel client libraries, for example: .. tabs:: .. code-tab:: typescript - import createClient from 'edgedb'; + import createClient from 'gel'; - const client = createClient().withGlobals({ + const client = createClient(); + + // 'authedClient' will share the network connection with 'client', + // but will have the 'current_user' global set. + const authedClient = client.withGlobals({ current_user: '2141a5b4-5634-4ccc-b835-437863534c51', }); - await client.query(`select global current_user;`); + const result = await authedClient.query( + `select global current_user;`); + console.log(result); .. code-tab:: python - from edgedb import create_client + from gel import create_client client = create_client().with_globals({ 'current_user': '580cc652-8ab8-4a20-8db9-4c79a4b1fd81' @@ -129,6 +122,7 @@ execute queries. The exact API depends on which client library you're using: result = client.query(""" select global current_user; """) + print(result) .. code-tab:: go @@ -139,23 +133,23 @@ execute queries. The exact API depends on which client library you're using: "fmt" "log" - "github.com/edgedb/edgedb-go" + "github.com/geldata/gel-go" ) func main() { ctx := context.Background() - client, err := edgedb.CreateClient(ctx, edgedb.Options{}) + client, err := gel.CreateClient(ctx, gel.Options{}) if err != nil { log.Fatal(err) } defer client.Close() - id, err := edgedb.ParseUUID("2141a5b4-5634-4ccc-b835-437863534c51") + id, err := gel.ParseUUID("2141a5b4-5634-4ccc-b835-437863534c51") if err != nil { log.Fatal(err) } - var result edgedb.UUID + var result gel.UUID err = client. WithGlobals(map[string]interface{}{"current_user": id}). QuerySingle(ctx, "SELECT global current_user;", &result) @@ -168,12 +162,12 @@ execute queries. The exact API depends on which client library you're using: .. code-tab:: rust - use edgedb_protocol::{ + use gel_protocol::{ model::Uuid, value::EnumValue }; - let client = edgedb_tokio::create_client() + let client = gel_tokio::create_client() .await .expect("Client should init") .with_globals_fn(|c| { @@ -195,101 +189,59 @@ execute queries. The exact API depends on which client library you're using: .expect("Returning value"); -Defining a policy -^^^^^^^^^^^^^^^^^ +Defining policies +================= -Let's add two policies to our sample schema. +A policy example for our simple blog schema might look like: .. code-block:: sdl-diff - :version-lt: 3.0 - - global current_user -> uuid; - required global current_country -> Country { - default := Country.None - } - scalar type Country extending enum; - - type User { - required property email -> str { constraint exclusive; } - } - - type BlogPost { - required property title -> str; - required link author -> User; - - + access policy author_has_full_access - + allow all - + using (global current_user ?= .author.id - + and global current_country ?= Country.Full) { - + errmessage := "User does not have full access"; - + } - + access policy author_has_read_access - + allow select - + using (global current_user ?= .author.id - + and global current_country ?= Country.ReadOnly); - } -.. code-block:: sdl-diff + global current_user: uuid; + required global current_country: Country { + default := Country.None + } + scalar type Country extending enum; - global current_user: uuid; - required global current_country: Country { - default := Country.None - } - scalar type Country extending enum; + type User { + required email: str { constraint exclusive; } + } - type User { - required email: str { constraint exclusive; } - } + type BlogPost { + required title: str; + required author: User; - type BlogPost { - required title: str; - required author: User; + + access policy author_has_full_access + + allow all + + using (global current_user ?= .author.id + + and global current_country ?= Country.Full) { + + errmessage := "User does not have full access"; + + } - + access policy author_has_full_access - + allow all - + using (global current_user ?= .author.id - + and global current_country ?= Country.Full) { - + errmessage := "User does not have full access"; - + } - + access policy author_has_read_access - + allow select - + using (global current_user ?= .author.id - + and global current_country ?= Country.ReadOnly); - } + + access policy author_has_read_access + + allow select + + using (global current_user ?= .author.id + + and global current_country ?= Country.ReadOnly); + } -Let's break down the access policy syntax piece-by-piece. These policies grant -full read-write access (``all``) to the ``author`` of each ``BlogPost``, if -the author is in a country that allows full access to the service. Otherwise, -the same author will be restricted to either read-only access or no access at -all, depending on the country. +Explanation: -.. note:: +- ``access policy `` introduces a new policy in an object type. +- ``allow all`` grants ``select``, ``insert``, ``update``, and ``delete`` + access if the condition passes. We also used a separate policy to allow + only ``select`` in some cases. +- ``using ()`` is a boolean filter restricting the set of objects to + which the policy applies. (We used the coalescing operator ``?=`` to + handle empty sets gracefully.) +- ``errmessage`` is an optional custom message to display in case of a write + violation. - We're using the *coalescing equality* operator ``?=`` because it returns - ``false`` even if one of its arguments is an empty set. - -- ``access policy``: The keyword used to declare a policy inside an object - type. -- ``author_has_full_access`` and ``author_has_read_access``: The names of these - policies; could be any string. -- ``allow``: The kind of policy; could be ``allow`` or ``deny`` -- ``all``: The set of operations being allowed/denied; a comma-separated list - of any number of the following: ``all``, ``select``, ``insert``, ``delete``, - ``update``, ``update read``, and ``update write``. -- ``using ()``: A boolean expression. Think of this as a ``filter`` - expression that defines the set of objects to which the policy applies. -- ``errmessage``: Here we have added an error message that will be shown in - case the policy expression returns ``false``. We could have added other - annotations of our own inside this code block instead of, or in addition - to ``errmessage``. - -Let's do some experiments. +Let's run some experiments in the REPL: .. code-block:: edgeql-repl - db> insert User { email := "test@edgedb.com" }; + db> insert User { email := "test@example.com" }; {default::User {id: be44b326-03db-11ed-b346-7f1594474966}} - db> set global current_user := + db> set global current_user := ... "be44b326-03db-11ed-b346-7f1594474966"; OK: SET GLOBAL db> set global current_country := Country.Full; @@ -300,58 +252,22 @@ Let's do some experiments. ... }; {default::BlogPost {id: e76afeae-03db-11ed-b346-fbb81f537ca6}} -We've created a ``User``, set the value of ``current_user`` to its ``id``, the -country to ``Country.Full``, and created a new ``BlogPost``. When we try to -select all ``BlogPost`` objects, we'll see the post we just created. - -.. code-block:: edgeql-repl - - db> select BlogPost; - {default::BlogPost {id: e76afeae-03db-11ed-b346-fbb81f537ca6}} - db> select count(BlogPost); - {1} - -Next, let's test what happens when the same user is in two other countries: -one that allows read-only access to our app, and another where we haven't -yet been given permission to roll out our service. +Because the user is in a "full access" country and the current user ID +matches the author, the new blog post is permitted. When the same user sets +``global current_country := Country.ReadOnly;``: .. code-block:: edgeql-repl db> set global current_country := Country.ReadOnly; OK: SET GLOBAL db> select BlogPost; - {default::BlogPost {id: dd274432-94ff-11ee-953e-0752e8ad3010}} + {default::BlogPost {id: e76afeae-03db-11ed-b346-fbb81f537ca6}} db> insert BlogPost { ... title := "My second post", ... author := (select User filter .id = global current_user) ... }; - edgedb error: AccessPolicyError: access policy violation on + gel error: AccessPolicyError: access policy violation on insert of default::BlogPost (User does not have full access) - db> set global current_country := Country.None; - OK: SET GLOBAL - db> select BlogPost; - {} - -Note that for a ``select`` operation, the access policy works as a filter -by simply returning an empty set. Meanwhile, when attempting an ``insert`` -operation, the operation may or may not work and thus we have provided a -helpful error message in the access policy to give users a heads up on what -went wrong. - -Now let's move back to a country with full access, but set the -``global current_user`` to some other id: a new user that has yet to write -any blog posts. Now the number of ``BlogPost`` objects returned via -the ``count`` function is zero: - -.. code-block:: edgeql-repl - - db> set global current_country := Country.Full; - OK: SET GLOBAL - db> set global current_user := - ... 'd1c64b84-8e3c-11ee-86f0-d7ddecf3e9bd'; - OK: SET GLOBAL - db> select count(BlogPost); - {0} Finally, let's unset ``current_user`` and see how many blog posts are returned when we count them. @@ -372,99 +288,43 @@ When ``current_user`` has no value or has a different value from the But thanks to ``Country`` being set to ``Country.Full``, this user will be able to write a new blog post. -The access policies use global variables to define a "subgraph" of data that -is visible to a particular query. - -Policy types -^^^^^^^^^^^^ +**The bottom line:** access policies use global variables to define a +"subgraph" of data that is visible to your queries. -For the most part, the policy types correspond to EdgeQL's *statement types*: -- ``select``: Applies to all queries; objects without a ``select`` permission - cannot be modified either. -- ``insert``: Applies to insert queries; executed *post-insert*. If an - inserted object violates the policy, the query will fail. -- ``delete``: Applies to delete queries. -- ``update``: Applies to update queries. - -Additionally, the ``update`` operation can be broken down into two -sub-policies: ``update read`` and ``update write``. +Policy types +============ -- ``update read``: This policy restricts *which* objects can be updated. It - runs *pre-update*; that is, this policy is executed before the updates have - been applied. As a result, an empty set is returned on an ``update read`` - when a query lacks access to perform the operation. -- ``update write``: This policy restricts *how* you update the objects; you - can think of it as a *post-update* validity check. As a result, an error - is returned on an ``update write`` when a query lacks access to perform - the operation. Preventing a ``User`` from transferring a ``BlogPost`` to - another ``User`` is one example of an ``update write`` access policy. +.. index:: access policy, select, insert, delete, update, update read, + update write, all -Finally, there's an umbrella policy that can be used as a shorthand for all -the others. +The types of policy rules map to the statement type in EdgeQL: -- ``all``: A shorthand policy that can be used to allow or deny full read/ - write permissions. Exactly equivalent to ``select, insert, update, delete``. +- ``select``: Controls which objects are visible to any query. +- ``insert``: Post-insert check. If the inserted object violates the policy, + the operation fails. +- ``delete``: Controls which objects can be deleted. +- ``update read``: Pre-update check on which objects can be updated at all. +- ``update write``: Post-update check for how objects can be updated. +- ``all``: Shorthand for granting or denying ``select, insert, update, + delete``. Resolution order -^^^^^^^^^^^^^^^^ - -An object type can contain an arbitrary number of access policies, including -several conflicting ``allow`` and ``deny`` policies. EdgeDB uses a particular -algorithm for resolving these policies. - -.. figure:: images/ols.png - - The access policy resolution algorithm, explained with Venn diagrams. - -1. When no policies are defined on a given object type, all objects of that - type can be read or modified by any appropriately authenticated connection. - -2. EdgeDB then applies all ``allow`` policies. Each policy grants a - *permission* that is scoped to a particular *set of objects* as defined by - the ``using`` clause. Conceptually, these permissions are merged with - the ``union`` / ``or`` operator to determine the set of allowable actions. - -3. After the ``allow`` policies are resolved, the ``deny`` policies can be - used to carve out exceptions to the ``allow`` rules. Deny rules *supersede* - allow rules! As before, the set of objects targeted by the policy is - defined by the ``using`` clause. +================ -4. This results in the final access level: a set of objects targetable by each - of ``select``, ``insert``, ``update read``, ``update write``, and - ``delete``. +If multiple policies apply (some are ``allow`` and some are ``deny``), the +logic is: -Currently, by default the access policies affect the values visible -in expressions of *other* access -policies. This means that they can affect each other in various ways. Because -of this, great care needs to be taken when creating access policies based on -objects other than the ones they are defined on. For example: +1. If there are no policies, access is allowed. +2. All ``allow`` policies collectively form a *union* / *or* of allowed sets. +3. All ``deny`` policies *subtract* from that union, overriding allows! +4. The final set of objects is the intersection of the above logic for each + operation: ``select, insert, update read, update write, delete``. -.. code-block:: sdl - :version-lt: 3.0 - - global current_user_id -> uuid; - global current_user := ( - select User filter .id = global current_user_id - ); - - type User { - required property email -> str { constraint exclusive; } - required property is_admin -> bool { default := false }; - - access policy admin_only - allow all - using (global current_user.is_admin ?? false); - } - - type BlogPost { - required property title -> str; - link author -> User; - - access policy author_has_full_access - allow all - using (global current_user ?= .author.id); - } +By default, once you define any policy on an object type, you must explicitly +allow the operations you need. This is a common **pitfall** when you are +starting out with access policies (but you will develop an intuition for this +quickly). Let's look at an example: .. code-block:: sdl @@ -491,45 +351,34 @@ objects other than the ones they are defined on. For example: using (global current_user ?= .author.id); } -In the above schema only the admin will see a non-empty ``author`` link, -because only the admin can see any user objects at all. This means that -instead of making ``BlogPost`` visible to its author, all non-admin authors -won't be able to see their own posts. The above issue can be remedied by -making the current user able to see their own ``User`` record. +In the above schema only admins will see a non-empty ``author`` link when +running ``select BlogPost { author }``. Why? Because only admins can see +``User`` objects at all: ``admin_only`` policy is the only one defined on +the ``User`` type! -.. _ref_datamodel_access_policies_nonrecursive: -.. _nonrecursive: - -.. note:: +This means that instead of making ``BlogPost`` visible to its author, all +non-admin authors won't be able to see their own posts. The above issue can be +remedied by making the current user able to see their own ``User`` record. - Starting with EdgeDB 3.0, access policy restrictions will **not** apply to - any access policy expression. This means that when reasoning about access - policies it is no longer necessary to take other policies into account. - Instead, all data is visible for the purpose of *defining* an access - policy. - This change is being made to simplify reasoning about access policies and - to allow certain patterns to be express efficiently. Since those who have - access to modifying the schema can remove unwanted access policies, no - additional security is provided by applying access policies to each - other's expressions. +Interaction between policies +============================ - It is possible (and recommended) to enable this :ref:`future - ` behavior in EdgeDB 2.6 and later by adding the - following to the schema: ``using future nonrecursive_access_policies;`` +Policy expressions themselves do not take other policies into account +(since |EdgeDB| 3). This makes it easier to reason about policies. Custom error messages -^^^^^^^^^^^^^^^^^^^^^ +===================== -.. versionadded:: 3.0 +.. index:: access policy, errmessage, using -When you run a query that attempts a write and is restricted by an access -policy, you will get a generic error message. +When an ``insert`` or ``update write`` violates an access policy, Gel will +raise a generic ``AccessPolicyError``: .. code-block:: - edgedb error: AccessPolicyError: access policy violation on insert of - + gel error: AccessPolicyError: access policy violation + on insert of .. note:: @@ -539,9 +388,8 @@ policy, you will get a generic error message. simply won't get the data that is being restricted. Other operations (``insert`` and ``update write``) will return an error message. -If you have multiple access policies, it can be useful to know which policy is -restricting your query and provide a friendly error message. You can do this -by adding a custom error message to your policy. +If multiple policies are in effect, it can be helpful to define a distinct +``errmessage`` in your policy: .. code-block:: sdl-diff @@ -577,102 +425,135 @@ will receive this error: .. code-block:: - edgedb error: AccessPolicyError: access policy violation on insert of + gel error: AccessPolicyError: access policy violation on insert of default::User (Only admins may query Users) + Disabling policies -^^^^^^^^^^^^^^^^^^ +================== + +.. index:: apply_access_policies You may disable all access policies by setting the ``apply_access_policies`` :ref:`configuration parameter ` to ``false``. -You may also toggle access policies using the "Disable Access Policies" -checkbox in the "Config" dropdown in the EdgeDB UI (accessible by running -the CLI command ``edgedb ui`` from inside your project). This is the most -convenient way to temporarily disable access policies since it applies only to -your UI session. +You may also temporarily disable access policies using the Gel UI configuration +checkbox (or via :gelcmd:`ui`), which only applies to your UI session. +More examples +============= -Examples -^^^^^^^^ +Here are some additional patterns: -Blog posts are publicly visible if ``published`` but only writable by the -author. +1. Publicly visible blog posts, only writable by the author: -.. code-block:: sdl-diff - :version-lt: 3.0 + .. code-block:: sdl-diff - global current_user -> uuid; + global current_user: uuid; - type User { - required property email -> str { constraint exclusive; } - } + type User { + required email: str { constraint exclusive; } + } - type BlogPost { - required property title -> str; - required link author -> User; - + required property published -> bool { default := false }; + type BlogPost { + required title: str; + required author: User; + + required published: bool { default := false }; - access policy author_has_full_access - allow all - using (global current_user ?= .author.id); - + access policy visible_if_published - + allow select - + using (.published); - } + access policy author_has_full_access + allow all + using (global current_user ?= .author.id); + + access policy visible_if_published + + allow select + + using (.published); + } -.. code-block:: sdl-diff +2. Visible to friends, only modifiable by the author: - global current_user: uuid; + .. code-block:: sdl-diff - type User { - required email: str { constraint exclusive; } - } + global current_user: uuid; - type BlogPost { - required title: str; - required author: User; - + required published: bool { default := false }; + type User { + required email: str { constraint exclusive; } + + multi friends: User; + } - access policy author_has_full_access - allow all - using (global current_user ?= .author.id); - + access policy visible_if_published - + allow select - + using (.published); - } + type BlogPost { + required title: str; + required author: User; -Blog posts are visible to friends but only modifiable by the author. + access policy author_has_full_access + allow all + using (global current_user ?= .author.id); + + access policy friends_can_read + + allow select + + using ((global current_user in .author.friends.id) ?? false); + } -.. code-block:: sdl-diff - :version-lt: 3.0 +3. Publicly visible except to those blocked by the author: - global current_user -> uuid; + .. code-block:: sdl-diff - type User { - required property email -> str { constraint exclusive; } - + multi link friends -> User; - } + type User { + required email: str { constraint exclusive; } + + multi blocked: User; + } - type BlogPost { - required property title -> str; - required link author -> User; + type BlogPost { + required title: str; + required author: User; - access policy author_has_full_access - allow all - using (global current_user ?= .author.id); - + access policy friends_can_read - + allow select - + using ((global current_user in .author.friends.id) ?? false); - } + access policy author_has_full_access + allow all + using (global current_user ?= .author.id); + + access policy anyone_can_read + + allow select; + + access policy exclude_blocked + + deny select + + using ((global current_user in .author.blocked.id) ?? false); + } -.. code-block:: sdl-diff +4. "Disappearing" posts that become invisible after 24 hours: - global current_user: uuid; + .. code-block:: sdl-diff + + type User { + required email: str { constraint exclusive; } + } + + type BlogPost { + required title: str; + required author: User; + + required created_at: datetime { + + default := datetime_of_statement() # non-volatile + + } + + access policy author_has_full_access + allow all + using (global current_user ?= .author.id); + + access policy hide_after_24hrs + + allow select + + using ( + + datetime_of_statement() - .created_at < '24 hours' + + ); + } + +Super constraints +================= + +Access policies can act like "super constraints." For instance, a policy on +``insert`` or ``update write`` can do a post-write validity check, rejecting +the operation if a certain condition is not met. + +E.g. here's a policy that limits the number of blog posts a +``User`` can post: + +.. code-block:: sdl-diff type User { required email: str { constraint exclusive; } - + multi friends: User; + + multi posts := . 500); } -Blog posts are publicly visible except to users that have been ``blocked`` by -the author. +.. _ref_eql_sdl_access_policies: +.. _ref_eql_sdl_access_policies_syntax: -.. code-block:: sdl-diff - :version-lt: 3.0 +Declaring access policies +========================= - type User { - required property email -> str { constraint exclusive; } - + multi link blocked -> User; - } +This section describes the syntax to declare access policies in your schema. - type BlogPost { - required property title -> str; - required link author -> User; +Syntax +------ - access policy author_has_full_access - allow all - using (global current_user ?= .author.id); - + access policy anyone_can_read - + allow select; - + access policy exclude_blocked - + deny select - + using ((global current_user in .author.blocked.id) ?? false); - } +.. sdl:synopsis:: -.. code-block:: sdl-diff + access policy + [ when () ] + { allow | deny } [, ... ] + [ using () ] + [ "{" + [ errmessage := value ; ] + [ ] + "}" ] ; - type User { - required email: str { constraint exclusive; } - + multi blocked: User; - } + # where is one of + all + select + insert + delete + update [{ read | write }] - type BlogPost { - required title: str; - required author: User; +Where: - access policy author_has_full_access - allow all - using (global current_user ?= .author.id); - + access policy anyone_can_read - + allow select; - + access policy exclude_blocked - + deny select - + using ((global current_user in .author.blocked.id) ?? false); - } +:eql:synopsis:`` + The name of the access policy. +:eql:synopsis:`when ()` + Specifies which objects this policy applies to. The + :eql:synopsis:`` has to be a :eql:type:`bool` expression. -"Disappearing" posts that become invisible after 24 hours. + When omitted, it is assumed that this policy applies to all objects of a + given type. -.. code-block:: sdl-diff - :version-lt: 3.0 +:eql:synopsis:`allow` + Indicates that qualifying objects should allow access under this policy. - type User { - required property email -> str { constraint exclusive; } - } +:eql:synopsis:`deny` + Indicates that qualifying objects should *not* allow access under this + policy. This flavor supersedes any :eql:synopsis:`allow` policy and can + be used to selectively deny access to a subset of objects that otherwise + explicitly allows accessing them. - type BlogPost { - required property title -> str; - required link author -> User; - + required property created_at -> datetime { - + default := datetime_of_statement() # non-volatile - + } +:eql:synopsis:`all` + Apply the policy to all actions. It is exactly equivalent to listing + :eql:synopsis:`select`, :eql:synopsis:`insert`, :eql:synopsis:`delete`, + :eql:synopsis:`update` actions explicitly. - access policy author_has_full_access - allow all - using (global current_user ?= .author.id); - + access policy hide_after_24hrs - + allow select - + using (datetime_of_statement() - .created_at < '24 hours'); - } +:eql:synopsis:`select` + Apply the policy to all selection queries. Note that any object that + cannot be selected, cannot be modified either. This makes + :eql:synopsis:`select` the most basic "visibility" policy. -.. code-block:: sdl-diff +:eql:synopsis:`insert` + Apply the policy to all inserted objects. If a newly inserted object would + violate this policy, an error is produced instead. - type User { - required email: str { constraint exclusive; } - } +:eql:synopsis:`delete` + Apply the policy to all objects about to be deleted. If an object does not + allow access under this kind of policy, it is not going to be considered + by any :eql:stmt:`delete` command. - type BlogPost { - required title: str; - required author: User; - + required created_at: datetime { - + default := datetime_of_statement() # non-volatile - + } + Note that any object that cannot be selected, cannot be modified either. - access policy author_has_full_access - allow all - using (global current_user ?= .author.id); - + access policy hide_after_24hrs - + allow select - + using (datetime_of_statement() - .created_at < '24 hours'); - } +:eql:synopsis:`update read` + Apply the policy to all objects selected for an update. If an object does + not allow access under this kind of policy, it is not visible cannot be + updated. -Super constraints -***************** + Note that any object that cannot be selected, cannot be modified either. -Access policies support arbitrary EdgeQL and can be used to define "super -constraints". Policies on ``insert`` and ``update write`` can -be thought of as post-write "validity checks"; if the check fails, the write -will be rolled back. +:eql:synopsis:`update write` + Apply the policy to all objects at the end of an update. If an updated + object violates this policy, an error is produced instead. -.. note:: + Note that any object that cannot be selected, cannot be modified either. - Due to an underlying Postgres limitation, :ref:`constraints on object types - ` can only reference properties, not - links. +:eql:synopsis:`update` + This is just a shorthand for :eql:synopsis:`update read` and + :eql:synopsis:`update write`. -Here's a policy that limits the number of blog posts a ``User`` can post. + Note that any object that cannot be selected, cannot be modified either. -.. code-block:: sdl-diff - :version-lt: 3.0 +:eql:synopsis:`using ` + Specifies what the policy is with respect to a given eligible (based on + :eql:synopsis:`when` clause) object. The :eql:synopsis:`` has to be + a :eql:type:`bool` expression. The specific meaning of this value also + depends on whether this policy flavor is :eql:synopsis:`allow` or + :eql:synopsis:`deny`. - type User { - required property email -> str { constraint exclusive; } - + multi link posts := .`. - type BlogPost { - required property title -> str; - required link author -> User; + When omitted, it is assumed that this policy applies to all eligible + objects of a given type. - access policy author_has_full_access - allow all - using (global current_user ?= .author.id); - + access policy max_posts_limit - + deny insert - + using (count(.author.posts) > 500); - } +:eql:synopsis:`set errmessage := ` + Set a custom error message of :eql:synopsis:`` that is displayed + when this access policy prevents a write action. -.. code-block:: sdl-diff - :version-lt: 4.0 +:sdl:synopsis:`` + Set access policy :ref:`annotation ` + to a given *value*. - type User { - required email: str { constraint exclusive; } - + multi link posts := . 500); - } +.. _ref_eql_ddl_access_policies: -.. code-block:: sdl-diff +DDL commands +============ - type User { - required email: str { constraint exclusive; } - + multi posts := . 500); - } +:eql-statement: + +Define a new object access policy on a type: + +.. eql:synopsis:: + + [ with [, ...] ] + { create | alter } type "{" + [ ... ] + create access policy + [ when () ; ] + { allow | deny } action [, action ... ; ] + [ using () ; ] + [ "{" + [ set errmessage := value ; ] + [ create annotation := value ; ] + "}" ] + "}" + + # where is one of + all + select + insert + delete + update [{ read | write }] + +See the meaning of each parameter in the `Declaring access policies`_ section. + +The following subcommands are allowed in the ``create access policy`` block: + +:eql:synopsis:`set errmessage := ` + Set a custom error message of :eql:synopsis:`` that is displayed + when this access policy prevents a write action. + +:eql:synopsis:`create annotation := ` + Set access policy annotation :eql:synopsis:`` to + :eql:synopsis:``. + + See :eql:stmt:`create annotation` for details. + + +Alter access policy +------------------- + +:eql-statement: + +Modify an existing access policy: + +.. eql:synopsis:: + + [ with [, ...] ] + alter type "{" + [ ... ] + alter access policy "{" + [ when () ; ] + [ reset when ; ] + { allow | deny } [, ... ; ] + [ using () ; ] + [ set errmessage := value ; ] + [ reset expression ; ] + [ create annotation := ; ] + [ alter annotation := ; ] + [ drop annotation ; ] + "}" + "}" + +You can change the policy's condition, actions, or error message, or add/drop +annotations. + +The parameters describing the action policy are identical to the parameters +used by ``create action policy``. There are a handful of additional +subcommands that are allowed in the ``alter access policy`` block: + +:eql:synopsis:`reset when` + Clear the :eql:synopsis:`when ()` so that the policy applies to + all objects of a given type. This is equivalent to ``when (true)``. + +:eql:synopsis:`reset expression` + Clear the :eql:synopsis:`using ()` so that the policy always + passes. This is equivalent to ``using (true)``. + +:eql:synopsis:`alter annotation ;` + Alter access policy annotation :eql:synopsis:``. + See :eql:stmt:`alter annotation` for details. + +:eql:synopsis:`drop annotation ;` + Remove access policy annotation :eql:synopsis:``. + See :eql:stmt:`drop annotation` for details. + + +All the subcommands allowed in the ``create access policy`` block are also +valid subcommands for ``alter access policy`` block. + +Drop access policy +------------------ + +:eql-statement: + +Remove an existing policy: -.. list-table:: - :class: seealso +.. eql:synopsis:: - * - **See also** - * - :ref:`SDL > Access policies ` - * - :ref:`DDL > Access policies ` + [ with [, ...] ] + alter type "{" + [ ... ] + drop access policy ; + "}" diff --git a/docs/datamodel/aliases.rst b/docs/datamodel/aliases.rst index d48c4f309d1..587c9eb4c3f 100644 --- a/docs/datamodel/aliases.rst +++ b/docs/datamodel/aliases.rst @@ -4,124 +4,101 @@ Aliases ======= -.. important:: +.. index:: alias, virtual type - This section assumes a basic understanding of EdgeQL. If you aren't familiar - with it, feel free to skip this page for now. +You can think of *aliases* as a way to give schema names to arbitrary EdgeQL +expressions. You can later refer to aliases in queries and in other aliases. +Aliases are functionally equivalent to expression aliases defined in EdgeQL +statements in :ref:`with block `, but are available +to all queries using the schema and can be introspected. -An **alias** is a *pointer* to a set of values. This set is defined with an -arbitrary EdgeQL expression. +Like computed properties, the aliased expression is evaluated on the fly +whenever the alias is referenced. -Like computed properties, this expression is evaluated on the fly whenever the -alias is referenced in a query. Unlike computed properties, aliases are -defined independent of an object type; they are standalone expressions. -As such, aliases are fairly open ended. Some examples are: -**Scalar alias** +Scalar alias +============ .. code-block:: sdl + # in your schema: alias digits := {0,1,2,3,4,5,6,7,8,9}; -**Object type alias** +Later, in some query: + +.. code-block:: edgeql + + select count(digits); + + +Object type alias +================= The name of a given object type (e.g. ``User``) is itself a pointer to the *set of all User objects*. After declaring the alias below, you can use ``User`` and -``UserAlias`` interchangably. +``UserAlias`` interchangeably: .. code-block:: sdl alias UserAlias := User; -**Object type alias with computeds** +Object type alias with computeds +================================ -Object type aliases can include a *shape* that declare additional computed -properties or links. +Object type aliases can include a *shape* that declares additional computed +properties or links: .. code-block:: sdl - :version-lt: 3.0 - type Post { - required property title -> str; - } + type Post { + required title: str; + } - alias PostAlias := Post { - trimmed_title := str_trim(.title) - } + alias PostWithTrimmedTitle := Post { + trimmed_title := str_trim(.title) + } -.. code-block:: sdl - - type Post { - required title: str; - } +Later, in some query: - alias PostAlias := Post { - trimmed_title := str_trim(.title) - } +.. code-block:: edgeql -In effect, this creates a *virtual subtype* of the base type, which can be -referenced in queries just like any other type. + select PostWithTrimmedTitle { + trimmed_title + }; -**Other arbitrary expressions** +Arbitrary expressions +===================== Aliases can correspond to any arbitrary EdgeQL expression, including entire queries. .. code-block:: sdl - :version-lt: 3.0 - - # Tuple alias - alias Color := ("Purple", 128, 0, 128); - - # Named tuple alias - alias GameInfo := ( - name := "Li Europan Lingues", - country := "Iceland", - date_published := 2023, - creators := ( - (name := "Bob Bobson", age := 20), - (name := "Trina TrinadΓ³ttir", age := 25), - ), - ); - - type BlogPost { - required property title -> str; - required property is_published -> bool; - } - - # Query alias - alias PublishedPosts := ( - select BlogPost - filter .is_published = true - ); -.. code-block:: sdl - - # Tuple alias - alias Color := ("Purple", 128, 0, 128); - - # Named tuple alias - alias GameInfo := ( - name := "Li Europan Lingues", - country := "Iceland", - date_published := 2023, - creators := ( - (name := "Bob Bobson", age := 20), - (name := "Trina TrinadΓ³ttir", age := 25), - ), - ); - - type BlogPost { - required title: str; - required is_published: bool; - } - - # Query alias - alias PublishedPosts := ( - select BlogPost - filter .is_published = true - ); + # Tuple alias + alias Color := ("Purple", 128, 0, 128); + + # Named tuple alias + alias GameInfo := ( + name := "Li Europan Lingues", + country := "Iceland", + date_published := 2023, + creators := ( + (name := "Bob Bobson", age := 20), + (name := "Trina TrinadΓ³ttir", age := 25), + ), + ); + + type BlogPost { + required title: str; + required is_published: bool; + } + + # Query alias + alias PublishedPosts := ( + select BlogPost + filter .is_published = true + ); .. note:: @@ -129,11 +106,127 @@ queries. `. +.. _ref_eql_sdl_aliases: +.. _ref_eql_sdl_aliases_syntax: + +Defining aliases +================ + +Syntax +------ + +Define a new alias corresponding to the :ref:`more explicit DDL +commands `. + +.. sdl:synopsis:: + + alias := ; + + alias "{" + using ; + [ ] + "}" ; + +Where: + +:eql:synopsis:`` + The name (optionally module-qualified) of an alias to be created. + +:eql:synopsis:`` + The aliased expression. Must be a :ref:`Stable ` + EdgeQL expression. + +The valid SDL sub-declarations are listed below: + +:sdl:synopsis:`` + Set alias :ref:`annotation ` + to a given *value*. + + +.. _ref_eql_ddl_aliases: + +DDL commands +============ + +This section describes the low-level DDL commands for creating and +dropping aliases. You typically don't need to use these commands +directly, but knowing about them is useful for reviewing migrations. + +Create alias +------------ + +:eql-statement: +:eql-haswith: + +Define a new alias in the schema. + +.. eql:synopsis:: + + [ with [, ...] ] + create alias := ; + + [ with [, ...] ] + create alias "{" + using ; + [ create annotation := ; ... ] + "}" ; + + # where is: + + [ := ] module + +Parameters +^^^^^^^^^^ + +Most sub-commands and options of this command are identical to the +:ref:`SDL alias declaration `, with some +additional features listed below: + +:eql:synopsis:`[ := ] module ` + An optional list of module alias declarations to be used in the + alias definition. + +:eql:synopsis:`create annotation := ;` + An optional list of annotation values for the alias. + See :eql:stmt:`create annotation` for details. + +Example +^^^^^^^ + +Create a new alias: + +.. code-block:: edgeql + + create alias Superusers := ( + select User filter User.groups.name = 'Superusers' + ); + + +Drop alias +---------- + +:eql-statement: +:eql-haswith: + +Remove an alias from the schema. + +.. eql:synopsis:: + + [ with [, ...] ] + drop alias ; + +Parameters +^^^^^^^^^^ + +*alias-name* + The name (optionally qualified with a module name) of an existing + expression alias. + +Example +^^^^^^^ + +Remove an alias: -.. list-table:: - :class: seealso +.. code-block:: edgeql - * - **See also** - * - :ref:`SDL > Aliases ` - * - :ref:`DDL > Aliases ` - * - :ref:`Cheatsheets > Aliases ` + drop alias SuperUsers; diff --git a/docs/datamodel/annotations.rst b/docs/datamodel/annotations.rst index 558fcb6c3f4..1ddb58929cb 100644 --- a/docs/datamodel/annotations.rst +++ b/docs/datamodel/annotations.rst @@ -1,56 +1,53 @@ .. _ref_datamodel_annotations: +.. _ref_eql_sdl_annotations: =========== Annotations =========== -*Annotations* are named values associated with schema items and -are designed to hold arbitrary schema-level metadata represented as a -:eql:type:`str`. +.. index:: annotation +*Annotations* are named values associated with schema items and are +designed to hold arbitrary schema-level metadata represented as a +:eql:type:`str` (unstructured text). -Standard annotations --------------------- +Users can store JSON-encoded data in annotations if they need to store +more complex metadata. -There are a number of annotations defined in the standard library. -The following are the annotations which can be set on any schema item: -- ``title`` -- ``description`` -- ``deprecated`` +Standard annotations +==================== -For example, consider the following declaration: +.. index:: title, description, deprecated -.. code-block:: sdl - :version-lt: 3.0 +There are a number of annotations defined in the standard library. The +following are the annotations which can be set on any schema item: - type Status { - annotation title := 'Activity status'; - annotation description := 'All possible user activities'; +- ``std::title`` +- ``std::description`` +- ``std::deprecated`` - required property name -> str { - constraint exclusive - } - } +For example, consider the following declaration: .. code-block:: sdl - type Status { - annotation title := 'Activity status'; - annotation description := 'All possible user activities'; + type Status { + annotation title := 'Activity status'; + annotation description := 'All possible user activities'; - required name: str { - constraint exclusive - } + required name: str { + constraint exclusive } + } -The ``deprecated`` annotation is used to mark deprecated items (e.g. -:eql:func:`str_rpad`) and to provide some information such as what +And the ``std::deprecated`` annotation can be used to mark deprecated items +(e.g., :eql:func:`str_rpad`) and to provide some information such as what should be used instead. - User-defined annotations ------------------------- +======================== + +.. index:: abstract annotation To declare a custom annotation type beyond the three built-ins, add an abstract annotation type to your schema. A custom annotation could be used to attach @@ -66,12 +63,328 @@ and code generation. } +.. _ref_eql_sdl_annotations_syntax: + +Declaring annotations +===================== + +This section describes the syntax to use annotations in your schema. + +Syntax +------ + +.. sdl:synopsis:: + + # Abstract annotation form: + abstract [ inheritable ] annotation + [ "{" ; [...] "}" ] ; + + # Concrete annotation (same as ) form: + annotation := ; + +Description +^^^^^^^^^^^ + +There are two forms of annotation declarations: abstract and concrete. +The *abstract annotation* form is used for declaring new kinds of +annotation in a module. The *concrete annotation* declarations are +used as sub-declarations for all other declarations in order to +actually annotate them. + +The annotation declaration options are as follows: + +:eql:synopsis:`abstract` + If specified, the annotation will be *abstract*. + +:eql:synopsis:`inheritable` + If specified, the annotation will be *inheritable*. The + annotations are non-inheritable by default. That is, if a schema + item has an annotation defined on it, the descendants of that + schema item will not automatically inherit the annotation. Normal + inheritance behavior can be turned on by declaring the annotation + with the ``inheritable`` qualifier. This is only valid for *abstract + annotation*. + +:eql:synopsis:`` + The name (optionally module-qualified) of the annotation. + +:eql:synopsis:`` + Any string value that the specified annotation is intended to have + for the given context. + +The only valid SDL sub-declarations are *concrete annotations*: + +:sdl:synopsis:`` + Annotations can also have annotations. Set the *annotation* of the + enclosing annotation to a specific value. + + +.. _ref_eql_ddl_annotations: + +DDL commands +============ + +This section describes the low-level DDL commands for creating, altering, +and dropping annotations and abstract annotations. You typically don't need to +use these commands directly, but knowing about them is useful for reviewing +migrations. + + +Create abstract annotation +-------------------------- + +:eql-statement: + +Define a new annotation. + +.. eql:synopsis:: + + [ with [, ...] ] + create abstract [ inheritable ] annotation + [ + "{" + create annotation := ; + [...] + "}" + ] ; + +Description +^^^^^^^^^^^ + +The command ``create abstract annotation`` defines a new annotation +for use in the current Gel database. + +If *name* is qualified with a module name, then the annotation is created +in that module, otherwise it is created in the current module. +The annotation name must be distinct from that of any existing schema item +in the module. + +The annotations are non-inheritable by default. That is, if a schema item +has an annotation defined on it, the descendants of that schema item will +not automatically inherit the annotation. Normal inheritance behavior can +be turned on by declaring the annotation with the ``inheritable`` qualifier. + +Most sub-commands and options of this command are identical to the +:ref:`SDL annotation declaration `. +There's only one subcommand that is allowed in the ``create +annotation`` block: + +:eql:synopsis:`create annotation := ` + Annotations can also have annotations. Set the + :eql:synopsis:`` of the + enclosing annotation to a specific :eql:synopsis:``. + See :eql:stmt:`create annotation` for details. + +Example +^^^^^^^ + +Declare an annotation ``extrainfo``: + +.. code-block:: edgeql + + create abstract annotation extrainfo; + + +Alter abstract annotation +------------------------- + +:eql-statement: + +Change the definition of an annotation. + +.. eql:synopsis:: + + alter abstract annotation + [ "{" ] ; [...] [ "}" ]; + + # where is one of + + rename to + create annotation := + alter annotation := + drop annotation + +Description +^^^^^^^^^^^ + +:eql:synopsis:`alter abstract annotation` changes the definition of an +abstract annotation. + +Parameters +^^^^^^^^^^ + +:eql:synopsis:`` + The name (optionally module-qualified) of the annotation to alter. + +The following subcommands are allowed in the ``alter abstract annotation`` +block: + +:eql:synopsis:`rename to ` + Change the name of the annotation to :eql:synopsis:``. + +:eql:synopsis:`alter annotation := ` + Annotations can also have annotations. Change + :eql:synopsis:`` to a specific + :eql:synopsis:``. See :eql:stmt:`alter annotation` for + details. + +:eql:synopsis:`drop annotation ` + Annotations can also have annotations. Remove annotation + :eql:synopsis:``. + See :eql:stmt:`drop annotation` for details. + +All the subcommands allowed in the ``create abstract annotation`` +block are also valid subcommands for ``alter annotation`` block. + +Example +^^^^^^^ + +Rename an annotation: + +.. code-block:: edgeql + + alter abstract annotation extrainfo + rename to extra_info; + + +Drop abstract annotation +------------------------ + +:eql-statement: + +Drop a schema annotation. + +.. eql:synopsis:: + + [ with [, ...] ] + drop abstract annotation ; + +Description +^^^^^^^^^^^ + +The command ``drop abstract annotation`` removes an existing schema +annotation from the database schema. Note that the ``inheritable`` +qualifier is not necessary in this statement. + +Example +^^^^^^^ + +Drop the annotation ``extra_info``: + +.. code-block:: edgeql + + drop abstract annotation extra_info; + + +Create annotation +----------------- + +:eql-statement: + +Define an annotation value for a given schema item. + +.. eql:synopsis:: + + create annotation := + +Description +^^^^^^^^^^^ + +The command ``create annotation`` defines an annotation for a schema item. + +:eql:synopsis:`` refers to the name of a defined annotation, +and :eql:synopsis:`` must be a constant EdgeQL expression +evaluating into a string. + +This statement can only be used as a subcommand in another +DDL statement. + +Example +^^^^^^^ + +Create an object type ``User`` and set its ``title`` annotation to +``"User type"``. + +.. code-block:: edgeql + + create type User { + create annotation title := "User type"; + }; + + +Alter annotation +---------------- + +:eql-statement: + +Alter an annotation value for a given schema item. + +.. eql:synopsis:: + + alter annotation := + +Description +^^^^^^^^^^^ + +The command ``alter annotation`` alters an annotation value on a schema item. + +:eql:synopsis:`` refers to the name of a defined annotation, +and :eql:synopsis:`` must be a constant EdgeQL expression +evaluating into a string. + +This statement can only be used as a subcommand in another +DDL statement. + +Example +^^^^^^^ + +Alter an object type ``User`` and alter the value of its previously set +``title`` annotation to ``"User type"``. + +.. code-block:: edgeql + + alter type User { + alter annotation title := "User type"; + }; + + +Drop annotation +--------------- + +:eql-statement: + +Remove an annotation from a given schema item. + +.. eql:synopsis:: + + drop annotation ; + +Description +^^^^^^^^^^^ + +The command ``drop annotation`` removes an annotation value from a schema item. + +:eql:synopsis:`` refers to the name of a defined annotation. +The annotation value does not have to exist on a schema item. + +This statement can only be used as a subcommand in another +DDL statement. + +Example +^^^^^^^ + +Drop the ``title`` annotation from the ``User`` object type: + +.. code-block:: edgeql + + alter type User { + drop annotation title; + }; + + .. list-table:: :class: seealso * - **See also** - * - :ref:`SDL > Annotations ` - * - :ref:`DDL > Annotations ` * - :ref:`Cheatsheets > Annotations ` - * - :ref:`Introspection > Object types - ` + * - :ref:`Introspection > Object types ` diff --git a/docs/datamodel/comparison.rst b/docs/datamodel/comparison.rst index 55a7cf538fb..2dc778df388 100644 --- a/docs/datamodel/comparison.rst +++ b/docs/datamodel/comparison.rst @@ -4,7 +4,7 @@ vs SQL and ORMs =============== -EdgeDB's approach to schema modeling builds upon the foundation of SQL while +|Gel's| approach to schema modeling builds upon the foundation of SQL while taking cues from modern tools like ORM libraries. Let's see how it stacks up. .. _ref_datamodel_sql_comparison: @@ -33,21 +33,9 @@ to query across tables. director_id uuid REFERENCES people(id) ); -In EdgeDB, connections between tables are represented with :ref:`Links +In |Gel|, connections between tables are represented with :ref:`Links `. -.. code-block:: sdl - :version-lt: 3.0 - - type Movie { - required property title -> str; - required link director -> Person; - } - - type Person { - required property name -> str; - } - .. code-block:: sdl type Movie { @@ -94,6 +82,6 @@ downsides too. the ORM library, not the maintainers of the database itself. Quality control and long-term maintenance is not always guaranteed. -From the beginning, EdgeDB was designed to incorporate the best aspects of ORMs +From the beginning, Gel was designed to incorporate the best aspects of ORMs β€” declarative modeling, object-oriented APIs, and intuitive querying β€” without the drawbacks. diff --git a/docs/datamodel/computeds.rst b/docs/datamodel/computeds.rst index bf1c77b2368..8562f92f53b 100644 --- a/docs/datamodel/computeds.rst +++ b/docs/datamodel/computeds.rst @@ -6,6 +6,8 @@ Computeds :edb-alt-title: Computed properties and links +.. index:: computeds, :=, __source__, backlinks + .. important:: This section assumes a basic understanding of EdgeQL. If you aren't familiar @@ -15,23 +17,8 @@ Object types can contain *computed* properties and links. Computed properties and links are not persisted in the database. Instead, they are evaluated *on the fly* whenever that field is queried. Computed properties must be declared with the ``property`` keyword and computed links must be declared with the -``link`` keyword in EdgeDB versions prior to 4.0. - -.. code-block:: sdl - :version-lt: 3.0 - - type Person { - property name -> str; - property all_caps_name := str_upper(__source__.name); - } - -.. code-block:: sdl - :version-lt: 4.0 +``link`` keyword in |EdgeDB| versions prior to 4.0. - type Person { - name: str; - property all_caps_name := str_upper(__source__.name); - } .. code-block:: sdl @@ -73,24 +60,6 @@ However, explicitly using ``__source__`` is optional here; inside the scope of an object type declaration, you can omit it entirely and use the ``.`` shorthand. -.. code-block:: sdl - :version-lt: 3.0 - - type Person { - property first_name -> str; - property last_name -> str; - property full_name := .first_name ++ ' ' ++ .last_name; - } - -.. code-block:: sdl - :version-lt: 4.0 - - type Person { - first_name: str; - last_name: str; - property full_name := .first_name ++ ' ' ++ .last_name; - } - .. code-block:: sdl type Person { @@ -109,26 +78,6 @@ makes the schema more readable and acts as a sanity check: if the provided EdgeQL expression disagrees with the modifiers, an error will be thrown the next time you try to :ref:`create a migration `. -.. code-block:: sdl - :version-lt: 3.0 - - type Person { - property first_name -> str; - - # this is invalid, because first_name is not a required property - required property first_name_upper := str_upper(.first_name); - } - -.. code-block:: sdl - :version-lt: 4.0 - - type Person { - first_name: str; - - # this is invalid, because first_name is not a required property - required property first_name_upper := str_upper(.first_name); - } - .. code-block:: sdl type Person { @@ -147,36 +96,6 @@ Filtering If you find yourself writing the same ``filter`` expression repeatedly in queries, consider defining a computed field that encapsulates the filter. -.. code-block:: sdl - :version-lt: 3.0 - - type Club { - multi link members -> Person; - multi link active_members := ( - select .members filter .is_active = true - ) - } - - type Person { - property name -> str; - property is_active -> bool; - } - -.. code-block:: sdl - :version-lt: 4.0 - - type Club { - multi members: Person; - multi link active_members := ( - select .members filter .is_active = true - ) - } - - type Person { - name: str; - is_active: bool; - } - .. code-block:: sdl type Club { @@ -196,36 +115,10 @@ queries, consider defining a computed field that encapsulates the filter. Backlinks ^^^^^^^^^ -Backlinks are one of the most common use cases for computed links. In EdgeDB +Backlinks are one of the most common use cases for computed links. In |Gel| links are *directional*; they have a source and a target. Often it's convenient to traverse a link in the *reverse* direction. -.. code-block:: sdl - :version-lt: 3.0 - - type BlogPost { - property title -> str; - link author -> User; - } - - type User { - property name -> str; - multi link blog_posts := .`, +:ref:`links`, +:ref:`object types `, +and :ref:`custom scalars `. -Constraints give users fine-grained control over which data is considered -valid. They can be defined on :ref:`properties `, -:ref:`links `, :ref:`object types -`, and :ref:`custom scalars -`. - -Below is a simple property constraint. - -.. code-block:: sdl - :version-lt: 3.0 - - type User { - required property username -> str { - constraint exclusive; - } - } - -.. code-block:: sdl - - type User { - required username: str { - constraint exclusive; - } - } .. _ref_datamodel_constraints_builtin: -This example uses a built-in constraint, ``exclusive``. Refer to the table -below for a complete list; click the name of a given constraint for the full -documentation. +Standard constraints +==================== + +|Gel| includes a number of standard ready-to-use constraints: .. include:: ../stdlib/constraint_table.rst -.. _ref_datamodel_constraints_properties: Constraints on properties -------------------------- - -The ``max_len_value`` constraint below uses the built-in :eql:func:`len` -function, which returns the length of a string. - -.. code-block:: sdl - :version-lt: 3.0 +========================= - type User { - required property username -> str { - # usernames must be unique - constraint exclusive; - - # max length (built-in) - constraint max_len_value(25); - }; - } +Example: enforce all ``User`` objects to have a unique ``username`` +no longer than 25 characters: .. code-block:: sdl - type User { - required username: str { - # usernames must be unique - constraint exclusive; + type User { + required username: str { + # usernames must be unique + constraint exclusive; - # max length (built-in) - constraint max_len_value(25); - }; - } - -Custom constraints -^^^^^^^^^^^^^^^^^^ - -The ``expression`` constraint is used to define custom constraint logic. Inside -custom constraints, the keyword ``__subject__`` can used to reference the -*value* being constrained. - -.. code-block:: sdl - :version-lt: 3.0 - - type User { - required property username -> str { - # max length (as custom constraint) - constraint expression on (len(__subject__) <= 25); - }; - } - -.. code-block:: sdl - - type User { - required username: str { - # max length (as custom constraint) - constraint expression on (len(__subject__) <= 25); - }; - } + # max length (built-in) + constraint max_len_value(25); + }; + } .. _ref_datamodel_constraints_objects: Constraints on object types ---------------------------- +=========================== + +.. index:: __subject__ Constraints can be defined on object types. This is useful when the constraint logic must reference multiple links or properties. -.. important:: - - Inside an object type declaration, you can omit ``__subject__`` and simply - refer to properties with the :ref:`leading dot notation ` - (e.g. ``.``). +Example: enforce that the magnitude of ``ConstrainedVector`` objects +is no more than 5 .. code-block:: sdl - :version-lt: 3.0 - type ConstrainedVector { - required property x -> float64; - required property y -> float64; + type ConstrainedVector { + required x: float64; + required y: float64; - constraint expression on ( - .x ^ 2 + .y ^ 2 <= 25 - ); - } + constraint expression on ( + (.x ^ 2 + .y ^ 2) ^ 0.5 <= 5 + # or, long form: `(__subject__.x + __subject__.y) ^ 0.5 <= 5` + ); + } -.. code-block:: sdl +The ``expression`` constraint is used here to define custom constraint logic. +Inside constraints, the keyword ``__subject__`` can be used to reference the +*value* being constrained. - type ConstrainedVector { - required x: float64; - required y: float64; +.. note:: + Note that inside an object type declaration, you can omit ``__subject__`` + and simply refer to properties with the + :ref:`leading dot notation ` (e.g. ``.property``). - constraint expression on ( - .x ^ 2 + .y ^ 2 <= 25 - ); - } +.. note:: -Note that the constraint expression cannot contain arbitrary EdgeQL! Due to -how constraints are implemented, you can only reference ``single`` (non-multi) -properties and links defined on the object type. + Also note that the constraint expression are fairly restricted. Due + to how constraints are implemented, you can only reference ``single`` + (non-multi) properties and links defined on the object type: -.. code-block:: sdl - :version-lt: 3.0 + .. code-block:: sdl - # Not valid! - type User { - required property username -> str; - multi link friends -> User; + # Not valid! + type User { + required username: str; + multi friends: User; - # ❌ constraints cannot contain paths with more than one hop - constraint expression on ('bob' in .friends.username); - } + # ❌ constraints cannot contain paths with more than one hop + constraint expression on ('bob' in .friends.username); + } + +Abstract constraints +==================== + +You can re-use constraints across multiple object types by declaring them as +abstract constraints. Example: .. code-block:: sdl - # Not valid! - type User { - required username: str; - multi friends: User; + abstract constraint min_value(min: anytype) { + errmessage := + 'Minimum allowed value for {__subject__} is {min}.'; - # ❌ constraints cannot contain paths with more than one hop - constraint expression on ('bob' in .friends.username); + using (__subject__ >= min); } -Computed constraints -^^^^^^^^^^^^^^^^^^^^ + # use it like this: -Constraints can be defined on computed properties. + scalar type posint64 extending int64 { + constraint min_value(0); + } -.. code-block:: sdl - :version-lt: 3.0 + # or like this: type User { - required property username -> str; - required property clean_username := str_trim(str_lower(.username)); - - constraint exclusive on (.clean_username); + required age: int16 { + constraint min_value(12); + }; } -.. code-block:: sdl - :version-lt: 4.0 - type User { - required username: str; - required property clean_username := str_trim(str_lower(.username)); +Computed constraints +==================== - constraint exclusive on (.clean_username); - } +Constraints can be defined on computed properties: .. code-block:: sdl - type User { - required username: str; - required clean_username := str_trim(str_lower(.username)); + type User { + required username: str; + required clean_username := str_trim(str_lower(.username)); - constraint exclusive on (.clean_username); - } + constraint exclusive on (.clean_username); + } Composite constraints -^^^^^^^^^^^^^^^^^^^^^ +===================== + +.. index:: tuple To define a composite constraint, create an ``exclusive`` constraint on a tuple of properties or links. .. code-block:: sdl - :version-lt: 3.0 - - type User { - property username -> str; - } - type BlogPost { - property title -> str; - link author -> User; + type User { + username: str; + } - constraint exclusive on ((.title, .author)); - } + type BlogPost { + title: str; -.. code-block:: sdl + author: User; - type User { - username: str; - } - - type BlogPost { - title: str; - author: User; - - constraint exclusive on ((.title, .author)); - } + constraint exclusive on ((.title, .author)); + } .. _ref_datamodel_constraints_partial: Partial constraints -^^^^^^^^^^^^^^^^^^^ - -.. versionadded:: 2.0 +=================== -Constraints on object types can be made partial, so that they don't apply -when some condition holds. +.. index:: constraint exclusive on, except -.. code-block:: sdl - :version-lt: 3.0 - - type User { - required property username -> str; - property deleted -> bool; - - # Usernames must be unique unless marked deleted - constraint exclusive on (.username) except (.deleted); - } +Constraints on object types can be made partial, so that they are not enforced +when the specified ``except`` condition is met. .. code-block:: sdl - type User { - required username: str; - deleted: bool; - - # Usernames must be unique unless marked deleted - constraint exclusive on (.username) except (.deleted); - } + type User { + required username: str; + deleted: bool; + # Usernames must be unique unless marked deleted + constraint exclusive on (.username) except (.deleted); + } -.. _ref_datamodel_constraints_links: Constraints on links --------------------- +==================== You can constrain links such that a given object can only be linked once by using :eql:constraint:`exclusive`: .. code-block:: sdl - :version-lt: 3.0 - type User { - required property name -> str; + type User { + required name: str; - # Make sure none of the "owned" items belong - # to any other user. - multi link owns -> Item { - constraint exclusive; - } + # Make sure none of the "owned" items belong + # to any other user. + multi owns: Item { + constraint exclusive; } + } -.. code-block:: sdl - - type User { - required name: str; - - # Make sure none of the "owned" items belong - # to any other user. - multi owns: Item { - constraint exclusive; - } - } Link property constraints -^^^^^^^^^^^^^^^^^^^^^^^^^ +========================= You can also add constraints for :ref:`link properties `: .. code-block:: sdl - :version-lt: 3.0 - type User { - property name -> str; - multi link friends -> User { - single property strength -> float64; - constraint expression on ( - @strength >= 0 - ); - } - } + type User { + name: str; -.. code-block:: sdl + multi friends: User { + strength: float64; - type User { - name: str; - multi friends: User { - strength: float64; - constraint expression on ( - @strength >= 0 - ); - } + constraint expression on ( + @strength >= 0 + ); } + } -Link ``@source`` and ``@target`` constraints -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. versionadded:: 4.0 -.. note:: +Link's "@source" and "@target" +============================== - ``@source`` and ``@target`` are available starting with version 4.3. +.. index:: constraint exclusive on, @source, @target You can create a composite exclusive constraint on the object linking/linked *and* a link property by using ``@source`` or ``@target`` respectively. Here's @@ -344,18 +235,20 @@ checked them out: .. code-block:: sdl - type Book { - required title: str; - } - type User { - name: str; - multi checked_out: Book { - date: cal::local_date; - # Ensures a given Book can be checked out - # only once on a given day. - constraint exclusive on ((@target, @date)); - } + type Book { + required title: str; + } + + type User { + name: str; + multi checked_out: Book { + date: cal::local_date; + + # Ensures a given Book can be checked out + # only once on a given day. + constraint exclusive on ((@target, @date)); } + } Here, the constraint ensures that no book can be checked out to two ``User``\s on the same ``@date``. @@ -365,24 +258,26 @@ player picks in a color-based memory game: .. code-block:: sdl - type Player { - required name: str; - multi picks: Color { - order: int16; - constraint exclusive on ((@source, @order)); - } - } - type Color { - required name: str; + type Player { + required name: str; + + multi picks: Color { + order: int16; + + constraint exclusive on ((@source, @order)); } + } + + type Color { + required name: str; + } This constraint ensures that a single ``Player`` cannot pick two ``Color``\s at the same ``@order``. -.. _ref_datamodel_constraints_scalars: Constraints on custom scalars ------------------------------ +============================= Custom scalar types can be constrained. @@ -409,59 +304,49 @@ using arbitrary EdgeQL expressions. The example below uses the built-in } -Constraints and type inheritence --------------------------------- +Constraints and inheritance +=========================== + +.. index:: delegated constraint If you define a constraint on a type and then extend that type, the constraint will *not* be applied individually to each extending type. Instead, it will apply globally across all the types that inherited the constraint. -.. code-block:: sdl - :version-lt: 3.0 - - type User { - required property name -> str { - constraint exclusive; - } - } - type Administrator extending User; - type Moderator extending User; - .. code-block:: sdl - type User { - required name: str { - constraint exclusive; - } + type User { + required name: str { + constraint exclusive; } - type Administrator extending User; - type Moderator extending User; + } + type Administrator extending User; + type Moderator extending User; .. code-block:: edgeql-repl - db> insert Administrator { - ... name := 'Jan' - ... }; - {default::Administrator {id: 7aeaa146-f5a5-11ed-a598-53ddff476532}} - db> insert Moderator { - ... name := 'Jan' - ... }; - edgedb error: ConstraintViolationError: name violates exclusivity - constraint - Detail: value of property 'name' of object type 'default::Moderator' - violates exclusivity constraint - db> insert User { - ... name := 'Jan' - ... }; - edgedb error: ConstraintViolationError: name violates exclusivity - constraint - Detail: value of property 'name' of object type 'default::User' - violates exclusivity constraint - - -As this example demonstrates, this means if an object of one of the extending -types has a value for a property that is exclusive, an object of a different -extending type cannot have the same value. + gel> insert Administrator { + .... name := 'Jan' + .... }; + {default::Administrator {id: 7aeaa146-f5a5-11ed-a598-53ddff476532}} + + gel> insert Moderator { + .... name := 'Jan' + .... }; + gel error: ConstraintViolationError: name violates exclusivity constraint + Detail: value of property 'name' of object type 'default::Moderator' + violates exclusivity constraint + + gel> insert User { + .... name := 'Jan' + .... }; + gel error: ConstraintViolationError: name violates exclusivity constraint + Detail: value of property 'name' of object type 'default::User' + violates exclusivity constraint + +As this example demonstrates, if an object of one extending type has a value +for a property that is exclusive, an object of a *different* extending type +cannot have the same value. If that's not what you want, you can instead delegate the constraint to the inheriting types by prepending the ``delegated`` keyword to the constraint. @@ -469,62 +354,602 @@ The constraint would then be applied just as if it were declared individually on each of the inheriting types. .. code-block:: sdl - :version-lt: 3.0 - type User { - required property name -> str { - delegated constraint exclusive; - } + type User { + required name: str { + delegated constraint exclusive; } - type Administrator extending User; - type Moderator extending User; + } + type Administrator extending User; + type Moderator extending User; -.. code-block:: sdl +.. code-block:: edgeql-repl - type User { - required name: str { - delegated constraint exclusive; - } - } - type Administrator extending User; - type Moderator extending User; + gel> insert Administrator { + .... name := 'Jan' + .... }; + {default::Administrator {id: 7aeaa146-f5a5-11ed-a598-53ddff476532}} -.. code-block:: edgeql-repl + gel> insert User { + .... name := 'Jan' + .... }; + {default::User {id: a6e3fdaf-c44b-4080-b39f-6a07496de66b}} + + gel> insert Moderator { + .... name := 'Jan' + .... }; + {default::Moderator {id: d3012a3f-0f16-40a8-8884-7203f393b63d}} - db> insert Administrator { - ... name := 'Jan' - ... }; - {default::Administrator {id: 7aeaa146-f5a5-11ed-a598-53ddff476532}} - db> insert User { - ... name := 'Jan' - ... }; - {default::User {id: a6e3fdaf-c44b-4080-b39f-6a07496de66b}} - db> insert Moderator { - ... name := 'Jan' - ... }; - {default::Moderator {id: d3012a3f-0f16-40a8-8884-7203f393b63d}} - db> insert Moderator { - ... name := 'Jan' - ... }; - edgedb error: ConstraintViolationError: name violates exclusivity - constraint - Detail: value of property 'name' of object type 'default::Moderator' - violates exclusivity constraint + gel> insert Moderator { + .... name := 'Jan' + .... }; + gel error: ConstraintViolationError: name violates exclusivity constraint + Detail: value of property 'name' of object type 'default::Moderator' + violates exclusivity constraint With the addition of ``delegated`` to the constraints, the inserts were -successful for each of the types. In this case, we did not hit a constraint -violation until we tried to insert a second ``Moderator`` object with the same -name as the one we had just inserted. +successful for each of the types. We did not hit a constraint violation +until we tried to insert a second ``Moderator`` object with the same +name as the existing one. + + +.. _ref_eql_sdl_constraints_syntax: + +Declaring constraints +===================== + +This section describes the syntax to declare constraints in your schema. + +Syntax +------ + +.. sdl:synopsis:: + + [{abstract | delegated}] constraint [ ( [] [, ...] ) ] + [ on ( ) ] + [ except ( ) ] + [ extending [, ...] ] + "{" + [ using ; ] + [ errmessage := ; ] + [ ] + [ ... ] + "}" ; + + # where is: + + [ : ] { | } + +Description +^^^^^^^^^^^ + +This declaration defines a new constraint with the following options: + +:eql:synopsis:`abstract` + If specified, the constraint will be *abstract*. + +:eql:synopsis:`delegated` + If specified, the constraint is defined as *delegated*, which means + that it will not be enforced on the type it's declared on, and the + enforcement will be delegated to the subtypes of this type. + This is particularly useful for :eql:constraint:`exclusive` + constraints in abstract types. This is only valid for *concrete + constraints*. + +:eql:synopsis:`` + The name (optionally module-qualified) of the new constraint. + +:eql:synopsis:`` + An optional list of constraint arguments. + + For an *abstract constraint* :eql:synopsis:`` optionally + specifies the argument name and :eql:synopsis:`` specifies + the argument type. + + For a *concrete constraint* :eql:synopsis:`` optionally + specifies the argument name and :eql:synopsis:`` specifies + the argument value. The argument value specification must match the + parameter declaration of the abstract constraint. + +:eql:synopsis:`on ( )` + An optional expression defining the *subject* of the constraint. + If not specified, the subject is the value of the schema item on which + the concrete constraint is defined. + + The expression must refer to the original subject of the constraint as + ``__subject__``. The expression must be + :ref:`Immutable `, but may refer to + ``__subject__`` and its properties and links. + + Note also that ```` itself has to + be parenthesized. + +:eql:synopsis:`except ( )` + An optional expression defining a condition to create exceptions to + the constraint. If ```` evaluates to ``true``, + the constraint is ignored for the current subject. If it evaluates + to ``false`` or ``{}``, the constraint applies normally. + + ``except`` may only be declared on object constraints, and otherwise + follows the same rules as ``on``. + +:eql:synopsis:`extending [, ...]` + If specified, declares the *parent* constraints for this abstract + constraint. + +The valid SDL sub-declarations are listed below: + +:eql:synopsis:`using ` + A boolean expression that returns ``true`` for valid data and + ``false`` for invalid data. The expression may refer to the + subject of the constraint as ``__subject__``. This declaration is + only valid for *abstract constraints*. + +:eql:synopsis:`errmessage := ` + An optional string literal defining the error message template + that is raised when the constraint is violated. The template is a + formatted string that may refer to constraint context variables in + curly braces. The template may refer to the following: + + - ``$argname`` -- the value of the specified constraint argument + - ``__subject__`` -- the value of the ``title`` annotation of the + scalar type, property or link on which the constraint is defined. + + If the content of curly braces does not match any variables, + the curly braces are emitted as-is. They can also be escaped by + using double curly braces. + +:sdl:synopsis:`` + Set constraint :ref:`annotation ` + to a given *value*. + + +.. _ref_eql_ddl_constraints: + +DDL commands +============ + +This section describes the low-level DDL commands for creating and dropping +constraints and abstract constraints. You typically don't need to use these +commands directly, but knowing about them is useful for reviewing migrations. + + +Create abstract constraint +-------------------------- + +:eql-statement: +:eql-haswith: + +Define a new abstract constraint. + +.. eql:synopsis:: + + [ with [ := ] module ] + create abstract constraint [ ( [] [, ...] ) ] + [ on ( ) ] + [ extending [, ...] ] + "{" ; [...] "}" ; + + # where is: + + [ : ] + + # where is one of + + using + set errmessage := + create annotation := + + +Description +^^^^^^^^^^^ +The command ``create abstract constraint`` defines a new abstract constraint. + +If *name* is qualified with a module name, then the constraint is created in +that module, otherwise it is created in the current module. The constraint +name must be distinct from that of any existing schema item in the module. + + +Parameters +^^^^^^^^^^ +Most sub-commands and options of this command are identical to the +:ref:`SDL constraint declaration `, +with some additional features listed below: + +:eql:synopsis:`[ := ] module ` + An optional list of module alias declarations to be used in the + migration definition. When *module-alias* is not specified, + *module-name* becomes the effective current module and is used + to resolve all unqualified names. + +:eql:synopsis:`set errmessage := ` + An optional string literal defining the error message template + that is raised when the constraint is violated. Other than a + slight syntactical difference this is the same as the + corresponding SDL declaration. + +:eql:synopsis:`create annotation := ;` + Set constraint annotation ```` to ````. + See :eql:stmt:`create annotation` for details. + + +Example +^^^^^^^ +Create an abstract constraint "uppercase" which checks if the subject +is a string in upper case: + +.. code-block:: edgeql + + create abstract constraint uppercase { + create annotation title := "Upper case constraint"; + + using (str_upper(__subject__) = __subject__); + + set errmessage := "{__subject__} is not in upper case"; + }; + + +Alter abstract constraint +------------------------- + +:eql-statement: +:eql-haswith: + +Alter the definition of an abstract constraint. + +.. eql:synopsis:: + + [ with [ := ] module ] + alter abstract constraint + "{" ; [...] "}" ; + + # where is one of + + rename to + using + set errmessage := + reset errmessage + create annotation := + alter annotation := + drop annotation + + +Description +^^^^^^^^^^^ + +The command ``alter abstract constraint`` changes the definition of an +abstract constraint item. *name* must be a name of an existing +abstract constraint, optionally qualified with a module name. + + +Parameters +^^^^^^^^^^ + +:eql:synopsis:`[ := ] module ` + An optional list of module alias declarations to be used in the + migration definition. When *module-alias* is not specified, + *module-name* becomes the effective current module and is used + to resolve all unqualified names. + +:eql:synopsis:`` + The name (optionally module-qualified) of the constraint to alter. + +Subcommands allowed in the ``alter abstract constraint`` block: + +:eql:synopsis:`rename to ` + Change the name of the constraint to *newname*. All concrete + constraints inheriting from this constraint are also renamed. + +:eql:synopsis:`alter annotation := ` + Alter constraint annotation ````. + See :eql:stmt:`alter annotation` for details. + +:eql:synopsis:`drop annotation ` + Remove annotation ````. + See :eql:stmt:`drop annotation` for details. + +:eql:synopsis:`reset errmessage` + Remove the error message from this abstract constraint. The error message + specified in the base abstract constraint will be used instead. + +All subcommands allowed in a ``create abstract constraint`` block are also +valid here. + + +Example +^^^^^^^ + +Rename the abstract constraint "uppercase" to "upper_case": + +.. code-block:: edgeql + + alter abstract constraint uppercase rename to upper_case; + + +Drop abstract constraint +------------------------ + +:eql-statement: +:eql-haswith: + +Remove an abstract constraint from the schema. + +.. eql:synopsis:: + + [ with [ := ] module ] + drop abstract constraint ; + + +Description +^^^^^^^^^^^ + +The command ``drop abstract constraint`` removes an existing abstract +constraint item from the database schema. If any schema items depending +on this constraint exist, the operation is refused. + + +Parameters +^^^^^^^^^^ + +:eql:synopsis:`[ := ] module ` + An optional list of module alias declarations to be used in the + migration definition. + +:eql:synopsis:`` + The name (optionally module-qualified) of the constraint to remove. + + +Example +^^^^^^^ + +Drop abstract constraint ``upper_case``: + +.. code-block:: edgeql + + drop abstract constraint upper_case; + + +Create constraint +----------------- + +:eql-statement: + +Define a concrete constraint on the specified schema item. + +.. eql:synopsis:: + + [ with [ := ] module ] + create [ delegated ] constraint + [ ( [] [, ...] ) ] + [ on ( ) ] + [ except ( ) ] + "{" ; [...] "}" ; + + # where is: + + [ : ] + + # where is one of + + set errmessage := + create annotation := + + +Description +^^^^^^^^^^^ + +The command ``create constraint`` defines a new concrete constraint. It can +only be used in the context of :eql:stmt:`create scalar`, +:eql:stmt:`alter scalar`, :eql:stmt:`create property`, +:eql:stmt:`alter property`, :eql:stmt:`create link`, or :eql:stmt:`alter link`. + +*name* must be a name (optionally module-qualified) of a previously defined +abstract constraint. + + +Parameters +^^^^^^^^^^ + +Most sub-commands and options of this command are identical to the +:ref:`SDL constraint declaration `, +with some additional features listed below: + +:eql:synopsis:`[ := ] module ` + An optional list of module alias declarations to be used in the + migration definition. + +:eql:synopsis:`set errmessage := ` + An optional string literal defining the error message template + that is raised when the constraint is violated. Other than a + slight syntactical difference, this is the same as the corresponding + SDL declaration. + +:eql:synopsis:`create annotation := ;` + An optional list of annotations for the constraint. See + :eql:stmt:`create annotation` for details. + + +Example +^^^^^^^ + +Create a "score" property on the "User" type with a minimum value +constraint: + +.. code-block:: edgeql + + alter type User create property score -> int64 { + create constraint min_value(0) + }; + +Create a Vector with a maximum magnitude: + +.. code-block:: edgeql + + create type Vector { + create required property x -> float64; + create required property y -> float64; + create constraint expression ON ( + __subject__.x^2 + __subject__.y^2 < 25 + ); + } + + +Alter constraint +---------------- + +:eql-statement: + +Alter the definition of a concrete constraint on the specified schema item. + +.. eql:synopsis:: + + [ with [ := ] module [, ...] ] + alter constraint + [ ( [] [, ...] ) ] + [ on ( ) ] + [ except ( ) ] + "{" ; [ ... ] "}" ; + + # -- or -- + + [ with [ := ] module [, ...] ] + alter constraint + [ ( [] [, ...] ) ] + [ on ( ) ] + ; + + # where is one of: + + set delegated + set not delegated + set errmessage := + reset errmessage + create annotation := + alter annotation + drop annotation + + +Description +^^^^^^^^^^^ + +The command ``alter constraint`` changes the definition of a concrete +constraint. Both single- and multi-command forms are supported. + + +Parameters +^^^^^^^^^^ + +:eql:synopsis:`[ := ] module ` + An optional list of module alias declarations for the migration. + +:eql:synopsis:`` + The name (optionally module-qualified) of the concrete constraint + that is being altered. + +:eql:synopsis:`` + A list of constraint arguments as specified at the time of + ``create constraint``. + +:eql:synopsis:`on ( )` + An expression defining the *subject* of the constraint as specified + at the time of ``create constraint``. + +The following subcommands are allowed in the ``alter constraint`` block: + +:eql:synopsis:`set delegated` + Mark the constraint as *delegated*, which means it will + not be enforced on the type it's declared on, and enforcement is + delegated to subtypes. Useful for :eql:constraint:`exclusive` constraints. + +:eql:synopsis:`set not delegated` + Mark the constraint as *not delegated*, so it is enforced globally across + the type and any extending types. + +:eql:synopsis:`rename to ` + Change the name of the constraint to ````. + +:eql:synopsis:`alter annotation ` + Alter a constraint annotation. + +:eql:synopsis:`drop annotation ` + Remove a constraint annotation. + +:eql:synopsis:`reset errmessage` + Remove the error message from this constraint, reverting to that of the + abstract constraint, if any. + +All subcommands allowed in ``create constraint`` are also valid in +``alter constraint``. + +Example +^^^^^^^ + +Change the error message on the minimum value constraint on the property +"score" of the "User" type: + +.. code-block:: edgeql + + alter type User alter property score + alter constraint min_value(0) + set errmessage := 'Score cannot be negative'; + + +Drop constraint +--------------- + +:eql-statement: +:eql-haswith: + +Remove a concrete constraint from the specified schema item. + +.. eql:synopsis:: + + [ with [ := ] module [, ...] ] + drop constraint + [ ( [] [, ...] ) ] + [ on ( ) ] + [ except ( ) ] ; + + +Description +^^^^^^^^^^^ + +The command ``drop constraint`` removes the specified constraint from +its containing schema item. + + +Parameters +^^^^^^^^^^ + +:eql:synopsis:`[ := ] module ` + Optional module alias declarations for the migration definition. + +:eql:synopsis:`` + The name (optionally module-qualified) of the concrete constraint + to remove. + +:eql:synopsis:`` + A list of constraint arguments as specified at the time of + ``create constraint``. + +:eql:synopsis:`on ( )` + Expression defining the *subject* of the constraint as specified + at the time of ``create constraint``. + +Example +^^^^^^^ + +Remove constraint "min_value" from the property "score" of the "User" type: + +.. code-block:: edgeql + + alter type User alter property score + drop constraint min_value(0); .. list-table:: :class: seealso * - **See also** - * - :ref:`SDL > Constraints ` - * - :ref:`DDL > Constraints ` - * - :ref:`Introspection > Constraints - ` + * - :ref:`Introspection > Constraints ` * - :ref:`Standard Library > Constraints ` - * - `Tutorial > Advanced EdgeQL > Constraints - `_ diff --git a/docs/datamodel/extensions.rst b/docs/datamodel/extensions.rst index d76174c4961..1d6a1f5b308 100644 --- a/docs/datamodel/extensions.rst +++ b/docs/datamodel/extensions.rst @@ -4,18 +4,24 @@ Extensions ========== -Extensions are the way EdgeDB adds more functionality. In principle, -extensions could add new types, scalars, functions, etc., but, more +.. index:: using extension + +Extensions are the way |Gel| can be extended with more functionality. +They can add new types, scalars, functions, etc., but, more importantly, they can add new ways of interacting with the database. + Built-in extensions -------------------- +=================== + +.. index:: edgeql_http, graphql, auth, ai, pg_trgm, pg_unaccent, pgcrypto, + pgvector There are a few built-in extensions available: - ``edgeql_http``: enables :ref:`EdgeQL over HTTP `, - ``graphql``: enables :ref:`GraphQL `, -- ``auth``: enables :ref:`EdgeDB Auth `, +- ``auth``: enables :ref:`Gel Auth `, - ``ai``: enables :ref:`ext::ai module `, - ``pg_trgm``: enables ``ext::pg_trgm``, which re-exports @@ -32,74 +38,172 @@ There are a few built-in extensions available: .. _ref_datamodel_using_extension: -To enable these extensions, add a ``using`` statement at the top level of your schema: +To enable these extensions, add a ``using`` statement at the top level of +your schema: .. code-block:: sdl - using extension auth; - + using extension auth; + # or / and + using extension ai; Standalone extensions ---------------------- +===================== -Additionally, standalone extension packages can be installed via the CLI. +.. index:: postgis + +Additionally, standalone extension packages can be installed via the CLI, +with ``postgis`` being a notable example. List installed extensions: .. code-block:: bash - $ edgedb extension list -I my_instance - β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β” - β”‚ Name β”‚ Version β”‚ - β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + $ gel extension list + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ Name β”‚ Version β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ List available extensions: .. code-block:: bash - $ edgedb extension list-available -I my_instance - β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” - β”‚ Name β”‚ Version β”‚ - β”‚ postgis β”‚ 3.4.3+6b82d77 β”‚ - β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + $ gel extension list-available + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ Name β”‚ Version β”‚ + β”‚ postgis β”‚ 3.4.3+6b82d77 β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ Install the ``postgis`` extension: .. code-block:: bash - $ edgedb extension install -I my_instance -E postgis - Found extension package: postgis version 3.4.3+6b82d77 - 00:00:03 [====================] 22.49 MiB/22.49 MiB - Extension 'postgis' installed successfully. + $ gel extension install -E postgis + Found extension package: postgis version 3.4.3+6b82d77 + 00:00:03 [====================] 22.49 MiB/22.49 MiB + Extension 'postgis' installed successfully. Check that extension is installed: .. code-block:: bash - $ edgedb extension list -I my_instance - β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” - β”‚ Name β”‚ Version β”‚ - β”‚ postgis β”‚ 3.4.3+6b82d77 β”‚ - β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + $ gel extension list + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ Name β”‚ Version β”‚ + β”‚ postgis β”‚ 3.4.3+6b82d77 β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ After installing extensions, make sure to restart your instance: .. code-block:: bash - $ edgedb instance restart -I my_instance + $ gel instance restart + +Standalone extensions can now be declared in the schema, same as +built-in extensions: + +.. code-block:: sdl + + using extension postgis; + +.. note:: + To restore a dump that uses a standalone extension, that extension must + be installed before the restore process. + +.. _ref_eql_sdl_extensions: + +Using extensions +================ + +Syntax +------ + +.. sdl:synopsis:: + + using extension ";" + + +Extension declaration must be outside any :ref:`module block +` since extensions affect the entire database and +not a specific module. + + + +.. _ref_eql_ddl_extensions: + +DDL commands +============ + +This section describes the low-level DDL commands for creating and +dropping extensions. You typically don't need to use these commands directly, +but knowing about them is useful for reviewing migrations. + + +create extension +---------------- + +:eql-statement: + +Enable a particular extension for the current schema. + +.. eql:synopsis:: + + create extension ";" + + +Description +^^^^^^^^^^^ + +The command ``create extension`` enables the specified extension for +the current :versionreplace:`database;5.0:branch`. + +Examples +^^^^^^^^ + +Enable :ref:`GraphQL ` extension for the current +schema: + +.. code-block:: edgeql + + create extension graphql; + +Enable :ref:`EdgeQL over HTTP ` extension for the +current :versionreplace:`database;5.0:branch`: + +.. code-block:: edgeql + + create extension edgeql_http; + + +drop extension +-------------- + +:eql-statement: + +Disable an extension. + +.. eql:synopsis:: + + drop extension ";" + + +The command ``drop extension`` disables a currently active extension for +the current |branch|. + +Examples +^^^^^^^^ + +Disable :ref:`GraphQL ` extension for the current +schema: -Standalone extensions can now be declared in the schema, same as :ref:`built-in -extensions `. +.. code-block:: edgeql -To restore a dump that uses a standalone extension, that extension must be installed -before the restore process. + drop extension graphql; +Disable :ref:`EdgeQL over HTTP ` extension for the +current :versionreplace:`database;5.0:branch`: -.. list-table:: - :class: seealso +.. code-block:: edgeql - * - **See also** - * - :ref:`SDL > Extensions ` - * - :eql:stmt:`DDL > CREATE EXTENSION ` - * - :eql:stmt:`DDL > DROP EXTENSION ` + drop extension edgeql_http; diff --git a/docs/datamodel/functions.rst b/docs/datamodel/functions.rst index 472641e0f49..7b9dcd4ec56 100644 --- a/docs/datamodel/functions.rst +++ b/docs/datamodel/functions.rst @@ -1,21 +1,23 @@ .. _ref_datamodel_functions: +.. _ref_eql_sdl_functions: ========= Functions ========= +.. index:: function, using + .. note:: - This page documents how to define custom functions, however EdgeDB provides a + This page documents how to define custom functions, however |Gel| provides a large library of built-in functions and operators. These are documented in :ref:`Standard Library `. -Functions are ways to transform one set of data into another. User-defined Functions ----------------------- +====================== -It is also possible to define custom functions. For example, consider +Gel allows you to define custom functions. For example, consider a function that adds an exclamation mark ``'!'`` at the end of the string: @@ -32,10 +34,11 @@ This function accepts a :eql:type:`str` as an argument and produces a test> select exclamation({'Hello', 'World'}); {'Hello!', 'World!'} + .. _ref_datamodel_functions_modifying: Sets as arguments -^^^^^^^^^^^^^^^^^ +================= Calling a user-defined function on a set will always apply it as :ref:`*element-wise* `. @@ -76,8 +79,9 @@ applied element-wise. db> select magnitude({[3, 4], [5, 12]}); {5, 13} + Modifying Functions -^^^^^^^^^^^^^^^^^^^ +=================== .. versionadded:: 6.0 @@ -107,10 +111,10 @@ Unlike other functions, the arguments of modifying functions **must** have a .. code-block:: edgeql-repl db> select add_user({'Feb','Mar'}); - edgedb error: QueryError: possibly more than one element passed into + gel error: QueryError: possibly more than one element passed into modifying function db> select add_user({}); - edgedb error: QueryError: possibly an empty set passed as non-optional + gel error: QueryError: possibly an empty set passed as non-optional argument into modifying function Optional arguments can still accept empty sets. For example, if ``add_user`` @@ -148,15 +152,431 @@ aggregated into an array as described above: } ); + +.. _ref_eql_sdl_functions_syntax: + +Declaring functions +=================== + +This section describes the syntax to declare a function in your schema. + +Syntax +------ + +.. sdl:synopsis:: + + function ([ ] [, ... ]) -> + using ( ); + + function ([ ] [, ... ]) -> + using ; + + function ([ ] [, ... ]) -> + "{" + [ ] + [ volatility := {'Immutable' | 'Stable' | 'Volatile' | 'Modifying'} ] + [ using ( ) ; ] + [ using ; ] + [ ... ] + "}" ; + + # where is: + + [ ] : [ ] [ = ] + + # is: + + [ { variadic | named only } ] + + # is: + + [ { set of | optional } ] + + # and is: + + [ ] + + +Description +^^^^^^^^^^^ + +This declaration defines a new **function** with the following options: + +:eql:synopsis:`` + The name (optionally module-qualified) of the function to create. + +:eql:synopsis:`` + The kind of an argument: ``variadic`` or ``named only``. + + If not specified, the argument is called *positional*. + + The ``variadic`` modifier indicates that the function takes an + arbitrary number of arguments of the specified type. The passed + arguments will be passed as an array of the argument type. + Positional arguments cannot follow a ``variadic`` argument. + ``variadic`` parameters cannot have a default value. + + The ``named only`` modifier indicates that the argument can only + be passed using that specific name. Positional arguments cannot + follow a ``named only`` argument. + +:eql:synopsis:`` + The name of an argument. If ``named only`` modifier is used this + argument *must* be passed using this name only. + +.. _ref_sdl_function_typequal: + +:eql:synopsis:`` + The type qualifier: ``set of`` or ``optional``. + + The ``set of`` qualifier indicates that the function is taking the + argument as a *whole set*, as opposed to being called on the input + product element-by-element. + + User defined functions can not use ``set of`` arguments. + + The ``optional`` qualifier indicates that the function will be called + if the argument is an empty set. The default behavior is to return + an empty set if the argument is not marked as ``optional``. + +:eql:synopsis:`` + The data type of the function's arguments + (optionally module-qualified). + +:eql:synopsis:`` + An expression to be used as default value if the parameter is not + specified. The expression has to be of a type compatible with the + type of the argument. + +.. _ref_sdl_function_rettype: + +:eql:synopsis:`` + The return data type (optionally module-qualified). + + The ``set of`` modifier indicates that the function will return + a non-singleton set. + + The ``optional`` qualifier indicates that the function may return + an empty set. + +The valid SDL sub-declarations are listed below: + +:eql:synopsis:`volatility := {'Immutable' | 'Stable' | 'Volatile' | 'Modifying'}` + Function volatility determines how aggressively the compiler can + optimize its invocations. + + If not explicitly specified the function volatility is + :ref:`inferred ` from the function body. + + * An ``Immutable`` function cannot modify the database and is + guaranteed to return the same results given the same arguments + *in all statements*. + + * A ``Stable`` function cannot modify the database and is + guaranteed to return the same results given the same + arguments *within a single statement*. + + * A ``Volatile`` function cannot modify the database and can return + different results on successive calls with the same arguments. + + * A ``Modifying`` function can modify the database and can return + different results on successive calls with the same arguments. + +:eql:synopsis:`using ( )` + Specifies the body of the function. :eql:synopsis:`` is an + arbitrary EdgeQL expression. + +:eql:synopsis:`using ` + A verbose version of the :eql:synopsis:`using` clause that allows + specifying the language of the function body. + + * :eql:synopsis:`` is the name of the language that + the function is implemented in. Currently can only be ``edgeql``. + + * :eql:synopsis:`` is a string constant defining + the function. It is often helpful to use + :ref:`dollar quoting ` + to write the function definition string. + +:sdl:synopsis:`` + Set function :ref:`annotation ` + to a given *value*. + +The function name must be distinct from that of any existing function +with the same argument types in the same module. Functions of +different argument types can share a name, in which case the functions +are called *overloaded functions*. + + +.. _ref_eql_ddl_functions: + +DDL commands +============ + +This section describes the low-level DDL commands for creating, altering, and +dropping functions. You typically don't need to use these commands directly, but +knowing about them is useful for reviewing migrations. + +Create function +--------------- + +:eql-statement: +:eql-haswith: + +Define a new function. + +.. eql:synopsis:: + + [ with [, ...] ] + create function ([ ] [, ... ]) -> + using ( ); + + [ with [, ...] ] + create function ([ ] [, ... ]) -> + using ; + + [ with [, ...] ] + create function ([ ] [, ... ]) -> + "{" [, ...] "}" ; + + # where is: + + [ ] : [ ] [ = ] + + # is: + + [ { variadic | named only } ] + + # is: + + [ { set of | optional } ] + + # and is: + + [ ] + + # and is one of + + set volatility := {'Immutable' | 'Stable' | 'Volatile' | 'Modifying'} ; + create annotation := ; + using ( ) ; + using ; + + +Description +^^^^^^^^^^^ + +The command ``create function`` defines a new function. If *name* is +qualified with a module name, then the function is created in that +module, otherwise it is created in the current module. + +The function name must be distinct from that of any existing function +with the same argument types in the same module. Functions of +different argument types can share a name, in which case the functions +are called *overloaded functions*. + + +Parameters +^^^^^^^^^^ + +Most sub-commands and options of this command are identical to the +:ref:`SDL function declaration `, with +some additional features listed below: + +:eql:synopsis:`set volatility := {'Immutable' | 'Stable' | 'Volatile' | 'Modifying'}` + Function volatility determines how aggressively the compiler can + optimize its invocations. Other than a slight syntactical + difference this is the same as the corresponding SDL declaration. + +:eql:synopsis:`create annotation := ` + Set the function's :eql:synopsis:`` to + :eql:synopsis:``. + + See :eql:stmt:`create annotation` for details. + + +Examples +^^^^^^^^ + +Define a function returning the sum of its arguments: + +.. code-block:: edgeql + + create function mysum(a: int64, b: int64) -> int64 + using ( + select a + b + ); + +The same, but using a variadic argument and an explicit language: + +.. code-block:: edgeql + + create function mysum(variadic argv: int64) -> int64 + using edgeql $$ + select sum(array_unpack(argv)) + $$; + +Define a function using the block syntax: + +.. code-block:: edgeql + + create function mysum(a: int64, b: int64) -> int64 { + using ( + select a + b + ); + create annotation title := "My sum function."; + }; + + +Alter function +-------------- + +:eql-statement: +:eql-haswith: + +Change the definition of a function. + +.. eql:synopsis:: + + [ with [, ...] ] + alter function ([ ] [, ... ]) "{" + [, ...] + "}" + + # where is: + + [ ] : [ ] [ = ] + + # and is one of + + set volatility := {'Immutable' | 'Stable' | 'Volatile' | 'Modifying'} ; + reset volatility ; + rename to ; + create annotation := ; + alter annotation := ; + drop annotation ; + using ( ) ; + using ; + + +Description +^^^^^^^^^^^ + +The command ``alter function`` changes the definition of a function. +The command allows changing annotations, the volatility level, and +other attributes. + + +Subcommands +^^^^^^^^^^^ + +The following subcommands are allowed in the ``alter function`` block +in addition to the commands common to the ``create function``: + +:eql:synopsis:`reset volatility` + Remove explicitly specified volatility in favor of the volatility + inferred from the function body. + +:eql:synopsis:`rename to ` + Change the name of the function to *newname*. + +:eql:synopsis:`alter annotation ;` + Alter function :eql:synopsis:``. + See :eql:stmt:`alter annotation` for details. + +:eql:synopsis:`drop annotation ;` + Remove function :eql:synopsis:``. + See :eql:stmt:`drop annotation` for details. + +:eql:synopsis:`reset errmessage;` + Remove the error message from this abstract constraint. + The error message specified in the base abstract constraint + will be used instead. + + +Example +^^^^^^^ + +.. code-block:: edgeql + + create function mysum(a: int64, b: int64) -> int64 { + using ( + select a + b + ); + create annotation title := "My sum function."; + }; + + alter function mysum(a: int64, b: int64) { + set volatility := 'Immutable'; + drop annotation title; + }; + + alter function mysum(a: int64, b: int64) { + using ( + select (a + b) * 100 + ) + }; + + +Drop function +------------- + +:eql-statement: +:eql-haswith: + + +Remove a function. + +.. eql:synopsis:: + + [ with [, ...] ] + drop function ([ ] [, ... ]); + + # where is: + + [ ] : [ ] [ = ] + + +Description +^^^^^^^^^^^ + +The command ``drop function`` removes the definition of an existing function. +The argument types to the function must be specified, since there +can be different functions with the same name. + + +Parameters +^^^^^^^^^^ + +:eql:synopsis:`` + The name (optionally module-qualified) of an existing function. + +:eql:synopsis:`` + The name of an argument used in the function definition. + +:eql:synopsis:`` + The mode of an argument: ``set of`` or ``optional`` or ``variadic``. + +:eql:synopsis:`` + The data type(s) of the function's arguments + (optionally module-qualified), if any. + + +Example +^^^^^^^ + +Remove the ``mysum`` function: + +.. code-block:: edgeql + + drop function mysum(a: int64, b: int64); + + .. list-table:: :class: seealso * - **See also** - * - :ref:`SDL > Functions ` - * - :ref:`DDL > Functions ` * - :ref:`Reference > Function calls ` * - :ref:`Introspection > Functions ` * - :ref:`Cheatsheets > Functions ` - * - `Tutorial > Advanced EdgeQL > User-Defined Functions - `_ diff --git a/docs/datamodel/future.rst b/docs/datamodel/future.rst index 63af1d91561..b48bf5c12a5 100644 --- a/docs/datamodel/future.rst +++ b/docs/datamodel/future.rst @@ -1,49 +1,156 @@ .. _ref_datamodel_future: =============== -Future Behavior +Future behavior =============== -Any time that we add new functionality to EdgeDB we strive to do it in the -least disruptive way possible. Deprecation warnings, documentation and guides -can help make these transitions smoother, but sometimes the changes are just -too big, especially if they affect already existing functionality. It is often -inconvenient dealing with these changes at the same time as upgrading to a new -major version of EdgeDB. To help with this transition we introduce -:ref:`future ` specification. - -The purpose of this specification is to provide a way to try out and ease into -an upcoming feature before a major release. Sometimes enabling future behavior -is necessary to fix some current issues. Other times enabling future behavior -can simply provide a way to test out the feature before it gets released, to -make sure that the current project codebase is compatible and well-behaved. It -provides a longer timeframe for adopting a new feature and for catching bugs -that arise from the change in behavior. - -The ``future`` specification is intended to help with transitions between -major releases. Once a feature is released this specification is no longer -necessary to enable that feature and it will be removed from the schema during -the upgrade process. - -Once some behavior is available as a ``future`` all new :ref:`projects -` enable this behavior by default when initializing an -empty database. It is possible to explicitly disable the ``future`` feature by -removing it from the schema, but it is not recommended unless the feature is -causing some issues which cannot be fixed otherwise. Existing projects don't -change their behavior by default, the ``future`` specification needs to be -added to the schema by the developer in order to gain early access to it. - -At the moment there is only one ``future`` available: - -- ``nonrecursive_access_policies``: makes access policies :ref:`non-recursive - ` and simplifies policy - interactions. - - -.. list-table:: - :class: seealso - - * - **See also** - * - :ref:`SDL > Future Behavior ` - * - :eql:stmt:`DDL > CREATE FUTURE ` - * - :eql:stmt:`DDL > DROP FUTURE ` +.. index:: future, nonrecursive_access_policies + +This article explains what the ``using future ...;`` statement means in your +schema. + +Our goal is to make |Gel| the best database system in the world, which requires +us to keep evolving. Usually, we can add new functionality while preserving +backward compatibility, but on rare occasions we must implement changes that +require elaborate transitions. + +To handle these cases, we introduce *future* behavior, which lets you try out +upcoming features before a major release. Sometimes enabling a future is +necessary to fix current issues; other times it offers a safe and easy way to +ensure your codebase remains compatible. This approach provides more time to +adopt a new feature and identify any resulting bugs. + +Any time a behavior is available as a ``future,`` all new :ref:`projects +` enable it by default for empty databases. You can remove +a ``future`` from your schema if absolutely necessary, but doing so is +discouraged. Existing projects are unaffected by default, so you must manually +add the ``future`` specification to gain early access. + +Flags +===== + +At the moment there are three ``future`` flags available: + +- ``simple_scoping`` + + Introduced in |Gel| 6.0, this flag simplifies the scoping rules for + path expressions. Read more about it and in great detail in + :ref:`ref_eql_path_resolution`. + +- ``warn_old_scoping`` + + Introduced in |Gel| 6.0, this flag will emit a warning when a query + is detected to depend on the old scoping rules. This is an intermediate + step towards enabling the ``simple_scoping`` flag in existing large + codebases. + + Read more about this flag in :ref:`ref_warn_old_scoping`. + +.. _ref_datamodel_access_policies_nonrecursive: +.. _nonrecursive: + +- ``nonrecursive_access_policies``: makes access policies non-recursive. + + This flag is no longer used becauae the behavior is enabled + by default since |EdgeDB| 4. The flag was helpful to ease transition + from EdgeDB 3.x to 4.x. + + Since |EdgeDB| 3.0, access policy restrictions do **not** apply + to any access policy expression. This means that when reasoning about access + policies it is no longer necessary to take other policies into account. + Instead, all data is visible for the purpose of *defining* an access + policy. + + This change was made to simplify reasoning about access policies and + to allow certain patterns to be expressed efficiently. Since those who have + access to modifying the schema can remove unwanted access policies, no + additional security is provided by applying access policies to each + other's expressions. + + +.. _ref_eql_sdl_future: + +Declaring future flags +====================== + +Syntax +------ + +Declare that the current schema enables a particular future behavior. + +.. sdl:synopsis:: + + using future ";" + +Description +^^^^^^^^^^^ + +Future behavior declaration must be outside any :ref:`module block +` since this behavior affects the entire database and not +a specific module. + +Example +^^^^^^^ + +.. code-block:: sdl-invalid + + using future simple_scoping; + + +.. _ref_eql_ddl_future: + +DDL commands +============ + +This section describes the low-level DDL commands for creating and +dropping future flags. You typically don't need to use these commands directly, +but knowing about them is useful for reviewing migrations. + +Create future +------------- + +:eql-statement: + +Enable a particular future behavior for the current schema. + +.. eql:synopsis:: + + create future ";" + + +The command ``create future`` enables the specified future behavior for +the current branch. + +Example +^^^^^^^ + +.. code-block:: edgeql + + create future simple_scoping; + + +Drop future +----------- + +:eql-statement: + +Disable a particular future behavior for the current schema. + +.. eql:synopsis:: + + drop future ";" + +Description +^^^^^^^^^^^ + +The command ``drop future`` disables a currently active future behavior for the +current branch. However, this is only possible for versions of |Gel| when the +behavior in question is not officially introduced. Once a particular behavior is +introduced as the standard behavior in a |Gel| release, it cannot be disabled. + +Example +^^^^^^^ + +.. code-block:: edgeql + + drop future warn_old_scoping; diff --git a/docs/datamodel/globals.rst b/docs/datamodel/globals.rst index a6bec677daf..c94fbed6233 100644 --- a/docs/datamodel/globals.rst +++ b/docs/datamodel/globals.rst @@ -1,70 +1,99 @@ -.. versionadded:: 2.0 - .. _ref_datamodel_globals: ======= Globals ======= -Schemas can contain scalar-typed *global variables*. +.. index:: global, required global -.. code-block:: sdl - :version-lt: 3.0 +Schemas in Gel can contain typed *global variables*. These create a mechanism +for specifying session-level context that can be referenced in queries, +access policies, triggers, and elsewhere with the ``global`` keyword. - global current_user_id -> uuid; +Here's a very common example of a global variable representing the current +user ID: .. code-block:: sdl - global current_user_id: uuid; + global current_user_id: uuid; -These provide a useful mechanism for specifying session-level data that can be -referenced in queries with the ``global`` keyword. +.. tabs:: -.. code-block:: edgeql + .. code-tab:: edgeql - select User { - id, - posts: { title, content } - } - filter .id = global current_user_id; + select User { + id, + posts: { title, content } + } + filter .id = global current_user_id; + .. code-tab:: python + + # In a non-trivial example, `global current_user_id` would + # be used indirectly in an access policy or some other context. + await client.with_globals({'user_id': user_id}).qeury(''' + select User { + id, + posts: { title, content } + } + filter .id = global current_user_id; + ''') + + .. code-tab:: typescript + + // In a non-trivial example, `global current_user_id` would + // be used indirectly in an access policy or some other context. + await client.withGlobals({user_id}).qeury(''' + select User { + id, + posts: { title, content } + } + filter .id = global current_user_id; + ''') -As in the example above, this is particularly useful for representing the -notion of a session or "current user". Setting global variables -^^^^^^^^^^^^^^^^^^^^^^^^ +======================== -Global variables are set when initializing a client. The exact API depends on -which client library you're using. +Global variables are set at session level or when initializing a client. +The exact API depends on which client library you're using, but the general +behavior and principles are the same across all libraries. .. tabs:: .. code-tab:: typescript - import createClient from 'edgedb'; + import createClient from 'gel'; const baseClient = createClient(); - // returns a new Client instance that stores the provided - // globals and sends them along with all future queries: + + // returns a new Client instance, that shares the underlying + // network connection with `baseClient` , but sends the configured + // globals along with all queries run through it: const clientWithGlobals = baseClient.withGlobals({ current_user_id: '2141a5b4-5634-4ccc-b835-437863534c51', }); - await clientWithGlobals.query(`select global current_user_id;`); + const result = await clientWithGlobals.query( + `select global current_user_id;` + ); .. code-tab:: python - from edgedb import create_client + from gel import create_client + + base_client = create_client() - client = create_client().with_globals({ + # returns a new Client instance, that shares the underlying + # network connection with `base_client` , but sends the configured + # globals along with all queries run through it: + client = base_client.with_globals({ 'current_user_id': '580cc652-8ab8-4a20-8db9-4c79a4b1fd81' }) result = client.query(""" select global current_user_id; """) - print(result) .. code-tab:: go @@ -75,23 +104,23 @@ which client library you're using. "fmt" "log" - "github.com/edgedb/edgedb-go" + "github.com/geldata/gel-go" ) func main() { ctx := context.Background() - client, err := edgedb.CreateClient(ctx, edgedb.Options{}) + client, err := gel.CreateClient(ctx, gel.Options{}) if err != nil { log.Fatal(err) } defer client.Close() - id, err := edgedb.ParseUUID("2141a5b4-5634-4ccc-b835-437863534c51") + id, err := gel.ParseUUID("2141a5b4-5634-4ccc-b835-437863534c51") if err != nil { log.Fatal(err) } - var result edgedb.UUID + var result gel.UUID err = client. WithGlobals(map[string]interface{}{"current_user": id}). QuerySingle(ctx, "SELECT global current_user;", &result) @@ -106,7 +135,7 @@ which client library you're using. use uuid::Uuid; - let client = edgedb_tokio::create_client().await.expect("Client init"); + let client = gel_tokio::create_client().await.expect("Client init"); let client_with_globals = client.with_globals_fn(|c| { c.set( @@ -125,149 +154,368 @@ which client library you're using. .. code-tab:: edgeql - set global current_user_id := + set global current_user_id := '2141a5b4-5634-4ccc-b835-437863534c51'; Cardinality ------------ - -Global variables can be marked ``required``; in this case, you must specify a -default value. +=========== -.. code-block:: sdl - :version-lt: 3.0 +A global variable can be declared with one of two cardinalities: - required global one_string -> str { - default := "Hi Mom!" - }; +- ``single`` (the default): At most one value. +- ``multi``: A set of values. Only valid for computed global variables. -.. code-block:: sdl +In addition, a global can be marked ``required`` or ``optional`` (the default). +If marked ``required``, a default value must be provided. - required global one_string: str { - default := "Hi Mom!" - }; Computed globals ----------------- +================ -Global variables can also be computed. The value of computed globals are +.. index:: global, := + +Global variables can also be computed. The value of computed globals is dynamically computed when they are referenced in queries. .. code-block:: sdl - required global random_global := datetime_of_transaction(); + required global now := datetime_of_transaction(); The provided expression will be computed at the start of each query in which -the global is referenced. There's no need to provide an explicit type; the -type is inferred from the computed expression. +the global is referenced. There's no need to provide an explicit type; the type +is inferred from the computed expression. -Computed globals are not subject to the same constraints as non-computed ones; -specifically, they can be object-typed and have a ``multi`` cardinality. +Computed globals can also be object-typed and have ``multi`` cardinality. +For example: .. code-block:: sdl - :version-lt: 3.0 - global current_user_id -> uuid; + global current_user_id: uuid; - # object-typed global - global current_user := ( - select User filter .id = global current_user_id - ); + # object-typed global + global current_user := ( + select User filter .id = global current_user_id + ); + + # multi global + global current_user_friends := (global current_user).friends; - # multi global - global current_user_friends := (global current_user).friends; + +Referencing globals +=================== + +Unlike query parameters, globals can be referenced *inside your schema +declarations*: .. code-block:: sdl - global current_user_id: uuid; + type User { + name: str; + is_self := (.id = global current_user_id) + }; - # object-typed global - global current_user := ( - select User filter .id = global current_user_id - ); +This is particularly useful when declaring :ref:`access policies +`: + +.. code-block:: sdl + + type Person { + required name: str; - # multi global - global current_user_friends := (global current_user).friends; + access policy my_policy allow all + using (.id = global current_user_id); + } +Refer to :ref:`Access Policies ` for complete +documentation. -Usage in schema ---------------- +.. _ref_eql_sdl_globals: +.. _ref_eql_sdl_globals_syntax: -.. You may be wondering what purpose globals serve that can't. -.. For instance, the simple ``current_user_id`` example above could easily -.. be rewritten like so: +Declaring globals +================= -.. .. code-block:: edgeql-diff +This section describes the syntax to declare a global variable in your schema. -.. select User { -.. id, -.. posts: { title, content } -.. } -.. - filter .id = global current_user_id -.. + filter .id = $current_user_id +Syntax +------ -.. There is a subtle difference between these two in terms of -.. developer experience. When using parameters, you must provide a -.. value for ``$current_user_id`` on each *query execution*. By constrast, -.. the value of ``global current_user_id`` is defined when you initialize -.. the client; you can use this "sessionified" client to execute -.. user-specific queries without needing to keep pass around the -.. value of the user's UUID. +Define a new global variable in SDL, corresponding to the more explicit DDL +commands described later: -.. But that's a comparatively marginal difference. +.. sdl:synopsis:: -Unlike query parameters, globals can be referenced -*inside your schema declarations*. + # Global variable declaration: + [{required | optional}] [single] + global -> + [ "{" + [ default := ; ] + [ ] + ... + "}" ] -.. code-block:: sdl - :version-lt: 3.0 + # Computed global variable declaration: + [{required | optional}] [{single | multi}] + global := ; - type User { - property name -> str; - property is_self := (.id = global current_user_id) - }; +Description +^^^^^^^^^^^ -.. code-block:: sdl - :version-lt: 4.0 +There are two different forms of ``global`` declarations, as shown in the +syntax synopsis above: - type User { - name: str; - property is_self := (.id = global current_user_id) - }; +1. A *settable* global (defined with ``-> ``) which can be changed using + a session-level :ref:`set ` command. -.. code-block:: sdl +2. A *computed* global (defined with ``:= ``), which cannot be + directly set but instead derives its value from the provided expression. - type User { - name: str; - is_self := (.id = global current_user_id) - }; +The following options are available: -This is particularly useful when declaring :ref:`access policies -`. +:eql:synopsis:`required` + If specified, the global variable is considered *required*. It is an + error for this variable to have an empty value. If a global variable is + declared *required*, it must also declare a *default* value. -.. code-block:: sdl - :version-lt: 3.0 +:eql:synopsis:`optional` + The global variable is considered *optional*, i.e. it is possible for the + variable to have an empty value. (This is the default.) + +:eql:synopsis:`multi` + Specifies that the global variable may have a set of values. Only + *computed* global variables can have this qualifier. + +:eql:synopsis:`single` + Specifies that the global variable must have at most a *single* value. It + is assumed that a global variable is ``single`` if neither ``multi`` nor + ``single`` is specified. All non-computed global variables must be *single*. + +:eql:synopsis:`` + The name of the global variable. It can be fully-qualified with the module + name, or it is assumed to belong to the module in which it appears. + +:eql:synopsis:`` + The type must be a valid :ref:`type expression ` denoting a + non-abstract scalar or a container type. + +:eql:synopsis:` := ` + Defines a *computed* global variable. The provided expression must be a + :ref:`Stable ` EdgeQL expression. It can refer + to other global variables. The type of a *computed* global variable is + not limited to scalar and container types; it can also be an object type. + +The valid SDL sub-declarations are: + +:eql:synopsis:`default := ` + Specifies the default value for the global variable as an EdgeQL + expression. The default value is used in a session if the value was not + explicitly specified by the client, or was reset with the :ref:`reset + ` command. + +:sdl:synopsis:`` + Set global variable :ref:`annotation ` + to a given *value*. - type Person { - required property name -> str; - access policy my_policy allow all using (.id = global current_user_id); - } + +Examples +-------- + +Declare a new global variable: .. code-block:: sdl - type Person { - required name: str; - access policy my_policy allow all using (.id = global current_user_id); - } + global current_user_id -> uuid; + global current_user := ( + select User filter .id = global current_user_id + ); -Refer to :ref:`Access Policies ` for complete -documentation. +Set the global variable to a specific value using :ref:`session-level commands +`: + +.. code-block:: edgeql + + set global current_user_id := + '00ea8eaa-02f9-11ed-a676-6bd11cc6c557'; + +Use the computed global variable that is based on the value that was just set: + +.. code-block:: edgeql + + select global current_user { name }; + +:ref:`Reset ` the global variable to +its default value: + +.. code-block:: edgeql -.. list-table:: - :class: seealso + reset global user_id; + + +.. _ref_eql_ddl_globals: + + +DDL commands +============ + +This section describes the low-level DDL commands for creating, altering, and +dropping globals. You typically don't need to use these commands directly, but +knowing about them is useful for reviewing migrations. + + +Create global +------------- + +:eql-statement: +:eql-haswith: + +Declare a new global variable using DDL. + +.. eql:synopsis:: + + [ with [, ...] ] + create [{required | optional}] [single] + global -> + [ "{" ; [...] "}" ] ; + + # Computed global variable form: + + [ with [, ...] ] + create [{required | optional}] [{single | multi}] + global := ; + + # where is one of + + set default := + create annotation := + +Description +^^^^^^^^^^^ + +As with SDL, there are two different forms of ``global`` declaration: + +- A global variable that can be :ref:`set ` + in a session. +- A *computed* global that is derived from an expression (and so cannot be + directly set in a session). + +The subcommands mirror those in SDL: + +:eql:synopsis:`set default := ` + Specifies the default value for the global variable as an EdgeQL + expression. The default value is used by the session if the value was not + explicitly specified or was reset with the :ref:`reset + ` command. + +:eql:synopsis:`create annotation := ` + Assign an annotation to the global variable. See :eql:stmt:`create annotation` + for details. + + +Examples +^^^^^^^^ + +Define a new global property ``current_user_id``: + +.. code-block:: edgeql + + create global current_user_id -> uuid; + +Define a new *computed* global property ``current_user`` based on the +previously defined ``current_user_id``: + +.. code-block:: edgeql + + create global current_user := ( + select User filter .id = global current_user_id + ); + + +Alter global +------------ + +:eql-statement: +:eql-haswith: + +Change the definition of a global variable. + +.. eql:synopsis:: + + [ with [, ...] ] + alter global + [ "{" ; [...] "}" ] ; + + # where is one of + + set default := + reset default + rename to + set required + set optional + reset optionalily + set single + set multi + reset cardinality + set type reset to default + using () + create annotation := + alter annotation := + drop annotation + +Description +^^^^^^^^^^^ + +The command :eql:synopsis:`alter global` changes the definition of a global +variable. It can modify default values, rename the global, or change other +attributes like optionality, cardinality, computed expressions, etc. + +Examples +^^^^^^^^ + +Set the ``description`` annotation of global variable ``current_user``: + +.. code-block:: edgeql + + alter global current_user + create annotation description := + 'Current User as specified by the global ID'; + +Make the ``current_user_id`` global variable ``required``: + +.. code-block:: edgeql + + alter global current_user_id { + set required; + # A required global variable MUST have a default value. + set default := '00ea8eaa-02f9-11ed-a676-6bd11cc6c557'; + } + + +Drop global +----------- + +:eql-statement: +:eql-haswith: + +Remove a global variable from the schema. + +.. eql:synopsis:: + + [ with [, ...] ] + drop global ; + +Description +^^^^^^^^^^^ + +The command :eql:synopsis:`drop global` removes the specified global variable +from the schema. + +Example +^^^^^^^ + +Remove the ``current_user`` global variable: + +.. code-block:: edgeql - * - **See also** - * - :ref:`SDL > Globals ` - * - :ref:`DDL > Globals ` + drop global current_user; diff --git a/docs/datamodel/index.rst b/docs/datamodel/index.rst index ea582e88919..54a9d372e1a 100644 --- a/docs/datamodel/index.rst +++ b/docs/datamodel/index.rst @@ -22,6 +22,7 @@ Schema annotations globals access_policies + modules functions triggers mutation_rewrites @@ -32,36 +33,22 @@ Schema introspection/index -EdgeDB schemas are declared using **SDL** (EdgeDB's Schema Definition +|Gel| schemas are declared using **SDL** (Gel's Schema Definition Language). SDL --- -Your schema is defined inside ``.esdl`` files. It's common to define your -entire schema in a single file called ``default.esdl``, but you can split it +Your schema is defined inside |.gel| files. It's common to define your +entire schema in a single file called :dotgel:`default`, but you can split it across multiple files if you wish. By convention, your schema files should live in a directory called ``dbschema`` in the root of your project. .. code-block:: sdl - :version-lt: 3.0 - # dbschema/default.esdl - - type Movie { - required property title -> str; - required link director -> Person; - } - - type Person { - required property name -> str; - } - -.. code-block:: sdl - - # dbschema/default.esdl + # dbschema/default.gel type Movie { required title: str; @@ -74,26 +61,26 @@ in the root of your project. .. important:: - Syntax highlighter packages/extensions for ``.esdl`` files are available for + Syntax highlighter packages/extensions for |.gel| files are available for `Visual Studio Code `_, `Sublime Text `_, `Atom `_, and `Vim `_. + geldata/edgedb-vim>`_. Migrations ---------- -EdgeDB's baked-in migration system lets you painlessly evolve your schema over -time. Just update the contents of your ``.esdl`` file(s) and use the EdgeDB CLI +Gel's baked-in migration system lets you painlessly evolve your schema over +time. Just update the contents of your |.gel| file(s) and use the |Gel| CLI to *create* and *apply* migrations. .. code-block:: bash - $ edgedb migration create - Created dbschema/migrations/00001.esdl - $ edgedb migrate - Applied dbschema/migrations/00001.esdl. + $ gel migration create + Created dbschema/migrations/00001.edgeql + $ gel migrate + Applied dbschema/migrations/00001.edgeql For a full guide on migrations, refer to the :ref:`Creating and applying migrations ` guide. @@ -116,105 +103,31 @@ Terminology Instance ^^^^^^^^ -An EdgeDB **instance** is a running EdgeDB process. Instances can be created, -started, stopped, and destroyed locally with the :ref:`EdgeDB CLI +A |Gel| **instance** is a running Gel process. Instances can be created, +started, stopped, and destroyed locally with the :ref:`Gel CLI `. +.. _ref_datamodel_databases: .. _ref_datamodel_branches: -Branches -^^^^^^^^ +Branch +^^^^^^ .. versionadded:: 5.0 +Prior to |EdgeDB| 5 and Gel, *branches* were called "databases" +(and "databases" is what Gel branches map to in PostgreSQL). + Instances can be branched when working on new features, similar to branches in your VCS. Each branch has its own schema and data. -.. _ref_datamodel_databases: - -Database -^^^^^^^^ - -.. versionadded:: 5.0 - - In EdgeDB 5, databases were replaced by branches. - -Each instance can contain several **databases**, each with a unique name. At -the time of creation, all instances contain a single default database called -``edgedb``. All incoming queries are executed -against it unless otherwise specified. - -.. _ref_datamodel_modules: Module ^^^^^^ -Each branch (or database pre-v5) has a schema consisting of several +Each |branch| has a schema consisting of several **modules**, each with a unique name. Modules can be used to organize large schemas into logical units. In practice, though, most users put their entire schema inside a single module called ``default``. -.. code-block:: sdl - - module default { - # declare types here - } - -.. versionadded:: 3.0 - - You may define nested modules using the following syntax: - - .. code-block:: sdl - - module dracula { - type Person { - required property name -> str; - multi link places_visited -> City; - property strength -> int16; - } - - module combat { - function fight( - one: dracula::Person, - two: dracula::Person - ) -> str - using ( - (one.name ?? 'Fighter 1') ++ ' wins!' - IF (one.strength ?? 0) > (two.strength ?? 0) - ELSE (two.name ?? 'Fighter 2') ++ ' wins!' - ); - } - } - - Here we have a ``dracula`` module containing a ``Person`` type. Nested in - the ``dracula`` module we have a ``combat`` module which will be used for - all the combat functionality for our game based on Bram Stoker's Dracula we - built in the `Easy EdgeDB textbook `_. - -.. _ref_name_resolution: - -.. note:: Name resolution - - When referencing schema objects from another module, you must use - a *fully-qualified* name in the form ``module_name::object_name``. - -The following module names are reserved by EdgeDB and contain pre-defined -types, utility functions, and operators. - -* ``std``: standard types, functions, and operators in the :ref:`standard - library ` -* ``math``: algebraic and statistical :ref:`functions ` -* ``cal``: local (non-timezone-aware) and relative date/time :ref:`types and - functions ` -* ``schema``: types describing the :ref:`introspection - ` schema -* ``sys``: system-wide entities, such as user roles and - :ref:`databases ` -* ``cfg``: configuration and settings - -.. versionadded:: 3.0 - - You can chain together module names in a fully-qualified name to traverse a - tree of nested modules. For example, to call the ``fight`` function in the - nested module example above, you would use - ``dracula::combat::fight()``. +Read more about modules in the :ref:`modules ` section. diff --git a/docs/datamodel/indexes.rst b/docs/datamodel/indexes.rst index afdb9a378ff..18329cf5845 100644 --- a/docs/datamodel/indexes.rst +++ b/docs/datamodel/indexes.rst @@ -4,239 +4,355 @@ Indexes ======= +.. index:: + index on, performance, postgres query planner + An index is a data structure used internally to speed up filtering, ordering, -and grouping operations. Indexes help accomplish this in two key ways: +and grouping operations in |Gel|. Indexes help accomplish this in two key ways: -- They are pre-sorted which saves time on costly sort operations on rows. +- They are pre-sorted, which saves time on costly sort operations on rows. - They can be used by the query planner to filter out irrelevant rows. .. note:: - The Postgres query planner decides when to use indexes for a query. In some - cases β€” for example, when tables are small and it would be faster to scan - the whole table than to use an index β€” an applicable index may be ignored. + The Postgres query planner decides when to use indexes for a query. In some + casesβ€”e.g. when tables are smallβ€”it may be faster to scan the whole table + rather than use an index. In such scenarios, the index might be ignored. - For more information on how it does this, read `the Postgres query planner - documentation - `_. + For more information on how the planner decides this, see + `the Postgres query planner documentation + `_. -Most commonly, indexes are declared within object type declarations and -reference a particular property. The index can be used to speed up queries -which reference that property in a ``filter``, ``order by``, or ``group`` -clause. -.. note:: +Tradeoffs +========= - While improving query performance, indexes also increase disk and memory - usage and slow down insertions and updates. Creating too many indexes may be - detrimental; only index properties you often filter, order, or group by. +While improving query performance, indexes also increase disk and memory usage +and can slow down insertions and updates. Creating too many indexes may be +detrimental; only index properties you often filter, order, or group by. -Index on a property -------------------- +.. important:: + **Foreign and primary keys** -Below, we are referencing the ``User.name`` property with the :ref:`dot -notation shorthand `: ``.name``. + In SQL databases, indexes are commonly used to index *primary keys* and + *foreign keys*. Gel's analog to a SQL primary key is the ``id`` field + automatically created for each object, while a link in Gel is the analog + to a SQL foreign key. Both of these are automatically indexed. -.. code-block:: sdl - :version-lt: 3.0 + Moreover, any property with an :eql:constraint:`exclusive` constraint + is also automatically indexed. + + +Index on a property +=================== - type User { - required property name -> str; - index on (.name); - } +Most commonly, indexes are declared within object type declarations and +reference a particular property. The index can be used to speed up queries +that reference that property in a filter, order by, or group by clause: .. code-block:: sdl - type User { - required name: str; - index on (.name); - } + type User { + required name: str; + index on (.name); + } By indexing on ``User.name``, the query planner will have access to that index -for use when planning queries containing the property in a filter, order, or -group by. This may result in better performance in these queries as the -database can look up a name in the index instead of scanning through all -``User`` objects sequentially, although whether or not to use the index is -ultimately up to the Postgres query planner. +when planning queries using the ``name`` property. This may result in better +performance as the database can look up a name in the index instead of scanning +through all ``User`` objects sequentiallyβ€”though ultimately it's up to the +Postgres query planner whether to use the index. -To see if an index can help your query, try adding the :ref:`analyze -` keyword before a query with an index compared to one -without. +To see if an index helps, compare query plans by adding +:ref:`analyze ` to your queries. .. note:: - Even if your database is too small now to benefit from an index, it may - benefit from one as it continues to grow. + Even if your database is small now, you may benefit from an index as it grows. Index on an expression ----------------------- +====================== Indexes may be defined using an arbitrary *singleton* expression that references multiple properties of the enclosing object type. .. important:: + A singleton expression is an expression that's guaranteed to return + *at most one* element. As such, you can't index on a ``multi`` property. - A singleton expression is an expression that's guaranteed to return *at most - one* element. As such, you can't index on a ``multi`` property. +Example: .. code-block:: sdl - :version-lt: 3.0 - type User { - required property first_name -> str; - required property last_name -> str; - index on (str_lower(.firstname + ' ' + .lastname)); - } + type User { + required first_name: str; + required last_name: str; + index on (str_lower(.first_name + ' ' + .last_name)); + } -.. code-block:: sdl - - type User { - required first_name: str; - required last_name: str; - index on (str_lower(.firstname + ' ' + .lastname)); - } Index on multiple properties ----------------------------- +============================ + +.. index:: tuple -A *composite index* is an index that references multiple properties. This can -speed up queries that filter, order, or group on both properties. +A *composite index* references multiple properties. This can speed up queries +that filter, order, or group on multiple properties at once. .. note:: - An index on multiple properties may also be used in queries where only a - single property in the index is filtered, ordered, or grouped by. It is - best to have the properties most likely to be used in this way listed first - when you create the index on multiple properties. + An index on multiple properties may also be used in queries where only a + single property in the index is referenced. In many traditional database + systems, placing the most frequently used columns first in the composite + index can improve the likelihood of its use. - Read `the Postgres documentation on multicolumn indexes - `_ to - learn more about how the query planner uses these indexes. + Read `the Postgres documentation on multicolumn indexes + `_ to learn + more about how the query planner uses these indexes. -In EdgeDB, this index is created by indexing on a ``tuple`` of properties. +In |Gel|, a composite index is created by indexing on a ``tuple`` of properties: .. code-block:: sdl - :version-lt: 3.0 - type User { - required property name -> str; - required property email -> str; - index on ((.name, .email)); - } + type User { + required name: str; + required email: str; + index on ((.name, .email)); + } + + +Index on a link property +======================== + +.. index:: __subject__, linkprops + +Link properties can also be indexed. The special placeholder +``__subject__`` refers to the source object in a link property expression: .. code-block:: sdl - type User { - required name: str; - required email: str; - index on ((.name, .email)); - } + abstract link friendship { + strength: float64; + index on (__subject__@strength); + } + type User { + multi friends: User { + extending friendship; + }; + } -Index on a link property ------------------------- -Link properties can also be indexed. +Specify a Postgres index type +============================= + +.. index:: pg::hash, pg::btree, pg::gin, pg::gist, pg::spgist, pg::brin + +.. versionadded:: 3.0 + +Gel exposes Postgres index types that can be used directly in schemas via +the ``pg`` module: + +- ``pg::hash`` : Index based on a 32-bit hash of the value +- ``pg::btree`` : B-tree index (can help with sorted data retrieval) +- ``pg::gin`` : Inverted index for multi-element data (arrays, JSON) +- ``pg::gist`` : Generalized Search Tree for range and geometric searches +- ``pg::spgist`` : Space-partitioned GiST +- ``pg::brin`` : Block Range INdex + +Example: .. code-block:: sdl - :version-lt: 3.0 - abstract link friendship { - property strength -> float64; - index on (__subject__@strength); - } + type User { + required name: str; + index pg::spgist on (.name); + } + + +Annotate an index +================= + +.. index:: annotation - type User { - multi link friends extending friendship -> User; - } +Indexes can include annotations: .. code-block:: sdl - abstract link friendship { - strength: float64; - index on (__subject__@strength); - } + type User { + name: str; + index on (.name) { + annotation description := 'Indexing all users by name.'; + }; + } - type User { - multi friends: User { - extending friendship; - }; - } +.. _ref_eql_sdl_indexes: -Specify a Postgres index type ------------------------------ +Declaring indexes +================= -.. versionadded:: 3.0 +This section describes the syntax to use indexes in your schema. -EdgeDB exposes Postgres indexes that you can use in your schemas. These are -exposed through the ``pg`` module. +Syntax +------ -* ``pg::hash``- Index based on a 32-bit hash derived from the indexed value +.. sdl:synopsis:: -* ``pg::btree``- B-tree index can be used to retrieve data in sorted order + index on ( ) + [ except ( ) ] + [ "{" "}" ] ; -* ``pg::gin``- GIN is an "inverted index" appropriate for data values that - contain multiple elements, such as arrays and JSON +.. rubric:: Description -* ``pg::gist``- GIST index can be used to optimize searches involving ranges +- :sdl:synopsis:`on ( )` -* ``pg::spgist``- SP-GIST index can be used to optimize searches involving - ranges and strings + The expression to index. It must be :ref:`Immutable ` + but may refer to the indexed object's properties/links. The expression itself + must be parenthesized. -* ``pg::brin``- BRIN (Block Range INdex) index works with summaries about the - values stored in consecutive physical block ranges in the database +- :eql:synopsis:`except ( )` -You can use them like this: + An optional condition. If ```` evaluates to ``true``, the object + is omitted from the index; if ``false`` or empty, it is included. -.. code-block:: sdl +- :sdl:synopsis:`` - type User { - required name: str; - index pg::spgist on (.name); - }; + Allows setting index :ref:`annotation ` to a given + value. -Annotate an index ------------------ +.. _ref_eql_ddl_indexes: -Indexes can be augmented with annotations. +DDL commands +============ -.. code-block:: sdl - :version-lt: 3.0 +This section describes the low-level DDL commands for creating, altering, and +dropping indexes. You typically don't need to use these commands directly, but +knowing about them is useful for reviewing migrations. - type User { - property name -> str; - index on (.name) { - annotation description := 'Indexing all users by name.'; - }; - } -.. code-block:: sdl +Create index +------------ - type User { - name: str; - index on (.name) { - annotation description := 'Indexing all users by name.'; - }; - } +:eql-statement: -.. important:: +.. eql:synopsis:: + + create index on ( ) + [ except ( ) ] + [ "{" ; [...] "}" ] ; + + # where is one of + + create annotation := + +Creates a new index for a given object type or link using *index-expr*. + +- Most parameters/options match those in + :ref:`Declaring indexes `. + +- Allowed subcommand: + + :eql:synopsis:`create annotation := ` + Assign an annotation to this index. + See :eql:stmt:`create annotation` for details. + +Example: + +.. code-block:: edgeql + + create type User { + create property name -> str { + set default := ''; + }; + + create index on (.name); + }; + + +Alter index +----------- + +:eql-statement: + +Alter the definition of an index. + +.. eql:synopsis:: + + alter index on ( ) [ except ( ) ] + [ "{" ; [...] "}" ] ; + + # where is one of + + create annotation := + alter annotation := + drop annotation + +The command ``alter index`` is used to change the :ref:`annotations +` of an index. The *index-expr* is used to +identify the index to be altered. + +:sdl:synopsis:`on ( )` + The specific expression for which the index is made. Note also + that ```` itself has to be parenthesized. + +The following subcommands are allowed in the ``alter index`` block: + +:eql:synopsis:`create annotation := ` + Set index :eql:synopsis:`` to + :eql:synopsis:``. + See :eql:stmt:`create annotation` for details. + +:eql:synopsis:`alter annotation ;` + Alter index :eql:synopsis:``. + See :eql:stmt:`alter annotation` for details. + +:eql:synopsis:`drop annotation ;` + Remove constraint :eql:synopsis:``. + See :eql:stmt:`drop annotation` for details. + + +Example: + +.. code-block:: edgeql + + alter type User { + alter index on (.name) { + create annotation title := 'User name index'; + }; + }; + + +Drop index +---------- + +:eql-statement: + +Remove an index from a given schema item. + +.. eql:synopsis:: + + drop index on ( ) [ except ( ) ] ; + +Removes an index from a schema item. + +- :sdl:synopsis:`on ( )` identifies the indexed expression. + +This statement can only be used as a subdefinition in another DDL statement. + +Example: + +.. code-block:: edgeql - **Foreign and primary keys** + alter type User { + drop index on (.name); + }; - In SQL databases, indexes are commonly used to index *primary keys* and - *foreign keys*. EdgeDB's analog to SQL's primary key is the ``id`` field - that gets automatically created for each object, while a link in EdgeDB - is the analog to SQL's foreign key. Both of these are automatically indexed. - Moreover, any property with an :eql:constraint:`exclusive` constraint - is also automatically indexed. .. list-table:: - :class: seealso + :class: seealso - * - **See also** - * - :ref:`SDL > Indexes ` - * - :ref:`DDL > Indexes ` - * - :ref:`Introspection > Indexes ` + * - **See also** + - :ref:`Introspection > Indexes ` diff --git a/docs/datamodel/inheritance.rst b/docs/datamodel/inheritance.rst index 821a77a2a8e..fb9d77ace25 100644 --- a/docs/datamodel/inheritance.rst +++ b/docs/datamodel/inheritance.rst @@ -4,7 +4,10 @@ Inheritance =========== -Inheritance is a crucial aspect of schema modeling in EdgeDB. Schema items can +.. index:: abstract, extending, extends, subtype, supertype, parent type, + child type + +Inheritance is a crucial aspect of schema modeling in Gel. Schema items can *extend* one or more parent types. When extending, the child (subclass) inherits the definition of its parents (superclass). @@ -26,17 +29,6 @@ Object types can *extend* other object types. The extending type (AKA the *subtype*) inherits all links, properties, indexes, constraints, etc. from its *supertypes*. -.. code-block:: sdl - :version-lt: 3.0 - - abstract type Animal { - property species -> str; - } - - type Dog extending Animal { - property breed -> str; - } - .. code-block:: sdl abstract type Animal { @@ -56,21 +48,6 @@ and can be inserted, which was not the case in the example above. The new ``CanBark`` type however is abstract and thus the database will not have any individual ``CanBark`` objects. -.. code-block:: sdl - :version-lt: 3.0 - - abstract type CanBark { - required property bark_sound -> str; - } - - type Animal { - property species -> str; - } - - type Dog extending Animal, CanBark { - property breed -> str; - } - .. code-block:: sdl abstract type CanBark { @@ -94,27 +71,13 @@ Polymorphic queries `. Multiple Inheritance ^^^^^^^^^^^^^^^^^^^^ +.. index:: Multiple Inheritance + Object types can :ref:`extend more than one type ` β€” that's called *multiple inheritance*. This mechanism allows building complex object types out of combinations of more basic types. -.. code-block:: sdl - :version-lt: 3.0 - - abstract type HasName { - property first_name -> str; - property last_name -> str; - } - - abstract type HasEmail { - property email -> str; - } - - type Person extending HasName, HasEmail { - property profession -> str; - } - .. code-block:: sdl abstract type HasName { @@ -136,25 +99,12 @@ types out of combinations of more basic types. Overloading ^^^^^^^^^^^ +.. index:: overloaded + An object type can overload an inherited property or link. All overloaded declarations must be prefixed with the ``overloaded`` prefix to avoid unintentional overloads. -.. code-block:: sdl - :version-lt: 3.0 - - abstract type Person { - property name -> str; - multi link friends -> Person; - } - - type Student extending Person { - overloaded property name -> str { - constraint exclusive; - } - overloaded multi link friends -> Student; - } - .. code-block:: sdl abstract type Person { @@ -199,18 +149,6 @@ It's possible to define ``abstract`` links that aren't tied to a particular *source* or *target*. Abstract links can be marked as readonly and contain annotations, property declarations, constraints, and indexes. -.. code-block:: sdl - :version-lt: 3.0 - - abstract link link_with_strength { - property strength -> float64; - index on (__subject__@strength); - } - - type Person { - multi link friends extending link_with_strength -> Person; - } - .. code-block:: sdl abstract link link_with_strength { @@ -232,21 +170,6 @@ Constraints Use ``abstract`` to declare reusable, user-defined constraint types. -.. code-block:: sdl - :version-lt: 3.0 - - abstract constraint in_range(min: anyreal, max: anyreal) { - errmessage := - 'Value must be in range [{min}, {max}].'; - using (min <= __subject__ and __subject__ < max); - } - - type Player { - property points -> int64 { - constraint in_range(0, 100); - } - } - .. code-block:: sdl abstract constraint in_range(min: anyreal, max: anyreal) { diff --git a/docs/datamodel/introspection/casts.rst b/docs/datamodel/introspection/casts.rst index 6bd45089114..acdb12529fd 100644 --- a/docs/datamodel/introspection/casts.rst +++ b/docs/datamodel/introspection/casts.rst @@ -4,7 +4,7 @@ Casts ===== -This section describes introspection of EdgeDB :eql:op:`type casts +This section describes introspection of Gel :eql:op:`type casts `. Features like whether the casts are implicit can be discovered by introspecting ``schema::Cast``. @@ -112,7 +112,7 @@ of those types: {1.0, 2.0} What happens if there's no implicit cast between a couple of scalars -in this type of example? EdgeDB checks whether there's a scalar type +in this type of example? Gel checks whether there's a scalar type such that all of the set elements can be implicitly cast into that: .. code-block:: edgeql-repl diff --git a/docs/datamodel/introspection/index.rst b/docs/datamodel/introspection/index.rst index e0ef0c69b8e..cd4bc14478c 100644 --- a/docs/datamodel/introspection/index.rst +++ b/docs/datamodel/introspection/index.rst @@ -3,7 +3,9 @@ Introspection ============= -All of the schema information in EdgeDB is stored in the ``schema`` +.. index:: describe, introspect, typeof, schema module + +All of the schema information in Gel is stored in the ``schema`` :ref:`module ` and is accessible via *introspection queries*. @@ -24,7 +26,7 @@ to the ``schema::ObjectType``. For scalars there's the to get the type of an expression. Finally, the command :eql:stmt:`describe` can be used to get -information about EdgeDB types in a variety of human-readable formats. +information about Gel types in a variety of human-readable formats. .. toctree:: :maxdepth: 3 diff --git a/docs/datamodel/introspection/mutation_rewrites.rst b/docs/datamodel/introspection/mutation_rewrites.rst index 4f718e434a4..075aea94d17 100644 --- a/docs/datamodel/introspection/mutation_rewrites.rst +++ b/docs/datamodel/introspection/mutation_rewrites.rst @@ -1,5 +1,3 @@ -.. versionadded:: 3.0 - .. _ref_datamodel_introspection_mutation_rewrites: ================= diff --git a/docs/datamodel/introspection/objects.rst b/docs/datamodel/introspection/objects.rst index 825469fe146..d62f18c3bae 100644 --- a/docs/datamodel/introspection/objects.rst +++ b/docs/datamodel/introspection/objects.rst @@ -46,23 +46,6 @@ Introspection of the ``schema::ObjectType``: Consider the following schema: -.. code-block:: sdl - :version-lt: 3.0 - - abstract type Addressable { - property address -> str; - } - - type User extending Addressable { - # define some properties and a link - required property name -> str; - - multi link friends -> User; - - # define an index for User based on name - index on (.name); - } - .. code-block:: sdl abstract type Addressable { diff --git a/docs/datamodel/introspection/operators.rst b/docs/datamodel/introspection/operators.rst index 063c8df9d6e..4abca8080b1 100644 --- a/docs/datamodel/introspection/operators.rst +++ b/docs/datamodel/introspection/operators.rst @@ -4,7 +4,7 @@ Operators ========= -This section describes introspection of EdgeDB operators. Much like +This section describes introspection of Gel operators. Much like functions, operators have parameters and return types as well as a few other features. diff --git a/docs/datamodel/introspection/triggers.rst b/docs/datamodel/introspection/triggers.rst index 8131ea9f587..156bacbfd6f 100644 --- a/docs/datamodel/introspection/triggers.rst +++ b/docs/datamodel/introspection/triggers.rst @@ -1,5 +1,3 @@ -.. versionadded:: 3.0 - .. _ref_datamodel_introspection_triggers: ========= diff --git a/docs/datamodel/links.rst b/docs/datamodel/links.rst index 81cffa6c96a..253bb454b6d 100644 --- a/docs/datamodel/links.rst +++ b/docs/datamodel/links.rst @@ -4,166 +4,200 @@ Links ===== -:index: link one-to-one one-to-many many-to-one many-to-many +Links define a relationship between two +:ref:`object types ` in Gel. -Links define a specific relationship between two :ref:`object -types `. +Links in |Gel| are incredibly powerful and flexible. They can be used to model +relationships of any cardinality, can be traversed in both directions, +can be polymorphic, can have constraints, and many other things. -Defining links --------------- -.. code-block:: sdl - :version-lt: 3.0 +Links are directional +===================== - type Person { - link best_friend -> Person; - } +Links are *directional*: they have a **source** (the type on which they are +declared) and a **target** (the type they point to). + +E.g. the following schema defines a link from ``Person`` to ``Person`` and +a link from ``Company`` to ``Person``: .. code-block:: sdl - type Person { - best_friend: Person; - } + type Person { + link best_friend: Person; + } + + type Company { + multi link employees: Person; + } + +The ``employees`` link's source is ``Company`` and its target is ``Person``. + +The ``link`` keyword is optional, and can be omitted. -Links are *directional*; they have a source (the object type on which they are -declared) and a *target* (the type they point to). Link cardinality ----------------- +================ + +.. index:: single, multi All links have a cardinality: either ``single`` or ``multi``. The default is ``single`` (a "to-one" link). Use the ``multi`` keyword to declare a "to-many" -link. +link: .. code-block:: sdl - :version-lt: 3.0 - type Person { - multi link friends -> Person; - } + type Person { + multi friends: Person; + } -.. code-block:: sdl - type Person { - multi friends: Person; - } +Required links +============== + +.. index:: required, optional, not null -On the other hand, backlinks work in reverse to find objects that link to the -object, and thus assume ``multi`` as a default. Use the ``single`` keyword to -declare a "to-one" backlink. +All links are either ``optional`` or ``required``; the default is ``optional``. +Use the ``required`` keyword to declare a required link. A required link must +point to *at least one* target instance, and if the cardinality of the required +link is ``single``, it must point to *exactly one* target instance. In this +scenario, every ``Person`` must have *exactly one* ``best_friend``: .. code-block:: sdl - :version-lt: 4.0 - type Author { - link posts := . Person; - } +You can add an ``exclusive`` constraint to a link to guarantee that no other +instances can link to the same target(s): .. code-block:: sdl - type Person { - required best_friend: Person; + type Person { + name: str; + } + + type GroupChat { + required multi members: Person { + constraint exclusive; } + } -Links with cardinality ``multi`` can also be ``required``; -``required multi`` links must point to *at least one* target object. +With ``exclusive`` on ``GroupChat.members``, two ``GroupChat`` objects cannot +link to the same ``Person``; put differently, no ``Person`` can be a +``member`` of multiple ``GroupChat`` objects. -.. code-block:: sdl - :version-lt: 3.0 +Backlinks +========= - type Person { - property name -> str; - } +.. index:: backlink - type GroupChat { - required multi link members -> Person; - } +In Gel you can traverse links in reverse to find objects that link to +the object. You can do that directly in your query. E.g. for this example +schema: .. code-block:: sdl - type Person { - name: str; - } + type Author { + name: str; + } - type GroupChat { - required multi members: Person; - } + type Article { + title: str; + multi authors: Author; + } -In this scenario, each ``GroupChat`` must contain at least one person. -Attempting to create a ``GroupChat`` with no members would fail. +You can find all articles by "John Doe" by traversing the ``authors`` +link in reverse: -Exclusive constraints ---------------------- +.. code-block:: edgeql -You can add an ``exclusive`` constraint to a link to guarantee that no other -instances can link to the same target(s). + select Author { + articles := . str; - } +* ``.<`` is used to traverse a link in reverse, it's the reverse of + the familiar ``.`` operator. - type GroupChat { - required multi link members -> Person { - constraint exclusive; - } - } +* ``authors`` is the name of the link that the type on the other side + has to point to ``Author``. In this case we know that ``Article`` + has a link ``authors`` to ``Author``, so we use it! -.. code-block:: sdl +* ``[is Article]`` is a filter that ensures we only traverse links + that point to ``Article`` objects. + +If there's a backlink that you will be traversing often, you can declare it +as a computed link: + +.. code-block:: sdl-diff - type Person { + type Author { name: str; + + articles := . str - } - - type Shirt { - required property color -> str; - link owner -> Person; - } - .. code-block:: sdl - type Person { - required name: str - } + type Person { + required name: str + } - type Shirt { - required color: str; - owner: Person; - } + type Shirt { + required color: str; + owner: Person; + } Since links are ``single`` by default, each ``Shirt`` only corresponds to one ``Person``. In the absence of any exclusivity constraints, multiple shirts @@ -223,53 +245,38 @@ can link to the same ``Person``. Thus, we have a one-to-many relationship between ``Person`` and ``Shirt``. When fetching a ``Person``, it's possible to deeply fetch their collection of -``Shirts`` by traversing the ``Shirt.owner`` link *in reverse*. This is known -as a **backlink**; read the :ref:`select docs ` to +``Shirts`` by traversing the ``Shirt.owner`` link *in reverse*, known as a +**backlink**. See the :ref:`select docs ` to learn more. + .. _ref_guide_one_to_many: One-to-many -^^^^^^^^^^^ +----------- Conceptually, one-to-many and many-to-one relationships are identical; the -"directionality" of a relation is just a matter of perspective. Here, the -same "shirt owner" relationship is represented with a ``multi`` link. +"directionality" is a matter of perspective. Here, the same "shirt owner" +relationship is represented with a ``multi`` link: .. code-block:: sdl - :version-lt: 3.0 - - type Person { - required property name -> str; - multi link shirts -> Shirt { - # ensures a one-to-many relationship - constraint exclusive; - } - } - type Shirt { - required property color -> str; + type Person { + required name: str; + multi shirts: Shirt { + # ensures a one-to-many relationship + constraint exclusive; } + } -.. code-block:: sdl - - type Person { - required name: str; - multi shirts: Shirt { - # ensures a one-to-many relationship - constraint exclusive; - } - } - - type Shirt { - required color: str; - } + type Shirt { + required color: str; + } .. note:: - Don't forget the exclusive constraint! This is required to ensure that each - ``Shirt`` corresponds to a single ``Person``. Without it, the relationship - will be many-to-many. + Don't forget the ``exclusive`` constraint! Without it, the relationship + becomes many-to-many. Under the hood, a ``multi`` link is stored in an intermediate `association table `_, whereas a @@ -277,137 +284,84 @@ table `_, whereas a .. note:: - Choosing a link direction can be tricky when modeling these kinds of - relationships. Should you model the relationship as one-to-many using a - ``multi`` link, or as many-to-one using a ``single`` link with a - backlink to traverse in the other direction? A general rule of thumb - in this case is as follows. + Choosing a link direction can be tricky. Should you model this + relationship as one-to-many (with a ``multi`` link) or as many-to-one + (with a ``single`` link and a backlink)? A general rule of thumb: - Use a ``multi`` link if: - - - The relationship is relatively stable and thus not updated very - frequently. For example, a list of postal addresses in a - user profile. - - The number of elements in the link tends to be small. - - Otherwise, prefer a single link from one object type coupled with a - computed backlink on the other. This is marginally more efficient - and generally recommended when modeling 1:N relations: + - Use a ``multi`` link if the relationship is relatively stable and + not updated frequently, and the set of related objects is typically + small. For example, a list of postal addresses in a user profile. + - Otherwise, prefer a single link from one object type and a computed + backlink on the other. This can be more efficient and is generally + recommended for 1:N relations: .. code-block:: sdl - :version-lt: 4.0 - - type Post { - required author: User; - } - - type User { - multi link posts := (. str; - link assigned_space -> ParkingSpace { - constraint exclusive; - } - } - - type ParkingSpace { - required property number -> int64; - } +of the target type, and vice versa. As an example, consider a schema to +represent assigned parking spaces: .. code-block:: sdl - type Employee { - required name: str; - assigned_space: ParkingSpace { - constraint exclusive; - } + type Employee { + required name: str; + assigned_space: ParkingSpace { + constraint exclusive; } + } - type ParkingSpace { - required number: int64; - } + type ParkingSpace { + required number: int64; + } All links are ``single`` unless otherwise specified, so no ``Employee`` can -have more than one ``assigned_space``. Moreover, the -:eql:constraint:`exclusive` constraint guarantees that a given ``ParkingSpace`` -can't be assigned to multiple employees at once. Together the ``single -link`` and exclusivity constraint constitute a *one-to-one* relationship. +have more than one ``assigned_space``. The :eql:constraint:`exclusive` +constraint guarantees that a given ``ParkingSpace`` can't be assigned to +multiple employees. Together, these form a one-to-one relationship. + .. _ref_guide_many_to_many: Many-to-many -^^^^^^^^^^^^ +------------ A *many-to-many* relation is the least constrained kind of relationship. There -is no exclusivity or cardinality constraints in either direction. As an example -consider a simple app where a ``User`` can "like" their favorite ``Movies``. +is no exclusivity or cardinality constraint in either direction. As an example, +consider a simple app where a ``User`` can "like" their favorite ``Movie``: .. code-block:: sdl - :version-lt: 3.0 - type User { - required property name -> str; - multi link likes -> Movie; - } - type Movie { - required property title -> str; - } + type User { + required name: str; + multi likes: Movie; + } -.. code-block:: sdl - - type User { - required name: str; - multi likes: Movie; - } - type Movie { - required title: str; - } + type Movie { + required title: str; + } A user can like multiple movies. And in the absence of an ``exclusive`` -constraint, each movie can be liked by multiple users. Thus this is a -*many-to-many* relationship. +constraint, each movie can be liked by multiple users, creating a many-to-many +relationship. .. note:: - Links are always distinct. That means it's not possible to link the same - objects twice. - - .. code-block:: sdl - :version-lt: 3.0 - - type User { - required property name -> str; - multi link watch_history -> Movie { - seen_at: datetime; - }; - } - type Movie { - required property title -> str; - } + Links are always distinct. It's not possible to link the **same** objects + twice. For example: .. code-block:: sdl @@ -417,26 +371,14 @@ constraint, each movie can be liked by multiple users. Thus this is a seen_at: datetime; }; } + type Movie { required title: str; } - With this model it's not possible to watch the same movie twice. Instead, you - might change your ``seen_at`` link property to an array to store multiple - watch times. - - .. code-block:: sdl - :version-lt: 3.0 - - type User { - required property name -> str; - multi link watch_history -> Movie { - seen_at: array; - }; - } - type Movie { - required property title -> str; - } + In this model, a user can't watch the same movie more than once (the link + from a specific user to a specific movie can exist only once). One approach + is to store multiple timestamps in an array on the link property: .. code-block:: sdl @@ -450,40 +392,7 @@ constraint, each movie can be liked by multiple users. Thus this is a required title: str; } - Alternatively, the watch history could be modeled more traditionally as its - own type. - - .. code-block:: sdl - :version-lt: 3.0 - - type User { - required property name -> str; - multi link watch_history := . User; - required link movie -> Movie; - property seen_at -> datetime; - } - - .. code-block:: sdl - :version-lt: 4.0 - - type User { - required name: str; - multi link watch_history := . str; - multi link friends -> Person { - default := (select Person order by random() limit 3); - } + type Person { + name: str; + multi family_members: Person { + relationship: str; } + } -.. code-block:: sdl +.. note:: - type Person { - required name: str; - multi friends: Person { - default := (select Person order by random() limit 3); - } - } + Link properties can only be **primitive** data (scalars, enums, + arrays, or tuples) β€” *not* links to other objects. Also note that + link properties cannot be made required. They are always optional + by design. -.. _ref_datamodel_link_properties: +Link properties are especially useful with many-to-many relationships, where +the link itself is a distinct concept with its own data. For relations +like one-to-one or one-to-many, it's often clearer to store data in the +object type itself instead of in a link property. -Link properties ---------------- +Inserting and updating link properties +-------------------------------------- -Like object types, links in EdgeDB can contain **properties**. Link properties -can be used to store metadata about links, such as *when* they were created or -the *nature/strength* of the relationship. +To add a link with a link property, include the property name (prefixed by +``@``) in the shape: -.. code-block:: sdl - :version-lt: 3.0 +.. code-block:: edgeql - type Person { - property name -> str; - multi link family_members -> Person { - property relationship -> str; + insert Person { + name := "Bob", + family_members := ( + select detached Person { + @relationship := "sister" } - } + filter .name = "Alice" + ) + }; -.. code-block:: sdl +Updating a link's property on an **existing** link is similar. You can select +the link from within the object being updated: - type Person { - name: str; - multi family_members: Person { - relationship: str; +.. code-block:: edgeql + + update Person + filter .name = "Bob" + set { + family_members := ( + select .family_members { + @relationship := "step-sister" } - } + filter .name = "Alice" + ) + }; -.. note:: +.. warning:: - The divide between "link" and "property" is important when it comes to - understanding what link properties can do. They are link **properties**, - not link **links**. This means link properties can contain only primitive - data β€” data of any of the :ref:`scalar types ` like - ``str``, ``int32``, or ``bool``, :ref:`enums `, - :ref:`arrays `, and :ref:`tuples - `. They cannot contain links to other objects. + A link property cannot be referenced in a set union *except* in the case of + a :ref:`for loop `. For instance: + + .. code-block:: edgeql + + # 🚫 Does not work + insert Movie { + title := 'The Incredible Hulk', + characters := { + ( + select Person { + @character_name := 'The Hulk' + } + filter .name = 'Mark Ruffalo' + ), + ( + select Person { + @character_name := 'Abomination' + } + filter .name = 'Tim Roth' + ) + } + }; - That means this would not work: + will produce an error ``QueryError: invalid reference to link property in + top level shape``. + + One workaround is to insert them via a ``for`` loop, combined with + :eql:func:`assert_distinct`: + + .. code-block:: edgeql + + # βœ… Works! + insert Movie { + title := 'The Incredible Hulk', + characters := assert_distinct(( + with actors := { + ('The Hulk', 'Mark Ruffalo'), + ('Abomination', 'Tim Roth') + }, + for actor in actors union ( + select Person { + @character_name := actor.0 + } + filter .name = actor.1 + ) + )) + }; - .. code-block:: - :version-lt: 3.0 +Querying link properties +------------------------ - type Person { - property name -> str; - multi link friends -> Person { - link introduced_by -> Person; - } - } +To query a link property, add the link property's name (prefixed with ``@``) +in the shape: - .. code-block:: +.. code-block:: edgeql-repl - type Person { - name: str; - multi friends: Person { - introduced_by: Person; - } - } + db> select Person { + ... name, + ... family_members: { + ... name, + ... @relationship + ... } + ... }; .. note:: - Link properties cannot be made required. They are always optional. + In the results above, Bob has a *step-sister* property on the link to + Alice, but Alice does not automatically have a property describing Bob. + Changes to link properties are not mirrored on the "backlink" side unless + explicitly updated, because link properties cannot be required. -Above, we model a family tree with a single ``Person`` type. The ``Person. -family_members`` link is a many-to-many relation; each ``family_members`` link -can contain a string ``relationship`` describing the relationship of the two -individuals. +.. note:: -Due to how they're persisted under the hood, link properties must always be -``single`` and ``optional``. + For a full guide on modeling, inserting, updating, and querying link + properties, see the :ref:`Using Link Properties ` + guide. -In practice, link properties are most useful with many-to-many relationships. -In that situation there's a significant difference between the *relationship* -described by the link and the *target object*. Thus it makes sense to separate -properties of the relationships and properties of the target objects. On the -other hand, for one-to-one, one-to-many, and many-to-one relationships there's -an exact correspondence between the link and one of the objects being linked. -In these situations any property of the relationship can be equally expressed -as the property of the source object (for one-to-many and one-to-one cases) or -as the property of the target object (for many-to-one and one-to-one cases). -It is generally advisable to use object properties instead of link properties -in these cases due to better ergonomics of selecting, updating, and even -casting into :eql:type:`json` when keeping all data in the same place rather -than spreading it across link and object properties. +.. _ref_datamodel_link_deletion: -Inserting and updating link properties -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Deletion policies +================= -To add a link with a link property, add the link property to a shape on the -linked object being added. Be sure to prepend the link property's name with -``@``. +.. index:: on target delete, on source delete, restrict, delete source, allow, + deferred restrict, delete target, if orphan -.. code-block:: edgeql +Links can declare their own **deletion policy** for when the **target** or +**source** is deleted. - insert Person { - name := "Bob", - family_members := ( - select detached Person { - @relationship := "sister" - } - filter .name = "Alice" - ) - }; +Target deletion +--------------- -The shape could alternatively be included on an insert if the object being -linked (the ``Person`` named "Alice" in this example) is being inserted as part -of the query. If the outer person ("Bob" in the example) already exists and -only the links need to be added, this can be done in an ``update`` query -instead of an ``insert`` as shown in the example above. +The clause ``on target delete`` determines the action when the target object is +deleted: -Updating a link's property is similar to adding a new one except that you no -longer need to select from the object type being linked: you can instead select -the existing link on the object being updated because the link has already been -established. Here, we've discovered that Alice is actually Bob's *step*-sister, -so we want to change the link property on the already-established link between -the two: +- ``restrict`` (default) β€” raises an exception if the target is deleted. +- ``delete source`` β€” deletes the source when the target is deleted (a cascade). +- ``allow`` β€” removes the target from the link if the target is deleted. +- ``deferred restrict`` β€” like ``restrict`` but defers the error until the + end of the transaction if the object remains linked. -.. code-block:: edgeql +.. code-block:: sdl - update Person - filter .name = "Bob" - set { - family_members := ( - select .family_members { - @relationship := "step-sister" - } - filter .name = "Alice" - ) - }; + type MessageThread { + title: str; + } -Using ``select .family_members`` here with the shape including the link -property allows us to modify the link property of the existing link. + type Message { + content: str; + chat: MessageThread { + on target delete delete source; + } + } -.. warning:: - A link property cannot be referenced in a set union *except* in the case of - a :ref:`for loop `. That means this will *not* work: - - .. code-block:: edgeql - - # 🚫 Does not work - insert Movie { - title := 'The Incredible Hulk', - characters := {( - select Person { - @character_name := 'The Hulk' - } filter .name = 'Mark Ruffalo' - ), - ( - select Person { - @character_name := 'Abomination' - } filter .name = 'Tim Roth' - )} - }; - - That query will produce an error: ``QueryError: invalid reference to link - property in top level shape`` - - You can use this workaround instead: - - .. code-block:: edgeql - - # βœ… Works! - insert Movie { - title := 'The Incredible Hulk', - characters := assert_distinct(( - with actors := { - ('The Hulk', 'Mark Ruffalo'), - ('Abomination', 'Tim Roth') - }, - for actor in actors union ( - select Person { - @character_name := actor.0 - } filter .name = actor.1 - ) - )) - }; - - Note that we are also required to wrap the ``actors`` query with - :eql:func:`assert_distinct` here to assure the compiler that the result set - is distinct. +.. _ref_datamodel_links_source_deletion: +Source deletion +--------------- -Querying link properties -^^^^^^^^^^^^^^^^^^^^^^^^ +The clause ``on source delete`` determines the action when the **source** is +deleted: -To query a link property, add the link property's name prepended with ``@`` to -a shape on the link. +- ``allow`` β€” deletes the source, removing the link to the target. +- ``delete target`` β€” unconditionally deletes the target as well. +- ``delete target if orphan`` β€” deletes the target if and only if it's no + longer linked by any other object *via the same link*. -.. code-block:: edgeql-repl +.. code-block:: sdl - db> select Person { - ... name, - ... family_members: { - ... name, - ... @relationship - ... } - ... }; - { - default::Person {name: 'Alice', family_members: {}}, - default::Person { - name: 'Bob', - family_members: { - default::Person {name: 'Alice', @relationship: 'step-sister'} - } - }, + type MessageThread { + title: str; + multi messages: Message { + on source delete delete target; } + } -.. note:: + type Message { + content: str; + } - In the query results above, Alice appears to have no family members even - though we know that, if she is Bob's step-sister, he must be her - step-brother. We would need to update Alice manually before this is - reflected in the database. Since link properties cannot be required, not - setting one is always allowed and results in the value being the empty set - (``{}``). +You can add ``if orphan`` if you'd like to avoid deleting a target that remains +linked elsewhere via the **same** link name. + +.. code-block:: sdl-diff + + type MessageThread { + title: str; + multi messages: Message { + - on source delete delete target; + + on source delete delete target if orphan; + } + } .. note:: - For a full guide on modeling, inserting, updating, and querying link - properties, see the :ref:`Using Link Properties ` - guide. + The ``if orphan`` qualifier **does not** apply globally across + all links in the database or even all links from the same type. If another + link *by a different name* or *with a different on-target-delete* policy + points at the same object, it *doesn't* prevent the object from being + considered "orphaned" for the link that includes ``if orphan``. -.. _ref_datamodel_link_deletion: -Deletion policies ------------------ +.. _ref_datamodel_link_polymorphic: -Links can declare their own **deletion policy**. There are two kinds of events -that might trigger these policies: *target deletion* and *source deletion*. +Polymorphic links +================= -Target deletion -^^^^^^^^^^^^^^^ +.. index:: abstract, subtypes, polymorphic -Target deletion policies determine what action should be taken when the -*target* of a given link is deleted. They are declared with the ``on target -delete`` clause. +Links can be **polymorphic**, i.e., have an ``abstract`` target. In the +example below, we have an abstract type ``Person`` with concrete subtypes +``Hero`` and ``Villain``: .. code-block:: sdl - :version-lt: 3.0 - type MessageThread { - property title -> str; - } + abstract type Person { + name: str; + } - type Message { - property content -> str; - link chat -> MessageThread { - on target delete delete source; - } - } + type Hero extending Person { + # additional fields + } + + type Villain extending Person { + # additional fields + } + +A polymorphic link can target any non-abstract subtype: .. code-block:: sdl - type MessageThread { - title: str; - } + type Movie { + title: str; + multi characters: Person; + } - type Message { - content: str; - chat: MessageThread { - on target delete delete source; - } - } +When querying a polymorphic link, you can filter by a specific subtype, cast +the link to a subtype, etc. See :ref:`Polymorphic Queries ` +for details. -The ``Message.chat`` link in the example uses the ``delete source`` policy. -There are 4 available target deletion policies. +Abstract links +============== -- ``restrict`` (default) - Any attempt to delete the target object immediately - raises an exception. -- ``delete source`` - when the target of a link is deleted, the source - is also deleted. This is useful for implementing cascading deletes. +.. index:: abstract - .. note:: +It's possible to define ``abstract`` links that aren't tied to a particular +source or target, and then extend them in concrete object types. This can help +eliminate repetitive declarations: - There is `a limit - `_ to the depth of a deletion - cascade due to an upstream stack size limitation. +.. code-block:: sdl -- ``allow`` - the target object is deleted and is removed from the - set of the link targets. -- ``deferred restrict`` - any attempt to delete the target object - raises an exception at the end of the transaction, unless by - that time this object is no longer in the set of link targets. + abstract link link_with_strength { + strength: float64; + index on (__subject__@strength); + } -.. _ref_datamodel_links_source_deletion: + type Person { + multi friends: Person { + extending link_with_strength; + }; + } -Source deletion -^^^^^^^^^^^^^^^ -.. versionadded:: 2.0 +.. _ref_eql_sdl_links_overloading: -Source deletion policies determine what action should be taken when the -*source* of a given link is deleted. They are declared with the ``on source -delete`` clause. +Overloading +=========== -There are 3 available source deletion policies: +.. index:: overloaded -- ``allow`` - the source object is deleted and is removed from the set of the - link's source objects. -- ``delete target`` - when the source of a link is deleted, the target - is unconditionally deleted. -- ``delete target if orphan`` - the source object is deleted and the target - object is unconditionally deleted unless the target object is linked to by - another source object via the same link. +When an inherited link is modified (by adding more constraints or changing its +target type, etc.), the ``overloaded`` keyword is required. This prevents +unintentional overloading due to name clashes: .. code-block:: sdl - :version-lt: 3.0 - type MessageThread { - property title -> str; - multi link messages -> Message { - on source delete delete target; - } - } + abstract type Friendly { + # this type can have "friends" + multi friends: Friendly; + } + + type User extending Friendly { + # overload the link target to to be specifically User + overloaded multi friends: User; + + # ... other links and properties + } + + +.. _ref_eql_sdl_links: +.. _ref_eql_sdl_links_syntax: + +Declaring links +=============== + +This section describes the syntax to use links in your schema. + +Syntax +------ + +.. sdl:synopsis:: + + # Concrete link form used inside type declaration: + [ overloaded ] [{required | optional}] [{single | multi}] + [ link ] : + [ "{" + [ extending [, ...] ; ] + [ default := ; ] + [ readonly := {true | false} ; ] + [ on target delete ; ] + [ on source delete ; ] + [ ] + [ ] + [ ] + ... + "}" ] + + # Computed link form used inside type declaration: + [{required | optional}] [{single | multi}] + [ link ] := ; + + # Computed link form used inside type declaration (extended): + [ overloaded ] [{required | optional}] [{single | multi}] + link [: ] + [ "{" + using () ; + [ extending [, ...] ; ] + [ ] + [ ] + ... + "}" ] + + # Abstract link form: + abstract link + [ "{" + [ extending [, ...] ; ] + [ readonly := {true | false} ; ] + [ ] + [ ] + [ ] + [ ] + ... + "}" ] + +There are several forms of link declaration, as shown in the syntax synopsis +above: + +- the first form is the canonical definition form; +- the second form is used for defining a + :ref:`computed link `; +- and the last form is used to define an abstract link. + +The following options are available: + +:eql:synopsis:`overloaded` + If specified, indicates that the link is inherited and that some + feature of it may be altered in the current object type. It is an + error to declare a link as *overloaded* if it is not inherited. + +:eql:synopsis:`required` + If specified, the link is considered *required* for the parent + object type. It is an error for an object to have a required + link resolve to an empty value. Child links **always** inherit + the *required* attribute, i.e it is not possible to make a + required link non-required by extending it. + +:eql:synopsis:`optional` + This is the default qualifier assumed when no qualifier is + specified, but it can also be specified explicitly. The link is + considered *optional* for the parent object type, i.e. it is + possible for the link to resolve to an empty value. + +:eql:synopsis:`multi` + Specifies that there may be more than one instance of this link + in an object, in other words, ``Object.link`` may resolve to a set + of a size greater than one. + +:eql:synopsis:`single` + Specifies that there may be at most *one* instance of this link + in an object, in other words, ``Object.link`` may resolve to a set + of a size not greater than one. ``single`` is assumed if nether + ``multi`` nor ``single`` qualifier is specified. + +:eql:synopsis:`extending [, ...]` + Optional clause specifying the *parents* of the new link item. + + Use of ``extending`` creates a persistent schema relationship + between the new link and its parents. Schema modifications + to the parent(s) propagate to the child. + + If the same *property* name exists in more than one parent, or + is explicitly defined in the new link and at least one parent, + then the data types of the property targets must be *compatible*. + If there is no conflict, the link properties are merged to form a + single property in the new link item. + +:eql:synopsis:`` + The type must be a valid :ref:`type expression ` + denoting an object type. + +The valid SDL sub-declarations are listed below: + +:eql:synopsis:`default := ` + Specifies the default value for the link as an EdgeQL expression. + The default value is used in an ``insert`` statement if an explicit + value for this link is not specified. + + The expression must be :ref:`Stable `. + +:eql:synopsis:`readonly := {true | false}` + If ``true``, the link is considered *read-only*. Modifications + of this link are prohibited once an object is created. All of the + derived links **must** preserve the original *read-only* value. + +:sdl:synopsis:`` + Set link :ref:`annotation ` + to a given *value*. + +:sdl:synopsis:`` + Define a concrete :ref:`property ` on the link. + +:sdl:synopsis:`` + Define a concrete :ref:`constraint ` on the link. + +:sdl:synopsis:`` + Define an :ref:`index ` for this abstract + link. Note that this index can only refer to link properties. + + +.. _ref_eql_ddl_links: + +DDL commands +============ + +This section describes the low-level DDL commands for creating, altering, and +dropping links. You typically don't need to use these commands directly, but +knowing about them is useful for reviewing migrations. + +Create link +----------- - type Message { - property content -> str; - } +:eql-statement: +:eql-haswith: -.. code-block:: sdl +Define a new link. - type MessageThread { - title: str; - multi messages: Message { - on source delete delete target; - } - } +.. eql:synopsis:: + + [ with [, ...] ] + {create|alter} type "{" + [ ... ] + create [{required | optional}] [{single | multi}] + link + [ extending [, ...] ] -> + [ "{" ; [...] "}" ] ; + [ ... ] + "}" - type Message { - content: str; - } + # Computed link form: + + [ with [, ...] ] + {create|alter} type "{" + [ ... ] + create [{required | optional}] [{single | multi}] + link := ; + [ ... ] + "}" -Under this policy, deleting a ``MessageThread`` will *unconditionally* delete -its ``messages`` as well. + # Abstract link form: -To avoid deleting a ``Message`` that is linked to by other ``MessageThread`` -objects via their ``message`` link, append ``if orphan`` to that link's -deletion policy. + [ with [, ...] ] + create abstract link [::] [extending [, ...]] + [ "{" ; [...] "}" ] -.. code-block:: sdl-diff - :version-lt: 3.0 + # where is one of - type MessageThread { - property title -> str; - multi link messages -> Message { - - on source delete delete target; - + on source delete delete target if orphan; - } - } + set default := + set readonly := {true | false} + create annotation := + create property ... + create constraint ... + on target delete + on source delete + reset on target delete + create index on -.. code-block:: sdl-diff +Description +^^^^^^^^^^^ - type MessageThread { - title: str; - multi messages: Message { - - on source delete delete target; - + on source delete delete target if orphan; - } - } +The combinations of ``create type ... create link`` and ``alter type ... +create link`` define a new concrete link for a given object type, in DDL form. -.. note:: +There are three forms of ``create link``: - The ``if orphan`` qualifier does not apply globally across all links in the - database or across any other links even if they're from the same type. - Deletion policies using ``if orphan`` will result in the target being - deleted unless +1. The canonical definition form (specifying a target type). +2. The computed link form (declaring a link via an expression). +3. The abstract link form (declaring a module-level link). - 1. it is linked by another object via **the same link the policy is on**, - or - 2. its deletion is restricted by another link's ``on target delete`` policy - (which defaults to ``restrict`` unless otherwise specified) +Parameters +^^^^^^^^^^^ - For example, a ``Message`` might be linked from both a ``MessageThread`` - and a ``Channel``, which is defined like this: +Most sub-commands and options mirror those found in the +:ref:`SDL link declaration `. In DDL form: - .. code-block:: sdl +- ``set default := `` specifies a default value. +- ``set readonly := {true | false}`` makes the link read-only or not. +- ``create annotation := `` adds an annotation. +- ``create property ...`` defines a property on the link. +- ``create constraint ...`` defines a constraint on the link. +- ``on target delete `` and ``on source delete `` specify + deletion policies. +- ``reset on target delete`` resets the target deletion policy to default + or inherited. +- ``create index on `` creates an index on the link. - type Channel { - title: str; - multi messages: Message { - on target delete allow; - } - } +Examples +^^^^^^^^ - If the ``MessageThread`` linking to the ``Message`` is deleted, the source - deletion policy would still result in the ``Message`` being deleted as long - as no other ``MessageThread`` objects link to it on their ``messages`` link - and the deletion isn't otherwise restricted (e.g., the default policy of - ``on target delete restrict`` has been overridden, as in the schema above). - The object is deleted despite not being orphaned with respect to *all* - links because it *is* orphaned with respect to the ``MessageThread`` type's - ``messages`` field, which is the link governed by the deletion policy. - - If the ``Channel`` type's ``messages`` link had the default policy, the - outcome would change. - - .. code-block:: sdl-diff - - type Channel { - title: str; - multi messages: Message { - - on target delete allow; - } - } - - With this schema change, the ``Message`` object would *not* be deleted, but - not because the message isn't globally orphaned. Deletion would be - prevented because of the default target deletion policy of ``restrict`` - which would now be in force on the linking ``Channel`` object's - ``messages`` link. +.. code-block:: edgeql - The limited scope of ``if orphan`` holds true even when the two links to an - object are from the same type. If ``MessageThread`` had two different links - both linking to messages β€” maybe the existing ``messages`` link and another - called ``related`` used to link other related ``Message`` objects that are - not in the thread β€” ``if orphan`` on a deletion policy on ``message`` could - result in linked messages being deleted even if they were also linked from - another ``MessageThread`` object's ``related`` link because they were - orphaned with respect to the ``messages`` link. + alter type User { + create multi link friends -> User + }; +.. code-block:: edgeql -.. _ref_datamodel_link_polymorphic: + alter type User { + create link special_group := ( + select __source__.friends + filter .town = __source__.town + ) + }; -Polymorphic links ------------------ +.. code-block:: edgeql -Links can have ``abstract`` targets, in which case the link is considered -**polymorphic**. Consider the following schema: + create abstract link orderable { + create property weight -> std::int64 + }; + + alter type User { + create multi link interests extending orderable -> Interest + }; + + +Alter link +---------- + +:eql-statement: +:eql-haswith: + +Changes the definition of a link. + +.. eql:synopsis:: + + [ with [, ...] ] + {create|alter} type "{" + [ ... ] + alter link + [ "{" ] ; [...] [ "}" ]; + [ ... ] + "}" + + [ with [, ...] ] + alter abstract link [::] + [ "{" ] ; [...] [ "}" ]; + + # where is one of + + set default := + reset default + set readonly := {true | false} + reset readonly + rename to + extending ... + set required + set optional + reset optionality + set single + set multi + reset cardinality + set type [using ()] + reset type + using () + create annotation := + alter annotation := + drop annotation + create property ... + alter property ... + drop property ... + create constraint ... + alter constraint ... + drop constraint ... + on target delete + on source delete + create index on + drop index on + +Description +^^^^^^^^^^^ -.. code-block:: sdl - :version-lt: 3.0 +This command modifies an existing link on a type. It can also be used on +an abstract link at the module level. - abstract type Person { - property name -> str; - } +Parameters +^^^^^^^^^^ - type Hero extending Person { - # additional fields - } +- ``rename to `` changes the link's name. +- ``extending ...`` changes or adds link parents. +- ``set required`` / ``set optional`` changes the link optionality. +- ``reset optionality`` reverts optionality to default or inherited value. +- ``set single`` / ``set multi`` changes cardinality. +- ``reset cardinality`` reverts cardinality to default or inherited value. +- ``set type [using ()]`` changes the link's target type. +- ``reset type`` reverts the link's type to inherited. +- ``using ()`` changes the expression of a computed link. +- ``create annotation``, ``alter annotation``, ``drop annotation`` manage + annotations. +- ``create property``, ``alter property``, ``drop property`` manage link + properties. +- ``create constraint``, ``alter constraint``, ``drop constraint`` manage + link constraints. +- ``on target delete `` and ``on source delete `` manage + deletion policies. +- ``reset on target delete`` reverts the target deletion policy. +- ``create index on `` / ``drop index on `` manage + indexes on link properties. + +Examples +^^^^^^^^ - type Villain extending Person { - # additional fields - } +.. code-block:: edgeql -.. code-block:: sdl + alter type User { + alter link friends create annotation title := "Friends"; + }; - abstract type Person { - name: str; - } +.. code-block:: edgeql - type Hero extending Person { - # additional fields - } + alter abstract link orderable rename to sorted; - type Villain extending Person { - # additional fields - } +.. code-block:: edgeql -The ``abstract`` type ``Person`` has two concrete subtypes: ``Hero`` and -``Villain``. Despite being abstract, ``Person`` can be used as a link target in -concrete object types. + alter type User { + alter link special_group using ( + # at least one of the friend's interests + # must match the user's + select __source__.friends + filter .interests IN __source__.interests + ); + }; -.. code-block:: sdl - :version-lt: 3.0 +Drop link +--------- - type Movie { - property title -> str; - multi link characters -> Person; - } +:eql-statement: +:eql-haswith: -.. code-block:: sdl +Removes the specified link from the schema. - type Movie { - title: str; - multi characters: Person; - } +.. eql:synopsis:: -In practice, the ``Movie.characters`` link can point to a ``Hero``, -``Villain``, or any other non-abstract subtype of ``Person``. For details on -how to write queries on such a link, refer to the :ref:`Polymorphic Queries -docs ` + [ with [, ...] ] + alter type "{" + [ ... ] + drop link + [ ... ] + "}" + [ with [, ...] ] + drop abstract link []:: -Abstract links --------------- +Description +^^^^^^^^^^^ -It's possible to define ``abstract`` links that aren't tied to a particular -*source* or *target*. If you're declaring several links with the same set -of properties, annotations, constraints, or indexes, abstract links can be used -to eliminate repetitive SDL. +- ``alter type ... drop link `` removes the link from an object type. +- ``drop abstract link `` removes an abstract link from the schema. -.. code-block:: sdl - :version-lt: 3.0 +Examples +^^^^^^^^ - abstract link link_with_strength { - property strength -> float64; - index on (__subject__@strength); - } +.. code-block:: edgeql - type Person { - multi link friends extending link_with_strength -> Person; - } + alter type User drop link friends; -.. code-block:: sdl +.. code-block:: edgeql - abstract link link_with_strength { - strength: float64; - index on (__subject__@strength); - } + drop abstract link orderable; - type Person { - multi friends: Person { - extending link_with_strength; - }; - } .. list-table:: :class: seealso * - **See also** - * - :ref:`SDL > Links ` - * - :ref:`DDL > Links ` - * - :ref:`Introspection > Object types - ` + - :ref:`Introspection > Object types ` diff --git a/docs/datamodel/modules.rst b/docs/datamodel/modules.rst new file mode 100644 index 00000000000..d47151019c2 --- /dev/null +++ b/docs/datamodel/modules.rst @@ -0,0 +1,289 @@ +.. _ref_datamodel_modules: +.. _ref_eql_sdl_modules: + +======= +Modules +======= + +Each |branch| has a schema consisting of several **modules**, each with +a unique name. Modules can be used to organize large schemas into +logical units. In practice, though, most users put their entire +schema inside a single module called ``default``. + +.. code-block:: sdl + + module default { + # declare types here + } + +.. _ref_name_resolution: + +Name resolution +=============== + +When you define a module that references schema objects from another module, +you must use a *fully-qualified* name in the form +``other_module_name::object_name``: + +.. code-block:: sdl + + module A { + type User extending B::AbstractUser; + } + + module B { + abstract type AbstractUser { + required name: str; + } + } + +Reserved module names +===================== + +The following module names are reserved by |Gel| and contain pre-defined +types, utility functions, and operators: + +* ``std``: standard types, functions, and operators in the :ref:`standard + library ` +* ``math``: algebraic and statistical :ref:`functions ` +* ``cal``: local (non-timezone-aware) and relative date/time :ref:`types and + functions ` +* ``schema``: types describing the :ref:`introspection + ` schema +* ``sys``: system-wide entities, such as user roles and + :ref:`databases ` +* ``cfg``: configuration and settings + + +Modules are containers +====================== + +They can contain types, functions, and other modules. Here's an example of an +empty module: + +.. code-block:: sdl + + module my_module {} + +And here's an example of a module with a type: + +.. code-block:: sdl + + module my_module { + type User { + required name: str; + } + } + + +Nested modules +============== + +.. code-block:: sdl + + module dracula { + type Person { + required name: str; + multi places_visited: City; + strength: int16; + } + + module combat { + function fight( + one: dracula::Person, + two: dracula::Person + ) -> str + using ( + (one.name ?? 'Fighter 1') ++ ' wins!' + IF (one.strength ?? 0) > (two.strength ?? 0) + ELSE (two.name ?? 'Fighter 2') ++ ' wins!' + ); + } + } + +You can chain together module names in a fully-qualified name to traverse a +tree of nested modules. For example, to call the ``fight`` function in the +nested module example above, you would use +``dracula::combat::fight()``. + + +Declaring modules +================= + +This section describes the syntax to declare a module in your schema. + + +Syntax +------ + +.. sdl:synopsis:: + + module "{" + [ ] + ... + "}" + +Define a nested module: + +.. sdl:synopsis:: + + module "{" + [ ] + module "{" + [ ] + "}" + ... + "}" + + +Description +^^^^^^^^^^^ + +The module block declaration defines a new module similar to the +:eql:stmt:`create module` command, but it also allows putting the +module content as nested declarations: + +:sdl:synopsis:`` + Define various schema items that belong to this module. + +Unlike :eql:stmt:`create module`, a module block with the +same name can appear multiple times in an SDL document. In that case +all blocks with the same name are merged into a single module under +that name. For example: + +.. code-block:: sdl + + module my_module { + abstract type Named { + required name: str; + } + } + + module my_module { + type User extending Named; + } + +The above is equivalent to: + +.. code-block:: sdl + + module my_module { + abstract type Named { + required name: str; + } + + type User extending Named; + } + +Typically, in the documentation examples of SDL the *module block* is +omitted and instead its contents are described without assuming which +specific module they belong to. + +It's also possible to declare modules implicitly. In this style, SDL +declaration uses a :ref:`fully-qualified name ` for the +item that is being declared. The *module* part of the *fully-qualified* name +implies that a module by that name will be automatically created in the +schema. The following declaration is equivalent to the previous examples, +but it declares module ``my_module`` implicitly: + +.. code-block:: sdl + + abstract type my_module::Named { + required name: str; + } + + type my_module::User extending my_module::Named; + +A module block can be nested inside another module block to create a nested +module. If you want to reference an entity in a nested module by its +fully-qualified name, you will need to include all of the containing +modules' names: ``::::`` + +.. _ref_eql_ddl_modules: + +DDL commands +============ + +This section describes the low-level DDL commands for creating and dropping +modules. You typically don't need to use these commands directly, but +knowing about them is useful for reviewing migrations. + + +Create module +------------- + +:eql-statement: + +Create a new module. + +.. eql:synopsis:: + + create module [ :: ] + [ if not exists ]; + +There's a :ref:`corresponding SDL declaration ` +for a module, although in SDL a module declaration is likely to also +include that module's content. + + +Description +^^^^^^^^^^^ + +The command ``create module`` defines a new module for the current +:versionreplace:`database;5.0:branch`. The name of the new module must be +distinct from any existing module in the current +:versionreplace:`database;5.0:branch`. Unlike :ref:`SDL module declaration +` the ``create module`` command does not have sub-commands; +module contents are created separately. + +Parameters +^^^^^^^^^^ + +:eql:synopsis:`if not exists` + Normally, creating a module that already exists is an error, but + with this flag the command will succeed. It is useful for scripts + that add something to a module or, if the module is missing, the + module is created as well. + +Examples +^^^^^^^^ + +Create a new module: + +.. code-block:: edgeql + + create module payments; + +Create a new nested module: + +.. code-block:: edgeql + + create module payments::currencies; + + +Drop module +----------- + +:eql-statement: + +Remove a module. + +.. eql:synopsis:: + + drop module ; + +Description +^^^^^^^^^^^ + +The command ``drop module`` removes an existing empty module from the +current :versionreplace:`database;5.0:branch`. If the module contains any +schema items, this command will fail. + +Examples +^^^^^^^^ + +Remove a module: + +.. code-block:: edgeql + + drop module payments; diff --git a/docs/datamodel/mutation_rewrites.rst b/docs/datamodel/mutation_rewrites.rst index b9a6ff6229a..b014fd956fa 100644 --- a/docs/datamodel/mutation_rewrites.rst +++ b/docs/datamodel/mutation_rewrites.rst @@ -1,12 +1,11 @@ -.. versionadded:: 3.0 - .. _ref_datamodel_mutation_rewrites: ================= Mutation rewrites ================= -.. edb:youtube-embed:: ImgMfb_jCJQ?end=41 +.. index:: rewrite, insert, update, using, __subject__, __specified__, __old__, + modify, modification Mutation rewrites allow you to intercept database mutations (i.e., :ref:`inserts ` and/or :ref:`updates `) and set @@ -17,111 +16,116 @@ Mutation rewrites are complementary to :ref:`triggers `. While triggers are unable to modify the triggering object, mutation rewrites are built for that purpose. +Example: last modified +====================== + Here's an example of a mutation rewrite that updates a property of a ``Post`` type to reflect the time of the most recent modification: .. code-block:: sdl - type Post { - required title: str; - required body: str; - modified: datetime { - rewrite insert, update using (datetime_of_statement()) - } - } - + type Post { + required title: str; + required body: str; + modified: datetime { + rewrite insert, update using (datetime_of_statement()) + } + } Every time a ``Post`` is updated, the mutation rewrite will be triggered, updating the ``modified`` property: .. code-block:: edgeql-repl - db> insert Post { - ... title := 'One wierd trick to fix all your spelling errors' - ... }; - {default::Post {id: 19e024dc-d3b5-11ed-968c-37f5d0159e5f}} - db> select Post {title, modified}; - { - default::Post { - title: 'One wierd trick to fix all your spelling errors', - modified: '2023-04-05T13:23:49.488335Z', - }, - } - db> update Post - ... filter .id = '19e024dc-d3b5-11ed-968c-37f5d0159e5f' - ... set {title := 'One weird trick to fix all your spelling errors'}; - {default::Post {id: 19e024dc-d3b5-11ed-968c-37f5d0159e5f}} - db> select Post {title, modified}; - { - default::Post { - title: 'One weird trick to fix all your spelling errors', - modified: '2023-04-05T13:25:04.119641Z', - }, - } + db> insert Post { + ... title := 'One wierd trick to fix all your spelling errors' + ... }; + {default::Post {id: 19e024dc-d3b5-11ed-968c-37f5d0159e5f}} + db> select Post {title, modified}; + { + default::Post { + title: 'One wierd trick to fix all your spelling errors', + modified: '2023-04-05T13:23:49.488335Z', + }, + } + db> update Post + ... filter .id = '19e024dc-d3b5-11ed-968c-37f5d0159e5f' + ... set {title := 'One weird trick to fix all your spelling errors'}; + {default::Post {id: 19e024dc-d3b5-11ed-968c-37f5d0159e5f}} + db> select Post {title, modified}; + { + default::Post { + title: 'One weird trick to fix all your spelling errors', + modified: '2023-04-05T13:25:04.119641Z', + }, + } In some cases, you will want different rewrites depending on the type of query. Here, we will add an ``insert`` rewrite and an ``update`` rewrite: .. code-block:: sdl - type Post { - required title: str; - required body: str; - created: datetime { - rewrite insert using (datetime_of_statement()) - } - modified: datetime { - rewrite update using (datetime_of_statement()) - } - } + type Post { + required title: str; + required body: str; + created: datetime { + rewrite insert using (datetime_of_statement()) + } + modified: datetime { + rewrite update using (datetime_of_statement()) + } + } With this schema, inserts will set the ``Post`` object's ``created`` property while updates will set the ``modified`` property: .. code-block:: edgeql-repl - db> insert Post { - ... title := 'One wierd trick to fix all your spelling errors' - ... }; - {default::Post {id: 19e024dc-d3b5-11ed-968c-37f5d0159e5f}} - db> select Post {title, created, modified}; - { - default::Post { - title: 'One wierd trick to fix all your spelling errors', - created: '2023-04-05T13:23:49.488335Z', - modified: {}, - }, - } - db> update Post - ... filter .id = '19e024dc-d3b5-11ed-968c-37f5d0159e5f' - ... set {title := 'One weird trick to fix all your spelling errors'}; - {default::Post {id: 19e024dc-d3b5-11ed-968c-37f5d0159e5f}} - db> select Post {title, created, modified}; - { - default::Post { - title: 'One weird trick to fix all your spelling errors', - created: '2023-04-05T13:23:49.488335Z', - modified: '2023-04-05T13:25:04.119641Z', - }, - } + db> insert Post { + ... title := 'One wierd trick to fix all your spelling errors' + ... }; + {default::Post {id: 19e024dc-d3b5-11ed-968c-37f5d0159e5f}} + db> select Post {title, created, modified}; + { + default::Post { + title: 'One wierd trick to fix all your spelling errors', + created: '2023-04-05T13:23:49.488335Z', + modified: {}, + }, + } + db> update Post + ... filter .id = '19e024dc-d3b5-11ed-968c-37f5d0159e5f' + ... set {title := 'One weird trick to fix all your spelling errors'}; + {default::Post {id: 19e024dc-d3b5-11ed-968c-37f5d0159e5f}} + db> select Post {title, created, modified}; + { + default::Post { + title: 'One weird trick to fix all your spelling errors', + created: '2023-04-05T13:23:49.488335Z', + modified: '2023-04-05T13:25:04.119641Z', + }, + } .. note:: - Each property may have a single ``insert`` and a single ``update`` mutation - rewrite rule, or they may have a single rule that covers both. + Each property may have a single ``insert`` and a single ``update`` mutation + rewrite rule, or they may have a single rule that covers both. + + +Mutation context +================ -Available variables -=================== +.. index:: rewrite, __subject__, __specified__, __old__ Inside the rewrite rule's expression, you have access to a few special values: * ``__subject__`` refers to the object type with the new property and link - values + values. * ``__specified__`` is a named tuple with a key for each property or link in the type and a boolean value indicating whether this value was explicitly set - in the mutation + in the mutation. * ``__old__`` refers to the object type with the previous property and link - values (available for update-only mutation rewrites) + values (available for update-only mutation rewrites). Here are some examples of the special values in use. Maybe your blog hosts articles about particularly controversial topics. You could use ``__subject__`` @@ -129,16 +133,16 @@ to enforce a "cooling off" period before publishing a blog post: .. code-block:: sdl - type Post { - required title: str; - required body: str; - publish_time: datetime { - rewrite insert, update using ( - __subject__.publish_time ?? datetime_of_statement() + - cal::to_relative_duration(days := 10) - ) - } - } + type Post { + required title: str; + required body: str; + publish_time: datetime { + rewrite insert, update using ( + __subject__.publish_time ?? datetime_of_statement() + + cal::to_relative_duration(days := 10) + ) + } + } Here we take the post's ``publish_time`` if set or the time the statement is executed and add 10 days to it. That should give our authors time to consider @@ -148,17 +152,17 @@ You can omit ``__subject__`` in many cases and achieve the same thing: .. code-block:: sdl-diff - type Post { - required title: str; - required body: str; - publish_time: datetime { - rewrite insert, update using ( - - __subject__.publish_time ?? datetime_of_statement() + - + .publish_time ?? datetime_of_statement() + - cal::to_relative_duration(days := 10) - ) - } - } + type Post { + required title: str; + required body: str; + publish_time: datetime { + rewrite insert, update using ( + - __subject__.publish_time ?? datetime_of_statement() + + + .publish_time ?? datetime_of_statement() + + cal::to_relative_duration(days := 10) + ) + } + } but only if the path prefix has not changed. In the following schema, for example, the ``__subject__`` in the rewrite rule is required, because in the @@ -167,25 +171,25 @@ context of the nested ``select`` query, the leading dot resolves from the .. code-block:: sdl - type Post { - required title: str; - required body: str; - author_email: str; - author_name: str { - rewrite insert, update using ( - (select User {name} filter .email = __subject__.author_email).name - ) - } - } - type User { - name: str; - email: str; - } + type Post { + required title: str; + required body: str; + author_email: str; + author_name: str { + rewrite insert, update using ( + (select User {name} filter .email = __subject__.author_email).name + ) + } + } + type User { + name: str; + email: str; + } .. note:: - Learn more about how this works in our documentation on :ref:`path - resolution `. + Learn more about how this works in our documentation on :ref:`path + resolution `. Using ``__specified__``, we can determine which fields were specified in the mutation. This would allow us to track when a single property was last modified @@ -193,17 +197,17 @@ as in the ``title_modified`` property in this schema: .. code-block:: sdl - type Post { - required title: str; - required body: str; - title_modified: datetime { - rewrite update using ( - datetime_of_statement() - if __specified__.title - else __old__.title_modified - ) - } - } + type Post { + required title: str; + required body: str; + title_modified: datetime { + rewrite update using ( + datetime_of_statement() + if __specified__.title + else __old__.title_modified + ) + } + } ``__specified__.title`` will be ``true`` if that value was set as part of the update, and this rewrite mutation rule will update ``title_modified`` to @@ -213,19 +217,19 @@ Another way you might use this is to set a default value but allow overriding: .. code-block:: sdl - type Post { - required title: str; - required body: str; - modified: datetime { - rewrite update using ( - datetime_of_statement() - if not __specified__.modified - else .modified - ) - } - } - -Here, we rewrite ``modified`` on updates to ``datetime_of_statment()`` unless + type Post { + required title: str; + required body: str; + modified: datetime { + rewrite update using ( + datetime_of_statement() + if not __specified__.modified + else .modified + ) + } + } + +Here, we rewrite ``modified`` on updates to ``datetime_of_statement()`` unless ``modified`` was set in the update. In that case, we allow the specified value to be set. This is different from a :ref:`default ` value because the rewrite happens on each @@ -247,17 +251,17 @@ comparing them: .. code-block:: sdl - type Post { - required title: str; - required body: str; - modified: datetime { - rewrite update using ( - datetime_of_statement() - if __subject__ {**} != __old__ {**} - else __old__.modified - ) - } - } + type Post { + required title: str; + required body: str; + modified: datetime { + rewrite update using ( + datetime_of_statement() + if __subject__ {**} != __old__ {**} + else __old__.modified + ) + } + } Lastly, if we want to add an ``author`` property that can be set for each write and keep a history of all the authors, we can do this with the help of @@ -265,59 +269,228 @@ and keep a history of all the authors, we can do this with the help of .. code-block:: sdl - type Post { - required title: str; - required body: str; - author: str; - all_authors: array { - default := >[]; - rewrite update using ( - __old__.all_authors - ++ [__subject__.author] - ); - } - } + type Post { + required title: str; + required body: str; + author: str; + all_authors: array { + default := >[]; + rewrite update using ( + __old__.all_authors + ++ [__subject__.author] + ); + } + } On insert, our ``all_authors`` property will get initialized to an empty array of strings. We will rewrite updates to concatenate that array with an array containing the new author value. -Mutation rewrite as cached computed -=================================== +Cached computed +=============== + +.. index:: cached computeds, caching computeds Mutation rewrites can be used to effectively create a cached computed value as demonstrated with the ``byline`` property in this schema: .. code-block:: sdl - type Post { - required title: str; - required body: str; - author: str; - created: datetime { - rewrite insert using (datetime_of_statement()) - } - byline: str { - rewrite insert, update using ( - 'by ' ++ - __subject__.author ++ - ' on ' ++ - to_str(__subject__.created, 'Mon DD, YYYY') - ) - } - } + type Post { + required title: str; + required body: str; + author: str; + created: datetime { + rewrite insert using (datetime_of_statement()) + } + byline: str { + rewrite insert, update using ( + 'by ' ++ + __subject__.author ++ + ' on ' ++ + to_str(__subject__.created, 'Mon DD, YYYY') + ) + } + } The ``byline`` property will be updated on each insert or update, but the value will not need to be calculated at read time like a proper :ref:`computed property `. +.. _ref_eql_sdl_mutation_rewrites: +.. _ref_eql_sdl_mutation_rewrites_syntax: + +Declaring mutation rewrites +=========================== + +This section describes the syntax to declare mutation rewrites in your schema. + +Syntax +------ + +Define a new mutation rewrite corresponding to the :ref:`more explicit DDL +commands `. + +.. sdl:synopsis:: + + rewrite {insert | update} [, ...] + using + +Mutation rewrites must be defined inside a property or link block. + +Description +^^^^^^^^^^^ + +This declaration defines a new trigger with the following options: + +:eql:synopsis:`insert | update [, ...]` + The query type (or types) the rewrite runs on. Separate multiple values + with commas to invoke the same rewrite for multiple types of queries. + +:eql:synopsis:`` + The expression to be evaluated to produce the new value of the property. + + +.. _ref_eql_ddl_mutation_rewrites: + +DDL commands +============ + +This section describes the low-level DDL commands for creatin and +dropping mutation rewrites. You typically don't need to use these commands +directly, but knowing about them is useful for reviewing migrations. + + +Create rewrite +-------------- + +:eql-statement: + +Define a new mutation rewrite. + +When creating a new property or link: + +.. eql:synopsis:: + + {create | alter} type "{" + create { property | link } -> "{" + create rewrite {insert | update} [, ...] + using + "}" ; + "}" ; + +When altering an existing property or link: + +.. eql:synopsis:: + + {create | alter} type "{" + alter { property | link } "{" + create rewrite {insert | update} [, ...] + using + "}" ; + "}" ; + + +Description +^^^^^^^^^^^ + +The command ``create rewrite`` nested under ``create type`` or ``alter type`` +and then under ``create property/link`` or ``alter property/link`` defines a +new mutation rewrite for the given property or link on the given object. + + +Parameters +^^^^^^^^^^ + +:eql:synopsis:`` + The name (optionally module-qualified) of the type containing the rewrite. + +:eql:synopsis:`` + The name (optionally module-qualified) of the property or link being + rewritten. + +:eql:synopsis:`insert | update [, ...]` + The query type (or types) that are rewritten. Separate multiple values with + commas to invoke the same rewrite for multiple types of queries. + + +Examples +^^^^^^^^ + +Declare two mutation rewrites on new properties: one that sets a ``created`` +property when a new object is inserted and one that sets a ``modified`` +property on each update: + +.. code-block:: edgeql + + alter type User { + create property created -> datetime { + create rewrite insert using (datetime_of_statement()); + }; + create property modified -> datetime { + create rewrite update using (datetime_of_statement()); + }; + }; + + +Drop rewrite +------------ + +:eql-statement: + +Drop a mutation rewrite. + +.. eql:synopsis:: + + alter type "{" + alter property "{" + drop rewrite {insert | update} ; + "}" ; + "}" ; + + +Description +^^^^^^^^^^^ + +The command ``drop rewrite`` inside an ``alter type`` block and further inside +an ``alter property`` block removes the definition of an existing mutation +rewrite on the specified property or link of the specified type. + + +Parameters +^^^^^^^^^^ + +:eql:synopsis:`` + The name (optionally module-qualified) of the type containing the rewrite. + +:eql:synopsis:`` + The name (optionally module-qualified) of the property or link being + rewritten. + +:eql:synopsis:`insert | update [, ...]` + The query type (or types) that are rewritten. Separate multiple values with + commas to invoke the same rewrite for multiple types of queries. + + +Example +^^^^^^^ + +Remove the ``insert`` rewrite of the ``created`` property on the ``User`` type: + +.. code-block:: edgeql + + alter type User { + alter property created { + drop rewrite insert; + }; + }; + + .. list-table:: :class: seealso * - **See also** - * - :ref:`SDL > Mutation rewrites ` - * - :ref:`DDL > Mutation rewrites ` * - :ref:`Introspection > Mutation rewrites ` diff --git a/docs/datamodel/objects.rst b/docs/datamodel/objects.rst index c017733b220..d803dd5424a 100644 --- a/docs/datamodel/objects.rst +++ b/docs/datamodel/objects.rst @@ -4,165 +4,494 @@ Object Types ============ -*Object types* are the primary components of an EdgeDB schema. They are +.. index:: type, tables, models + +*Object types* are the primary components of a Gel schema. They are analogous to SQL *tables* or ORM *models*, and consist of :ref:`properties ` and :ref:`links `. -Properties are used to attach primitive data to an object type. -For the full documentation on properties, -see :ref:`Properties `. +Properties +========== + +Properties are used to attach primitive/scalar data to an object type. +For the full documentation on properties, see :ref:`ref_datamodel_props`. .. code-block:: sdl - :version-lt: 3.0 - type Person { - property email -> str; - } + type Person { + email: str; + } -.. code-block:: sdl +Using in a query: + +.. code-block:: edgeql - type Person { - email: str; - } + select Person { + email + }; + + +Links +===== Links are used to define relationships between object types. For the full -documentation on links, see :ref:`Links `. +documentation on links, see :ref:`ref_datamodel_links`. .. code-block:: sdl - :version-lt: 3.0 - type Person { - link best_friend -> Person; - } + type Person { + email: str; + best_friend: Person; + } -.. code-block:: sdl +Using in a query: + +.. code-block:: edgeql - type Person { - best_friend: Person; - } + select Person { + email, + best_friend: { + email + } + }; +ID +== -IDs ---- +.. index:: uuid, primary key There's no need to manually declare a primary key on your object types. All object types automatically contain a property ``id`` of type ``UUID`` that's -*required*, *globally unique*, and *readonly*. This ``id`` is assigned upon -creation and never changes. +*required*, *globally unique*, *readonly*, and has an index on it. +The ``id`` is assigned upon creation and cannot be changed. +Using in a query: -Abstract types --------------- +.. code-block:: edgeql -Object types can either be *abstract* or *non-abstract*. By default all object -types are non-abstract. You can't create or store instances of abstract types, -but they're a useful way to share functionality and structure among -other object types. + select Person { id }; + select Person { email } filter .id = '123e4567-e89b-...'; -.. code-block:: sdl - :version-lt: 3.0 - abstract type HasName { - property first_name -> str; - property last_name -> str; - } +Abstract types +============== + +.. index:: abstract, inheritance -.. code-block:: sdl +Object types can either be *abstract* or *non-abstract*. By default all object +types are non-abstract. You can't create or store instances of abstract types +(a.k.a. mixins), but they're a useful way to share functionality and +structure among other object types. - abstract type HasName { - first_name: str; - last_name: str; - } +.. code-block:: sdl -Abstract types are commonly used in tandem with inheritance. + abstract type HasName { + first_name: str; + last_name: str; + } .. _ref_datamodel_objects_inheritance: +.. _ref_eql_sdl_object_types_inheritance: Inheritance ------------ +=========== + +.. index:: extending, extends, subtypes, supertypes Object types can *extend* other object types. The extending type (AKA the *subtype*) inherits all links, properties, indexes, constraints, etc. from its *supertypes*. .. code-block:: sdl - :version-lt: 3.0 - abstract type Animal { - property species -> str; - } + abstract type HasName { + first_name: str; + last_name: str; + } - type Dog extending Animal { - property breed -> str; - } + type Person extending HasName { + email: str; + best_friend: Person; + } -.. code-block:: sdl +Using in a query: + +.. code-block:: edgeql - abstract type Animal { - species: str; - } + select Person { + first_name, + email, + best_friend: { + last_name + } + }; - type Dog extending Animal { - breed: str; - } .. _ref_datamodel_objects_multiple_inheritance: Multiple Inheritance -^^^^^^^^^^^^^^^^^^^^ +==================== -Object types can :ref:`extend more -than one type ` β€” that's called +Object types can extend more than one type β€” that's called *multiple inheritance*. This mechanism allows building complex object types out of combinations of more basic types. -.. code-block:: sdl - :version-lt: 3.0 - - abstract type HasName { - property first_name -> str; - property last_name -> str; - } +.. note:: - abstract type HasEmail { - property email -> str; - } + Gel's multiple inheritance should not be confused with the multiple + inheritance of C++ or Python, where the complexity usually arises + from fine-grained mixing of logic. Gel's multiple inheritance is + structural and allows for natural composition. - type Person extending HasName, HasEmail { - property profession -> str; - } +.. code-block:: sdl-diff -.. code-block:: sdl + abstract type HasName { + first_name: str; + last_name: str; + } - abstract type HasName { - first_name: str; - last_name: str; - } + + abstract type HasEmail { + + email: str; + + } - abstract type HasEmail { - email: str; - } - - type Person extending HasName, HasEmail { - profession: str; - } + - type Person extending HasName { + + type Person extending HasName, HasEmail { + - email: str; + best_friend: Person; + } If multiple supertypes share links or properties, those properties must be of the same type and cardinality. -.. note:: - Refer to the dedicated pages on :ref:`Indexes `, - :ref:`Constraints `, :ref:`Access Policies - `, and :ref:`Annotations - ` for documentation on these concepts. +.. _ref_eql_sdl_object_types: +.. _ref_eql_sdl_object_types_syntax: + + +Defining object types +===================== + +This section describes the syntax to declare object types in your schema. + +Syntax +------ + +.. sdl:synopsis:: + + [abstract] type [extending [, ...] ] + [ "{" + [ ] + [ ] + [ ] + [ ] + [ ] + ... + "}" ] + +Description +^^^^^^^^^^^ + +This declaration defines a new object type with the following options: + +:eql:synopsis:`abstract` + If specified, the created type will be *abstract*. + +:eql:synopsis:`` + The name (optionally module-qualified) of the new type. + +:eql:synopsis:`extending [, ...]` + Optional clause specifying the *supertypes* of the new type. + + Use of ``extending`` creates a persistent type relationship + between the new subtype and its supertype(s). Schema modifications + to the supertype(s) propagate to the subtype. + + References to supertypes in queries will also include objects of + the subtype. + + If the same *link* name exists in more than one supertype, or + is explicitly defined in the subtype and at least one supertype, + then the data types of the link targets must be *compatible*. + If there is no conflict, the links are merged to form a single + link in the new type. + +These sub-declarations are allowed in the ``Type`` block: + +:sdl:synopsis:`` + Set object type :ref:`annotation ` + to a given *value*. + +:sdl:synopsis:`` + Define a concrete :ref:`property ` for this object type. + +:sdl:synopsis:`` + Define a concrete :ref:`link ` for this object type. + +:sdl:synopsis:`` + Define a concrete :ref:`constraint ` for this + object type. + +:sdl:synopsis:`` + Define an :ref:`index ` for this object type. + + +.. _ref_eql_ddl_object_types: + +DDL commands +============ + +This section describes the low-level DDL commands for creating, altering, and +dropping object types. You typically don't need to use these commands directly, +but knowing about them is useful for reviewing migrations. + +Create type +----------- + +:eql-statement: +:eql-haswith: + +Define a new object type. + +.. eql:synopsis:: + + [ with [, ...] ] + create [abstract] type [ extending [, ...] ] + [ "{" ; [...] "}" ] ; + + # where is one of + + create annotation := + create link ... + create property ... + create constraint ... + create index on + +Description +^^^^^^^^^^^ + +The command ``create type`` defines a new object type for use in the +current |branch|. + +If *name* is qualified with a module name, then the type is created +in that module, otherwise it is created in the current module. +The type name must be distinct from that of any existing schema item +in the module. + +Parameters +^^^^^^^^^^ + +Most sub-commands and options of this command are identical to the +:ref:`SDL object type declaration `, +with some additional features listed below: + +:eql:synopsis:`with [, ...]` + Alias declarations. + + The ``with`` clause allows specifying module aliases + that can be referenced by the command. See :ref:`ref_eql_statements_with` + for more information. + +The following subcommands are allowed in the ``create type`` block: + +:eql:synopsis:`create annotation := ` + Set object type :eql:synopsis:`` to + :eql:synopsis:``. + + See :eql:stmt:`create annotation` for details. + +:eql:synopsis:`create link ...` + Define a new link for this object type. See + :eql:stmt:`create link` for details. + +:eql:synopsis:`create property ...` + Define a new property for this object type. See + :eql:stmt:`create property` for details. + +:eql:synopsis:`create constraint ...` + Define a concrete constraint for this object type. See + :eql:stmt:`create constraint` for details. + +:eql:synopsis:`create index on ` + Define a new :ref:`index ` + using *index-expr* for this object type. See + :eql:stmt:`create index` for details. + +Example +^^^^^^^ + +Create an object type ``User``: + +.. code-block:: edgeql + + create type User { + create property name -> str; + }; + + +Alter type +---------- + +:eql-statement: +:eql-haswith: + +Change the definition of an object type. + +.. eql:synopsis:: + + [ with [, ...] ] + alter type + [ "{" ; [...] "}" ] ; + + [ with [, ...] ] + alter type ; + + # where is one of + + rename to + extending [, ...] + create annotation := + alter annotation := + drop annotation + create link ... + alter link ... + drop link ... + create property ... + alter property ... + drop property ... + create constraint ... + alter constraint ... + drop constraint ... + create index on + drop index on + +Description +^^^^^^^^^^^ + +The command ``alter type`` changes the definition of an object type. +*name* must be a name of an existing object type, optionally qualified +with a module name. + +Parameters +^^^^^^^^^^ + +:eql:synopsis:`with [, ...]` + Alias declarations. + + The ``with`` clause allows specifying module aliases + that can be referenced by the command. See :ref:`ref_eql_statements_with` + for more information. + +:eql:synopsis:`` + The name (optionally module-qualified) of the type being altered. + +:eql:synopsis:`extending [, ...]` + Alter the supertype list. The full syntax of this subcommand is: + + .. eql:synopsis:: + + extending [, ...] + [ first | last | before | after ] + + This subcommand makes the type a subtype of the specified list + of supertypes. The requirements for the parent-child relationship + are the same as when creating an object type. + + It is possible to specify the position in the parent list + using the following optional keywords: + + * ``first`` -- insert parent(s) at the beginning of the + parent list, + * ``last`` -- insert parent(s) at the end of the parent list, + * ``before `` -- insert parent(s) before an + existing *parent*, + * ``after `` -- insert parent(s) after an existing + *parent*. + +:eql:synopsis:`alter annotation ;` + Alter object type annotation :eql:synopsis:``. + See :eql:stmt:`alter annotation` for details. + +:eql:synopsis:`drop annotation ` + Remove object type :eql:synopsis:``. + See :eql:stmt:`drop annotation` for details. + +:eql:synopsis:`alter link ...` + Alter the definition of a link for this object type. See + :eql:stmt:`alter link` for details. + +:eql:synopsis:`drop link ` + Remove a link item from this object type. See + :eql:stmt:`drop link` for details. + +:eql:synopsis:`alter property ...` + Alter the definition of a property item for this object type. + See :eql:stmt:`alter property` for details. + +:eql:synopsis:`drop property ` + Remove a property item from this object type. See + :eql:stmt:`drop property` for details. + +:eql:synopsis:`alter constraint ...` + Alter the definition of a constraint for this object type. See + :eql:stmt:`alter constraint` for details. + +:eql:synopsis:`drop constraint ;` + Remove a constraint from this object type. See + :eql:stmt:`drop constraint` for details. + +:eql:synopsis:`drop index on ` + Remove an :ref:`index ` defined as *index-expr* + from this object type. See :eql:stmt:`drop index` for details. + +All the subcommands allowed in the ``create type`` block are also +valid subcommands for the ``alter type`` block. + +Example +^^^^^^^ + +Alter the ``User`` object type to make ``name`` required: + +.. code-block:: edgeql + + alter type User { + alter property name { + set required; + } + }; + + +Drop type +--------- + +:eql-statement: +:eql-haswith: + +Remove the specified object type from the schema. + +.. eql:synopsis:: + + drop type ; + +Description +^^^^^^^^^^^ + +The command ``drop type`` removes the specified object type from the +schema. All subordinate schema items defined on this type, +such as links and indexes, are removed as well. + +Example +^^^^^^^ + +Remove the ``User`` object type: + +.. code-block:: edgeql + + drop type User; .. list-table:: :class: seealso * - **See also** - * - :ref:`SDL > Object types ` - * - :ref:`DDL > Object types ` * - :ref:`Introspection > Object types ` * - :ref:`Cheatsheets > Object types ` diff --git a/docs/datamodel/primitives.rst b/docs/datamodel/primitives.rst index 1f6d39c9ece..508325382e9 100644 --- a/docs/datamodel/primitives.rst +++ b/docs/datamodel/primitives.rst @@ -4,188 +4,164 @@ Primitives ========== -EdgeDB has a robust type system consisting of primitive and object types. -Below is a review of EdgeDB's primitive types; later, these will be used to -declare *properties* on object types. - +|Gel| has a robust type system consisting of primitive and object types. +types. Primitive types are used to declare *properties* on object types, +as query and function arguments, as as well as in other contexts. .. _ref_datamodel_scalars: -Scalar types -^^^^^^^^^^^^ - -.. include:: ../stdlib/scalar_table.rst +Built-in scalar types +===================== -Custom scalar types can also be declared. For full documentation, see :ref:`SDL -> Scalar types `. +Gel comes with a range of built-in scalar types, such as: -.. _ref_datamodel_enums: +* String: :eql:type:`str` +* Boolean: :eql:type:`bool` +* Various numeric types: :eql:type:`int16`, :eql:type:`int32`, + :eql:type:`int64`, :eql:type:`float32`, :eql:type:`float64`, :eql:type:`bigint`, :eql:type:`decimal` +* JSON: :eql:type:`json`, +* UUID: :eql:type:`uuid`, +* Date/time: :eql:type:`datetime`, :eql:type:`duration` + :eql:type:`cal::local_datetime`, :eql:type:`cal::local_date`, + :eql:type:`cal::local_time`, :eql:type:`cal::relative_duration`, + :eql:type:`cal::date_duration` +* Miscellaneous: :eql:type:`sequence`, :eql:type:`bytes`, etc. -Enums -^^^^^ +Custom scalars +============== -To represent an enum, declare a custom scalar that extends the abstract -:ref:`enum ` type. +You can extend built-in scalars with additional constraints or annotations. +Here's an example of a non-negative custom ``int64`` variant: .. code-block:: sdl - :version-lt: 3.0 - scalar type Color extending enum; - - type Shirt { - property color -> Color; + scalar type posint64 extending int64 { + constraint min_value(0); } +.. _ref_datamodel_enums: + +Enums +===== + +Enum types are created by extending the abstract :eql:type:`enum` type, e.g.: + .. code-block:: sdl - scalar type Color extending enum; + scalar type Color extending enum; - type Shirt { - color: Color; - } + type Shirt { + color: Color; + } -.. important:: +which can be queries with: - To reference enum values inside EdgeQL queries, use dot notation, e.g. - ``Color.Green``. +.. code-block:: edgeql -For a full reference on enum types, see the :ref:`Enum docs `. + select Shirt filter .color = Color.Red; +For a full reference on enum types, see the :ref:`Enum docs `. .. _ref_datamodel_arrays: Arrays -^^^^^^ +====== Arrays store zero or more primitive values of the same type in an ordered list. -Arrays cannot contain object types or other arrays. +Arrays cannot contain object types or other arrays, but can contain virtually +any other type. .. code-block:: sdl - :version-lt: 3.0 - type Person { - property str_array -> array; - property json_array -> array; + type Person { + str_array: array; + json_array: array; + tuple_array: array>; - # INVALID: arrays of object types not allowed - # property friends -> array + # INVALID: arrays of object types not allowed: + # friends: array - # INVALID: arrays cannot be nested - # property nested_array -> array> - } + # INVALID: arrays cannot be nested: + # nested_array: array> -.. code-block:: sdl + # VALID: arrays can contain tuples with arrays in them + nested_array_via_tuple: array>> + } - type Person { - str_array: array; - json_array: array; +Array syntax in EdgeQL is very intuitive (indexing starts at ``0``): - # INVALID: arrays of object types not allowed - # friends: array +.. code-block:: edgeql - # INVALID: arrays cannot be nested - # nested_array: array> - } + select [1, 2, 3]; + select [1, 2, 3][1] = 2; # true For a full reference on array types, see the :ref:`Array docs `. - .. _ref_datamodel_tuples: Tuples -^^^^^^ +====== Like arrays, tuples are ordered sequences of primitive data. Unlike arrays, each element of a tuple can have a distinct type. Tuple elements can be *any type*, including primitives, objects, arrays, and other tuples. .. code-block:: sdl - :version-lt: 3.0 - - type Person { - - property unnamed_tuple -> tuple; - property nested_tuple -> tuple>>; - property tuple_of_arrays -> tuple, array>; - - } - -.. code-block:: sdl - - type Person { - unnamed_tuple: tuple; - nested_tuple: tuple>>; - tuple_of_arrays: tuple, array>; - - } + type Person { + unnamed_tuple: tuple; + nested_tuple: tuple>>; + tuple_of_arrays: tuple, array>; + } Optionally, you can assign a *key* to each element of the tuple. Tuples containing explicit keys are known as *named tuples*. You must assign keys to all elements (or none of them). .. code-block:: sdl - :version-lt: 3.0 - - type BlogPost { - property metadata -> tuple; - } -.. code-block:: sdl - - type BlogPost { - metadata: tuple; - } + type BlogPost { + metadata: tuple; + } Named and unnamed tuples are the same data structure under the hood. You can add, remove, and change keys in a tuple type after it's been declared. For -details, see :ref:`EdgeQL > Literals > Tuples `. +details, see :ref:`Tuples `. -.. important:: +.. note:: - When you query an *unnamed* tuple using one of EdgeQL's :ref:`client - libraries `, its value is converted to a list/array. When - you fetch a named tuple, it is converted into an object/dictionary/hashmap - depending on the language. + When you query an *unnamed* tuple using one of EdgeQL's + :ref:`client libraries `, its value is converted to a + list/array. When you fetch a named tuple, it is converted into an + object/dictionary/hashmap depending on the language. .. _ref_datamodel_ranges: Ranges -^^^^^^ - -.. versionadded:: 2.0 +====== Ranges represent some interval of values. The intervals can be bound or unbound on either end. They can also be empty, containing no values. Only some scalar types have corresponding range types: -- ``range`` -- ``range`` -- ``range`` -- ``range`` -- ``range`` -- ``range`` -- ``range`` -- ``range`` - -.. code-block:: sdl - :version-lt: 3.0 +- Numeric ranges: ``range``, ``range``, ``range``, + ``range``, ``range`` +- Date/time ranges: ``range``, ``range``, + ``range`` - type DieRoll { - property values -> range; - } +Example: .. code-block:: sdl - type DieRoll { - values: range; - } + type DieRoll { + values: range; + } -For a full reference on ranges, functions and operators see the :ref:`Range -docs `. +For a full reference on ranges, functions and operators see the +:ref:`Range docs `. Sequences -^^^^^^^^^ +========= To represent an auto-incrementing integer property, declare a custom scalar that extends the abstract ``sequence`` type. Creating a sequence type @@ -194,19 +170,265 @@ object is created. All properties that point to the same sequence type will share the counter. .. code-block:: sdl - :version-lt: 3.0 - scalar type ticket_number extending sequence; - type Ticket { - property number -> ticket_number; - } + scalar type ticket_number extending sequence; + type Ticket { + number: ticket_number; + rendered_number := 'TICKET-\(.number)'; + } -.. code-block:: sdl +For a full reference on sequences, see the :ref:`Sequence docs `. - scalar type ticket_number extending sequence; - type Ticket { - number: ticket_number; - } +.. _ref_eql_sdl_scalars: +.. _ref_eql_sdl_scalars_syntax: + +Declaring scalars +================= + +This section describes the syntax to declare a custom scalar type in your +schema. + + +Syntax +------ + +.. sdl:synopsis:: + + [abstract] scalar type [extending [, ...] ] + [ "{" + [ ] + [ ] + ... + "}" ] + +Description +^^^^^^^^^^^ + +This declaration defines a new object type with the following options: + +:eql:synopsis:`abstract` + If specified, the created scalar type will be *abstract*. + +:eql:synopsis:`` + The name (optionally module-qualified) of the new scalar type. + +:eql:synopsis:`extending ` + Optional clause specifying the *supertype* of the new type. + + If :eql:synopsis:`` is an + :eql:type:`enumerated type ` declaration then + an enumerated scalar type is defined. + + Use of ``extending`` creates a persistent type relationship + between the new subtype and its supertype(s). Schema modifications + to the supertype(s) propagate to the subtype. + +The valid SDL sub-declarations are listed below: + +:sdl:synopsis:`` + Set scalar type :ref:`annotation ` + to a given *value*. + +:sdl:synopsis:`` + Define a concrete :ref:`constraint ` for + this scalar type. + + +.. _ref_eql_ddl_scalars: + +DDL commands +============ + +This section describes the low-level DDL commands for creating, altering, and +dropping scalar types. You typically don't need to use these commands directly, +but knowing about them is useful for reviewing migrations. + +Create scalar +------------- + +:eql-statement: +:eql-haswith: + +Define a new scalar type. + +.. eql:synopsis:: + + [ with [, ...] ] + create [abstract] scalar type [ extending ] + [ "{" ; [...] "}" ] ; + + # where is one of + + create annotation := + create constraint ... + +Description +^^^^^^^^^^^ + +The command ``create scalar type`` defines a new scalar type for use in the +current |branch|. + +If *name* is qualified with a module name, then the type is created +in that module, otherwise it is created in the current module. +The type name must be distinct from that of any existing schema item +in the module. + +If the ``abstract`` keyword is specified, the created type will be +*abstract*. + +All non-abstract scalar types must have an underlying core +implementation. For user-defined scalar types this means that +``create scalar type`` must have another non-abstract scalar type +as its *supertype*. + +The most common use of ``create scalar type`` is to define a scalar +subtype with constraints. + +Most sub-commands and options of this command are identical to the +:ref:`SDL scalar type declaration `. The +following subcommands are allowed in the ``create scalar type`` block: + +:eql:synopsis:`create annotation := ;` + Set scalar type's :eql:synopsis:`` to + :eql:synopsis:``. + + See :eql:stmt:`create annotation` for details. + +:eql:synopsis:`create constraint ...` + Define a new constraint for this scalar type. See + :eql:stmt:`create constraint` for details. + + +Examples +^^^^^^^^ + +Create a new non-negative integer type: + +.. code-block:: edgeql + + create scalar type posint64 extending int64 { + create constraint min_value(0); + }; + +Create a new enumerated type: + +.. code-block:: edgeql + + create scalar type Color + extending enum; + + +Alter scalar +------------ + +:eql-statement: +:eql-haswith: + +Alter the definition of a scalar type. + +.. eql:synopsis:: + + [ with [, ...] ] + alter scalar type + "{" ; [...] "}" ; + + # where is one of + + rename to + extending ... + create annotation := + alter annotation := + drop annotation + create constraint ... + alter constraint ... + drop constraint ... + +Description +^^^^^^^^^^^ + +The command ``alter scalar type`` changes the definition of a scalar type. +*name* must be a name of an existing scalar type, optionally qualified +with a module name. + +The following subcommands are allowed in the ``alter scalar type`` block: + +:eql:synopsis:`rename to ;` + Change the name of the scalar type to *newname*. + +:eql:synopsis:`extending ...` + Alter the supertype list. It works the same way as in + :eql:stmt:`alter type`. + +:eql:synopsis:`alter annotation ;` + Alter scalar type :eql:synopsis:``. + See :eql:stmt:`alter annotation` for details. + +:eql:synopsis:`drop annotation ` + Remove scalar type's :eql:synopsis:`` from + :eql:synopsis:``. + See :eql:stmt:`drop annotation` for details. + +:eql:synopsis:`alter constraint ...` + Alter the definition of a constraint for this scalar type. See + :eql:stmt:`alter constraint` for details. + +:eql:synopsis:`drop constraint ` + Remove a constraint from this scalar type. See + :eql:stmt:`drop constraint` for details. + +All the subcommands allowed in the ``create scalar type`` block are also +valid subcommands for ``alter scalar type`` block. + + +Examples +^^^^^^^^ + +Define a new constraint on a scalar type: + +.. code-block:: edgeql + + alter scalar type posint64 { + create constraint max_value(100); + }; + +Add one more label to an enumerated type: + +.. code-block:: edgeql + + alter scalar type Color + extending enum; + + +Drop scalar +----------- + +:eql-statement: +:eql-haswith: + +Remove a scalar type. + +.. eql:synopsis:: + + [ with [, ...] ] + drop scalar type ; + +Description +^^^^^^^^^^^ + +The command ``drop scalar type`` removes a scalar type. + +Parameters +^^^^^^^^^^ + +*name* + The name (optionally qualified with a module name) of an existing + scalar type. + +Example +^^^^^^^ + +Remove a scalar type: + +.. code-block:: edgeql -For a full reference on sequences, see the :ref:`Sequence docs -`. + drop scalar type posint64; diff --git a/docs/datamodel/properties.rst b/docs/datamodel/properties.rst index 4f1a6cc6a97..59c3071c860 100644 --- a/docs/datamodel/properties.rst +++ b/docs/datamodel/properties.rst @@ -4,21 +4,11 @@ Properties ========== -:index: property +.. index:: property, primitive types, fields, columns Properties are used to associate primitive data with an :ref:`object type ` or :ref:`link `. - -.. code-block:: sdl - :version-lt: 3.0 - - type Player { - property email -> str; - property points -> int64; - property is_online -> bool; - } - .. code-block:: sdl type Player { @@ -37,14 +27,9 @@ encompasses :ref:`scalar types ` like ``str`` and Required properties ------------------- -Properties can be either ``optional`` (the default) or ``required``. - -.. code-block:: sdl - :version-lt: 3.0 +.. index:: required, optional, not null - type User { - required property email -> str; - } +Properties can be either ``optional`` (the default) or ``required``. .. code-block:: sdl @@ -57,26 +42,12 @@ Properties can be either ``optional`` (the default) or ``required``. Property cardinality -------------------- +.. index:: cardinality, single, multi + Properties have a **cardinality**, either ``single`` (the default) or ``multi``. A ``multi`` property of type ``str`` points to an *unordered set* of strings. -.. code-block:: sdl - :version-lt: 3.0 - - type User { - - # single isn't necessary here - # properties are single by default - single property name -> str; - - # an unordered set of strings - multi property nicknames -> str; - - # an unordered set of string arrays - multi property set_of_arrays -> array; - } - .. code-block:: sdl type User { @@ -105,22 +76,11 @@ more involved discussion, see :ref:`EdgeQL > Sets Default values -------------- +.. index:: default + Properties can have a default value. This default can be a static value or an arbitrary EdgeQL expression, which will be evaluated upon insertion. -.. code-block:: sdl - :version-lt: 3.0 - - type Player { - required property points -> int64 { - default := 0; - } - - required property latitude -> float64 { - default := (360 * random() - 180); - } - } - .. code-block:: sdl type Player { @@ -136,19 +96,12 @@ arbitrary EdgeQL expression, which will be evaluated upon insertion. Readonly properties ------------------- +.. index:: readonly, immutable + Properties can be marked as ``readonly``. In the example below, the ``User.external_id`` property can be set at the time of creation but not modified thereafter. -.. code-block:: sdl - :version-lt: 3.0 - - type User { - required property external_id -> uuid { - readonly := true; - } - } - .. code-block:: sdl type User { @@ -160,29 +113,10 @@ modified thereafter. Constraints ----------- -Properties can be augmented wth constraints. The example below showcases a -subset of EdgeDB's built-in constraints. - -.. code-block:: sdl - :version-lt: 3.0 - - type BlogPost { - property title -> str { - constraint exclusive; # all post titles must be unique - constraint min_len_value(8); - constraint max_len_value(30); - constraint regexp(r'^[A-Za-z0-9 ]+$'); - } - - property status -> str { - constraint one_of('Draft', 'InReview', 'Published'); - } +.. index:: constraint - property upvotes -> int64 { - constraint min_value(0); - constraint max_value(9999); - } - } +Properties can be augmented wth constraints. The example below showcases a +subset of Gel's built-in constraints. .. code-block:: sdl @@ -208,17 +142,6 @@ You can constrain properties with arbitrary :ref:`EdgeQL ` expressions returning ``bool``. To reference the value of the property, use the special scope keyword ``__subject__``. -.. code-block:: sdl - :version-lt: 3.0 - - type BlogPost { - property title -> str { - constraint expression on ( - __subject__ = str_trim(__subject__) - ); - } - } - .. code-block:: sdl type BlogPost { @@ -240,21 +163,12 @@ reference `. Annotations ----------- +.. index:: annotation, metadata, title, description, deprecated + Properties can contain annotations, small human-readable notes. The built-in annotations are ``title``, ``description``, and ``deprecated``. You may also declare :ref:`custom annotation types `. -.. code-block:: sdl - :version-lt: 3.0 - - type User { - property email -> str { - annotation title := 'Email address'; - annotation description := "The user's email address."; - annotation deprecated := 'Use NewUser instead.'; - } - } - .. code-block:: sdl type User { @@ -269,23 +183,12 @@ declare :ref:`custom annotation types `. Abstract properties ------------------- +.. index:: abstract property + Properties can be *concrete* (the default) or *abstract*. Abstract properties are declared independent of a source or target, can contain :ref:`annotations `, and can be marked as ``readonly``. -.. code-block:: sdl - :version-lt: 3.0 - - abstract property email_prop { - annotation title := 'An email address'; - readonly := true; - } - - type Student { - # inherits annotations and "readonly := true" - property email extending email_prop -> str; - } - .. code-block:: sdl abstract property email_prop { @@ -304,6 +207,8 @@ are declared independent of a source or target, can contain :ref:`annotations Link properties --------------- +.. index:: linkprops, relations, link table + Properties can also be defined on **links**. For a full guide, refer to :ref:`Guides > Using link properties `. diff --git a/docs/datamodel/triggers.rst b/docs/datamodel/triggers.rst index 9e8116cb9bf..10141f8191f 100644 --- a/docs/datamodel/triggers.rst +++ b/docs/datamodel/triggers.rst @@ -1,40 +1,83 @@ -.. versionadded:: 3.0 - .. _ref_datamodel_triggers: +.. _ref_eql_sdl_triggers: ======== Triggers ======== -.. edb:youtube-embed:: ImgMfb_jCJQ?start=41 +.. index:: trigger, after insert, after update, after delete, for each, for all, + when, do, __new__, __old__ Triggers allow you to define an expression to be executed whenever a given query type is run on an object type. The original query will *trigger* your pre-defined expression to run in a transaction along with the original query. These can be defined in your schema. -.. note:: - Triggers cannot be used to *modify* the object that set off the trigger, - although they can be used with :eql:func:`assert` to do *validation* on - that object. If you need to modify the object, you can use :ref:`mutation - rewrites `. +Important notes +=============== + +Triggers are an advanced feature and have some caveats that +you should be aware of. + +Consider using mutation rewrites +-------------------------------- + +Triggers cannot be used to *modify* the object that set off the trigger, +although they can be used with :eql:func:`assert` to do *validation* on +that object. If you need to modify the object, you can use :ref:`mutation +rewrites `. + +Unified trigger query execution +------------------------------- + +All queries within triggers, along with the initial triggering query, are +compiled into a single combined SQL query under the hood. Keep this in mind +when designing triggers that modify existing records. If multiple ``update`` +queries within your triggers target the same object, only one of these +queries will ultimately be executed. To ensure all desired updates on an +object are applied, consolidate them into a single ``update`` query within +one trigger, instead of distributing them across multiple updates. + +Multi-stage trigger execution +----------------------------- + +In some cases, a trigger can cause another trigger to fire. When this +happens, Gel completes all the triggers fired by the initial query +before kicking off a new "stage" of triggers. In the second stage, any +triggers fired by the initial stage of triggers will fire. Gel will +continue adding trigger stages until all triggers are complete. + +The exception to this is when triggers would cause a loop or would cause +the same trigger to be run in two different stages. These triggers will +generate an error. -Here's an example that creates a simple audit log type so that we can keep +Data visibility +--------------- + +Any query in your trigger will return the state of the database *after* the +triggering query. If this query's results include the object that flipped +the trigger, the results will contain that object in the same state as +``__new__``. + + +Example: audit log +================== + +Here's an example that creates a simple **audit log** type so that we can keep track of what's happening to our users in a database. First, we will create a ``Log`` type: .. code-block:: sdl - type Log { - action: str; - timestamp: datetime { - default := datetime_current(); - } - target_name: str; - change: str; - } - + type Log { + action: str; + timestamp: datetime { + default := datetime_current(); + } + target_name: str; + change: str; + } With the ``Log`` type in place, we can write some triggers that will automatically create ``Log`` objects for any insert, update, or delete queries @@ -42,157 +85,126 @@ on the ``Person`` type: .. code-block:: sdl - type Person { - required name: str; - - trigger log_insert after insert for each do ( - insert Log { - action := 'insert', - target_name := __new__.name - } - ); - - trigger log_update after update for each do ( - insert Log { - action := 'update', - target_name := __new__.name, - change := __old__.name ++ '->' ++ __new__.name - } - ); - - trigger log_delete after delete for each do ( - insert Log { - action := 'delete', - target_name := __old__.name - } - ); - } + type Person { + required name: str; + + trigger log_insert after insert for each do ( + insert Log { + action := 'insert', + target_name := __new__.name + } + ); + + trigger log_update after update for each do ( + insert Log { + action := 'update', + target_name := __new__.name, + change := __old__.name ++ '->' ++ __new__.name + } + ); + + trigger log_delete after delete for each do ( + insert Log { + action := 'delete', + target_name := __old__.name + } + ); + } In a trigger's expression, we have access to the ``__old__`` and/or ``__new__`` variables which capture the object before and after the query. Triggers on ``update`` can use both variables. Triggers on ``delete`` can use ``__old__``. Triggers on ``insert`` can use ``__new__``. -.. note:: - - Any query in your trigger will return the state of the database *after* the - triggering query. If this query's results include the object that flipped - the trigger, the results will contain that object in the same state as - ``__new__``. - Now, whenever we run a query, we get a log entry as well: .. code-block:: edgeql-repl - db> insert Person {name := 'Jonathan Harker'}; - {default::Person {id: b4d4e7e6-bd19-11ed-8363-1737d8d4c3c3}} - db> select Log {action, timestamp, target_name, change}; - { - default::Log { - action: 'insert', - timestamp: '2023-03-07T18:56:02.403817Z', - target_name: 'Jonathan Harker', - change: {} - } - } - db> update Person filter .name = 'Jonathan Harker' - ... set {name := 'Mina Murray'}; - {default::Person {id: b4d4e7e6-bd19-11ed-8363-1737d8d4c3c3}} - db> select Log {action, timestamp, target_name, change}; - { - default::Log { - action: 'insert', - timestamp: '2023-03-07T18:56:02.403817Z', - target_name: 'Jonathan Harker', - change: {} - }, - default::Log { - action: 'update', - timestamp: '2023-03-07T18:56:39.520889Z', - target_name: 'Mina Murray', - change: 'Jonathan Harker->Mina Murray' - }, + db> insert Person {name := 'Jonathan Harker'}; + {default::Person {id: b4d4e7e6-bd19-11ed-8363-1737d8d4c3c3}} + db> select Log {action, timestamp, target_name, change}; + { + default::Log { + action: 'insert', + timestamp: '2023-03-07T18:56:02.403817Z', + target_name: 'Jonathan Harker', + change: {} + } + } + db> update Person filter .name = 'Jonathan Harker' + ... set {name := 'Mina Murray'}; + {default::Person {id: b4d4e7e6-bd19-11ed-8363-1737d8d4c3c3}} + db> select Log {action, timestamp, target_name, change}; + { + default::Log { + action: 'insert', + timestamp: '2023-03-07T18:56:02.403817Z', + target_name: 'Jonathan Harker', + change: {} + }, + default::Log { + action: 'update', + timestamp: '2023-03-07T18:56:39.520889Z', + target_name: 'Mina Murray', + change: 'Jonathan Harker->Mina Murray' + }, + } + db> delete Person filter .name = 'Mina Murray'; + {default::Person {id: b4d4e7e6-bd19-11ed-8363-1737d8d4c3c3}} + db> select Log {action, timestamp, target_name, change}; + { + default::Log { + action: 'insert', + timestamp: '2023-03-07T18:56:02.403817Z', + target_name: 'Jonathan Harker', + change: {} + }, + default::Log { + action: 'update', + timestamp: '2023-03-07T18:56:39.520889Z', + target_name: 'Mina Murray', + change: 'Jonathan Harker->Mina Murray' + }, + default::Log { + action: 'delete', + timestamp: '2023-03-07T19:00:52.636084Z', + target_name: 'Mina Murray', + change: {} + }, + } + +Our audit logging works, but the update logs have a major shortcoming: they +log an update even when nothing changes. Any time an ``update`` query runs, +we get a log, even if the values are the same. We can prevent that by +using the trigger's ``when`` to run the trigger conditionally. Here's a +rework of our ``update`` logging query: + +.. code-block:: sdl-invalid + + trigger log_update after update for each + when (__old__.name != __new__.name) + do ( + insert Log { + action := 'update', + target_name := __new__.name, + change := __old__.name ++ '->' ++ __new__.name } - db> delete Person filter .name = 'Mina Murray'; - {default::Person {id: b4d4e7e6-bd19-11ed-8363-1737d8d4c3c3}} - db> select Log {action, timestamp, target_name, change}; - { - default::Log { - action: 'insert', - timestamp: '2023-03-07T18:56:02.403817Z', - target_name: 'Jonathan Harker', - change: {} - }, - default::Log { - action: 'update', - timestamp: '2023-03-07T18:56:39.520889Z', - target_name: 'Mina Murray', - change: 'Jonathan Harker->Mina Murray' - }, - default::Log { - action: 'delete', - timestamp: '2023-03-07T19:00:52.636084Z', - target_name: 'Mina Murray', - change: {} - }, - } - -.. note:: - - All queries within triggers, along with the initial triggering query, are - compiled into a single combined query. Keep this in mind when - designing triggers that modify existing records. If multiple ``update`` - queries within your triggers target the same object, only one of these - queries will ultimately be executed. To ensure all desired updates on an - object are applied, consolidate them into a single ``update`` query within - one trigger, instead of distributing them across multiple updates. - -.. note:: - - In some cases, a trigger can cause another trigger to fire. When this - happens, EdgeDB completes all the triggers fired by the initial query - before kicking off a new "stage" of triggers. In the second stage, any - triggers fired by the initial stage of triggers will fire. EdgeDB will - continue adding trigger stages until all triggers are complete. - - The exception to this is when triggers would cause a loop or would cause - the same trigger to be run in two different stages. These triggers will - generate an error. - -.. versionadded:: 4.0 + ); - Our audit logging works, but the update logs have a major shortcoming: they - log an update even when nothing changes. Any time an ``update`` query runs, - we get a log, even if the values are the same. We can prevent that by - using the trigger's ``when`` to run the trigger conditionally. Here's a - rework of our ``update`` logging query: +If this object were more complicated and we had many properties to compare, +we could use a ``json`` cast to compare them all in one shot: - .. code-block:: sdl +.. code-block:: sdl-invalid - trigger log_update after update for each - when (__old__.name != __new__.name) - do ( - insert Log { - action := 'update', - target_name := __new__.name, - change := __old__.name ++ '->' ++ __new__.name - } - ); - - If this object were more complicated and we had many properties to compare, - we could use a ``json`` cast to compare them all in one shot: - - .. code-block:: sdl - - trigger log_update after update for each - when (__old__ {**} != __new__ {**}) - do ( - insert Log { - action := 'update', - target_name := __new__.name, - change := __old__.name ++ '->' ++ __new__.name - } - ); + trigger log_update after update for each + when (__old__ {**} != __new__ {**}) + do ( + insert Log { + action := 'update', + target_name := __new__.name, + change := __old__.name ++ '->' ++ __new__.name + } + ); You might find that one log entry per row is too granular or too noisy for your use case. In that case, a ``for all`` trigger may be a better fit. Here's a @@ -207,25 +219,25 @@ writes by making ``target_name`` and ``change`` :ref:`multi properties timestamp: datetime { default := datetime_current(); } - - target_name: str; - - change: str; - + multi target_name: str; - + multi change: str; + - target_name: str; + - change: str; + + multi target_name: str; + + multi change: str; } type Person { required name: str; - - trigger log_insert after insert for each do ( - + trigger log_insert after insert for all do ( + - trigger log_insert after insert for each do ( + + trigger log_insert after insert for all do ( insert Log { action := 'insert', target_name := __new__.name } ); - - trigger log_update after update for each do ( - + trigger log_update after update for all do ( + - trigger log_update after update for each do ( + + trigger log_update after update for all do ( insert Log { action := 'update', target_name := __new__.name, @@ -233,8 +245,8 @@ writes by making ``target_name`` and ``change`` :ref:`multi properties } ); - - trigger log_delete after delete for each do ( - + trigger log_delete after delete for all do ( + - trigger log_delete after delete for each do ( + + trigger log_delete after delete for all do ( insert Log { action := 'delete', target_name := __old__.name @@ -247,55 +259,57 @@ object instead of one ``Log`` object per row: .. code-block:: edgeql-repl - db> for name in {'Jonathan Harker', 'Mina Murray', 'Dracula'} - ... union ( - ... insert Person {name := name} - ... ); - { - default::Person {id: 3836f9c8-d393-11ed-9638-3793d3a39133}, - default::Person {id: 38370a8a-d393-11ed-9638-d3e9b92ca408}, - default::Person {id: 38370abc-d393-11ed-9638-5390f3cbd375}, - } - db> select Log {action, timestamp, target_name, change}; - { - default::Log { - action: 'insert', - timestamp: '2023-03-07T19:12:21.113521Z', - target_name: {'Jonathan Harker', 'Mina Murray', 'Dracula'}, - change: {}, - }, - } - db> for change in { - ... (old_name := 'Jonathan Harker', new_name := 'Jonathan'), - ... (old_name := 'Mina Murray', new_name := 'Mina') - ... } - ... union ( - ... update Person filter .name = change.old_name set { - ... name := change.new_name - ... } - ... ); - { - default::Person {id: 3836f9c8-d393-11ed-9638-3793d3a39133}, - default::Person {id: 38370a8a-d393-11ed-9638-d3e9b92ca408}, - } - db> select Log {action, timestamp, target_name, change}; - { - default::Log { - action: 'insert', - timestamp: '2023-04-05T09:21:17.514089Z', - target_name: {'Jonathan Harker', 'Mina Murray', 'Dracula'}, - change: {}, - }, - default::Log { - action: 'update', - timestamp: '2023-04-05T09:35:30.389571Z', - target_name: {'Jonathan', 'Mina'}, - change: {'Jonathan Harker->Jonathan', 'Mina Murray->Mina'}, - }, - } - -Validation using triggers -========================= + db> for name in {'Jonathan Harker', 'Mina Murray', 'Dracula'} + ... union ( + ... insert Person {name := name} + ... ); + { + default::Person {id: 3836f9c8-d393-11ed-9638-3793d3a39133}, + default::Person {id: 38370a8a-d393-11ed-9638-d3e9b92ca408}, + default::Person {id: 38370abc-d393-11ed-9638-5390f3cbd375}, + } + db> select Log {action, timestamp, target_name, change}; + { + default::Log { + action: 'insert', + timestamp: '2023-03-07T19:12:21.113521Z', + target_name: {'Jonathan Harker', 'Mina Murray', 'Dracula'}, + change: {}, + }, + } + db> for change in { + ... (old_name := 'Jonathan Harker', new_name := 'Jonathan'), + ... (old_name := 'Mina Murray', new_name := 'Mina') + ... } + ... union ( + ... update Person filter .name = change.old_name set { + ... name := change.new_name + ... } + ... ); + { + default::Person {id: 3836f9c8-d393-11ed-9638-3793d3a39133}, + default::Person {id: 38370a8a-d393-11ed-9638-d3e9b92ca408}, + } + db> select Log {action, timestamp, target_name, change}; + { + default::Log { + action: 'insert', + timestamp: '2023-04-05T09:21:17.514089Z', + target_name: {'Jonathan Harker', 'Mina Murray', 'Dracula'}, + change: {}, + }, + default::Log { + action: 'update', + timestamp: '2023-04-05T09:35:30.389571Z', + target_name: {'Jonathan', 'Mina'}, + change: {'Jonathan Harker->Jonathan', 'Mina Murray->Mina'}, + }, + } + +Example: validation +=================== + +.. index:: trigger, validate, assert Triggers may also be used for validation by calling :eql:func:`assert` inside the trigger. In this example, the ``Person`` type has two multi links to other @@ -305,50 +319,264 @@ common objects linked in both. .. code-block:: sdl - type Person { - required name: str; - multi friends: Person; - multi enemies: Person; - - trigger prohibit_frenemies after insert, update for each do ( - assert( - not exists (__new__.friends intersect __new__.enemies), - message := "Invalid frenemies", - ) - ) - } + type Person { + required name: str; + multi friends: Person; + multi enemies: Person; + + trigger prohibit_frenemies after insert, update for each do ( + assert( + not exists (__new__.friends intersect __new__.enemies), + message := "Invalid frenemies", + ) + ) + } With this trigger in place, it is impossible to link the same ``Person`` as both a friend and an enemy of any other person. .. code-block:: edgeql-repl - db> insert Person {name := 'Quincey Morris'}; - {default::Person {id: e4a55480-d2de-11ed-93bd-9f4224fc73af}} - db> insert Person {name := 'Dracula'}; - {default::Person {id: e7f2cff0-d2de-11ed-93bd-279780478afb}} - db> update Person - ... filter .name = 'Quincey Morris' - ... set { - ... enemies := ( - ... select detached Person filter .name = 'Dracula' - ... ) - ... }; - {default::Person {id: e4a55480-d2de-11ed-93bd-9f4224fc73af}} - db> update Person - ... filter .name = 'Quincey Morris' - ... set { - ... friends := ( - ... select detached Person filter .name = 'Dracula' - ... ) - ... }; - edgedb error: EdgeDBError: Invalid frenemies + db> insert Person {name := 'Quincey Morris'}; + {default::Person {id: e4a55480-d2de-11ed-93bd-9f4224fc73af}} + db> insert Person {name := 'Dracula'}; + {default::Person {id: e7f2cff0-d2de-11ed-93bd-279780478afb}} + db> update Person + ... filter .name = 'Quincey Morris' + ... set { + ... enemies := ( + ... select detached Person filter .name = 'Dracula' + ... ) + ... }; + {default::Person {id: e4a55480-d2de-11ed-93bd-9f4224fc73af}} + db> update Person + ... filter .name = 'Quincey Morris' + ... set { + ... friends := ( + ... select detached Person filter .name = 'Dracula' + ... ) + ... }; + gel error: GelError: Invalid frenemies + + +Example: logging +================ + +Declare a trigger that inserts a ``Log`` object for each new ``User`` object: + +.. code-block:: sdl + + type User { + required name: str; + + trigger log_insert after insert for each do ( + insert Log { + action := 'insert', + target_name := __new__.name + } + ); + } + +Declare a trigger that inserts a ``Log`` object conditionally when an update +query makes a change to a ``User`` object: + +.. code-block:: sdl + + type User { + required name: str; + + trigger log_update after update for each + when (__old__ {**} != __new__ {**}) + do ( + insert Log { + action := 'update', + target_name := __new__.name, + change := __old__.name ++ '->' ++ __new__.name + } + ); + } + + +.. _ref_eql_sdl_triggers_syntax: + + +Declaring triggers +================== + +This section describes the syntax to declare a trigger in your schema. + +Syntax +------ + +.. sdl:synopsis:: + + type "{" + trigger + after + {insert | update | delete} [, ...] + for {each | all} + [ when () ] + do + "}" + +Description +----------- + +This declaration defines a new trigger with the following options: + +:eql:synopsis:`` + The name (optionally module-qualified) of the type to be triggered on. + +:eql:synopsis:`` + The name of the trigger. + +:eql:synopsis:`insert | update | delete [, ...]` + The query type (or types) to trigger on. Separate multiple values with + commas to invoke the same trigger for multiple types of queries. + +:eql:synopsis:`each` + The expression will be evaluated once per modified object. ``__new__`` and + ``__old__`` in this context within the expression will refer to a single + object. + +:eql:synopsis:`all` + The expression will be evaluted once for the entire query, even if multiple + objects were modified. ``__new__`` and ``__old__`` in this context within + the expression refer to sets of the modified objects. + +.. versionadded:: 4.0 + + :eql:synopsis:`when ()` + Optionally provide a condition for the trigger. If the condition is + met, the trigger will run. If not, the trigger is skipped. + +:eql:synopsis:`` + The expression to be evaluated when the trigger is invoked. + +The trigger name must be distinct from that of any existing trigger +on the same type. + + +.. _ref_eql_ddl_triggers: + +DDL commands +============ + +This section describes the low-level DDL commands for creating and dropping +triggers. You typically don't need to use these commands directly, but +knowing about them is useful for reviewing migrations. + + +Create trigger +-------------- + +:eql-statement: + +:ref:`Define ` a new trigger. + +.. eql:synopsis:: + + {create | alter} type "{" + create trigger + after + {insert | update | delete} [, ...] + for {each | all} + [ when () ] + do + "}" + +Description +^^^^^^^^^^^ + +The command ``create trigger`` nested under ``create type`` or ``alter type`` +defines a new trigger for a given object type. + +The trigger name must be distinct from that of any existing trigger +on the same type. + +Parameters +^^^^^^^^^^ + +The options of this command are identical to the +:ref:`SDL trigger declaration `. + +Example +^^^^^^^ + +Declare a trigger that inserts a ``Log`` object for each new ``User`` object: + +.. code-block:: edgeql + + alter type User { + create trigger log_insert after insert for each do ( + insert Log { + action := 'insert', + target_name := __new__.name + } + ); + }; + +.. versionadded:: 4.0 + + Declare a trigger that inserts a ``Log`` object conditionally when an update + query makes a change to a ``User`` object: + + .. code-block:: edgeql + + alter type User { + create trigger log_update after update for each + when (__old__ {**} != __new__ {**}) + do ( + insert Log { + action := 'update', + target_name := __new__.name, + change := __old__.name ++ '->' ++ __new__.name + } + ); + } + +Drop trigger +------------ + +:eql-statement: + +Remove a trigger. + +.. eql:synopsis:: + + alter type "{" + drop trigger ; + "}" + +Description +^^^^^^^^^^^ + +The command ``drop trigger`` inside an ``alter type`` block removes the +definition of an existing trigger on the specified type. + +Parameters +^^^^^^^^^^ + +:eql:synopsis:`` + The name (optionally module-qualified) of the type being triggered on. + +:eql:synopsis:`` + The name of the trigger. + +Example +^^^^^^^ + +Remove the ``log_insert`` trigger on the ``User`` type: + +.. code-block:: edgeql + + alter type User { + drop trigger log_insert; + }; .. list-table:: :class: seealso * - **See also** - * - :ref:`SDL > Triggers ` - * - :ref:`DDL > Triggers ` * - :ref:`Introspection > Triggers ` diff --git a/docs/edgeql/analyze.rst b/docs/edgeql/analyze.rst index 09311e4b016..e90211a43ec 100644 --- a/docs/edgeql/analyze.rst +++ b/docs/edgeql/analyze.rst @@ -1,11 +1,9 @@ .. _ref_eql_analyze: -.. versionadded:: 3.0 - Analyze ======= -:index: performance +.. index:: analyze, explain, performance, postgres query planner Prefix an EdgeQL query with ``analyze`` to run a performance analysis of that query. @@ -36,8 +34,8 @@ query. In addition to using the ``analyze`` statement in the CLI or UI's REPL, you may also run performance analysis via our CLI's :ref:`analyze command - ` and the UI's query builder (accessible by running - :ref:`ref_cli_edgedb_ui` to invoke your instance's UI) by prepending your + ` and the UI's query builder (accessible by running + :ref:`ref_cli_gel_ui` to invoke your instance's UI) by prepending your query with ``analyze``. This method offers helpful visualizations to to make it easy to understand your query's performance. @@ -49,5 +47,5 @@ more fine-grained performance metrics on the previously analyzed query. :class: seealso * - **See also** - * - :ref:`CLI > edgedb analyze ` + * - :ref:`CLI > gel analyze ` * - :ref:`Reference > EdgeQL > analyze ` diff --git a/docs/edgeql/delete.rst b/docs/edgeql/delete.rst index 97c28190ea4..bd1ff829cff 100644 --- a/docs/edgeql/delete.rst +++ b/docs/edgeql/delete.rst @@ -3,6 +3,8 @@ Delete ====== +.. index:: delete + The ``delete`` command is used to delete objects from the database. .. code-block:: edgeql @@ -28,6 +30,8 @@ on these clauses. Link deletion ------------- +.. index:: ConstraintViolationError + Every link is associated with a *link deletion policy*. By default, it isn't possible to delete an object linked to by another. @@ -56,18 +60,6 @@ deleted. To avoid this behavior, we could update the ``Movie.characters`` link to use the ``allow`` deletion policy. -.. code-block:: sdl-diff - :version-lt: 3.0 - - type Movie { - required property title -> str { constraint exclusive }; - required property release_year -> int64; - - multi link characters -> Person; - + multi link characters -> Person { - + on target delete allow; - + }; - } - .. code-block:: sdl-diff type Movie { @@ -83,6 +75,8 @@ the ``allow`` deletion policy. Cascading deletes ^^^^^^^^^^^^^^^^^ +.. index:: delete cascade, delete source, delete target, deletion policy + If a link uses the ``delete source`` policy, then deleting a *target* of the link will also delete the object that links to it (the *source*). This behavior can be used to implement cascading deletes; be careful with this power! @@ -93,6 +87,8 @@ The full list of deletion policies is documented at :ref:`Schema > Links Return value ------------ +.. index:: delete, returning + A ``delete`` statement returns the set of deleted objects. You can pass this set into ``select`` to fetch properties and links of the (now-deleted) objects. This is the last moment this data will be available before being @@ -113,5 +109,3 @@ permanently deleted. * - **See also** * - :ref:`Reference > Commands > Delete ` * - :ref:`Cheatsheets > Deleting data ` - * - `Tutorial > Data Mutations > Delete - `_ diff --git a/docs/edgeql/for.rst b/docs/edgeql/for.rst index dcbf542b978..bb85ff52be1 100644 --- a/docs/edgeql/for.rst +++ b/docs/edgeql/for.rst @@ -3,6 +3,8 @@ For === +.. index:: for in, union + EdgeQL supports a top-level ``for`` statement. These "for loops" iterate over each element of some input set, execute some expression with it, and merge the results into a single output set. @@ -22,7 +24,7 @@ are merged into a single output set. .. note:: - The ``union`` keyword is required prior to EdgeDB 5.0 and is intended to + The ``union`` keyword is required prior to |EdgeDB| 5.0 and is intended to indicate explicitly that the results of each loop execution are ultimately merged. @@ -42,6 +44,8 @@ are merged into a single output set. Bulk inserts ------------ +.. index:: bulk inserts + The ``for`` statement is commonly used for bulk inserts. .. code-block:: edgeql-repl @@ -87,13 +91,11 @@ A similar approach can be used for bulk updates. Conditional DML --------------- +.. index:: for, if else, unless conflict + .. versionadded:: 4.0 - DML is now supported in ``if..else``. The method of achieving conditional - DML demonstrated below is a workaround for earlier versions of EdgeDB - before this support was introduced in EdgeDB 4.0. If you're on EdgeDB 4.0 - or higher, use :eql:op:`if..else` for a cleaner way to achieve conditional - DML. + DML is now supported in ``if..else``. DML (i.e., :ref:`insert `, :ref:`update `, :ref:`delete `) is not supported in :eql:op:`if..else`. If you diff --git a/docs/edgeql/group.rst b/docs/edgeql/group.rst index aa53c885c5e..af99a683cc9 100644 --- a/docs/edgeql/group.rst +++ b/docs/edgeql/group.rst @@ -1,10 +1,11 @@ -.. versionadded:: 2.0 - .. _ref_eql_group: Group ===== +.. index:: group by, group using by, key, grouping, elements, analytics, + aggregate, rollup, cube, partition + EdgeQL supports a top-level ``group`` statement. This is used to partition sets into subsets based on some parameters. These subsets then can be additionally aggregated to provide some analytics. diff --git a/docs/edgeql/index.rst b/docs/edgeql/index.rst index 2b07a9d0379..02047a150dd 100644 --- a/docs/edgeql/index.rst +++ b/docs/edgeql/index.rst @@ -42,12 +42,12 @@ mind. spent attempting to `bridge the gap `_ between the *relational* paradigm of SQL and the *object-oriented* nature of modern programming -languages. EdgeDB sidesteps this problem by modeling data in an +languages. Gel sidesteps this problem by modeling data in an *object-relational* way. -**Strongly typed**. EdgeQL is *inextricably tied* to EdgeDB's rigorous +**Strongly typed**. EdgeQL is *inextricably tied* to Gel's rigorous object-oriented type system. The type of all expressions is statically -inferred by EdgeDB. +inferred by Gel. **Designed for programmers**. EdgeQL prioritizes syntax over keywords; It uses ``{ curly braces }`` to define scopes/structures and the *assignment @@ -62,24 +62,10 @@ like code and less like word soup. .. single PostgreSQL query under the hood. With the exception of ``group by``, .. EdgeQL is equivalent to SQL in terms of power and expressivity. -**Easy deep querying**. EdgeDB's object-relational nature makes it painless +**Easy deep querying**. Gel's object-relational nature makes it painless to write deep, performant queries that traverse links, no ``JOINs`` required. **Composable**. `Unlike SQL -`_, +`_, EdgeQL's syntax is readily composable; queries can be cleanly nested without worrying about Cartesian explosion. - -.. note:: - - For a detailed writeup on the design of SQL, see `We Can Do Better Than SQL - `_ - on the EdgeDB blog. - -Follow along ------------- - -The best way to learn EdgeQL is to play with it! Use the `online EdgeQL shell -`_ to execute any and all EdgeQL snippets in the following pages. Or -follow the :ref:`Quickstart ` to spin up an EdgeDB instance on -your computer, then open an :ref:`interactive shell `. diff --git a/docs/edgeql/insert.rst b/docs/edgeql/insert.rst index 70f7f01bfc8..6e7dbd80883 100644 --- a/docs/edgeql/insert.rst +++ b/docs/edgeql/insert.rst @@ -3,57 +3,11 @@ Insert ====== +.. index:: insert, returning + The ``insert`` command is used to create instances of object types. The code samples on this page assume the following schema: -.. code-block:: sdl - :version-lt: 3.0 - - module default { - abstract type Person { - required property name -> str { constraint exclusive }; - } - - type Hero extending Person { - property secret_identity -> str; - multi link villains := . Hero; - } - - type Movie { - required property title -> str { constraint exclusive }; - required property release_year -> int64; - multi link characters -> Person; - } - } - -.. code-block:: sdl - :version-lt: 4.0 - - module default { - abstract type Person { - required name: str { constraint exclusive }; - } - - type Hero extending Person { - secret_identity: str; - multi link villains := .` statement. This lets you express *upsert* logic in a single EdgeQL query. @@ -379,9 +343,6 @@ When a conflict occurs during the initial ``insert``, the statement falls back to the ``update`` statement in the ``else`` clause. This updates the ``release_year`` of the conflicting object. -To learn to use upserts by trying them yourself, see `our interactive upserts -tutorial `_. - .. note:: It can be useful to know the outcome of an upsert. Here's an example @@ -458,6 +419,8 @@ tutorial `_. Suppressing failures ^^^^^^^^^^^^^^^^^^^^ +.. index:: unless conflict + The ``else`` clause is optional; when omitted, the ``insert`` statement will return an *empty set* if a conflict occurs. This is a common way to prevent ``insert`` queries from failing on constraint violations. @@ -476,6 +439,8 @@ return an *empty set* if a conflict occurs. This is a common way to prevent Bulk inserts ------------ +.. index:: bulk inserts + Bulk inserts are performed by passing in a JSON array as a :ref:`query parameter `, :eql:func:`unpacking ` it, and using a :ref:`for loop ` to insert the objects. @@ -502,7 +467,3 @@ using a :ref:`for loop ` to insert the objects. * - **See also** * - :ref:`Reference > Commands > Insert ` * - :ref:`Cheatsheets > Inserting data ` - * - `Tutorial > Data Mutations > Insert - `_ - * - `Tutorial > Data Mutations > Upsert - `_ diff --git a/docs/edgeql/literals.rst b/docs/edgeql/literals.rst index 3d8c50075ad..3dea0d1a0f3 100644 --- a/docs/edgeql/literals.rst +++ b/docs/edgeql/literals.rst @@ -3,7 +3,9 @@ Literals ======== -EdgeQL is *inextricably tied* to EdgeDB's rigorous type system. Below is an +.. index:: primitive types + +EdgeQL is *inextricably tied* to Gel's rigorous type system. Below is an overview of how to declare a literal value of each *primitive type*. Click a link in the left column to jump to the associated section. @@ -55,13 +57,15 @@ link in the left column to jump to the associated section. Strings ------- +.. index:: str, unicode, quotes, raw strings, escape character + The :eql:type:`str` type is a variable-length string of Unicode characters. A string can be declared with either single or double quotes. .. code-block:: edgeql-repl - db> select 'i ❀️ edgedb'; - {'i ❀️ edgedb'} + db> select 'I ❀️ EdgeQL'; + {'I ❀️ EdgeQL'} db> select "hello there!"; {'hello there!'} db> select 'hello\nthere!'; @@ -146,6 +150,8 @@ For a complete reference on strings, see :ref:`Standard Library > String Booleans -------- +.. index:: bool + The :eql:type:`bool` type represents a true/false value. .. code-block:: edgeql-repl @@ -155,7 +161,7 @@ The :eql:type:`bool` type represents a true/false value. db> select false; {false} -EdgeDB provides a set of operators that operate on boolean values. +|Gel| provides a set of operators that operate on boolean values. .. list-table:: @@ -174,7 +180,7 @@ EdgeDB provides a set of operators that operate on boolean values. Numbers ------- -There are several numerical types in EdgeDB's type system. +There are several numerical types in Gel's type system. .. list-table:: @@ -296,6 +302,8 @@ Generate a random UUID. Enums ----- +.. index:: enums + Enum types must be :ref:`declared in your schema `. .. code-block:: sdl @@ -318,7 +326,9 @@ casting an appropriate string literal: Dates and times --------------- -EdgeDB's typesystem contains several temporal types. +.. index:: temporal + +|Gel's| typesystem contains several temporal types. .. list-table:: @@ -378,7 +388,7 @@ EdgeQL supports a set of functions and operators on datetime types. Durations --------- -EdgeDB's type system contains three duration types. +|Gel's| type system contains three duration types. .. list-table:: @@ -441,8 +451,6 @@ To declare relative duration literals: Date durations ^^^^^^^^^^^^^^ -.. versionadded:: 2.0 - The :eql:type:`cal::date_duration` represents spans consisting of some number of *months* and *days*. This type is primarily intended to simplify logic involving :eql:type:`cal::local_date` values. @@ -481,7 +489,8 @@ EdgeQL supports a set of functions and operators on duration types. Ranges ------ -.. versionadded:: 2.0 +.. index:: ranges, lower bound, upper bound, inclusive, inc_lower, inc_upper, + empty Ranges represent a range of orderable scalar values. A range comprises a lower bound, upper bound, and two boolean flags indicating whether each bound is @@ -526,13 +535,15 @@ ranges cannot be unpacked. db> select range_unpack(range(1, 1)); {} db> select range_unpack(range(0, {})); - edgedb error: InvalidValueError: cannot unpack an unbounded range + gel error: InvalidValueError: cannot unpack an unbounded range .. _ref_eql_literal_bytes: Bytes ----- +.. index:: binary, raw byte strings + The ``bytes`` type represents raw binary data. .. code-block:: edgeql-repl @@ -557,6 +568,8 @@ character. Arrays ------ +.. index:: collection, lists, ordered + An array is an *ordered* collection of values of the *same type*. For example: .. code-block:: edgeql-repl @@ -597,6 +610,8 @@ reference on array data types. Tuples ------ +.. index:: fixed length ordered collection, named tuples + A tuple is *fixed-length*, *ordered* collection of values, each of which may have a *different type*. The elements of a tuple can be of any type, including scalars, arrays, other tuples, and object types. @@ -647,6 +662,8 @@ For a full reference on tuples, see :ref:`Standard Library > Tuple JSON ---- +.. index:: json + The :eql:type:`json` scalar type is a stringified representation of structured data. JSON literals are declared by explicitly casting other values or passing a properly formatted JSON string into :eql:func:`to_json`. Any type can be diff --git a/docs/edgeql/parameters.rst b/docs/edgeql/parameters.rst index f799056944f..c01ddd0f568 100644 --- a/docs/edgeql/parameters.rst +++ b/docs/edgeql/parameters.rst @@ -3,6 +3,8 @@ Parameters ========== +.. index:: query params, query arguments, query args, $, < >$, input + :edb-alt-title: Query Parameters EdgeQL queries can reference parameters with ``$`` notation. The value of these @@ -15,18 +17,16 @@ parameters are supplied externally. select BlogPost filter .id = $blog_id; Note that we provided an explicit type cast before the parameter. This is -required, as it enables EdgeDB to enforce the provided types at runtime. - -.. versionadded:: 3.0 +required, as it enables Gel to enforce the provided types at runtime. - Parameters can be named or unnamed tuples. +Parameters can be named or unnamed tuples. - .. code-block:: edgeql +.. code-block:: edgeql - select >$var; - select >$var; - select >$var; - select >$var; + select >$var; + select >$var; + select >$var; + select >$var; Usage with clients ------------------ @@ -34,14 +34,14 @@ Usage with clients REPL ^^^^ -When you include a parameter reference in an EdgeDB REPL, you'll be prompted +When you include a parameter reference in an Gel REPL, you'll be prompted interactively to provide a value or values. .. code-block:: edgeql-repl db> select 'I ❀️ ' ++ $var ++ '!'; - Parameter $var: EdgeDB - {'I ❀️ EdgeDB!'} + Parameter $var: Gel + {'I ❀️ Gel!'} Python @@ -87,7 +87,7 @@ Go Refer to the Datatypes page of your preferred :ref:`client library -` to learn more about mapping between EdgeDB types and +` to learn more about mapping between Gel types and language-native types. @@ -96,10 +96,10 @@ language-native types. Parameter types and JSON ------------------------ -Prior to EdgeDB 3.0, parameters can be only :ref:`scalars -` or arrays of scalars. In EdgeDB 3.0, parameters -can also be tuples. If you need to pass complex structures as parameters, use -EdgeDB's built-in :ref:`JSON ` functionality. +.. index:: complex parameters + +In Gel, parameters can also be tuples. If you need to pass complex structures +as parameters, use Gel's built-in :ref:`JSON ` functionality. .. code-block:: edgeql-repl @@ -128,6 +128,8 @@ properties. Optional parameters ------------------- +.. index:: $ + By default, query parameters are ``required``; the query will fail if the parameter value is an empty set. You can use an ``optional`` modifier inside the type cast if the parameter is optional. @@ -150,6 +152,8 @@ the type cast if the parameter is optional. Default parameter values ------------------------ +.. index:: ?? + When using optional parameters, you may want to provide a default value to use in case the parameter is not passed. You can do this by using the :eql:op:`?? (coalesce) ` operator. @@ -157,8 +161,8 @@ in case the parameter is not passed. You can do this by using the .. code-block:: edgeql-repl db> select 'Hello ' ++ $name ?? 'there'; - Parameter $name (Ctrl+D for empty set `{}`): EdgeDB - {'Hello EdgeDB'} + Parameter $name (Ctrl+D for empty set `{}`): Gel + {'Hello Gel'} db> select 'Hello ' ++ $name ?? 'there'; Parameter $name (Ctrl+D for empty set `{}`): {'Hello there'} @@ -167,9 +171,11 @@ in case the parameter is not passed. You can do this by using the What can be parameterized? -------------------------- +.. index:: order by parameters + Any data manipulation language (DML) statement can be parameterized: ``select``, ``insert``, ``update``, and ``delete``. Since -parameters can only be scalars, arrays of scalars, and, as of EdgeDB 3.0, +parameters can only be scalars, arrays of scalars, and tuples of scalars, only parts of the query that would be one of those types can be parameterized. This excludes parts of the query like the type being queried and the property to order by. diff --git a/docs/edgeql/path_resolution.rst b/docs/edgeql/path_resolution.rst index 5b447ffcfb4..324cafbd097 100644 --- a/docs/edgeql/path_resolution.rst +++ b/docs/edgeql/path_resolution.rst @@ -4,13 +4,15 @@ Path scoping ============ -Beginning with EdgeDB 6.0, we are phasing out our historical (and +.. index:: using future simple_scoping, using future warn_old_scoping + +Beginning with Gel 6.0, we are phasing out our historical (and somewhat notorious) :ref:`"path scoping" algorithm ` in favor of a much simpler algorithm that nevertheless behaves identically on *most* idiomatic EdgeQL queries. -EdgeDB 6.0 will contain features to support migration to and testing +Gel 6.0 will contain features to support migration to and testing of the new semantics. We expect the migration to be relatively painless for most users. @@ -84,7 +86,7 @@ Path scoping configuration .. versionadded:: 6.0 -EdgeDB 6.0 introduces a new +Gel 6.0 introduces a new :ref:`future feature ` named ``simple_scoping`` alongside a configuration setting also named ``simple_scoping``. The future @@ -130,6 +132,8 @@ configuration value ``simple_scoping``: - No - Yes +.. _ref_warn_old_scoping: + Warning on old scoping ---------------------- @@ -184,10 +188,10 @@ Legacy path scoping =================== This section describes the path scoping algorithm used exclusively -until EdgeDB 5.0 and by default in EdgeDB 6.0. -It will be removed in EdgeDB 7.0. +until |EdgeDB| 5.0 and by default in |Gel| 6.0. +It will be removed in Gel 7.0. -Element-wise operations with multiple arguments in EdgeDB are generally applied +Element-wise operations with multiple arguments in Gel are generally applied to the :ref:`cartesian product ` of all the input sets. @@ -197,7 +201,7 @@ the input sets. {'aaaccc', 'aaaddd', 'bbbccc', 'bbbddd'} However, in cases where multiple element-wise arguments share a common path -(``User.`` in this example), EdgeDB factors out the common path rather than +(``User.`` in this example), Gel factors out the common path rather than using cartesian multiplication. .. code-block:: edgeql-repl @@ -211,7 +215,7 @@ product, you can accomplish it one of three ways. You could use .. code-block:: edgeql-repl - edgedb> select User.first_name ++ ' ' ++ detached User.last_name; + gel> select User.first_name ++ ' ' ++ detached User.last_name; { 'Mina Murray', 'Mina Harker', @@ -236,8 +240,8 @@ your set of ``User`` objects. .. code-block:: edgeql-repl - edgedb> with U := User - ....... select U.first_name ++ ' ' ++ User.last_name; + gel> with U := User + .... select U.first_name ++ ' ' ++ User.last_name; { 'Mina Murray', 'Mina Harker', @@ -269,7 +273,7 @@ cartesian multiplication. That may leave you still wondering why ``U`` and ``User`` did not get a common path factored. ``U`` is just an alias of ``select User`` and ``User`` is the -same symbol that we use in our name query. That's true, but EdgeDB doesn't +same symbol that we use in our name query. That's true, but |Gel| doesn't factor in this case because of the queries' scopes. .. _ref_eql_path_resolution_scopes: @@ -283,7 +287,7 @@ use a common symbol. .. code-block:: edgeql-repl - edgedb> select ((select User.first_name), (select User.last_name)); + gel> select ((select User.first_name), (select User.last_name)); { ('Mina', 'Murray'), ('Mina', 'Harker'), @@ -310,9 +314,9 @@ object because it has been factored. .. code-block:: edgeql-repl - edgedb> select User { - ....... name:= (select User.first_name) ++ ' ' ++ (select User.last_name) - ....... }; + gel> select User { + .... name:= (select User.first_name) ++ ' ' ++ (select User.last_name) + .... }; { default::User {name: 'Mina Murray'}, default::User {name: 'Jonathan Harker'}, @@ -325,7 +329,7 @@ paths are still factored. .. code-block:: edgeql-repl - edgedb> select (Person.name, count(Person.friends)); + gel> select (Person.name, count(Person.friends)); {('Fran', 3), ('Bam', 2), ('Emma', 3), ('Geoff', 1), ('Tyra', 1)} In this example, ``count``, like all aggregate function, creates a nested @@ -341,10 +345,10 @@ are *not* factored. .. code-block:: edgeql-repl - edgedb> select (array_agg(distinct Person.name), count(Person.friends)); + gel> select (array_agg(distinct Person.name), count(Person.friends)); {(['Fran', 'Bam', 'Emma', 'Geoff'], 3)} -This query selects a tuple containing two nested scopes. Here, EdgeDB assumes +This query selects a tuple containing two nested scopes. Here, |Gel| assumes you want an array of all unique names and a count of the total number of people who are anyone's friend. @@ -362,4 +366,4 @@ The :ref:`offset ` and because they need to be applied globally to the entire result set of your query. -.. _rfc: https://github.com/edgedb/rfcs/blob/master/text/1027-no-factoring.rst +.. _rfc: https://github.com/geldata/rfcs/blob/master/text/1027-no-factoring.rst diff --git a/docs/edgeql/paths.rst b/docs/edgeql/paths.rst index b1e6fcb8bda..d72d6441102 100644 --- a/docs/edgeql/paths.rst +++ b/docs/edgeql/paths.rst @@ -4,6 +4,7 @@ Paths ===== +.. index:: links, relations A *path expression* (or simply a *path*) represents a set of values that are reachable by traversing a given sequence of links or properties from some @@ -11,24 +12,6 @@ source set of objects. Consider the following schema: -.. code-block:: sdl - :version-lt: 3.0 - - type User { - required property email -> str; - multi link friends -> User; - } - - type BlogPost { - required property title -> str; - required link author -> User; - } - - type Comment { - required property text -> str; - required link author -> User; - } - .. code-block:: sdl type User { @@ -69,17 +52,17 @@ The first user reciprocates, adding the new user as a friend: .. code-block:: edgeql-repl - db> update User filter .email = "user1@me.com" - ... set { + db> update User filter .email = "user1@me.com" + ... set { ... friends += (select detached User filter .email = "user2@me.com") ... }; -The second user writes a blog post about how nice EdgeDB is: +The second user writes a blog post about how nice Gel is: .. code-block:: edgeql-repl db> insert BlogPost { - ... title := "EdgeDB is awesome", + ... title := "Gel is awesome", ... author := assert_single((select User filter .email = "user2@me.com")) ... }; @@ -129,6 +112,8 @@ Paths can terminate with a property reference. Backlinks --------- +.. index:: .< + All examples thus far have traversed links in the *forward direction*, however it's also possible to traverse links *backwards* with ``.<`` notation. These are called **backlinks**. @@ -147,10 +132,10 @@ database. However, we can't impose a shape on it: select User.` operator: +To do so, use the :eql:op:`type intersection ` operator: ``[is Foo]``: .. code-block:: edgeql - + # BlogPost objects that link to the user via a link named author select User. str; - multi link friends -> User; - + link all_links := . str; - required link author -> User; - } - type Comment { - required property text -> str; - required link author -> User; - } - -.. code-block:: sdl-diff - :version-lt: 4.0 - - type User { - required email: str; - multi friends: User; - + link all_links := .` with ``@`` notation. To demonstrate this, let's add a property to the ``User. friends`` link: -.. code-block:: sdl-diff - :version-lt: 3.0 - - type User { - required property email -> str; - - multi link friends -> User; - + multi link friends -> User { - + property since -> cal::local_date; - + } - } - .. code-block:: sdl-diff type User { @@ -304,13 +240,13 @@ Below, the root of the path is a *subquery*. .. code-block:: edgeql-repl - db> with edgedb_lovers := ( - ... select BlogPost filter .title ilike "EdgeDB is awesome" + db> with gel_lovers := ( + ... select BlogPost filter .title ilike "Gel is awesome" ... ) - ... select edgedb_lovers.author; + ... select gel_lovers.author; This expression returns a set of all ``Users`` who have written a blog post -titled "EdgeDB is awesome". +titled "Gel is awesome". For a full syntax definition, see the :ref:`Reference > Paths `. diff --git a/docs/edgeql/select.rst b/docs/edgeql/select.rst index 8ebee596ac8..8098038930a 100644 --- a/docs/edgeql/select.rst +++ b/docs/edgeql/select.rst @@ -3,6 +3,7 @@ Select ====== +.. index:: select The ``select`` command retrieves or computes a set of values. We've already seen simple queries that select primitive values. @@ -51,54 +52,6 @@ Selecting objects However most queries are selecting *objects* that live in the database. For demonstration purposes, the queries below assume the following schema: -.. code-block:: sdl - :version-lt: 3.0 - - module default { - abstract type Person { - required property name -> str { constraint exclusive }; - } - - type Hero extending Person { - property secret_identity -> str; - multi link villains := . Hero; - } - - type Movie { - required property title -> str { constraint exclusive }; - required property release_year -> int64; - multi link characters -> Person; - } - } - -.. code-block:: sdl - :version-lt: 4.0 - - module default { - abstract type Person { - required name: str { constraint exclusive }; - } - - type Hero extending Person { - secret_identity: str; - multi link villains := .`_. - .. _ref_eql_shapes: Shapes ------ +.. index:: select, shapes, { } + To specify which properties to select, we attach a **shape** to ``Villain``. A shape can be attached to any object type expression in EdgeQL. @@ -228,12 +180,11 @@ shape can be attached to any object type expression in EdgeQL. default::Villain {id: 6c42c4ec..., name: 'Obadiah Stane'}, } -To learn to use shapes by trying them yourself, see `our interactive shapes -tutorial `_. - Nested shapes ^^^^^^^^^^^^^ +.. index:: select, nested shapes + Nested shapes can be used to fetch linked objects and their properties. Here we fetch all ``Villain`` objects and their nemeses. @@ -279,7 +230,7 @@ identically to concrete/non-computed links like ``Villain.nemesis``. Splats ^^^^^^ -.. versionadded:: 3.0 +.. index:: select, splats, *, **, select *, select all, [is ].*, [is ].** Splats allow you to select all properties of a type using the asterisk (``*``) or all properties of the type and a single level of linked types with a double @@ -530,6 +481,8 @@ we wouldn't get those with this query either. Filtering --------- +.. index:: select, filter, where + To filter the set of selected objects, use a ``filter `` clause. The ```` that follows the ``filter`` keyword can be *any boolean expression*. @@ -571,9 +524,6 @@ of the ``Villain`` type. In other words, we are in the **scope** of the boolean cheatsheet ` for more info and help on how to mitigate this if you know your operands may be an empty set. -Learn to filter your queries by trying it in `our interactive filters -tutorial `_. - Filtering by ID ^^^^^^^^^^^^^^^ @@ -639,14 +589,14 @@ links to a second object without a link back to the first. Spider-Man's villains always have a grudging respect for him, and their names can be displayed to reflect that if we know the ID of a movie that they -starred in. (Note the ability to :ref:`cast from a uuid ` -to an object type, which was added in EdgeDB 3.0!) +starred in. Note the ability to :ref:`cast from a uuid ` +to an object type. .. code-block:: edgeql-repl - - db> select Villain filter .'6c60c28a-5c03-11ee-99ff-dfa425012a05' { - ... name := .name ++ ', who got to see Spider-Man!' + + db> select Villain filter .'6c60c28a-5c03-11ee-99ff-dfa425012a05' { + ... name := .name ++ ', who got to see Spider-Man!' ... }; { 'Obadiah Stane', @@ -664,7 +614,7 @@ traversing a backlink would look like this: .. code-block:: edgeql-repl - db> with movie := + db> with movie := ... '6c60c28a-5c03-11ee-99ff-dfa425012a05', ... select movie.characters[is Villain] { ... name := .name ++ ', who got to see Spider-Man!' @@ -673,9 +623,36 @@ traversing a backlink would look like this: .. _ref_eql_select_order: +Filtering, ordering, and limiting of links +========================================== + +Clauses like ``filter``, ``order by``, and ``limit`` can be used on links. +If no properties of a link are selected, you can place the clauses directly +inside the shape: + +.. code-block:: edgeql + + select User { + likes order by .title desc limit 10 + }; + +If properties are selected, place the clauses after the link's shape: + +.. code-block:: edgeql + + select User { + likes: { + id, + title + } order by .title desc limit 10 + }; + + Ordering -------- +.. index:: order by, sorting, asc, desc, then, empty first, empty last + Order the result of a query with an ``order by`` clause. .. code-block:: edgeql-repl @@ -695,7 +672,7 @@ expression, primitive or otherwise. .. note:: - In EdgeDB all values are orderable. Objects are compared using their ``id``; + In Gel all values are orderable. Objects are compared using their ``id``; tuples and arrays are compared element-by-element from left to right. By extension, the generic comparison operators :eql:op:`= `, :eql:op:`\< `, :eql:op:`\> `, etc. can be used with any two @@ -735,7 +712,9 @@ are handled, see :ref:`Reference > Commands > Select Pagination ---------- -EdgeDB supports ``limit`` and ``offset`` clauses. These are +.. index:: limit, offset + +|Gel| supports ``limit`` and ``offset`` clauses. These are typically used in conjunction with ``order by`` to maintain a consistent ordering across pagination queries. @@ -798,6 +777,8 @@ providing one or the other. Computed fields --------------- +.. index:: computeds, := + Shapes can contain *computed fields*. These are EdgeQL expressions that are computed on the fly during the execution of the query. As with other clauses, we can use :ref:`leading dot notation ` (e.g. ``.name``) to @@ -851,6 +832,8 @@ As with nested filters, the *current scope* changes inside nested shapes. Backlinks --------- +.. index:: .< + Fetching backlinks is a common use case for computed fields. To demonstrate this, let's fetch a list of all movies starring a particular Hero. @@ -879,26 +862,6 @@ this, let's fetch a list of all movies starring a particular Hero. Instead of re-declaring backlinks inside every query where they're needed, it's common to add them directly into your schema as computed links. -.. code-block:: sdl-diff - :version-lt: 3.0 - - abstract type Person { - required property name -> str { - constraint exclusive; - }; - + multi link movies := .`_. - Polymorphic sets ^^^^^^^^^^^^^^^^ @@ -1016,6 +978,8 @@ abstract type (such as ``Movie.characters``) or a :eql:op:`union type Polymorphic fields ^^^^^^^^^^^^^^^^^^ +.. index:: [is ]. + We can fetch different properties *conditional* on the subtype of each object by prefixing property/link references with ``[is ]``. This is known as a **polymorphic query**. @@ -1166,7 +1130,7 @@ know about the type of the current object. The splat operator can be used to see this object's makeup, while the double splat operator produces too much output to show on this page. Playing around with the splat and double splat operator inside ``__type__`` is a quick way to get some insight into the -internals of EdgeDB. +internals of Gel. .. code-block:: edgeql-repl @@ -1196,6 +1160,8 @@ internals of EdgeDB. Free objects ------------ +.. index:: ad hoc type + To select several values simultaneously, you can "bundle" them into a "free object". Free objects are a set of key-value pairs that can contain any expression. Here, the term "free" is used to indicate that the object in @@ -1251,13 +1217,3 @@ For full documentation on ``with``, see :ref:`EdgeQL > With `. * - **See also** * - :ref:`Reference > Commands > Select ` * - :ref:`Cheatsheets > Selecting data ` - * - `Tutorial > Basic Queries > Objects - `_ - * - `Tutorial > Basic Queries > Filters - `_ - * - `Tutorial > Basic Queries > Aggregates - `_ - * - `Tutorial > Nested Structures > Shapes - `_ - * - `Tutorial > Nested Structures > Polymorphism - `_ diff --git a/docs/edgeql/sets.rst b/docs/edgeql/sets.rst index 768c9efa8ba..9105194609c 100644 --- a/docs/edgeql/sets.rst +++ b/docs/edgeql/sets.rst @@ -8,6 +8,8 @@ Sets Everything is a set ------------------- +.. index:: set, multiset, cardinality, empty set, singleton + All values in EdgeQL are actually **sets**: a collection of values of a given **type**. All elements of a set must have the same type. The number of items in a set is known as its **cardinality**. A set with a cardinality of zero is @@ -19,6 +21,8 @@ referred to as an **empty set**. A set with a cardinality of one is known as a Constructing sets ----------------- +.. index:: constructor, { }, union + Set literals are declared with *set constructor* syntax: a comma-separated list of values inside a set of ``{curly braces}``. @@ -49,7 +53,7 @@ A consequence of this is that nested sets are *flattened*. db> select 1 union (2 union (3 union 4)); {1, 2, 3, 4} -All values in a set must have the same type. For convenience, EdgeDB will +All values in a set must have the same type. For convenience, Gel will *implicitly cast* values to other types, as long as there is no loss of information (e.g. converting a ``int16`` to an ``int64``). For a full reference, see the casting table in :ref:`Standard Library > Casts @@ -121,9 +125,11 @@ You can retrieve the cardinality of a set with the :eql:func:`count` function. Empty sets ---------- +.. index:: null, exists + The reason EdgeQL introduced the concept of *sets* is to eliminate the concept of ``null``. In SQL databases ``null`` is a special value denoting the absence -of data; in EdgeDB the absence of data is just an empty set. +of data; in Gel the absence of data is just an empty set. .. note:: @@ -131,8 +137,8 @@ of data; in EdgeDB the absence of data is just an empty set. permeates all of SQL and is often handled inconsistently in different circumstances. A number of specific inconsistencies are documented in detail in the `We Can Do Better Than SQL - `_ - post on the EdgeDB blog. For broader context, see Tony Hoare's talk + `_ + post on the Gel blog. For broader context, see Tony Hoare's talk `"The Billion Dollar Mistake" `_. @@ -173,6 +179,8 @@ operator. Set references -------------- +.. index:: pointer, alias, with + A set reference is a *pointer* to a set of values. Most commonly, this is the name of an :ref:`object type ` you've declared in your schema. @@ -207,7 +215,9 @@ schema. Multisets --------- -Technically sets in EdgeDB are actually *multisets*, because they can contain +.. index:: multisets, distinct, duplicates + +Technically sets in Gel are actually *multisets*, because they can contain duplicates of the same element. To eliminate duplicates, use the :eql:op:`distinct` set operator. @@ -223,6 +233,8 @@ duplicates of the same element. To eliminate duplicates, use the Checking membership ------------------- +.. index:: in + Use the :eql:op:`in` operator to check whether a set contains a particular element. @@ -239,6 +251,8 @@ element. Merging sets ------------ +.. index:: union, merge + Use the :eql:op:`union` operator to merge two sets. .. code-block:: edgeql-repl @@ -251,7 +265,7 @@ Use the :eql:op:`union` operator to merge two sets. Finding common members ---------------------- -.. versionadded:: 3.0 +.. index:: intersect Use the :eql:op:`intersect` operator to find common members between two sets. @@ -281,7 +295,7 @@ resulting set. Removing common members ----------------------- -.. versionadded:: 3.0 +.. index:: except Use the :eql:op:`except` operator to leave only the members in the first set that do not appear in the second set. @@ -314,6 +328,8 @@ first set's ``3`` members are eliminated from the resulting set. Coalescing ---------- +.. index:: empty set, ??, default values, optional + Occasionally in queries, you need to handle the case where a set is empty. This can be achieved with a coalescing operator :eql:op:`?? `. This is commonly used to provide default values for optional :ref:`query parameters @@ -341,26 +357,13 @@ commonly used to provide default values for optional :ref:`query parameters Inheritance ----------- -EdgeDB schemas support :ref:`inheritance `; +.. index:: type intersection, backlinks, [is ] + +|Gel| schemas support :ref:`inheritance `; types (usually object types) can extend one or more other types. For instance you may declare an abstract object type ``Media`` that is extended by ``Movie`` and ``TVShow``. -.. code-block:: sdl - :version-lt: 3.0 - - abstract type Media { - required property title -> str; - } - - type Movie extending Media { - property release_year -> int64; - } - - type TVShow extending Media { - property num_seasons -> int64; - } - .. code-block:: sdl abstract type Media { @@ -410,6 +413,8 @@ Type filters are commonly used in conjunction with :ref:`backlinks Aggregate vs element-wise operations ------------------------------------ +.. index:: cartesian product + EdgeQL provides a large library of built-in functions and operators for handling data structures. It's useful to consider functions/operators as either *aggregate* or *element-wise*. @@ -417,7 +422,7 @@ handling data structures. It's useful to consider functions/operators as either .. note:: This is an over-simplification, but it's a useful mental model when just - starting out with EdgeDB. For a more complete guide, see :ref:`Reference > + starting out with Gel. For a more complete guide, see :ref:`Reference > Cardinality `. *Aggregate* operations are applied to the set *as a whole*; they @@ -472,6 +477,8 @@ Cardinality `. Conversion to/from arrays ------------------------- +.. index:: array_unpack, array_agg, converting sets + Both arrays and sets are collections of values that share a type. EdgeQL provides ways to convert one into the other. @@ -524,10 +531,3 @@ Reference * - Cardinality assertion - :eql:func:`assert_distinct` :eql:func:`assert_single` :eql:func:`assert_exists` - -.. list-table:: - :class: seealso - - * - **See also** - * - `Tutorial > Building Blocks > Sets - `_ diff --git a/docs/edgeql/transactions.rst b/docs/edgeql/transactions.rst index df010ea18ce..b32da5495ca 100644 --- a/docs/edgeql/transactions.rst +++ b/docs/edgeql/transactions.rst @@ -3,6 +3,9 @@ Transactions ============ +.. index:: start transaction, declare savepoint, release savepoint, + rollback to savepoint, rollback, commit + EdgeQL supports atomic transactions. The transaction API consists of several commands: @@ -35,13 +38,13 @@ of several commands: Client libraries ---------------- -There is rarely a reason to use these commands directly. All EdgeDB client +There is rarely a reason to use these commands directly. All Gel client libraries provide dedicated transaction APIs that handle transaction creation under the hood. Examples below show a transaction that sends 10 cents from the account of a ``BankCustomer`` called ``'Customer1'`` to ``BankCustomer`` called -``'Customer2'``. The equivalent EdgeDB schema and queries are: +``'Customer2'``. The equivalent Gel schema and queries are: .. code-block:: @@ -96,7 +99,7 @@ Using the querybuilder: await query2.run(tx); }); -Full documentation at :ref:`Client Libraries > TypeScript/JS `; +Full documentation at :ref:`Client Libraries > TypeScript/JS `; Python ^^^^^^ @@ -112,14 +115,14 @@ Python filter .name = 'Customer2' set { bank_balance := .bank_balance +10 };""") -Full documentation at :ref:`Client Libraries > Python `; +Full documentation at :ref:`Client Libraries > Python `; Golang ^^^^^^ .. code-block:: go - err = client.Tx(ctx, func(ctx context.Context, tx *edgedb.Tx) error { + err = client.Tx(ctx, func(ctx context.Context, tx *gel.Tx) error { query1 := `update BankCustomer filter .name = 'Customer1' set { bank_balance := .bank_balance -10 };` @@ -138,7 +141,7 @@ Golang log.Fatal(err) } -Full documentation at :ref:`Client Libraries > Go `. +Full documentation at :ref:`Client Libraries > Go `. Rust ^^^^ @@ -162,4 +165,5 @@ Rust .await .expect("Transaction should have worked"); -Full documentation at :ref:`Client Libraries > Rust `. +.. XXX: Add Rust docs +.. Full documentation at :ref:`Client Libraries > Rust `. diff --git a/docs/edgeql/types.rst b/docs/edgeql/types.rst index 249a2592b64..2fdf29defd0 100644 --- a/docs/edgeql/types.rst +++ b/docs/edgeql/types.rst @@ -5,7 +5,7 @@ Types ===== -The foundation of EdgeQL is EdgeDB's rigorous type system. There is a set of +The foundation of EdgeQL is Gel's rigorous type system. There is a set of EdgeQL operators and functions for changing, introspecting, and filtering by types. @@ -14,6 +14,8 @@ types. Type expressions ---------------- +.. index:: array< >, tuple< > + Type expressions are exactly what they sound like: EdgeQL expressions that refer to a type. Most commonly, these are simply the *names* of established types: ``str``, ``int64``, ``BlogPost``, etc. Arrays and tuples have a @@ -38,6 +40,8 @@ For additional details on type syntax, see :ref:`Schema > Primitive Types Type casting ------------ +.. index:: casts, < >, find object by id + Type casting is used to convert primitive values into another type. Casts are indicated with angle brackets containing a type expression. @@ -89,22 +93,20 @@ typed; you can't simply convert an object to an object of a different type. .. lint-off -.. versionadded:: 3.0 +You can cast a UUID into an object: - You can cast a UUID into an object: - - .. code-block:: edgeql-repl +.. code-block:: edgeql-repl - db> select '01d9cc22-b776-11ed-8bef-73f84c7e91e7'; - {default::Hero {id: 01d9cc22-b776-11ed-8bef-73f84c7e91e7}} + db> select '01d9cc22-b776-11ed-8bef-73f84c7e91e7'; + {default::Hero {id: 01d9cc22-b776-11ed-8bef-73f84c7e91e7}} - If you try to cast a UUID that no object of the type has as its ``id`` - property, you'll get an error: +If you try to cast a UUID that no object of the type has as its ``id`` +property, you'll get an error: - .. code-block:: edgeql-repl +.. code-block:: edgeql-repl - db> select 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'; - edgedb error: CardinalityViolationError: 'default::Hero' with id 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa' does not exist + db> select 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'; + gel error: CardinalityViolationError: 'default::Hero' with id 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa' does not exist .. lint-on @@ -114,6 +116,8 @@ typed; you can't simply convert an object to an object of a different type. Type intersections ------------------ +.. index:: [is ] + All elements of a given set have the same type; however, in the context of *sets of objects*, this type might be ``abstract`` and contain elements of multiple concrete subtypes. For instance, a set of ``Media`` objects may @@ -160,6 +164,8 @@ a "filter" that removes all elements that aren't of type ``Movie``. Type checking ------------- +.. index:: is + The ``[is foo]`` "type intersection" syntax should not be confused with the *type checking* operator :eql:op:`is`. @@ -176,6 +182,8 @@ The ``[is foo]`` "type intersection" syntax should not be confused with the The ``typeof`` operator ----------------------- +.. index:: typeof + The type of any expression can be extracted with the :eql:op:`typeof` operator. This can be used in any expression that expects a type. @@ -189,9 +197,7 @@ operator. This can be used in any expression that expects a type. Introspection ------------- -The entire type system of EdgeDB is *stored inside EdgeDB*. All types are +The entire type system of Gel is *stored inside Gel*. All types are introspectable as instances of the ``schema::Type`` type. For a set of introspection examples, see :ref:`Guides > Introspection -`. To try introspection for yourself, see `our -interactive introspection tutorial -`_. +`. diff --git a/docs/edgeql/update.rst b/docs/edgeql/update.rst index f79ec7bed92..ff80ad85a7f 100644 --- a/docs/edgeql/update.rst +++ b/docs/edgeql/update.rst @@ -3,6 +3,8 @@ Update ====== +.. index:: update, filter, set + The ``update`` command is used to update existing objects. .. code-block:: edgeql-repl @@ -35,6 +37,8 @@ set is specified, then filters are applied, then the data is updated. Updating properties ------------------- +.. index:: unset + To explicitly unset a property that is not required, set it to an empty set. .. code-block:: edgeql @@ -44,6 +48,8 @@ To explicitly unset a property that is not required, set it to an empty set. Updating links -------------- +.. index:: :=, +=, -= + When updating links, the ``:=`` operator will *replace* the set of linked values. @@ -93,6 +99,8 @@ To remove items, use ``-=``. Returning data on update ------------------------ +.. index:: update, returning + By default, ``update`` returns only the inserted object's ``id`` as seen in the examples above. If you want to get additional data back, you may wrap your ``update`` with a ``select`` and apply a shape specifying any properties and @@ -114,6 +122,8 @@ links you want returned: With blocks ----------- +.. index:: with update + All top-level EdgeQL statements (``select``, ``insert``, ``update``, and ``delete``) can be prefixed with a ``with`` block. This is useful for updating the results of a complex query. @@ -170,5 +180,3 @@ For documentation on performing *upsert* operations, see :ref:`EdgeQL > Insert * - :ref:`Reference > Commands > Update ` * - :ref:`Cheatsheets > Updating data ` - * - `Tutorial > Data Mutations > Update - `_ diff --git a/docs/edgeql/with.rst b/docs/edgeql/with.rst index 9582ab20a93..e67d7867f56 100644 --- a/docs/edgeql/with.rst +++ b/docs/edgeql/with.rst @@ -3,6 +3,9 @@ With ==== +.. index:: composition, composing queries, composable, CTE, + common table expressions, subquery, subqueries + All top-level EdgeQL statements (``select``, ``insert``, ``update``, and ``delete``) can be prefixed by a ``with`` block. These blocks contain declarations of standalone expressions that can be used in your query. @@ -61,6 +64,8 @@ Avengers. Query parameters ^^^^^^^^^^^^^^^^ +.. index:: with + A common use case for ``with`` clauses is the initialization of :ref:`query parameters `. @@ -77,6 +82,7 @@ For a full reference on using query parameters, see :ref:`EdgeQL > Parameters Module alias ^^^^^^^^^^^^ +.. index:: with, as module Another use of ``with`` is to provide aliases for modules. This can be useful for long queries which reuse many objects or functions from the same module. @@ -100,6 +106,7 @@ part of the ``std`` module, that will be used automatically. Module selection ^^^^^^^^^^^^^^^^ +.. index:: with module, fully-qualified names By default, the *active module* is ``default``, so all schema objects inside this module can be referenced by their *short name*, e.g. ``User``, @@ -115,7 +122,7 @@ module* on a per-query basis. ... select ObjectType; This ``with module`` clause changes the default module to schema, so we can -refer to ``schema::ObjectType`` (a built-in EdgeDB type) as simply +refer to ``schema::ObjectType`` (a built-in Gel type) as simply ``ObjectType``. As with module aliases, if the active module does not exist at the top level, diff --git a/docs/guides/auth/built_in_ui.rst b/docs/guides/auth/built_in_ui.rst index d1d8eebb88a..d603d2c1dcd 100644 --- a/docs/guides/auth/built_in_ui.rst +++ b/docs/guides/auth/built_in_ui.rst @@ -4,22 +4,22 @@ Built-in UI =========== -:edb-alt-title: Integrating EdgeDB Auth's built-in UI +:edb-alt-title: Integrating Gel Auth's built-in UI -To use the built-in UI for EdgeDB Auth, enable the built-in Auth UI by clicking +To use the built-in UI for Gel Auth, enable the built-in Auth UI by clicking the "Enable UI" button under "Login UI" in the configuration section of the -EdgeDB UI. Set these configuration values: +|Gel| UI. Set these configuration values: -- ``redirect_to``: Once the authentication flow is complete, EdgeDB will - redirect the user’s browser back to this URL in your application’s +- ``redirect_to``: Once the authentication flow is complete, Gel will + redirect the user's browser back to this URL in your application's backend. -- ``redirect_to_on_signup``: If this is a new user, EdgeDB will redirect - the user’s browser back to this URL in your application’s backend. +- ``redirect_to_on_signup``: If this is a new user, Gel will redirect + the user's browser back to this URL in your application's backend. - ``app_name``: Used in the built-in UI to show the user the - application’s name in a few important places. + application's name in a few important places. - ``logo_url``: If provided, will show in the built-in UI as part of the page design. -- ``dark_logo_url``: If provided and the user’s system has indicated +- ``dark_logo_url``: If provided and the user's system has indicated that they prefer a dark UI, this will show instead of ``logo_url`` in the built-in UI as part of the page design. - ``brand_color``: If provided, used in the built-in UI as part of the @@ -83,11 +83,11 @@ base64url encode the resulting string. This new string is called the import crypto from "node:crypto"; /** - * You can get this value by running `edgedb instance credentials`. + * You can get this value by running `gel instance credentials`. * Value should be: * `${protocol}://${host}:${port}/branch/${branch}/ext/auth/ */ - const EDGEDB_AUTH_BASE_URL = process.env.EDGEDB_AUTH_BASE_URL; + const GEL_AUTH_BASE_URL = process.env.GEL_AUTH_BASE_URL; const SERVER_PORT = 3000; /** @@ -111,7 +111,7 @@ base64url encode the resulting string. This new string is called the .. note:: - For EdgeDB versions before 5.0, the value for ``EDGEDB_AUTH_BASE_URL`` + For |EdgeDB| versions before 5.0, the value for :gelenv:`AUTH_BASE_URL` in the above snippet should have the form: ``${protocol}://${host}:${port}/db/${database}/ext/auth/`` @@ -174,7 +174,7 @@ to the built-in UI with the ``challenge`` in the search parameters. }); /** - * Redirects browser requests to EdgeDB Auth UI sign in page with the + * Redirects browser requests to Gel Auth UI sign in page with the * PKCE challenge, and saves PKCE verifier in an HttpOnly cookie. * * @param {Request} req @@ -183,18 +183,18 @@ to the built-in UI with the ``challenge`` in the search parameters. const handleUiSignIn = async (req, res) => { const { verifier, challenge } = generatePKCE(); - const redirectUrl = new URL("ui/signin", EDGEDB_AUTH_BASE_URL); + const redirectUrl = new URL("ui/signin", GEL_AUTH_BASE_URL); redirectUrl.searchParams.set("challenge", challenge); res.writeHead(301, { - "Set-Cookie": `edgedb-pkce-verifier=${verifier}; HttpOnly; Path=/; Secure; SameSite=Strict`, + "Set-Cookie": `gel-pkce-verifier=${verifier}; HttpOnly; Path=/; Secure; SameSite=Strict`, Location: redirectUrl.href, }); res.end(); }; /** - * Redirects browser requests to EdgeDB Auth UI sign up page with the + * Redirects browser requests to Gel Auth UI sign up page with the * PKCE challenge, and saves PKCE verifier in an HttpOnly cookie. * * @param {Request} req @@ -203,11 +203,11 @@ to the built-in UI with the ``challenge`` in the search parameters. const handleUiSignUp = async (req, res) => { const { verifier, challenge } = generatePKCE(); - const redirectUrl = new URL("ui/signup", EDGEDB_AUTH_BASE_URL); + const redirectUrl = new URL("ui/signup", GEL_AUTH_BASE_URL); redirectUrl.searchParams.set("challenge", challenge); res.writeHead(301, { - "Set-Cookie": `edgedb-pkce-verifier=${verifier}; HttpOnly; Path=/; Secure; SameSite=Strict`, + "Set-Cookie": `gel-pkce-verifier=${verifier}; HttpOnly; Path=/; Secure; SameSite=Strict`, Location: redirectUrl.href, }); res.end(); @@ -224,12 +224,13 @@ to the built-in UI with the ``challenge`` in the search parameters. Retrieve ``auth_token`` ----------------------- -At the very end of the flow, the EdgeDB server will redirect the user's browser +At the very end of the flow, the Gel server will redirect the user's browser to the ``redirect_to`` address with a single query parameter: ``code``. This route should be a server route that has access to the ``verifier``. You then -take that ``code`` and look up the ``verifier`` in the ``edgedb-pkce-verifier`` -cookie, and make a request to the EdgeDB Auth extension to exchange these two -pieces of data for an ``auth_token``. +take that ``code`` and look up the ``verifier`` in the ``gel-pkce-verifier`` +cookie (``gel-pkce-verifier`` with |EdgeDB| <= 5), and make a request +to the Gel Auth extension to exchange these two pieces of data for an +``auth_token``. .. lint-off @@ -258,7 +259,7 @@ pieces of data for an ``auth_token``. const cookies = req.headers.cookie?.split("; "); const verifier = cookies - ?.find((cookie) => cookie.startsWith("edgedb-pkce-verifier=")) + ?.find((cookie) => cookie.startsWith("gel-pkce-verifier=")) ?.split("=")[1]; if (!verifier) { res.status = 400; @@ -269,7 +270,7 @@ pieces of data for an ``auth_token``. return; } - const codeExchangeUrl = new URL("token", EDGEDB_AUTH_BASE_URL); + const codeExchangeUrl = new URL("token", GEL_AUTH_BASE_URL); codeExchangeUrl.searchParams.set("code", code); codeExchangeUrl.searchParams.set("verifier", verifier); const codeExchangeResponse = await fetch(codeExchangeUrl.href, { @@ -285,7 +286,7 @@ pieces of data for an ``auth_token``. const { auth_token } = await codeExchangeResponse.json(); res.writeHead(204, { - "Set-Cookie": `edgedb-auth-token=${auth_token}; HttpOnly; Path=/; Secure; SameSite=Strict`, + "Set-Cookie": `gel-auth-token=${auth_token}; HttpOnly; Path=/; Secure; SameSite=Strict`, }); res.end(); }; @@ -293,4 +294,4 @@ pieces of data for an ``auth_token``. .. lint-on -:ref:`Back to the EdgeDB Auth guide ` +:ref:`Back to the Gel Auth guide ` diff --git a/docs/guides/auth/email_password.rst b/docs/guides/auth/email_password.rst index d0c7852d0f8..bc36a1b9f38 100644 --- a/docs/guides/auth/email_password.rst +++ b/docs/guides/auth/email_password.rst @@ -4,7 +4,7 @@ Email and password ================== -:edb-alt-title: Integrating EdgeDB Auth's email and password provider +:edb-alt-title: Integrating Gel Auth's email and password provider Along with using the :ref:`built-in UI `, you can also create your own UI that calls to your own web application backend. @@ -90,11 +90,11 @@ base64url encode the resulting string. This new string is called the import crypto from "node:crypto"; /** - * You can get this value by running `edgedb instance credentials`. + * You can get this value by running `gel instance credentials`. * Value should be: * `${protocol}://${host}:${port}/branch/${branch}/ext/auth/ */ - const EDGEDB_AUTH_BASE_URL = process.env.EDGEDB_AUTH_BASE_URL; + const GEL_AUTH_BASE_URL = process.env.GEL_AUTH_BASE_URL; const SERVER_PORT = 3000; /** @@ -119,7 +119,7 @@ base64url encode the resulting string. This new string is called the .. note:: - For EdgeDB versions before 5.0, the value for ``EDGEDB_AUTH_BASE_URL`` + For |EdgeDB| versions before 5.0, the value for :gelenv:`AUTH_BASE_URL` in the above snippet should have the form: ``${protocol}://${host}:${port}/db/${database}/ext/auth/`` @@ -199,7 +199,7 @@ an existing user. return; } - const registerUrl = new URL("register", EDGEDB_AUTH_BASE_URL); + const registerUrl = new URL("register", GEL_AUTH_BASE_URL); const registerResponse = await fetch(registerUrl.href, { method: "post", headers: { @@ -225,7 +225,7 @@ an existing user. if ("code" in registerJson) { // No verification required, we can immediately get an auth token - const tokenUrl = new URL("token", EDGEDB_AUTH_BASE_URL); + const tokenUrl = new URL("token", GEL_AUTH_BASE_URL); tokenUrl.searchParams.set("code", registerJson.code); tokenUrl.searchParams.set("verifier", pkce.verifier); const tokenResponse = await fetch(tokenUrl.href, { @@ -241,7 +241,7 @@ an existing user. const { auth_token } = await tokenResponse.json(); res.writeHead(204, { - "Set-Cookie": `edgedb-auth-token=${auth_token}; HttpOnly; Path=/; Secure; SameSite=Strict`, + "Set-Cookie": `gel-auth-token=${auth_token}; HttpOnly; Path=/; Secure; SameSite=Strict`, }); res.end(); @@ -282,7 +282,7 @@ an existing user. return; } - const authenticateUrl = new URL("authenticate", EDGEDB_AUTH_BASE_URL); + const authenticateUrl = new URL("authenticate", GEL_AUTH_BASE_URL); const authenticateResponse = await fetch(authenticateUrl.href, { method: "post", headers: { @@ -307,7 +307,7 @@ an existing user. if ("code" in authenticateJson) { // User is verified, we can get an auth token - const tokenUrl = new URL("token", EDGEDB_AUTH_BASE_URL); + const tokenUrl = new URL("token", GEL_AUTH_BASE_URL); tokenUrl.searchParams.set("code", authenticateJson.code); tokenUrl.searchParams.set("verifier", pkce.verifier); const tokenResponse = await fetch(tokenUrl.href, { @@ -323,7 +323,7 @@ an existing user. const { auth_token } = await tokenResponse.json(); res.writeHead(204, { - "Set-Cookie": `edgedb-auth-token=${auth_token}; HttpOnly; Path=/; Secure; SameSite=Strict`, + "Set-Cookie": `gel-auth-token=${auth_token}; HttpOnly; Path=/; Secure; SameSite=Strict`, }); res.end(); } else { @@ -381,7 +381,7 @@ handle the verification flow, we implement an endpoint: return; } - const verifyUrl = new URL("verify", EDGEDB_AUTH_BASE_URL); + const verifyUrl = new URL("verify", GEL_AUTH_BASE_URL); const verifyResponse = await fetch(verifyUrl.href, { method: "post", headers: { @@ -404,12 +404,12 @@ handle the verification flow, we implement an endpoint: const cookies = req.headers.cookie?.split("; "); const verifier = cookies - ?.find((cookie) => cookie.startsWith("edgedb-pkce-verifier=")) + ?.find((cookie) => cookie.startsWith("gel-pkce-verifier=")) ?.split("=")[1]; if (verifier) { // Email verification flow is continuing from the original // user agent/browser, so we can immediately get an auth token - const tokenUrl = new URL("token", EDGEDB_AUTH_BASE_URL); + const tokenUrl = new URL("token", GEL_AUTH_BASE_URL); tokenUrl.searchParams.set("code", code); tokenUrl.searchParams.set("verifier", verifier); const tokenResponse = await fetch(tokenUrl.href, { @@ -425,7 +425,7 @@ handle the verification flow, we implement an endpoint: const { auth_token } = await tokenResponse.json(); res.writeHead(204, { - "Set-Cookie": `edgedb-auth-token=${auth_token}; HttpOnly; Path=/; Secure; SameSite=Strict`, + "Set-Cookie": `gel-auth-token=${auth_token}; HttpOnly; Path=/; Secure; SameSite=Strict`, }); res.end(); return; @@ -532,7 +532,7 @@ that updates the password and logs in the user. const provider = "builtin::local_emailpassword"; const pkce = generatePKCE(); - const sendResetUrl = new URL("send-reset-email", EDGEDB_AUTH_BASE_URL); + const sendResetUrl = new URL("send-reset-email", GEL_AUTH_BASE_URL); const sendResetResponse = await fetch(sendResetUrl.href, { method: "post", headers: { @@ -556,7 +556,7 @@ that updates the password and logs in the user. const { email_sent } = await sendResetResponse.json(); res.writeHead(200, { - "Set-Cookie": `edgedb-pkce-verifier=${pkce.verifier}; HttpOnly; Path=/; Secure; SameSite=Strict`, + "Set-Cookie": `gel-pkce-verifier=${pkce.verifier}; HttpOnly; Path=/; Secure; SameSite=Strict`, }); res.end(`Reset email sent to '${email_sent}'`); }); @@ -589,7 +589,7 @@ that updates the password and logs in the user. }; /** - * Send new password with reset token to EdgeDB Auth. + * Send new password with reset token to Gel Auth. * * @param {Request} req * @param {Response} res @@ -611,7 +611,7 @@ that updates the password and logs in the user. const provider = "builtin::local_emailpassword"; const cookies = req.headers.cookie.split("; "); const verifier = cookies - .find((cookie) => cookie.startsWith("edgedb-pkce-verifier=")) + .find((cookie) => cookie.startsWith("gel-pkce-verifier=")) .split("=")[1]; if (!verifier) { res.status = 400; @@ -620,7 +620,7 @@ that updates the password and logs in the user. ); return; } - const resetUrl = new URL("reset-password", EDGEDB_AUTH_BASE_URL); + const resetUrl = new URL("reset-password", GEL_AUTH_BASE_URL); const resetResponse = await fetch(resetUrl.href, { method: "post", headers: { @@ -639,7 +639,7 @@ that updates the password and logs in the user. return; } const { code } = await resetResponse.json(); - const tokenUrl = new URL("token", EDGEDB_AUTH_BASE_URL); + const tokenUrl = new URL("token", GEL_AUTH_BASE_URL); tokenUrl.searchParams.set("code", code); tokenUrl.searchParams.set("verifier", verifier); const tokenResponse = await fetch(tokenUrl.href, { @@ -653,7 +653,7 @@ that updates the password and logs in the user. } const { auth_token } = await tokenResponse.json(); res.writeHead(204, { - "Set-Cookie": `edgedb-auth-token=${auth_token}; HttpOnly; Path=/; Secure; SameSite=Strict`, + "Set-Cookie": `gel-auth-token=${auth_token}; HttpOnly; Path=/; Secure; SameSite=Strict`, }); res.end(); }); @@ -661,4 +661,4 @@ that updates the password and logs in the user. .. lint-on -:ref:`Back to the EdgeDB Auth guide ` +:ref:`Back to the Gel Auth guide ` diff --git a/docs/guides/auth/index.rst b/docs/guides/auth/index.rst index 7b160b44ff4..cdac14eff7c 100644 --- a/docs/guides/auth/index.rst +++ b/docs/guides/auth/index.rst @@ -14,17 +14,17 @@ Auth magic_link webauthn -:edb-alt-title: Using EdgeDB Auth +:edb-alt-title: Using Gel Auth -EdgeDB Auth is a batteries-included authentication solution for your app built -into the EdgeDB server. Here's how you can integrate it with your app. +|Gel| Auth is a batteries-included authentication solution for your app built +into the Gel server. Here's how you can integrate it with your app. Enable extension in your schema =============================== -Auth is an EdgeDB extension. To enable it, you will need to add the extension -to your app’s schema: +Auth is an Gel extension. To enable it, you will need to add the extension +to your app's schema: .. code-block:: sdl @@ -35,12 +35,12 @@ Extension configuration ======================= The best and easiest way to configure the extension for your database is -to use the built-in UI. To access it, run ``edgedb ui``. If you have the +to use the built-in UI. To access it, run :gelcmd:`ui`. If you have the extension enabled in your schema as shown above and have migrated that schema change, you will see the "Auth Admin" icon in the left-hand toolbar. .. image:: images/ui-auth.png - :alt: The EdgeDB local development server UI highlighting the auth admin + :alt: The Gel local development server UI highlighting the auth admin icon in the left-hand toolbar. The icon is two nested shield outlines, the inner being a light pink color and the outer being a light blue when selected. @@ -99,7 +99,7 @@ To configure via query or script: token_time_to_live ------------------ -This value controls the expiration time on the authentication token’s +This value controls the expiration time on the authentication token's JSON Web Token. This is effectively the β€œsession” time. To configure via query or script: @@ -277,7 +277,7 @@ like `Mailpit `__. Enabling authentication providers ================================= -In order to use the auth extension, you’ll need to enable at least one of these +In order to use the auth extension, you'll need to enable at least one of these authentication providers. Providers can be added from the "Providers" section of the admin auth UI by clicking "Add Provider." This will add a form to the UI allowing for selection of the provider and configuration of the values @@ -315,8 +315,8 @@ To enable via query or script: ``require_verification`` defaults to ``true``. If you use the Email and Password provider, in addition to the -``require_verification`` configuration, you’ll need to configure SMTP to allow -EdgeDB to send email verification and password reset emails on your behalf or +``require_verification`` configuration, you'll need to configure SMTP to allow +|Gel| to send email verification and password reset emails on your behalf or set up webhooks for the relevant events: - ``ext::auth::WebhookEvent.EmailVerificationRequested`` @@ -368,8 +368,8 @@ We currently support six different OAuth providers: .. lint-on The instructions for creating an app for each provider can be found on -each provider’s developer documentation website, which is linked above. -The important things you’ll need to find and make note of for your +each provider's developer documentation website, which is linked above. +The important things you'll need to find and make note of for your configuration are the **client ID** and **secret**. Once you select the OAuth provider in the configuration UI, you will need to @@ -390,14 +390,14 @@ provide those values and the ``additional_scope``: We return this authentication token with this scope from the Identity Provider when we return our own authentication token. -You’ll also need to set a callback URL in each provider’s interface. To build +You'll also need to set a callback URL in each provider's interface. To build this callback URL, you will need the hostname, port, and branch name of your -database. The branch name is ``main`` by default. The hostname and port can +database. The branch name is |main| by default. The hostname and port can be found running this CLI command: .. code-block:: bash - $ edgedb instance credentials + $ gel instance credentials This will output a table that includes the hostnames and ports of all your instances. Grab those from the row corresponding to the correct instance for @@ -405,7 +405,7 @@ use in your callback URL, which takes on this format: .. code-block:: - http[s]://{edgedb_host}[:port]/db/{db_name}/ext/auth/callback + http[s]://{gel_host}[:port]/db/{db_name}/ext/auth/callback To enable the Azure OAuth provider via query or script: @@ -513,7 +513,7 @@ WebAuthn - ``relying_party_origin``: This is the URL of the web application handling the WebAuthn request. If you're using the built-in UI, it's the origin of - the EdgeDB web server. + the Gel web server. - ``require_verification``: (Default: ``true``) If ``true``, your application will not be able to retrieve an authentication token until the user has @@ -533,8 +533,8 @@ WebAuthn .. note:: You will need to configure CORS to allow the client-side script to call the - EdgeDB Auth extension's endpoints from the web browser. You can do this by - updating the ``cors_allow_origins`` configuration in the EdgeDB server + Gel Auth extension's endpoints from the web browser. You can do this by + updating the ``cors_allow_origins`` configuration in the Gel server configuration. Here is an example of setting a local SMTP server, in this case using a @@ -567,7 +567,7 @@ Integrating your application ============================ In the end, what we want to end up with is an authentication token -created by EdgeDB that we can set as a global in any authenticated +created by Gel that we can set as a global in any authenticated queries executed from our application, which will set a computed global linked to an ``ext::auth::Identity``. @@ -595,8 +595,8 @@ Select your method for detailed configuration: Example usage ============= -Here’s an example schema that we can use to show how you would use the -``auth_token`` you get back from EdgeDB to make queries against a +Here's an example schema that we can use to show how you would use the +``auth_token`` you get back from Gel to make queries against a protected resource, in this case being able to insert a ``Post``. .. code-block:: sdl @@ -629,7 +629,7 @@ protected resource, in this case being able to insert a ``Post``. } } -Let’s now insert a ``Post``. +Let's now insert a ``Post``. .. lint-off diff --git a/docs/guides/auth/magic_link.rst b/docs/guides/auth/magic_link.rst index c31334e98c9..f16b885d0d9 100644 --- a/docs/guides/auth/magic_link.rst +++ b/docs/guides/auth/magic_link.rst @@ -4,25 +4,25 @@ Magic Link Auth ================ -:edb-alt-title: Integrating EdgeDB Auth's Magic Link provider +:edb-alt-title: Integrating Gel Auth's Magic Link provider -Magic Link is a passwordless authentication method that allows users to log in via a unique, time-sensitive link sent to their email. This guide will walk you through integrating Magic Link authentication with your application using EdgeDB Auth. +Magic Link is a passwordless authentication method that allows users to log in via a unique, time-sensitive link sent to their email. This guide will walk you through integrating Magic Link authentication with your application using Gel Auth. Enable Magic Link provider ========================== -Before you can use Magic Link authentication, you need to enable the Magic Link provider in your EdgeDB Auth configuration. This can be done through the EdgeDB UI under the "Providers" section. +Before you can use Magic Link authentication, you need to enable the Magic Link provider in your Gel Auth configuration. This can be done through the Gel UI under the "Providers" section. Magic Link flow =============== The Magic Link authentication flow involves three main steps: -1. **Sending a Magic Link Email**: Your application requests EdgeDB Auth to send a magic link to the user's email. +1. **Sending a Magic Link Email**: Your application requests Gel Auth to send a magic link to the user's email. 2. **User Clicks Magic Link**: The user receives the email and clicks on the magic link. -3. **Authentication and Token Retrieval**: The magic link directs the user to your application, which then authenticates the user and retrieves an authentication token from EdgeDB Auth. +3. **Authentication and Token Retrieval**: The magic link directs the user to your application, which then authenticates the user and retrieves an authentication token from Gel Auth. UI considerations ================= @@ -80,11 +80,11 @@ base64url encode the resulting string. This new string is called the import crypto from "node:crypto"; /** - * You can get this value by running `edgedb instance credentials`. + * You can get this value by running `gel instance credentials`. * Value should be: * `${protocol}://${host}:${port}/branch/${branch}/ext/auth/ */ - const EDGEDB_AUTH_BASE_URL = process.env.EDGEDB_AUTH_BASE_URL; + const GEL_AUTH_BASE_URL = process.env.GEL_AUTH_BASE_URL; const SERVER_PORT = 3000; /** @@ -175,7 +175,7 @@ Sign up return; } - const registerUrl = new URL("magic-link/register", EDGEDB_AUTH_BASE_URL); + const registerUrl = new URL("magic-link/register", GEL_AUTH_BASE_URL); const registerResponse = await fetch(registerUrl.href, { method: "post", headers: { @@ -201,7 +201,7 @@ Sign up } res.writeHead(204, { - "Set-Cookie": `edgedb-pkce-verifier=${pkce.verifier}; HttpOnly; Path=/; Secure; SameSite=Strict`, + "Set-Cookie": `gel-pkce-verifier=${pkce.verifier}; HttpOnly; Path=/; Secure; SameSite=Strict`, }); res.end(); }); @@ -212,7 +212,7 @@ Sign up Sign in ------- -Signing in with a magic link simply involves telling the EdgeDB Auth server to +Signing in with a magic link simply involves telling the Gel Auth server to send a magic link to the user's email. The user will then click on the link to authenticate. @@ -242,7 +242,7 @@ authenticate. return; } - const emailUrl = new URL("magic-link/email", EDGEDB_AUTH_BASE_URL); + const emailUrl = new URL("magic-link/email", GEL_AUTH_BASE_URL); const authenticateResponse = await fetch(emailUrl.href, { method: "post", headers: { @@ -263,7 +263,7 @@ authenticate. } res.writeHead(204, { - "Set-Cookie": `edgedb-pkce-verifier=${pkce.verifier}; HttpOnly; Path=/; Secure; SameSite=Strict`, + "Set-Cookie": `gel-pkce-verifier=${pkce.verifier}; HttpOnly; Path=/; Secure; SameSite=Strict`, }); res.end(); }); @@ -304,7 +304,7 @@ this code for an authentication token. const cookies = req.headers.cookie?.split("; "); const verifier = cookies - ?.find((cookie) => cookie.startsWith("edgedb-pkce-verifier=")) + ?.find((cookie) => cookie.startsWith("gel-pkce-verifier=")) ?.split("=")[1]; if (!verifier) { res.status = 400; @@ -314,7 +314,7 @@ this code for an authentication token. return; } - const codeExchangeUrl = new URL("token", EDGEDB_AUTH_BASE_URL); + const codeExchangeUrl = new URL("token", GEL_AUTH_BASE_URL); codeExchangeUrl.searchParams.set("code", code); codeExchangeUrl.searchParams.set("verifier", verifier); const codeExchangeResponse = await fetch(codeExchangeUrl.href, { @@ -330,7 +330,7 @@ this code for an authentication token. const { auth_token } = await codeExchangeResponse.json(); res.writeHead(204, { - "Set-Cookie": `edgedb-auth-token=${auth_token}; HttpOnly; Path=/; Secure; SameSite=Strict`, + "Set-Cookie": `gel-auth-token=${auth_token}; HttpOnly; Path=/; Secure; SameSite=Strict`, }); res.end(); }; @@ -403,4 +403,4 @@ object: .. lint-on -:ref:`Back to the EdgeDB Auth guide ` +:ref:`Back to the Gel Auth guide ` diff --git a/docs/guides/auth/oauth.rst b/docs/guides/auth/oauth.rst index 0253c3ad777..a0ef22ef3fb 100644 --- a/docs/guides/auth/oauth.rst +++ b/docs/guides/auth/oauth.rst @@ -4,7 +4,7 @@ OAuth ===== -:edb-alt-title: Integrating EdgeDB Auth's OAuth provider +:edb-alt-title: Integrating Gel Auth's OAuth provider Along with using the :ref:`built-in UI `, you can also create your own UI that calls to your own web application backend. @@ -86,11 +86,11 @@ base64url encode the resulting string. This new string is called the import crypto from "node:crypto"; /** - * You can get this value by running `edgedb instance credentials`. + * You can get this value by running `gel instance credentials`. * Value should be: * `${protocol}://${host}:${port}/branch/${branch}/ext/auth/ */ - const EDGEDB_AUTH_BASE_URL = process.env.EDGEDB_AUTH_BASE_URL; + const GEL_AUTH_BASE_URL = process.env.GEL_AUTH_BASE_URL; const SERVER_PORT = 3000; /** @@ -114,7 +114,7 @@ base64url encode the resulting string. This new string is called the .. note:: - For EdgeDB versions before 5.0, the value for ``EDGEDB_AUTH_BASE_URL`` + For |EdgeDB| versions before 5.0, the value for :gelenv:`AUTH_BASE_URL` in the above snippet should have the form: ``${protocol}://${host}:${port}/db/${database}/ext/auth/`` @@ -154,7 +154,7 @@ the end user's browser to the Identity Provider with the proper setup. }); /** - * Redirects OAuth requests to EdgeDB Auth OAuth authorize redirect + * Redirects OAuth requests to Gel Auth OAuth authorize redirect * with the PKCE challenge, and saves PKCE verifier in an HttpOnly * cookie for later retrieval. * @@ -172,7 +172,7 @@ the end user's browser to the Identity Provider with the proper setup. } const pkce = generatePKCE(); - const redirectUrl = new URL("authorize", EDGEDB_AUTH_BASE_URL); + const redirectUrl = new URL("authorize", GEL_AUTH_BASE_URL); redirectUrl.searchParams.set("provider", provider); redirectUrl.searchParams.set("challenge", pkce.challenge); redirectUrl.searchParams.set( @@ -185,7 +185,7 @@ the end user's browser to the Identity Provider with the proper setup. ); res.writeHead(302, { - "Set-Cookie": `edgedb-pkce-verifier=${pkce.verifier}; HttpOnly; Path=/; Secure; SameSite=Strict`, + "Set-Cookie": `gel-pkce-verifier=${pkce.verifier}; HttpOnly; Path=/; Secure; SameSite=Strict`, Location: redirectUrl.href, }); res.end(); @@ -197,12 +197,13 @@ the end user's browser to the Identity Provider with the proper setup. Retrieve ``auth_token`` ----------------------- -At the very end of the flow, the EdgeDB server will redirect the user's browser +At the very end of the flow, the Gel server will redirect the user's browser to the ``redirect_to`` address with a single query parameter: ``code``. This route should be a server route that has access to the ``verifier``. You then -take that ``code`` and look up the ``verifier`` in the ``edgedb-pkce-verifier`` -cookie, and make a request to the EdgeDB Auth extension to exchange these two -pieces of data for an ``auth_token``. +take that ``code`` and look up the ``verifier`` in the ``gel-pkce-verifier`` +cookie (``gel-pkce-verifier`` with |EdgeDB| <= 5), and make a request to +the Gel Auth extension to exchange these two pieces of data for an +``auth_token``. .. lint-off @@ -230,7 +231,7 @@ pieces of data for an ``auth_token``. const cookies = req.headers.cookie?.split("; "); const verifier = cookies - ?.find((cookie) => cookie.startsWith("edgedb-pkce-verifier=")) + ?.find((cookie) => cookie.startsWith("gel-pkce-verifier=")) ?.split("=")[1]; if (!verifier) { res.status = 400; @@ -240,7 +241,7 @@ pieces of data for an ``auth_token``. return; } - const codeExchangeUrl = new URL("token", EDGEDB_AUTH_BASE_URL); + const codeExchangeUrl = new URL("token", GEL_AUTH_BASE_URL); codeExchangeUrl.searchParams.set("code", code); codeExchangeUrl.searchParams.set("verifier", verifier); const codeExchangeResponse = await fetch(codeExchangeUrl.href, { @@ -256,7 +257,7 @@ pieces of data for an ``auth_token``. const { auth_token } = await codeExchangeResponse.json(); res.writeHead(204, { - "Set-Cookie": `edgedb-auth-token=${auth_token}; HttpOnly; Path=/; Secure; SameSite=Strict`, + "Set-Cookie": `gel-auth-token=${auth_token}; HttpOnly; Path=/; Secure; SameSite=Strict`, }); res.end(); }; @@ -313,7 +314,7 @@ Identity which sets a search parameter on the URL to ``isSignUp=true``: + } + res.writeHead(204, { - "Set-Cookie": `edgedb-auth-token=${auth_token}; HttpOnly; Path=/; Secure; SameSite=Strict`, + "Set-Cookie": `gel-auth-token=${auth_token}; HttpOnly; Path=/; Secure; SameSite=Strict`, }); @@ -414,7 +415,7 @@ it: } res.writeHead(204, { - "Set-Cookie": `edgedb-auth-token=${auth_token}; HttpOnly; Path=/; Secure; SameSite=Strict`, + "Set-Cookie": `gel-auth-token=${auth_token}; HttpOnly; Path=/; Secure; SameSite=Strict`, }); -:ref:`Back to the EdgeDB Auth guide ` +:ref:`Back to the Gel Auth guide ` diff --git a/docs/guides/auth/webauthn.rst b/docs/guides/auth/webauthn.rst index 5dfca7dc86c..30adcc165d5 100644 --- a/docs/guides/auth/webauthn.rst +++ b/docs/guides/auth/webauthn.rst @@ -4,13 +4,13 @@ WebAuthn ======== -:edb-alt-title: Integrating EdgeDB Auth's WebAuthn provider +:edb-alt-title: Integrating Gel Auth's WebAuthn provider WebAuthn, short for Web Authentication, is a web standard published by the World Wide Web Consortium (W3C) for secure and passwordless authentication on the web. It allows users to log in using biometrics, mobile devices, or FIDO2 security keys instead of traditional passwords. This guide will walk you -through integrating WebAuthn authentication with your application using EdgeDB +through integrating WebAuthn authentication with your application using Gel Auth. Why choose WebAuthn? @@ -33,14 +33,14 @@ and aim to simplify the user experience further by leveraging cloud synchronization of credentials. Many operating systems and password managers have added support for Passkeys, -making it easier for users to manage their credentials across devices. EdgeDB +making it easier for users to manage their credentials across devices. Gel Auth's WebAuthn provider supports Passkeys, allowing users to log in to your application using their Passkeys. Security considerations ======================= -For maximum flexibility, EdgeDB Auth's WebAuthn provider allows multiple +For maximum flexibility, Gel Auth's WebAuthn provider allows multiple WebAuthn credentials per email. This means that it's very important to verify the email before trusting a WebAuthn credential. This can be done by setting the ``require_verification`` option to ``true`` (which is the default) in your @@ -109,11 +109,11 @@ base64url encode the resulting string. This new string is called the import crypto from "node:crypto"; /** - * You can get this value by running `edgedb instance credentials`. + * You can get this value by running `gel instance credentials`. * Value should be: * `${protocol}://${host}:${port}/branch/${branch}/ext/auth/ */ - const EDGEDB_AUTH_BASE_URL = process.env.EDGEDB_AUTH_BASE_URL; + const GEL_AUTH_BASE_URL = process.env.GEL_AUTH_BASE_URL; const SERVER_PORT = 3000; /** @@ -191,7 +191,7 @@ Handle register and authenticate options The first step in the WebAuthn flow is to get the options for registering a new credential or authenticating an existing credential. The server generates a JSON object that is used to configure the WebAuthn registration or -authentication ceremony. The EdgeDB Auth extension provides these endpoints +authentication ceremony. The Gel Auth extension provides these endpoints directly, so you can either proxy the request to the Auth extension or redirect the user to the Auth extension's URL. We'll show the proxy option here. @@ -214,7 +214,10 @@ the user to the Auth extension's URL. We'll show the proxy option here. return; } - const registerUrl = new URL("webauthn/register/options", EDGEDB_AUTH_BASE_URL); + const registerUrl = new URL( + "webauthn/register/options", + GEL_AUTH_BASE_URL + ); registerUrl.searchParams.set("email", email); const registerResponse = await fetch(registerUrl.href); @@ -248,7 +251,10 @@ the user to the Auth extension's URL. We'll show the proxy option here. return; } - const authenticateUrl = new URL("webauthn/authenticate/options", EDGEDB_AUTH_BASE_URL); + const authenticateUrl = new URL( + "webauthn/authenticate/options", + GEL_AUTH_BASE_URL + ); authenticateUrl.searchParams.set("email", email); const authenticateResponse = await fetch(authenticateUrl.href); @@ -274,7 +280,7 @@ Register a new credential The client script will call the Web Authentication API to create a new credential payload and send it to this endpoint. This endpoints job will be to -forward the serialized credential payload to the EdgeDB Auth extension for +forward the serialized credential payload to the Gel Auth extension for verification, and then associate the credential with the user's email address. .. lint-off @@ -297,7 +303,7 @@ verification, and then associate the credential with the user's email address. return; } - const registerUrl = new URL("webauthn/register", EDGEDB_AUTH_BASE_URL); + const registerUrl = new URL("webauthn/register", GEL_AUTH_BASE_URL); const registerResponse = await fetch(registerUrl.href, { method: "post", @@ -323,7 +329,7 @@ verification, and then associate the credential with the user's email address. const registerData = await registerResponse.json(); if ("code" in registerData) { - const tokenUrl = new URL("token", EDGEDB_AUTH_BASE_URL); + const tokenUrl = new URL("token", GEL_AUTH_BASE_URL); tokenUrl.searchParams.set("code", registerData.code); tokenUrl.searchParams.set("verifier", verifier); const tokenResponse = await fetch(tokenUrl.href, { @@ -339,12 +345,12 @@ verification, and then associate the credential with the user's email address. const { auth_token } = await tokenResponse.json(); res.writeHead(204, { - "Set-Cookie": `edgedb-auth-token=${auth_token}; HttpOnly; Path=/; Secure; SameSite=Strict`, + "Set-Cookie": `gel-auth-token=${auth_token}; HttpOnly; Path=/; Secure; SameSite=Strict`, }); res.end(); } else { res.writeHead(204, { - "Set-Cookie": `edgedb-pkce-verifier=${pkce.verifier}; HttpOnly; Path=/; Secure; SameSite=Strict`, + "Set-Cookie": `gel-pkce-verifier=${pkce.verifier}; HttpOnly; Path=/; Secure; SameSite=Strict`, }); res.end(); } @@ -358,7 +364,7 @@ Authenticate with an existing credential The client script will call the Web Authentication API to authenticate with an existing credential and send the assertion to this endpoint. This endpoint's -job will be to forward the serialized assertion to the EdgeDB Auth extension +job will be to forward the serialized assertion to the Gel Auth extension for verification. .. lint-off @@ -381,7 +387,7 @@ for verification. return; } - const authenticateUrl = new URL("webauthn/authenticate", EDGEDB_AUTH_BASE_URL); + const authenticateUrl = new URL("webauthn/authenticate", GEL_AUTH_BASE_URL); const authenticateResponse = await fetch(authenticateUrl.href, { method: "post", @@ -405,7 +411,7 @@ for verification. const authenticateData = await authenticateResponse.json(); if ("code" in authenticateData) { - const tokenUrl = new URL("token", EDGEDB_AUTH_BASE_URL); + const tokenUrl = new URL("token", GEL_AUTH_BASE_URL); tokenUrl.searchParams.set("code", authenticateData.code); const tokenResponse = await fetch(tokenUrl.href, { method: "get", @@ -420,7 +426,7 @@ for verification. const { auth_token } = await tokenResponse.json(); res.writeHead(204, { - "Set-Cookie": `edgedb-auth-token=${auth_token}; HttpOnly; Path=/; Secure; SameSite=Strict`, + "Set-Cookie": `gel-auth-token=${auth_token}; HttpOnly; Path=/; Secure; SameSite=Strict`, }); res.end(); } else { @@ -470,7 +476,7 @@ handle the verification flow, we implement an endpoint: const cookies = req.headers.cookie?.split("; "); const verifier = cookies - ?.find((cookie) => cookie.startsWith("edgedb-pkce-verifier=")) + ?.find((cookie) => cookie.startsWith("gel-pkce-verifier=")) ?.split("=")[1]; if (!verifier) { res.status = 400; @@ -480,7 +486,7 @@ handle the verification flow, we implement an endpoint: return; } - const verifyUrl = new URL("verify", EDGEDB_AUTH_BASE_URL); + const verifyUrl = new URL("verify", GEL_AUTH_BASE_URL); const verifyResponse = await fetch(verifyUrl.href, { method: "post", headers: { @@ -502,7 +508,7 @@ handle the verification flow, we implement an endpoint: const { code } = await verifyResponse.json(); - const tokenUrl = new URL("token", EDGEDB_AUTH_BASE_URL); + const tokenUrl = new URL("token", GEL_AUTH_BASE_URL); tokenUrl.searchParams.set("code", code); tokenUrl.searchParams.set("verifier", verifier); const tokenResponse = await fetch(tokenUrl.href, { @@ -518,7 +524,7 @@ handle the verification flow, we implement an endpoint: const { auth_token } = await tokenResponse.json(); res.writeHead(204, { - "Set-Cookie": `edgedb-auth-token=${auth_token}; HttpOnly; Path=/; Secure; SameSite=Strict`, + "Set-Cookie": `gel-auth-token=${auth_token}; HttpOnly; Path=/; Secure; SameSite=Strict`, }); res.end(); }; @@ -529,12 +535,12 @@ Client-side script ------------------ On the client-side, you will need to write a script that retrieves the options -from the EdgeDB Auth extension, calls the Web Authentication API, and sends the +from the Gel Auth extension, calls the Web Authentication API, and sends the resulting credential or assertion to the server. Writing out the low-level handling of serialization and deserialization of the WebAuthn data is beyond the scope of this guide, but we publish a WebAuthn client library that you can use to simlify this process. The library is available on npm as part of our -``@edgedb/auth-core`` library. Here is an example of how you might set up a form +``@gel/auth-core`` library. Here is an example of how you might set up a form with appropriate click handlers to perform the WebAuthn sign in and sign up ceremonies. @@ -542,7 +548,7 @@ ceremonies. .. code-block:: javascript - import { WebAuthnClient } from "@edgedb/auth-core/webauthn"; + import { WebAuthnClient } from "@gel/auth-core/webauthn"; const webAuthnClient = new WebAuthnClient({ signupOptionsUrl: "http://localhost:3000/auth/webauthn/register/options", diff --git a/docs/guides/cloud/cli.rst b/docs/guides/cloud/cli.rst deleted file mode 100644 index 7bac7f359b2..00000000000 --- a/docs/guides/cloud/cli.rst +++ /dev/null @@ -1,72 +0,0 @@ -.. _ref_guide_cloud_cli: - -=== -CLI -=== - -:edb-alt-title: Using EdgeDB Cloud via the CLI - -To use EdgeDB Cloud via the CLI, first log in using -:ref:`ref_cli_edgedb_cloud_login`. - -.. note:: - - This is the way you'll log in interactively on your development machine, - but when interacting with EdgeDB Cloud via a script or in CI, you'll - instead set the ``EDGEDB_SECRET_KEY`` environment variable to your secret - key. Generate a secret key in the EdgeDB Cloud UI or by running - :ref:`ref_cli_edgedb_cloud_secretkey_create`. The ``edgedb cloud login`` - and ``edgedb cloud logout`` commands are not intended for use in this - context. - -Once your login is successful, you will be able to create an instance using -either :ref:`ref_cli_edgedb_instance_create` or -:ref:`ref_cli_edgedb_project_init`, depending on whether you also want to -create a local project linked to your instance. - -* :ref:`ref_cli_edgedb_instance_create` with an instance name of - ``/``. - - .. code-block:: bash - - $ edgedb instance create / - -* :ref:`ref_cli_edgedb_project_init` with the ``--server-instance`` option. Set - the server instance name to ``/``. - - .. code-block:: bash - - $ edgedb project init \ - --server-instance / - - Alternatively, you can run ``edgedb project init`` *without* the - ``--server-instance`` option and enter an instance name in the - ``/`` format when prompted interactively. - -.. note:: - - Please be aware of the following restrictions on EdgeDB Cloud instance - names: - - * can contain only Latin alpha-numeric characters or ``-`` - * cannot start with a dash (``-``) or contain double dashes (``--``) - * maximum instance name length is 61 characters minus the length of your - organization name (i.e., length of organization name + length of instance - name must be fewer than 62 characters) - -To use ``edgedb instance create``: - -.. code-block:: bash - - $ edgedb instance create / - -To use ``edgedb project init``: - -.. code-block:: bash - - $ edgedb project init \ - --server-instance / - -Alternatively, you can run ``edgedb project init`` *without* the -``--server-instance`` option and enter an instance name in the -``/`` format when prompted interactively. diff --git a/docs/guides/contributing/code.rst b/docs/guides/contributing/code.rst index b252b607e09..ef921a425d8 100644 --- a/docs/guides/contributing/code.rst +++ b/docs/guides/contributing/code.rst @@ -4,9 +4,9 @@ Code ==== -:edb-alt-title: Developing EdgeDB +:edb-alt-title: Developing Gel -This section describes how to build EdgeDB locally, how to use its +This section describes how to build Gel locally, how to use its internal tools, and how to contribute to it. .. warning:: @@ -74,7 +74,7 @@ be built with the following ``shell.nix`` file. with import {}; pkgs.mkShell { - name = "edgedb dev shell"; + name = "gel dev shell"; venvDir = "./venv"; buildInputs = with pkgs; [ @@ -116,8 +116,8 @@ be built with the following ``shell.nix`` file. The easiest way to set up a development environment is to create a Python "venv" with all dependencies and commands installed into it. -#. Make a new directory that will contain checkouts of `edgedb `_ - and `edgedb-python `_. The name of the directory is +#. Make a new directory that will contain checkouts of `gel `_ + and `gel-python `_. The name of the directory is arbitrary, we will use "dev" in this guide: .. code-block:: bash @@ -125,29 +125,29 @@ Python "venv" with all dependencies and commands installed into it. $ mkdir ~/dev $ cd ~/dev -#. Clone the edgedb repository using ``--recursive`` +#. Clone the gel repository using ``--recursive`` to clone all submodules: .. code-block:: bash - $ git clone --recursive https://github.com/edgedb/edgedb.git + $ git clone --recursive https://github.com/geldata/gel.git #. Create a Python 3.12 virtual environment and activate it: .. code-block:: bash - $ python3.12 -m venv edgedb-dev - $ source edgedb-dev/bin/activate + $ python3.12 -m venv gel-dev + $ source gel-dev/bin/activate -#. Build edgedb (the build will take a while): +#. Build gel (the build will take a while): .. code-block:: bash - $ cd edgedb + $ cd gel $ pip install -v -e ".[test]" - In addition to compiling EdgeDB and all dependencies, this will also - install the ``edb`` and ``edgedb`` command line tools into the current + In addition to compiling Gel and all dependencies, this will also + install the ``edb`` and |gelcmd| command line tools into the current Python virtual environment. It will also install libraries used during development. @@ -165,7 +165,7 @@ activated at any time. Running Tests ============= -To run all EdgeDB tests simply use the ``$ edb test`` command without +To run all Gel tests simply use the ``$ edb test`` command without arguments. The command also supports running a few selected tests. To run all @@ -196,7 +196,7 @@ Dev Server Use the ``$ edb server`` command to start the development server. You can then use another terminal to open a REPL to the server using the -``$ edgedb`` command, or connect to it using one of the language bindings. +|gelcmd| command, or connect to it using one of the language bindings. Test Branches @@ -206,5 +206,5 @@ Use the ``$ edb inittestdb`` command to create and populate branches that are used by unit tests. .. _rst: https://www.sphinx-doc.org/en/master/usage/restructuredtext/index.html -.. _edgedbpy: https://github.com/edgedb/edgedb-python -.. _edgedb: https://github.com/edgedb/edgedb +.. _gelpy: https://github.com/geldata/gel-python +.. _gel: https://github.com/geldata/gel diff --git a/docs/guides/contributing/documentation.rst b/docs/guides/contributing/documentation.rst index e10dc3f1294..9706686f3ee 100644 --- a/docs/guides/contributing/documentation.rst +++ b/docs/guides/contributing/documentation.rst @@ -4,11 +4,11 @@ Documentation ============= -:edb-alt-title: Writing EdgeDB Documentation +:edb-alt-title: Writing Gel Documentation We pride ourselves on having some of the best documentation around, but we want you to help us make it even better. Documentation is a great way to get started -contributing to EdgeDB. Improvements to our documentation create a better +contributing to Gel. Improvements to our documentation create a better experience for every developer coming through the door behind you. Follow our general and style guidelines to make for a smooth contributing @@ -54,8 +54,8 @@ Style that in favor of ``*param*``, in order to distinguish between parameter references and inline code (which *should* be surrounded by double backticks). -- **EdgeDB is singular.** Choose "EdgeDB is" over "EdgeDB are" and "EdgeDB - does" over "EdgeDB do." +- **Gel is singular.** Choose "Gel is" over "Gel are" and "Gel + does" over "Gel do." - **Use American English spellings.** Choose "color" over "colour" and "organize" over "organise." - **Use the Oxford comma.** When delineating a series, place a comma between @@ -66,45 +66,38 @@ Style like a computer science textbook. Sometimes that's necessary, but in most cases, it isn't. Prioritize accuracy first and accessibility a close second. - **Be careful using words that have a special meaning in the context of - EdgeDB.** In casual speech or writing, you might talk about a "set" of - something in a generic sense. Using the word this way in EdgeDB documentation - might easily be interpreted as a reference to EdgeDB's :ref:`sets + Gel.** In casual speech or writing, you might talk about a "set" of + something in a generic sense. Using the word this way in Gel documentation + might easily be interpreted as a reference to Gel's :ref:`sets `. Avoid this kind of casual usage of key terms. Where to Find It ================ -Most of our documentation (including this guide) lives in `the edgedb -repository `_ in `the docs directory -`_. +Most of our documentation (including this guide) lives in `the geldata +repository `_ in `the docs directory +`_. Documentation for some of our client libraries lives inside the client's repo. -If you don't find it in the edgedb repo at ``docs/clients``, you'll probably +If you don't find it in the geldata repo at ``docs/clients``, you'll probably find it alongside the client itself. These clients will also have documentation -stubs inside the edgedb repository directing you to the documentation's +stubs inside the geldata repository directing you to the documentation's location. -The `EdgeDB tutorial `_ is part of `our web -site repository `_. You'll find it in `the -tutorial directory `_. - -Finally, our book for beginners titled `Easy EdgeDB `_ lives in -`its own repo `_. - How to Build It =============== -edgedb/edgedb -------------- +geldata/gel +----------- -The ``edgedb`` repository contains all of its documentation in the ``docs/`` -directory. Run ``make docs`` to build the documentation in the edgedb repo. The +The ``geldata`` repository contains all of its documentation in the ``docs/`` +directory. Run ``make docs`` to build the documentation in the geldata repo. The repository contains a ``Makefile`` for all of Sphinx's necessary build options. The documentation will be built to ``docs/build``. -To run tests, first :ref:`build EdgeDB locally +To run tests, first :ref:`build Gel locally `. Then run ``edb test -k doc``. Building the docs from this repo will not give you a high-fidelity @@ -119,9 +112,9 @@ your documentation exactly as the user will see it. This is not required, but it can be useful to help us review and approve your request more quickly by avoiding mistakes that would be easier to spot when they are fully rendered. -To build, clone `our website repository `_ +To build, clone `our website repository `_ and `follow the installation instructions -`_. Then run ``yarn dev`` to +`_. Then run ``yarn dev`` to start a development server which also triggers a build of all the documentation. @@ -494,13 +487,13 @@ Below are the most common languages used in our docs: .. code-block:: bash - $ edgedb configure set listen_addresses 127.0.0.1 ::1 + $ gel configure set listen_addresses 127.0.0.1 ::1 **Rendered** .. code-block:: bash - $ edgedb configure set listen_addresses 127.0.0.1 ::1 + $ gel configure set listen_addresses 127.0.0.1 ::1 * ``edgeql``- Used for queries. @@ -895,13 +888,13 @@ Document a CLI command using the ``cli:synopsis`` directive like this: .. cli:synopsis:: - edgedb dump [] + gel dump [] **Rendered** .. cli:synopsis:: - edgedb dump [] + gel dump [] The synopsis should follow the format used in the PostgreSQL documentation. See `the PostgreSQL SELECT statement reference page @@ -925,7 +918,7 @@ You can then document arguments and options using the ``:cli:synopsis:`` role. Documentation Versioning ======================== -Since EdgeDB functionality is mostly consistent across versions, we offer a +Since |Gel| functionality is mostly consistent across versions, we offer a simple method of versioning documentation using two directives. .. warning:: @@ -957,15 +950,15 @@ The directive behaves differently depending on the context. .. code-block:: - .. versionadded:: 2.0 + .. versionadded:: 7.0 - This is a new feature that was added in EdgeDB 2.0. + This is a new feature that was added in Gel 7.0. **Rendered** -.. versionadded:: 2.0 +.. versionadded:: 7.0 - This is a new feature that was added in EdgeDB 2.0. + This is a new feature that was added in Gel 7.0. .. note:: @@ -979,7 +972,7 @@ The directive behaves differently depending on the context. Source deletion ^^^^^^^^^^^^^^^ - .. versionadded:: 2.0 + .. versionadded:: 7.0 Source deletion policies determine what action should be taken when the *source* of a given link is deleted. They are declared with the ``on source @@ -998,8 +991,6 @@ versionadded:: 2.0``. .. eql:type:: cal::date_duration - .. versionadded:: 2.0 - A type for representing a span of time in days. **Rendered** @@ -1029,7 +1020,7 @@ Changed in Version ------------------ Use the ``versionchanged`` directive to mark content related to a change in -existing functionality across EdgeDB versions. Provide the applicable version +existing functionality across |Gel| versions. Provide the applicable version as an argument by placing it just after the directive on the same line. Unlike ``versionadded``, ``versionchanged`` is always used with content to show @@ -1041,9 +1032,9 @@ or hide that content based on the user's selection in the version dropdown. .. code-block:: - .. versionchanged:: 3.0 + .. versionchanged:: 8.0 - Starting with the upcoming EdgeDB 3.0, access policy restrictions will + Starting with the upcoming Gel 8.0, access policy restrictions will **not** apply to any access policy expression. This means that when reasoning about access policies it is no longer necessary to take other policies into account. Instead, all data is visible for the purpose of @@ -1053,9 +1044,9 @@ or hide that content based on the user's selection in the version dropdown. **Rendered** -.. versionchanged:: 3.0 +.. versionchanged:: 8.0 - Starting with the upcoming EdgeDB 3.0, access policy restrictions will + Starting with the upcoming Gel 8.0, access policy restrictions will **not** apply to any access policy expression. This means that when reasoning about access policies it is no longer necessary to take other policies into account. Instead, all data is visible for the purpose of @@ -1111,7 +1102,7 @@ before the offending block and back on with ``.. lint-on`` after the block. Embedding a YouTube Video ------------------------- -Embed only videos from `the EdgeDB YouTube channel +Embed only videos from `the Gel YouTube channel `_ .. code-block:: @@ -1139,8 +1130,8 @@ placing it after the directive on the same line. .. lint-off See `the list of illustration names -`_ +`_ and `view the images they map to -`_. +`_. .. lint-on diff --git a/docs/guides/contributing/index.rst b/docs/guides/contributing/index.rst index 0d1f9bcc34b..a9b550089de 100644 --- a/docs/guides/contributing/index.rst +++ b/docs/guides/contributing/index.rst @@ -4,9 +4,9 @@ Contributing ============ -:edb-alt-title: Contributing to EdgeDB +:edb-alt-title: Contributing to Gel -EdgeDB is an open-source project, and we welcome contributions from our +|Gel| is an open-source project, and we welcome contributions from our community. You can contribute by writing code or by helping us improve our documentation. @@ -43,7 +43,7 @@ General Guidelines Thank You! ========== -Thank you for contributing to EdgeDB! We love our open source community and +Thank you for contributing to Gel! We love our open source community and want to foster a healthy contributor ecosystem. We're happy to have you as a part of it. diff --git a/docs/guides/datamigrations/index.rst b/docs/guides/datamigrations/index.rst index 5771b26b1fc..c82cfc702e2 100644 --- a/docs/guides/datamigrations/index.rst +++ b/docs/guides/datamigrations/index.rst @@ -1,10 +1,10 @@ .. _ref_guide_data_migrations: -=================== -Switching to EdgeDB -=================== +================ +Switching to Gel +================ -Perhaps you like EdgeDB so much you want to migrate an existing project to it. +Perhaps you like Gel so much you want to migrate an existing project to it. Here we'll show you some possible ways to import your data. .. toctree:: diff --git a/docs/guides/datamigrations/postgres.rst b/docs/guides/datamigrations/postgres.rst index 3d36feb026c..ea6cb3fc9f5 100644 --- a/docs/guides/datamigrations/postgres.rst +++ b/docs/guides/datamigrations/postgres.rst @@ -4,7 +4,7 @@ Postgres ======== -In this guide, we show how to move your data from Postgres to EdgeDB. However, +In this guide, we show how to move your data from Postgres to Gel. However, most of the approaches covered here should be applicable to other SQL databases as well. @@ -12,8 +12,8 @@ As an example we'll use an app that allowed users to chat. The main features of this app revolve around posting and responding to messages. Once the data is moved, it is then possible to use :ref:`EdgeQL ` instead of SQL to fetch the desired data in the app's API calls. Here we'll mainly focus on -the data structures used for that, how to reflect them into EdgeDB, and how to -script moving the data across to the EdgeDB database. +the data structures used for that, how to reflect them into Gel, and how to +script moving the data across to the Gel database. Schema modeling @@ -77,7 +77,7 @@ are such tables, so let's look at them: .. lint-on The ``badges`` table uses the ``name`` of the badge as a primary key as -opposed to a separate ``id``. In order to reflect that properly in EdgeDB, we +opposed to a separate ``id``. In order to reflect that properly in Gel, we would have to add an :eql:constraint:`exclusive` constraint to this property. Meanwhile ``not null`` makes the property ``required``, leaving us with a type like this: @@ -92,7 +92,7 @@ like this: } The ``statuses`` table has a dedicated ``id`` column in addition to ``title``. -However, the automatic ``id`` in EdgeDB is a :eql:type:`uuid`, whereas in our +However, the automatic ``id`` in Gel is a :eql:type:`uuid`, whereas in our original dataset it is an ``integer``. Let's assume that for this table we never actually use the ``id`` in our code, relying instead on the fact that ``title`` is ``UNIQUE`` and serves as a much more descriptive identifier. We @@ -140,8 +140,8 @@ Next, we can look at the ``users`` table: The ``users`` table, like ``statuses``, has an ``id`` column, which is not a :eql:type:`uuid`. Instead of omitting the ``id`` data, we'll record it as -``app_id`` in EdgeDB to facilitate the transition. We may still want to -eventually drop it in favor of the built-in ``id`` from EdgeDB, but we need it +``app_id`` in Gel to facilitate the transition. We may still want to +eventually drop it in favor of the built-in ``id`` from Gel, but we need it for now. Incidentally, even if the ``id`` was specified as a ``uuid`` value the recommended process is to record it as ``app_id`` as opposed to try and replicate it as the main object ``id``. It is, however, also possible to bring @@ -149,7 +149,7 @@ it over as the main ``id`` by adjusting certain :ref:`client connection settings `. The column ``client_settings`` would become a :eql:type:`json` property. The columns ``badge_name`` and ``status_id`` reference ``badges`` and ``statuses`` respectively and will -become *links* in EdgeDB instead of *properties*, even though a property would +become *links* in Gel instead of *properties*, even though a property would more closely mirror how they are stored in Postgres: .. code-block:: sql @@ -239,7 +239,7 @@ Then we look at the ``posts`` table: The ``posts`` table also has an ``id`` that we want to keep around, at least during the transition. We have a couple of columns using a ``timestamp with time zone`` value, so they'll become :eql:type:`datetime` properties in -EdgeDB. The ``user_id``, ``thread_id``, and ``reply_to_id`` columns will +|Gel|. The ``user_id``, ``thread_id``, and ``reply_to_id`` columns will become *links* to ``User``, ``Thread``, and ``Post`` respectively: .. code-block:: sql @@ -360,12 +360,12 @@ type. In the end we end up with a schema that looks something like this: Copying the data ---------------- -Now that we have a schema, we can use :ref:`ref_cli_edgedb_project_init` to -set up our new EdgeDB database. A new schema migration is added via -:ref:`ref_cli_edgedb_migration_create` and then :ref:`edgedb migrate -` applies the schema changes to the database. +Now that we have a schema, we can use :ref:`ref_cli_gel_project_init` to +set up our new Gel database. A new schema migration is added via +:ref:`ref_cli_gel_migration_create` and then :ref:`gel migrate +` applies the schema changes to the database. After the schema migration, we'll still need to copy the existing data from -Postgres. JSON is a pretty good intermediate format for this operation. EdgeDB +Postgres. JSON is a pretty good intermediate format for this operation. Gel can cast data from :eql:type:`json` to all of the built-in scalar types, so we should be able to use a JSON dump with minimal additional processing when importing all the data. @@ -396,7 +396,7 @@ We will dump ``badges`` and ``statuses`` first: These tables can be dumped directly to a file using a ``COPY ... TO `` command. We can then read the files and use a simple loop to -import the data into EdgeDB. +import the data into Gel. .. note:: @@ -430,7 +430,7 @@ import the data into EdgeDB. The ``threads`` table can likewise be dumped directly as JSON with the only minor difference being that we want to change the ``id`` to ``app_id`` when we -move the data to EdgeDB: +move the data to Gel: .. code-block:: python @@ -486,7 +486,7 @@ The ``posts`` table can be dumped as JSON directly, but we'll need to write sub-queries in the import script to correctly link ``Post`` objects. In order to make this simpler, we can order the original data by ``creation_time`` so we know any ``Post`` object that is referenced by the ``reply_to_id`` has -already been re-created in EdgeDB. +already been re-created in Gel. .. code-block:: python @@ -514,7 +514,7 @@ already been re-created in EdgeDB. Finally, we can deal with the bookmarks since we've imported both the users and the posts. The ``bookmarks`` table can be dumped as JSON directly, and -then we can write appropriate ``update`` query to add this data to EdgeDB: +then we can write appropriate ``update`` query to add this data to Gel: .. code-block:: python @@ -559,7 +559,7 @@ this: { default::User { name: 'Cameron', - email: 'cameron@edgedb.com', + email: 'cameron@example.com', status: {}, badge: default::Badge {name: 'admin'}, bookmark: { @@ -569,7 +569,7 @@ this: @note: 'rendering glitch', }, default::Post { - body: 'Funny you ask, Alice. I actually work at EdgeDB!', + body: 'Funny you ask, Alice. I actually work at Gel!', user: default::User {name: 'Dana'}, @note: 'follow-up', }, @@ -582,4 +582,4 @@ this: }, } -.. lint-on \ No newline at end of file +.. lint-on diff --git a/docs/guides/deployment/aws_aurora_ecs.rst b/docs/guides/deployment/aws_aurora_ecs.rst index a6d8561835c..7877548bc38 100644 --- a/docs/guides/deployment/aws_aurora_ecs.rst +++ b/docs/guides/deployment/aws_aurora_ecs.rst @@ -4,9 +4,9 @@ AWS === -:edb-alt-title: Deploying EdgeDB to AWS +:edb-alt-title: Deploying Gel to AWS -In this guide we show how to deploy EdgeDB on AWS using Amazon Aurora and +In this guide we show how to deploy Gel on AWS using Amazon Aurora and Elastic Container Service. Prerequisites @@ -24,7 +24,7 @@ Quick Install with CloudFormation ================================= We maintain a `CloudFormation template `_ for easy automated -deployment of EdgeDB in your AWS account. The template deploys EdgeDB +deployment of Gel in your AWS account. The template deploys Gel to a new ECS service and connects it to a newly provisioned Aurora PostgreSQL cluster. The created instance has a public IP address with TLS configured and is protected by a password you provide. @@ -36,16 +36,16 @@ Click `here `_ to start the deployment process using CloudFormation portal and follow the prompts. You'll be prompted to provide a value for the following parameters: -- ``DockerImage``: defaults to the latest version (``edgedb/edgedb``), or you +- ``DockerImage``: defaults to the latest version (``geldata/gel``), or you can specify a particular tag from the ones published to `Docker Hub - `_. + `_. - ``InstanceName``: ⚠️ Due to limitations with AWS, this must be 22 characters or less! -- ``SuperUserPassword``: this will be used as the password for the new EdgeDB +- ``SuperUserPassword``: this will be used as the password for the new Gel instance. Keep track of the value you provide. Once the deployment is complete, follow these steps to find the host name that -has been assigned to your EdgeDB instance: +has been assigned to your Gel instance: .. lint-off @@ -54,28 +54,28 @@ has been assigned to your EdgeDB instance: 2. Wait for the status to read ``CREATE_COMPLETE``β€”it can take 15 minutes or more. 3. Once deployment is complete, click the ``Outputs`` tab. The value of - ``PublicHostname`` is the hostname at which your EdgeDB instance is + ``PublicHostname`` is the hostname at which your Gel instance is publicly available. 4. Copy the hostname and run the following command to open a REPL to your instance. .. code-block:: bash - $ edgedb --dsn edgedb://edgedb:@ --tls-security insecure - EdgeDB 3.x + $ gel --dsn gel://admin:@ --tls-security insecure + Gel x.x Type \help for help, \quit to quit. - edgedb> + gel> .. lint-on It's often convenient to create an alias for the remote instance using -``edgedb instance link``. +:gelcmd:`instance link`. .. code-block:: bash - $ edgedb instance link \ + $ gel instance link \ --trust-tls-cert \ - --dsn edgedb://edgedb:@ + --dsn gel://admin:@ my_aws_instance This aliases the remote instance to ``my_aws_instance`` (this name can be @@ -84,23 +84,23 @@ against this instance, as with local instances. .. note:: - The command groups ``edgedb instance`` and ``edgedb project`` are not + The command groups :gelcmd:`instance` and :gelcmd:`project` are not intended to manage production instances. .. code-block:: bash - $ edgedb -I my_aws_instance - EdgeDB 3.x + $ gel -I my_aws_instance + Gel x.x Type \help for help, \quit to quit. - edgedb> + gel> -To make changes to your EdgeDB deployment like upgrading the EdgeDB version or +To make changes to your Gel deployment like upgrading the Gel version or enabling the UI you can follow the CloudFormation `Updating a stack `_ instructions. Search for -``ContainerDefinitions`` in the template and you will find where EdgeDB's +``ContainerDefinitions`` in the template and you will find where Gel's :ref:`environment variables ` are -defined. To upgrade the EdgeDB version specify a -`docker image tag `_ with the image name ``edgedb/edgedb`` in the +defined. To upgrade the Gel version specify a +`docker image tag `_ with the image name ``geldata/gel`` in the second step of the update workflow. CloudFormation CLI @@ -112,25 +112,25 @@ your terminal: .. code-block:: bash $ aws cloudformation create-stack \ - --stack-name EdgeDB \ + --stack-name Gel \ --template-url \ - https://edgedb-deploy.s3.us-east-2.amazonaws.com/edgedb-aurora.yml \ + https://gel-deploy.s3.us-east-2.amazonaws.com/gel-aurora.yml \ --capabilities CAPABILITY_NAMED_IAM \ --parameters ParameterKey=SuperUserPassword,ParameterValue= -.. _cf-template: https://github.com/edgedb/edgedb-deploy/tree/dev/aws-cf +.. _cf-template: https://github.com/geldata/gel-deploy/tree/dev/aws-cf .. _cf-deploy: https://console.aws.amazon.com - /cloudformation/home#/stacks/new?stackName=EdgeDB&templateURL= - https%3A%2F%2Fedgedb-deploy.s3.us-east-2.amazonaws.com%2Fedgedb-aurora.yml + /cloudformation/home#/stacks/new?stackName=Gel&templateURL= + https%3A%2F%gel-deploy.s3.us-east-2.amazonaws.com%gel-aurora.yml .. _aws_console: https://console.aws.amazon.com /ec2/v2/home#NIC:search=ec2-security-group .. _stack-update: https://docs.aws.amazon.com /AWSCloudFormation/latest/UserGuide/cfn-whatis-howdoesitwork.html -.. _docker-tags: https://hub.docker.com/r/edgedb/edgedb/tags +.. _docker-tags: https://hub.docker.com/r/geldata/gel/tags Manual Install with CLI @@ -551,7 +551,7 @@ Create an RDS Security Group $ aws rds create-db-subnet-group \ --region $REGION \ --db-subnet-group-name "$RDS_SUBNET_GROUP_NAME" \ - --db-subnet-group-description "EdgeDB RDS subnet group for ${NAME}" \ + --db-subnet-group-description "Gel RDS subnet group for ${NAME}" \ --subnet-ids $SUBNET_A_PRIVATE_ID $SUBNET_B_PRIVATE_ID Create an RDS Cluster @@ -627,7 +627,7 @@ Then use this password to create an AWS `secret Create a Load Balancer ---------------------- -Adding a load balancer will facilitate scaling the EdgeDB cluster. +Adding a load balancer will facilitate scaling the Gel cluster. .. code-block:: bash @@ -673,7 +673,7 @@ Adding a load balancer will facilitate scaling the EdgeDB cluster. Create an ECS Cluster --------------------- -The only thing left to do is create and ECS cluster and deploy the EdgeDB +The only thing left to do is create and ECS cluster and deploy the Gel container in it. .. code-block:: bash @@ -745,7 +745,7 @@ container in it. }" \ )" - $ LOG_GROUP_NAME="/ecs/edgedb/$NAME" + $ LOG_GROUP_NAME="/ecs/gel/$NAME" $ aws logs create-log-group \ --region $REGION \ @@ -780,20 +780,20 @@ container in it. --container-definitions \ "[{ \ \"name\": \"$NAME\", \ - \"image\": \"edgedb/edgedb\", \ + \"image\": \"geldata/gel\", \ \"portMappings\": [{\"containerPort\": 5656}], \ - \"command\": [\"edgedb-server\"], \ + \"command\": [\"gel-server\"], \ \"environment\": [{ \ - \"name\": \"EDGEDB_SERVER_GENERATE_SELF_SIGNED_CERT\", \ + \"name\": \"GEL_SERVER_GENERATE_SELF_SIGNED_CERT\", \ \"value\": \"1\" \ }], \ \"secrets\": [ \ { \ - \"name\": \"EDGEDB_SERVER_PASSWORD\", \ + \"name\": \"GEL_SERVER_PASSWORD\", \ \"valueFrom\": \"$PASSWORD_ARN\" \ }, \ { \ - \"name\": \"EDGEDB_SERVER_BACKEND_DSN\", \ + \"name\": \"GEL_SERVER_BACKEND_DSN\", \ \"valueFrom\": \"$DSN_ARN\" \ } \ ], \ @@ -829,15 +829,14 @@ container in it. containerPort=5656, \ targetGroupArn=$TARGET_GROUP_ARN" -Create a local link to the new EdgeDB instance ----------------------------------------------- +Create a local link to the new Gel instance +------------------------------------------- -Create an local alias to the remote EdgeDB instance with ``edgedb instance -link``: +Create an local alias to the remote Gel instance with :gelcmd:`instance link`: .. code-block:: bash - $ printf $PASSWORD | edgedb instance link \ + $ printf $PASSWORD | gel instance link \ --password-from-stdin \ --trust-tls-cert \ --non-interactive \ @@ -853,7 +852,7 @@ link``: .. note:: - The command groups ``edgedb instance`` and ``edgedb project`` are not + The command groups :gelcmd:`instance` and :gelcmd:`project` are not intended to manage production instances. You can now open a REPL to this instance @@ -862,5 +861,5 @@ Health Checks ============= Using an HTTP client, you can perform health checks to monitor the status of -your EdgeDB instance. Learn how to use them with our :ref:`health checks guide +your Gel instance. Learn how to use them with our :ref:`health checks guide `. diff --git a/docs/guides/deployment/azure_flexibleserver.rst b/docs/guides/deployment/azure_flexibleserver.rst index ecd48d7647c..21b5b30e8f2 100644 --- a/docs/guides/deployment/azure_flexibleserver.rst +++ b/docs/guides/deployment/azure_flexibleserver.rst @@ -4,9 +4,9 @@ Azure ===== -:edb-alt-title: Deploying EdgeDB to Azure +:edb-alt-title: Deploying Gel to Azure -In this guide we show how to deploy EdgeDB using Azure's `Postgres +In this guide we show how to deploy Gel using Azure's `Postgres Flexible Server `_ as the backend. @@ -22,8 +22,8 @@ Prerequisites .. _azure-install: https://docs.microsoft.com/en-us/cli/azure/install-azure-cli -Provision an EdgeDB instance -============================ +Provision an Gel instance +========================= Login to your Microsoft Azure account. @@ -49,7 +49,7 @@ variable; we'll use this variable in multiple later commands. .. code-block:: bash - $ PG_SERVER_NAME=postgres-for-edgedb + $ PG_SERVER_NAME=postgres-for-gel Use the ``read`` command to securely assign a value to the ``PASSWORD`` environment variable. @@ -66,7 +66,7 @@ Then create a Postgres Flexible server. --resource-group $GROUP \ --name $PG_SERVER_NAME \ --location westus \ - --admin-user edgedb \ + --admin-user admin \ --admin-password $PASSWORD \ --sku-name Standard_D2s_v3 \ --version 14 \ @@ -88,7 +88,7 @@ Allow other Azure services access to the Postgres instance. --start-ip-address 0.0.0.0 \ --end-ip-address 0.0.0.0 -EdgeDB requires Postgres' ``uuid-ossp`` extension which needs to be enabled. +|Gel| requires Postgres' ``uuid-ossp`` extension which needs to be enabled. .. code-block:: bash @@ -98,7 +98,7 @@ EdgeDB requires Postgres' ``uuid-ossp`` extension which needs to be enabled. --name azure.extensions \ --value uuid-ossp -Start an EdgeDB container. +Start an Gel container. .. code-block:: bash @@ -108,85 +108,85 @@ Start an EdgeDB container. --query "[?name=='$PG_SERVER_NAME'].fullyQualifiedDomainName | [0]" \ --output tsv ) - $ DSN="postgresql://edgedb:$PASSWORD@$PG_HOST/postgres?sslmode=require" + $ DSN="postgresql://gel:$PASSWORD@$PG_HOST/postgres?sslmode=require" $ az container create \ --resource-group $GROUP \ - --name edgedb-container-group \ - --image edgedb/edgedb \ - --dns-name-label edgedb \ + --name gel-container-group \ + --image geldata/gel \ + --dns-name-label gel \ --ports 5656 \ --secure-environment-variables \ - "EDGEDB_SERVER_PASSWORD=$PASSWORD" \ - "EDGEDB_SERVER_BACKEND_DSN=$DSN" \ + "GEL_SERVER_PASSWORD=$PASSWORD" \ + "GEL_SERVER_BACKEND_DSN=$DSN" \ --environment-variables \ - EDGEDB_SERVER_TLS_CERT_MODE=generate_self_signed \ + GEL_SERVER_TLS_CERT_MODE=generate_self_signed \ -Persist the SSL certificate. We have configured EdgeDB to generate a self +Persist the SSL certificate. We have configured Gel to generate a self signed SSL certificate when it starts. However, if the container is restarted a new certificate would be generated. To preserve the certificate across failures or reboots copy the certificate files and use their contents in the -``EDGEDB_SERVER_TLS_KEY`` and ``EDGEDB_SERVER_TLS_CERT`` environment variables. +:gelenv:`SERVER_TLS_KEY` and :gelenv:`SERVER_TLS_CERT` environment variables. .. code-block:: bash $ key="$( az container exec \ --resource-group $GROUP \ - --name edgedb-container-group \ - --exec-command "cat /tmp/edgedb/edbprivkey.pem" \ + --name gel-container-group \ + --exec-command "cat /tmp/gel/edbprivkey.pem" \ | tr -d "\r" )" $ cert="$( az container exec \ --resource-group $GROUP \ - --name edgedb-container-group \ - --exec-command "cat /tmp/edgedb/edbtlscert.pem" \ + --name gel-container-group \ + --exec-command "cat /tmp/gel/edbtlscert.pem" \ | tr -d "\r" )" $ az container delete \ --resource-group $GROUP \ - --name edgedb-container-group \ + --name gel-container-group \ --yes $ az container create \ --resource-group $GROUP \ - --name edgedb-container-group \ - --image edgedb/edgedb \ - --dns-name-label edgedb \ + --name gel-container-group \ + --image geldata/gel \ + --dns-name-label gel \ --ports 5656 \ --secure-environment-variables \ - "EDGEDB_SERVER_PASSWORD=$PASSWORD" \ - "EDGEDB_SERVER_BACKEND_DSN=$DSN" \ - "EDGEDB_SERVER_TLS_KEY=$key" \ + "GEL_SERVER_PASSWORD=$PASSWORD" \ + "GEL_SERVER_BACKEND_DSN=$DSN" \ + "GEL_SERVER_TLS_KEY=$key" \ --environment-variables \ - "EDGEDB_SERVER_TLS_CERT=$cert" + "GEL_SERVER_TLS_CERT=$cert" -To access the EdgeDB instance you've just provisioned on Azure from your local +To access the Gel instance you've just provisioned on Azure from your local machine link the instance. .. code-block:: bash - $ printf $PASSWORD | edgedb instance link \ + $ printf $PASSWORD | gel instance link \ --password-from-stdin \ --non-interactive \ --trust-tls-cert \ --host $( \ az container list \ --resource-group $GROUP \ - --query "[?name=='edgedb-container-group'].ipAddress.fqdn | [0]" \ + --query "[?name=='gel-container-group'].ipAddress.fqdn | [0]" \ --output tsv ) \ azure .. note:: - The command groups ``edgedb instance`` and ``edgedb project`` are not + The command groups :gelcmd:`instance` and :gelcmd:`project` are not intended to manage production instances. You can now connect to your instance. .. code-block:: bash - $ edgedb -I azure + $ gel -I azure Health Checks ============= Using an HTTP client, you can perform health checks to monitor the status of -your EdgeDB instance. Learn how to use them with our :ref:`health checks guide +your Gel instance. Learn how to use them with our :ref:`health checks guide `. diff --git a/docs/guides/deployment/bare_metal.rst b/docs/guides/deployment/bare_metal.rst index f4312afd299..35b08858641 100644 --- a/docs/guides/deployment/bare_metal.rst +++ b/docs/guides/deployment/bare_metal.rst @@ -4,62 +4,62 @@ Bare Metal ========== -:edb-alt-title: Deploying EdgeDB to a Bare Metal Server +:edb-alt-title: Deploying Gel to a Bare Metal Server -In this guide we show how to deploy EdgeDB to bare metal using your system's +In this guide we show how to deploy Gel to bare metal using your system's package manager and systemd. -Install the EdgeDB Package +Install the Gel Package ========================== -The steps for installing the EdgeDB package will be slightly different +The steps for installing the Gel package will be slightly different depending on your Linux distribution. Once you have the package installed you can jump to :ref:`ref_guide_deployment_bare_metal_enable_unit`. Debian/Ubuntu LTS ----------------- -Import the EdgeDB packaging key. +Import the Gel packaging key. .. code-block:: bash $ sudo mkdir -p /usr/local/share/keyrings && \ sudo curl --proto '=https' --tlsv1.2 -sSf \ - -o /usr/local/share/keyrings/edgedb-keyring.gpg \ - https://packages.edgedb.com/keys/edgedb-keyring.gpg + -o /usr/local/share/keyrings/gel-keyring.gpg \ + https://packages.geldata.com/keys/gel-keyring.gpg -Add the EdgeDB package repository. +Add the Gel package repository. .. code-block:: bash - $ echo deb [signed-by=/usr/local/share/keyrings/edgedb-keyring.gpg] \ - https://packages.edgedb.com/apt \ + $ echo deb [signed-by=/usr/local/share/keyrings/gel-keyring.gpg] \ + https://packages.geldata.com/apt \ $(grep "VERSION_CODENAME=" /etc/os-release | cut -d= -f2) main \ - | sudo tee /etc/apt/sources.list.d/edgedb.list + | sudo tee /etc/apt/sources.list.d/gel.list -Install the EdgeDB package. +Install the Gel package. .. code-block:: bash - $ sudo apt-get update && sudo apt-get install edgedb-5 + $ sudo apt-get update && sudo apt-get install gel-6 CentOS/RHEL 7/8 --------------- -Add the EdgeDB package repository. +Add the Gel package repository. .. code-block:: bash $ sudo curl --proto '=https' --tlsv1.2 -sSfL \ - https://packages.edgedb.com/rpm/edgedb-rhel.repo \ - > /etc/yum.repos.d/edgedb.repo + https://packages.geldata.com/rpm/gel-rhel.repo \ + > /etc/yum.repos.d/gel.repo -Install the EdgeDB package. +Install the Gel package. .. code-block:: bash - $ sudo yum install edgedb-5 + $ sudo yum install gel-6 .. _ref_guide_deployment_bare_metal_enable_unit: @@ -67,28 +67,28 @@ Install the EdgeDB package. Enable a systemd unit ===================== -The EdgeDB package comes bundled with a systemd unit that is disabled by +The Gel package comes bundled with a systemd unit that is disabled by default. You can start the server by enabling the unit. .. code-block:: bash - $ sudo systemctl enable --now edgedb-server-5 + $ sudo systemctl enable --now gel-server-6 This will start the server on port 5656, and the data directory will be -``/var/lib/edgedb/1/data``. +``/var/lib/gel/1/data``. .. warning:: - ``edgedb-server`` cannot be run as root. + |gel-server| cannot be run as root. Set environment variables ========================= -To set environment variables when running EdgeDB with ``systemctl``, +To set environment variables when running Gel with ``systemctl``, .. code-block:: bash - $ systemctl edit --full edgedb-server-5 + $ systemctl edit --full gel-server-6 This opens a ``systemd`` unit file. Set the desired environment variables under the ``[Service]`` section. View the supported environment variables at @@ -97,14 +97,14 @@ under the ``[Service]`` section. View the supported environment variables at .. code-block:: toml [Service] - Environment="EDGEDB_SERVER_TLS_CERT_MODE=generate_self_signed" - Environment="EDGEDB_SERVER_ADMIN_UI=enabled" + Environment="GEL_SERVER_TLS_CERT_MODE=generate_self_signed" + Environment="GEL_SERVER_ADMIN_UI=enabled" Save the file and exit, then restart the service. .. code-block:: bash - $ systemctl restart edgedb-server-5 + $ systemctl restart gel-server-6 Set a password @@ -114,25 +114,25 @@ socket directory. You can find this by looking at your system.d unit file. .. code-block:: bash - $ sudo systemctl cat edgedb-server-5 + $ sudo systemctl cat gel-server-6 Set a password by connecting from localhost. .. code-block:: bash $ echo -n "> " && read -s PASSWORD - $ RUNSTATE_DIR=$(systemctl show edgedb-server-5 -P ExecStart | \ + $ RUNSTATE_DIR=$(systemctl show gel-server-6 -P ExecStart | \ grep -o -m 1 -- "--runstate-dir=[^ ]\+" | \ awk -F "=" '{print $2}') - $ sudo edgedb --port 5656 --tls-security insecure --admin \ + $ sudo gel --port 5656 --tls-security insecure --admin \ --unix-path $RUNSTATE_DIR \ - query "ALTER ROLE edgedb SET password := '$PASSWORD'" + query "ALTER ROLE admin SET password := '$PASSWORD'" The server listens on localhost by default. Changing this looks like this. .. code-block:: bash - $ edgedb --port 5656 --tls-security insecure --password query \ + $ gel --port 5656 --tls-security insecure --password query \ "CONFIGURE INSTANCE SET listen_addresses := {'0.0.0.0'};" The listen port can be changed from the default ``5656`` if your deployment @@ -140,14 +140,14 @@ scenario requires a different value. .. code-block:: bash - $ edgedb --port 5656 --tls-security insecure --password query \ + $ gel --port 5656 --tls-security insecure --password query \ "CONFIGURE INSTANCE SET listen_port := 1234;" You may need to restart the server after changing the listen port or addresses. .. code-block:: bash - $ sudo systemctl restart edgedb-server-5 + $ sudo systemctl restart gel-server-6 Link the instance with the CLI @@ -159,10 +159,10 @@ convenient to refer to when running CLI commands. .. code-block:: bash - $ edgedb instance link \ + $ gel instance link \ --host localhost \ --port 5656 \ - --user edgedb \ + --user admin \ --branch main \ --trust-tls-cert \ bare_metal_instance @@ -171,19 +171,19 @@ This allows connecting to the instance with its name. .. code-block:: bash - $ edgedb -I bare_metal_instance + $ gel -I bare_metal_instance -Upgrading EdgeDB -================ +Upgrading Gel +============= .. note:: - The command groups ``edgedb instance`` and ``edgedb project`` are not + The command groups :gelcmd:`instance` and :gelcmd:`project` are not intended to manage production instances. When you want to upgrade to the newest point release upgrade the package and -restart the ``edgedb-server-5`` unit. +restart the ``gel-server-6`` unit. Debian/Ubuntu LTS @@ -191,8 +191,8 @@ Debian/Ubuntu LTS .. code-block:: bash - $ sudo apt-get update && sudo apt-get install --only-upgrade edgedb-5 - $ sudo systemctl restart edgedb-server-5 + $ sudo apt-get update && sudo apt-get install --only-upgrade gel-6 + $ sudo systemctl restart gel-server-6 CentOS/RHEL 7/8 @@ -200,12 +200,12 @@ CentOS/RHEL 7/8 .. code-block:: bash - $ sudo yum update edgedb-5 - $ sudo systemctl restart edgedb-server-5 + $ sudo yum update gel-6 + $ sudo systemctl restart gel-server-6 Health Checks ============= Using an HTTP client, you can perform health checks to monitor the status of -your EdgeDB instance. Learn how to use them with our :ref:`health checks guide +your Gel instance. Learn how to use them with our :ref:`health checks guide `. diff --git a/docs/guides/deployment/digitalocean.rst b/docs/guides/deployment/digitalocean.rst index d96c345e098..dfe68a7706e 100644 --- a/docs/guides/deployment/digitalocean.rst +++ b/docs/guides/deployment/digitalocean.rst @@ -4,9 +4,9 @@ DigitalOcean ============ -:edb-alt-title: Deploying EdgeDB to DigitalOcean +:edb-alt-title: Deploying Gel to DigitalOcean -In this guide we show how to deploy EdgeDB to DigitalOcean either with a +In this guide we show how to deploy Gel to DigitalOcean either with a One-click Deploy option or a :ref:`managed PostgreSQL ` database as the backend. @@ -17,11 +17,11 @@ One-click Deploy Prerequisites ============= -* ``edgedb`` CLI (`install `_) +* |gelcmd| CLI (`install `_) * DigitalOcean account Click the button below and follow the droplet creation workflow on -DigitalOcean to deploy an EdgeDB instance. +DigitalOcean to deploy an Gel instance. .. image:: https://www.deploytodo.com/do-btn-blue.svg :target: 1-click-button_ @@ -30,13 +30,13 @@ DigitalOcean to deploy an EdgeDB instance. .. _1-click-button: https://marketplace.digitalocean.com/apps/edgedb?refcode=f0b0d77b5d49 -By default, the admin password is ``edgedbpassword``; let's change that to +By default, the admin password is ``gelpassword``; let's change that to something more secure. First, find your droplet's IP address on the `DigitalOcean dashboard `_ and assign it to an environment variable ``IP``. .. _DigitalOcean: https://cloud.digitalocean.com/droplets? -.. _here: edgedb-install_ +.. _here: gel-install_ .. code-block:: bash @@ -49,15 +49,15 @@ environment variable. $ echo -n "> " && read -s PASSWORD -Use these variables to change the password for the default role ``edgedb``. +Use these variables to change the password for the default role |admin|. .. code-block:: bash - $ printf edgedbpassword | edgedb query \ + $ printf gelpassword | gel query \ --host $IP \ --password-from-stdin \ --tls-security insecure \ - "alter role edgedb set password := '${PASSWORD}'" + "alter role admin set password := '${PASSWORD}'" OK: ALTER ROLE .. _ref_guide_deployment_digitalocean_link: @@ -71,41 +71,41 @@ shell logs. .. code-block:: bash - $ echo edgedb://edgedb:$PASSWORD@$IP > dsn.txt + $ echo gel://admin:$PASSWORD@$IP > dsn.txt Copy the value from ``dsn.txt``. Run the following command to open a REPL to the new instance. .. code-block:: bash - $ edgedb --dsn --tls-security insecure - edgedb> + $ gel --dsn --tls-security insecure + gel> Success! You're now connected to your remote instance. -It's often useful to assign an alias to the remote instance using ``edgedb -instance link``. +It's often useful to assign an alias to the remote instance using +:gelcmd:`instance link`. .. code-block:: bash - $ edgedb instance link \ + $ gel instance link \ --dsn \ --trust-tls-cert \ --non-interactive \ my_instance - Authenticating to edgedb://edgedb@1.2.3.4:5656/main + Authenticating to gel://admin@1.2.3.4:5656/main Trusting unknown server certificate: SHA1:1880da9527be464e2cad3bdb20dfc430a6af5727 Successfully linked to remote instance. To connect run: - edgedb -I my_instance + gel -I my_instance You can now use the ``-I`` CLI flag to execute commands against your remote instance: .. code-block:: bash - $ edgedb -I my_instance - edgedb> + $ gel -I my_instance + gel> .. _ref_guide_deployment_digitalocean_managed: @@ -116,12 +116,12 @@ Deploy with Managed PostgreSQL Prerequisites ============= -* ``edgedb`` CLI (`install `_) +* |gelcmd| CLI (`install `_) * DigitalOcean account * ``doctl`` CLI (`install `_) * ``jq`` (`install `_) -.. _edgedb-install: https://www.edgedb.com/install +.. _gel-install: https://www.edgedb.com/install .. _doclt-install: https://docs.digitalocean.com/reference/doctl/how-to/install .. _jq: https://stedolan.github.io/jq/ @@ -134,7 +134,7 @@ If you already have a PostgreSQL instance you can skip this step. .. code-block:: bash $ DSN="$( \ - doctl databases create edgedb-postgres \ + doctl databases create gel-postgres \ --engine pg \ --version 14 \ --size db-s-1vcpu-1gb \ @@ -160,8 +160,8 @@ add one now. .. code-block:: bash $ IP="$( \ - doctl compute droplet create edgedb \ - --image edgedb \ + doctl compute droplet create gel \ + --image gel \ --region sfo3 \ --size s-2vcpu-4gb \ --ssh-keys $SSH_KEY_IDS \ @@ -170,17 +170,17 @@ add one now. --wait )" Configure the backend Postgres DSN. To simplify the initial deployment, let's -instruct EdgeDB to run in insecure mode (with password authentication off and +instruct Gel to run in insecure mode (with password authentication off and an autogenerated TLS certificate). We will secure the instance once things are up and running. .. code-block:: bash - $ printf "EDGEDB_SERVER_BACKEND_DSN=${DSN} \ - \nEDGEDB_SERVER_SECURITY=insecure_dev_mode\n" \ - | ssh root@$IP -T "cat > /etc/edgedb/env" + $ printf "GEL_SERVER_BACKEND_DSN=${DSN} \ + \nGEL_SERVER_SECURITY=insecure_dev_mode\n" \ + | ssh root@$IP -T "cat > /etc/gel/env" - $ ssh root@$IP "systemctl restart edgedb.service" + $ ssh root@$IP "systemctl restart gel.service" Set the superuser password. @@ -188,30 +188,30 @@ Set the superuser password. $ echo -n "> " && read -s PASSWORD - $ edgedb -H $IP --tls-security insecure query \ - "alter role edgedb set password := '$PASSWORD'" + $ gel -H $IP --tls-security insecure query \ + "alter role admin set password := '$PASSWORD'" OK: ALTER ROLE Set the security policy to strict. .. code-block:: bash - $ printf "EDGEDB_SERVER_BACKEND_DSN=${DSN} \ - \nEDGEDB_SERVER_SECURITY=strict\n" \ - | ssh root@$IP -T "cat > /etc/edgedb/env" + $ printf "GEL_SERVER_BACKEND_DSN=${DSN} \ + \nGEL_SERVER_SECURITY=strict\n" \ + | ssh root@$IP -T "cat > /etc/gel/env" - $ ssh root@$IP "systemctl restart edgedb.service" + $ ssh root@$IP "systemctl restart gel.service" .. note:: - To upgrade an existing EdgeDB droplet to the latest point release, ``ssh`` + To upgrade an existing Gel droplet to the latest point release, ``ssh`` into your droplet and run the following. .. code-block:: bash - $ apt-get update && apt-get install --only-upgrade edgedb-server-5 - $ systemctl restart edgedb + $ apt-get update && apt-get install --only-upgrade gel-server-6 + $ systemctl restart gel That's it! Refer to the :ref:`Construct the DSN ` section above to connect to your @@ -219,12 +219,12 @@ instance. .. note:: - The command groups ``edgedb instance`` and ``edgedb project`` are not + The command groups :gelcmd:`instance` and :gelcmd:`project` are not intended to manage production instances. Health Checks ============= Using an HTTP client, you can perform health checks to monitor the status of -your EdgeDB instance. Learn how to use them with our :ref:`health checks guide +your Gel instance. Learn how to use them with our :ref:`health checks guide `. diff --git a/docs/guides/deployment/docker.rst b/docs/guides/deployment/docker.rst index 46dab8fe5a2..67e8d6babba 100644 --- a/docs/guides/deployment/docker.rst +++ b/docs/guides/deployment/docker.rst @@ -4,18 +4,18 @@ Docker ====== -:edb-alt-title: Deploying EdgeDB with Docker +:edb-alt-title: Deploying Gel with Docker -When to use the `edgedb/edgedb`_ Docker image -============================================= +When to use the "geldata/gel" Docker image +========================================== -.. _edgedb/edgedb: https://hub.docker.com/r/edgedb/edgedb +.. _geldata/gel: https://hub.docker.com/r/geldata/gel This image is primarily intended to be used directly when there is a requirement to use Docker containers, such as in production, or in a development setup that involves multiple containers orchestrated by Docker -Compose or a similar tool. Otherwise, using the :ref:`ref_cli_edgedb_server` -CLI on the host system is the recommended way to install and run EdgeDB +Compose or a similar tool. Otherwise, using the :ref:`ref_cli_gel_server` +CLI on the host system is the recommended way to install and run Gel servers. @@ -26,29 +26,29 @@ The simplest way to run the image (without data persistence) is this: .. code-block:: bash - $ docker run --name edgedb -d \ - -e EDGEDB_SERVER_SECURITY=insecure_dev_mode \ - edgedb/edgedb + $ docker run --name gel -d \ + -e GEL_SERVER_SECURITY=insecure_dev_mode \ + geldata/gel See the :ref:`ref_guides_deployment_docker_customization` section below for the -meaning of the ``EDGEDB_SERVER_SECURITY`` variable and other options. +meaning of the :gelenv:`SERVER_SECURITY` variable and other options. -Then, to authenticate to the EdgeDB instance and store the credentials in a +Then, to authenticate to the Gel instance and store the credentials in a Docker volume, run: .. code-block:: bash - $ docker run -it --rm --link=edgedb \ - -e EDGEDB_SERVER_PASSWORD=secret \ - -v edgedb-cli-config:/.config/edgedb edgedb/edgedb-cli \ - -H edgedb instance link my_instance + $ docker run -it --rm --link=gel \ + -e GEL_SERVER_PASSWORD=secret \ + -v gel-cli-config:/.config/gel geldata/gel-cli \ + -H gel instance link my_instance Now, to open an interactive shell to the database instance run this: .. code-block:: bash - $ docker run -it --rm --link=edgedb \ - -v edgedb-cli-config:/.config/edgedb edgedb/edgedb-cli \ + $ docker run -it --rm --link=gel \ + -v gel-cli-config:/.config/gel geldata/gel-cli \ -I my_instance @@ -57,31 +57,31 @@ Data Persistence If you want the contents of the database to survive container restarts, you must mount a persistent volume at the path specified by -``EDGEDB_SERVER_DATADIR`` (``/var/lib/edgedb/data`` by default). For example: +:gelenv:`SERVER_DATADIR` (``/var/lib/gel/data`` by default). For example: .. code-block:: bash $ docker run \ - --name edgedb \ - -e EDGEDB_SERVER_PASSWORD=secret \ - -e EDGEDB_SERVER_TLS_CERT_MODE=generate_self_signed \ - -v /my/data/directory:/var/lib/edgedb/data \ - -d edgedb/edgedb + --name gel \ + -e GEL_SERVER_PASSWORD=secret \ + -e GEL_SERVER_TLS_CERT_MODE=generate_self_signed \ + -v /my/data/directory:/var/lib/gel/data \ + -d geldata/gel Note that on Windows you must use a Docker volume instead: .. code-block:: bash - $ docker volume create --name=edgedb-data + $ docker volume create --name=gel-data $ docker run \ - --name edgedb \ - -e EDGEDB_SERVER_PASSWORD=secret \ - -e EDGEDB_SERVER_TLS_CERT_MODE=generate_self_signed \ - -v edgedb-data:/var/lib/edgedb/data \ - -d edgedb/edgedb + --name gel \ + -e GEL_SERVER_PASSWORD=secret \ + -e GEL_SERVER_TLS_CERT_MODE=generate_self_signed \ + -v gel-data:/var/lib/gel/data \ + -d geldata/gel -It is also possible to run an ``edgedb`` container on a remote PostgreSQL -cluster specified by ``EDGEDB_SERVER_BACKEND_DSN``. See below for details. +It is also possible to run an ``gel`` container on a remote PostgreSQL +cluster specified by :gelenv:`SERVER_BACKEND_DSN`. See below for details. Schema Migrations @@ -89,7 +89,7 @@ Schema Migrations A derived image may include application schema and migrations in ``/dbschema``, in which case the container will attempt to apply the schema migrations found -in ``/dbschema/migrations``, unless the ``EDGEDB_DOCKER_APPLY_MIGRATIONS`` +in ``/dbschema/migrations``, unless the :gelenv:`DOCKER_APPLY_MIGRATIONS` environment variable is set to ``never``. @@ -103,10 +103,10 @@ With a ``docker-compose.yaml`` containing: version: "3" services: - edgedb: - image: edgedb/edgedb + gel: + image: geldata/gel environment: - EDGEDB_SERVER_SECURITY: insecure_dev_mode + GEL_SERVER_SECURITY: insecure_dev_mode volumes: - "./dbschema:/dbschema" ports: @@ -117,14 +117,14 @@ migration can be created with: .. code-block:: bash - $ edgedb --tls-security=insecure -P 5656 migration create + $ gel --tls-security=insecure -P 5656 migration create -Alternatively, if you don't have the EdgeDB CLI installed on your host +Alternatively, if you don't have the Gel CLI installed on your host machine, you can use the CLI bundled with the server container: .. code-block:: bash - $ docker-compose exec edgedb edgedb --tls-security=insecure migration create + $ docker-compose exec gel gel --tls-security=insecure migration create .. _ref_guides_deployment_docker_customization: @@ -132,11 +132,11 @@ machine, you can use the CLI bundled with the server container: Configuration ============= -The Docker image supports the same set of enviroment variables as the EdgeDB +The Docker image supports the same set of enviroment variables as the Gel server process, which are documented under :ref:`Reference > Environment Variables `. -EdgeDB containers can be additionally configured using initialization scripts +|Gel| containers can be additionally configured using initialization scripts and some Docker-specific environment variables, documented below. .. note:: @@ -149,69 +149,74 @@ and some Docker-specific environment variables, documented below. Initial configuration --------------------- -When an EdgeDB container starts on the specified data directory or remote +When an Gel container starts on the specified data directory or remote Postgres cluster for the first time, initial instance setup is performed. This is called the *bootstrap phase*. The following environment variables affect the bootstrap only and have no effect on subsequent container runs. +.. note:: + + For |EdgeDB| versions before 6.0 (Gel) the prefix for all environment + variables is ``EDGEDB_`` instead of ``GEL_``. + -EDGEDB_SERVER_BOOTSTRAP_COMMAND -............................... +GEL_SERVER_BOOTSTRAP_COMMAND +............................ Useful to fine-tune initial user and branch creation, and other initial -setup. If neither the ``EDGEDB_SERVER_BOOTSTRAP_COMMAND`` variable or the -``EDGEDB_SERVER_BOOTSTRAP_SCRIPT_FILE`` are explicitly specified, the container -will look for the presence of ``/edgedb-bootstrap.edgeql`` in the container +setup. If neither the :gelenv:`SERVER_BOOTSTRAP_COMMAND` variable or the +:gelenv:`SERVER_BOOTSTRAP_SCRIPT_FILE` are explicitly specified, the container +will look for the presence of ``/gel-bootstrap.edgeql`` in the container (which can be placed in a derived image). -Maps directly to the ``edgedb-server`` flag ``--bootstrap-command``. The +Maps directly to the |gel-server| flag ``--bootstrap-command``. The ``*_FILE`` and ``*_ENV`` variants are also supported. -EDGEDB_SERVER_BOOTSTRAP_SCRIPT_FILE -................................... -Deprecated in image version 2.8: use ``EDGEDB_SERVER_BOOTSTRAP_COMMAND_FILE`` +GEL_SERVER_BOOTSTRAP_SCRIPT_FILE +................................ +Deprecated in image version 2.8: use :gelenv:`SERVER_BOOTSTRAP_COMMAND_FILE` instead. Run the script when initializing the database. The script is run by default user within default branch. -EDGEDB_SERVER_PASSWORD -...................... +GEL_SERVER_PASSWORD +................... The password for the default superuser account will be set to this value. If no value is provided a password will not be set, unless set via -``EDGEDB_SERVER_BOOTSTRAP_COMMAND``. (If a value for -``EDGEDB_SERVER_BOOTSTRAP_COMMAND`` is provided, this variable will be +:gelenv:`SERVER_BOOTSTRAP_COMMAND`. (If a value for +:gelenv:`SERVER_BOOTSTRAP_COMMAND` is provided, this variable will be ignored.) The ``*_FILE`` and ``*_ENV`` variants are also supported. -EDGEDB_SERVER_PASSWORD_HASH -........................... +GEL_SERVER_PASSWORD_HASH +........................ -A variant of ``EDGEDB_SERVER_PASSWORD``, where the specified value is a hashed +A variant of :gelenv:`SERVER_PASSWORD`, where the specified value is a hashed password verifier instead of plain text. -If ``EDGEDB_SERVER_BOOTSTRAP_COMMAND`` is set, this variable will be ignored. +If :gelenv:`SERVER_BOOTSTRAP_COMMAND` is set, this variable will be ignored. The ``*_FILE`` and ``*_ENV`` variants are also supported. -EDGEDB_SERVER_GENERATE_SELF_SIGNED_CERT -....................................... +GEL_SERVER_GENERATE_SELF_SIGNED_CERT +.................................... .. warning:: - Deprecated: use ``EDGEDB_SERVER_TLS_CERT_MODE=generate_self_signed`` + Deprecated: use :gelenv:`SERVER_TLS_CERT_MODE=generate_self_signed` instead. Set this option to ``1`` to tell the server to automatically generate a -self-signed certificate with key file in the ``EDGEDB_SERVER_DATADIR`` (if +self-signed certificate with key file in the :gelenv:`SERVER_DATADIR` (if present, see below), and echo the certificate content in the logs. If the certificate file exists, the server will use it instead of generating a new one. @@ -221,17 +226,17 @@ should likely provide your own certificate and key file with the variables below. -EDGEDB_SERVER_TLS_CERT/EDGEDB_SERVER_TLS_KEY -............................................ +GEL_SERVER_TLS_CERT/GEL_SERVER_TLS_KEY +...................................... The TLS certificate and private key data, exclusive with -``EDGEDB_SERVER_TLS_CERT_MODE=generate_self_signed``. +:gelenv:`SERVER_TLS_CERT_MODE=generate_self_signed`. The ``*_FILE`` and ``*_ENV`` variants are also supported. -Custom scripts in ``/docker-entrypoint.d/`` -........................................... +Custom scripts in "/docker-entrypoint.d/" +......................................... To perform additional initialization, a derived image may include one or more executable files in ``/docker-entrypoint.d/``, which will get executed by the @@ -241,8 +246,8 @@ container entrypoint *before* any other processing takes place. Runtime configuration --------------------- -EDGEDB_DOCKER_LOG_LEVEL -....................... +GEL_DOCKER_LOG_LEVEL +.................... Determines the log verbosity level in the entrypoint script. Valid levels are ``trace``, ``debug``, ``info``, ``warning``, and ``error``. The default is @@ -250,15 +255,15 @@ Determines the log verbosity level in the entrypoint script. Valid levels are .. _ref_guide_deployment_docker_custom_bootstrap_scripts: -Custom scripts in ``/edgedb-bootstrap.d/`` and ``/edgedb-bootstrap-late.d`` -........................................................................... +Custom scripts in "/gel-bootstrap.d/" and "/gel-bootstrap-late.d" +................................................................. To perform additional initialization, a derived image may include one or more ``*.edgeql`` or ``*.sh`` scripts, which are executed in addition to and *after* the initialization specified by the environment variables above or the -``/edgedb-bootstrap.edgeql`` script. Parts in ``/edgedb-bootstrap.d`` are +``/gel-bootstrap.edgeql`` script. Parts in ``/gel-bootstrap.d`` are executed *before* any schema migrations are applied, and parts in -``/edgedb-bootstrap-late.d`` are executed *after* the schema migration have +``/gel-bootstrap-late.d`` are executed *after* the schema migration have been applied. .. note:: @@ -271,5 +276,5 @@ Health Checks ============= Using an HTTP client, you can perform health checks to monitor the status of -your EdgeDB instance. Learn how to use them with our :ref:`health checks guide +your Gel instance. Learn how to use them with our :ref:`health checks guide `. diff --git a/docs/guides/deployment/fly_io.rst b/docs/guides/deployment/fly_io.rst index 6d75eec713a..271ca3290ad 100644 --- a/docs/guides/deployment/fly_io.rst +++ b/docs/guides/deployment/fly_io.rst @@ -4,11 +4,11 @@ Fly.io ====== -:edb-alt-title: Deploying EdgeDB to Fly.io +:edb-alt-title: Deploying Gel to Fly.io -In this guide we show how to deploy EdgeDB using a `Fly.io `_ +In this guide we show how to deploy Gel using a `Fly.io `_ PostgreSQL cluster as the backend. The deployment consists of two apps: one -running Postgres and the other running EdgeDB. +running Postgres and the other running Gel. Prerequisites @@ -20,19 +20,19 @@ Prerequisites .. _flyctl-install: https://fly.io/docs/getting-started/installing-flyctl/ -Provision a Fly.io app for EdgeDB -================================= +Provision a Fly.io app for Gel +============================== Every Fly.io app must have a globally unique name, including service VMs like -Postgres and EdgeDB. Pick a name and assign it to a local environment variable -called ``EDB_APP``. In the command below, replace ``myorg-edgedb`` with a name +Postgres and Gel. Pick a name and assign it to a local environment variable +called ``EDB_APP``. In the command below, replace ``myorg-gel`` with a name of your choosing. .. code-block:: bash - $ EDB_APP=myorg-edgedb + $ EDB_APP=myorg-gel $ flyctl apps create --name $EDB_APP - New app created: myorg-edgedb + New app created: myorg-gel Now let's use the ``read`` command to securely assign a value to the @@ -50,36 +50,36 @@ we'll need. There are a couple more environment variables we need to set: .. code-block:: bash $ flyctl secrets set \ - EDGEDB_SERVER_PASSWORD="$PASSWORD" \ - EDGEDB_SERVER_BACKEND_DSN_ENV=DATABASE_URL \ - EDGEDB_SERVER_TLS_CERT_MODE=generate_self_signed \ - EDGEDB_SERVER_PORT=8080 \ + GEL_SERVER_PASSWORD="$PASSWORD" \ + GEL_SERVER_BACKEND_DSN_ENV=DATABASE_URL \ + GEL_SERVER_TLS_CERT_MODE=generate_self_signed \ + GEL_SERVER_PORT=8080 \ --app $EDB_APP Secrets are staged for the first deployment Let's discuss what's going on with all these secrets. -- The ``EDGEDB_SERVER_BACKEND_DSN_ENV`` tells the EdgeDB container where to +- The :gelenv:`SERVER_BACKEND_DSN_ENV` tells the Gel container where to look for the PostgreSQL connection string (more on that below) -- The ``EDGEDB_SERVER_TLS_CERT_MODE`` tells EdgeDB to auto-generate a +- The :gelenv:`SERVER_TLS_CERT_MODE` tells Gel to auto-generate a self-signed TLS certificate. You may instead choose to provision a custom TLS certificate. In this case, you should instead create two other secrets: assign your certificate - to ``EDGEDB_SERVER_TLS_CERT`` and your private key to - ``EDGEDB_SERVER_TLS_KEY``. -- Lastly, ``EDGEDB_SERVER_PORT`` tells EdgeDB to listen on port 8080 instead + to :gelenv:`SERVER_TLS_CERT` and your private key to + :gelenv:`SERVER_TLS_KEY`. +- Lastly, :gelenv:`SERVER_PORT` tells Gel to listen on port 8080 instead of the default 5656, because Fly.io prefers ``8080`` for its default health checks. -Finally, let's configure the VM size as EdgeDB requires a little bit more than +Finally, let's configure the VM size as Gel requires a little bit more than the default Fly.io VM side provides. Put this in a file called ``fly.toml`` in your current directory.: .. code-block:: yaml [build] - image = "edgedb/edgedb" + image = "geldata/gel" [[vm]] memory = "512mb" @@ -90,7 +90,7 @@ your current directory.: Create a PostgreSQL cluster =========================== -Now we need to provision a PostgreSQL cluster and attach it to the EdgeDB app. +Now we need to provision a PostgreSQL cluster and attach it to the Gel app. .. note:: @@ -141,20 +141,20 @@ this command: ... With the VM scaled sufficiently, we can now attach the PostgreSQL cluster to -the EdgeDB app: +the Gel app: .. code-block:: bash - $ PG_ROLE=myorg_edgedb + $ PG_ROLE=myorg_gel $ flyctl pg attach "$PG_APP" \ --database-user "$PG_ROLE" \ --app $EDB_APP - Postgres cluster myorg-postgres is now attached to myorg-edgedb - The following secret was added to myorg-edgedb: + Postgres cluster myorg-postgres is now attached to myorg-gel + The following secret was added to myorg-gel: DATABASE_URL=postgres://... -Lastly, EdgeDB needs the ability to create Postgres databases and roles, -so let's adjust the permissions on the role that EdgeDB will use to connect +Lastly, Gel needs the ability to create Postgres databases and roles, +so let's adjust the permissions on the role that Gel will use to connect to Postgres: .. code-block:: bash @@ -164,12 +164,12 @@ to Postgres: ... ALTER ROLE -.. _ref_guide_deployment_fly_io_start_edgedb: +.. _ref_guide_deployment_fly_io_start_gel: -Start EdgeDB -============ +Start Gel +========= -Everything is set! Time to start EdgeDB. +Everything is set! Time to start Gel. .. code-block:: bash @@ -180,8 +180,8 @@ Everything is set! Time to start EdgeDB. βœ” Machine e286630dce9638 [app] was created ------- -That's it! You can now start using the EdgeDB instance located at -``edgedb://myorg-edgedb.internal`` in your Fly.io apps. +That's it! You can now start using the Gel instance located at +:geluri:`myorg-gel.internal` in your Fly.io apps. If deploy did not succeed: @@ -194,14 +194,14 @@ Persist the generated TLS certificate ===================================== Now we need to persist the auto-generated TLS certificate to make sure it -survives EdgeDB app restarts. (If you've provided your own certificate, +survives Gel app restarts. (If you've provided your own certificate, skip this step). .. code-block:: bash - $ EDB_SECRETS="EDGEDB_SERVER_TLS_KEY EDGEDB_SERVER_TLS_CERT" + $ EDB_SECRETS="GEL_SERVER_TLS_KEY GEL_SERVER_TLS_CERT" $ flyctl ssh console --app $EDB_APP -C \ - "edgedb-show-secrets.sh --format=toml $EDB_SECRETS" \ + "gel-show-secrets.sh --format=toml $EDB_SECRETS" \ | tr -d '\r' | flyctl secrets import --app $EDB_APP @@ -209,15 +209,15 @@ Connecting to the instance ========================== Let's construct the DSN (AKA "connection string") for our instance. DSNs have -the following format: ``edgedb://:@:``. We +the following format: :geluri:`:@:`. We can construct the DSN with the following components: -- ````: the default value β€” ``edgedb`` +- ````: the default value β€” |admin| - ````: the value we assigned to ``$PASSWORD`` -- ````: the name of your EdgeDB app (stored in the +- ````: the name of your Gel app (stored in the ``$EDB_APP`` environment variable) suffixed with ``.internal``. Fly uses this synthetic TLD to simplify inter-app communication. Ex: - ``myorg-edgedb.internal``. + ``myorg-gel.internal``. - ````: ``8080``, which we configured earlier We can construct this value and assign it to a new environment variable called @@ -225,7 +225,7 @@ We can construct this value and assign it to a new environment variable called .. code-block:: bash - $ DSN=edgedb://edgedb:$PASSWORD@$EDB_APP.internal:8080 + $ DSN=gel://admin:$PASSWORD@$EDB_APP.internal:8080 Consider writing it to a file to ensure the DSN looks correct. Remember to delete the file after you're done. (Printing this value to the terminal with @@ -241,21 +241,21 @@ From a Fly.io app ----------------- To connect to this instance from another Fly app (say, an app that runs your -API server) set the value of the ``EDGEDB_DSN`` secret inside that app. +API server) set the value of the :gelenv:`DSN` secret inside that app. .. code-block:: bash $ flyctl secrets set \ - EDGEDB_DSN=$DSN \ + GEL_DSN=$DSN \ --app my-other-fly-app -We'll also set another variable that will disable EdgeDB's TLS checks. +We'll also set another variable that will disable Gel's TLS checks. Inter-application communication is secured by Fly so TLS isn't vital in this case; configuring TLS certificates is also beyond the scope of this guide. .. code-block:: bash - $ flyctl secrets set EDGEDB_CLIENT_TLS_SECURITY=insecure \ + $ flyctl secrets set GEL_CLIENT_TLS_SECURITY=insecure \ --app my-other-fly-app @@ -266,7 +266,7 @@ You can also set these values as environment variables inside your From external application ------------------------- -If you need to access EdgeDB from outside the Fly.io network, you'll need to +If you need to access Gel from outside the Fly.io network, you'll need to configure the Fly.io proxy to let external connections in. Let's make sure the ``[[services]]`` section in our ``fly.toml`` looks @@ -294,54 +294,54 @@ something like this: restart_limit = 0 timeout = "2s" -In the same directory, :ref:`redeploy the EdgeDB app -`. This makes the EdgeDB port +In the same directory, :ref:`redeploy the Gel app +`. This makes the Gel port available to the outside world. You can now access the instance from any host -via the following public DSN: ``edgedb://edgedb:$PASSWORD@$EDB_APP.fly.dev``. +via the following public DSN: :geluri:`admin:$PASSWORD@$EDB_APP.fly.dev`. To secure communication between the server and the client, you will also -need to set the ``EDGEDB_TLS_CA`` environment secret in your application. +need to set the :gelenv:`TLS_CA` environment secret in your application. You can securely obtain the certificate content by running: .. code-block:: bash $ flyctl ssh console -a $EDB_APP \ - -C "edgedb-show-secrets.sh --format=raw EDGEDB_SERVER_TLS_CERT" + -C "gel-show-secrets.sh --format=raw GEL_SERVER_TLS_CERT" From your local machine ----------------------- -To access the EdgeDB instance from local development machine/laptop, install +To access the Gel instance from local development machine/laptop, install the Wireguard `VPN `_ and create a tunnel, as described on Fly's `Private Networking `_ docs. -Once it's up and running, use ``edgedb instance link`` to create a local +Once it's up and running, use :gelcmd:`instance link` to create a local alias to the remote instance. .. code-block:: bash - $ edgedb instance link \ + $ gel instance link \ --trust-tls-cert \ --dsn $DSN \ --non-interactive \ fly - Authenticating to edgedb://edgedb@myorg-edgedb.internal:5656/edgedb + Authenticating to gel://admin@myorg-gel.internal:5656/main Successfully linked to remote instance. To connect run: - edgedb -I fly + gel -I fly You can now run CLI commands against this instance by specifying it by name with ``-I fly``; for example, to apply migrations: .. note:: - The command groups ``edgedb instance`` and ``edgedb project`` are not + The command groups :gelcmd:`instance` and :gelcmd:`project` are not intended to manage production instances. .. code-block:: bash - $ edgedb -I fly migrate + $ gel -I fly migrate .. _vpn: https://fly.io/docs/reference/private-networking/#private-network-vpn @@ -349,5 +349,5 @@ Health Checks ============= Using an HTTP client, you can perform health checks to monitor the status of -your EdgeDB instance. Learn how to use them with our :ref:`health checks guide +your Gel instance. Learn how to use them with our :ref:`health checks guide `. diff --git a/docs/guides/deployment/gcp.rst b/docs/guides/deployment/gcp.rst index b9a5325136f..1fa6e573b68 100644 --- a/docs/guides/deployment/gcp.rst +++ b/docs/guides/deployment/gcp.rst @@ -4,9 +4,9 @@ Google Cloud ============ -:edb-alt-title: Deploying EdgeDB to Google Cloud +:edb-alt-title: Deploying Gel to Google Cloud -In this guide we show how to deploy EdgeDB on GCP using Cloud SQL and +In this guide we show how to deploy Gel on GCP using Cloud SQL and Kubernetes. Prerequisites @@ -34,7 +34,7 @@ use. Google Cloud only allow letters, numbers, and hyphens. .. code-block:: bash - $ PROJECT=edgedb + $ PROJECT=gel Then create a project with this name. Skip this step if your project already exists. @@ -130,19 +130,19 @@ Then use this ``credentials.json`` to authenticate the Kubernetes CLI tool --from-literal=password=$PASSWORD \ --from-literal=instance=${INSTANCE_CONNECTION_NAME}=tcp:5432 -Deploy EdgeDB -============= +Deploy Gel +========== -Download the starter EdgeDB Kubernetes configuration file. This file specifies +Download the starter Gel Kubernetes configuration file. This file specifies a persistent volume, a container running a `Cloud SQL authorization proxy `_, and a container to -run `EdgeDB itself `_. It relies on +run `Gel itself `_. It relies on the secrets we declared in the previous step. .. code-block:: bash $ wget "https://raw.githubusercontent.com\ - /edgedb/edgedb-deploy/dev/gcp/deployment.yaml" + /geldata/gel-deploy/dev/gcp/deployment.yaml" $ kubectl apply -f deployment.yaml @@ -152,21 +152,21 @@ Ensure the pods are running. $ kubectl get pods NAME READY STATUS RESTARTS AGE - edgedb-977b8fdf6-jswlw 0/2 ContainerCreating 0 16s + gel-977b8fdf6-jswlw 0/2 ContainerCreating 0 16s The ``READY 0/2`` tells us neither of the two pods have finished booting. Re-run the command until ``2/2`` pods are ``READY``. -If there were errors you can check EdgeDB's logs with: +If there were errors you can check Gel's logs with: .. code-block:: bash - $ kubectl logs deployment/edgedb --container edgedb + $ kubectl logs deployment/gel --container gel Persist TLS Certificate ======================= -Now that our EdgeDB instance is up and running, we need to download a local +Now that our Gel instance is up and running, we need to download a local copy of its self-signed TLS certificate (which it generated on startup) and pass it as a secret into Kubernetes. Then we'll redeploy the pods. @@ -174,24 +174,24 @@ pass it as a secret into Kubernetes. Then we'll redeploy the pods. $ kubectl create secret generic cloudsql-tls-credentials \ --from-literal=tlskey="$( - kubectl exec deploy/edgedb -c=edgedb -- \ - edgedb-show-secrets.sh --format=raw EDGEDB_SERVER_TLS_KEY + kubectl exec deploy/gel -c=gel -- \ + gel-show-secrets.sh --format=raw GEL_SERVER_TLS_KEY )" \ --from-literal=tlscert="$( - kubectl exec deploy/edgedb -c=edgedb -- \ - edgedb-show-secrets.sh --format=raw EDGEDB_SERVER_TLS_CERT + kubectl exec deploy/gel -c=gel -- \ + gel-show-secrets.sh --format=raw GEL_SERVER_TLS_CERT )" $ kubectl delete -f deployment.yaml $ kubectl apply -f deployment.yaml -Expose EdgeDB -============= +Expose Gel +========== .. code-block:: bash - $ kubectl expose deploy/edgedb --type LoadBalancer + $ kubectl expose deploy/gel --type LoadBalancer Get your instance's DSN @@ -203,17 +203,17 @@ Get the public-facing IP address of your database. $ kubectl get service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) - edgedb LoadBalancer 5656:30841/TCP + gel LoadBalancer 5656:30841/TCP Copy and paste the ``EXTERNAL-IP`` associated with the service named -``edgedb``. With this IP address, you can construct your instance's :ref:`DSN +``gel``. With this IP address, you can construct your instance's :ref:`DSN `: .. code-block:: bash - $ EDGEDB_IP= - $ EDGEDB_DSN="edgedb://edgedb:${PASSWORD}@${EDGEDB_IP}" + $ GEL_IP= + $ GEL_DSN="gel://admin:${PASSWORD}@${GEL_IP}" To print the final DSN, you can ``echo`` it. Note that you should only run this command on a computer you trust, like a personal laptop or sandboxed @@ -221,33 +221,33 @@ environment. .. code-block:: bash - $ echo $EDGEDB_DSN + $ echo $GEL_DSN The resuling DSN can be used to connect to your instance. To test it, try opening a REPL: .. code-block:: bash - $ edgedb --dsn $EDGEDB_DSN --tls-security insecure - EdgeDB 3.x (repl 3.x) + $ gel --dsn $GEL_DSN --tls-security insecure + Gel x.x (repl x.x) Type \help for help, \quit to quit. - edgedb> select "hello world!"; + gel> select "hello world!"; In development -------------- To make this instance easier to work with during local development, create an -alias using ``edgedb instance link``. +alias using :gelcmd:`instance link`. .. note:: - The command groups ``edgedb instance`` and ``edgedb project`` are not + The command groups :gelcmd:`instance` and :gelcmd:`project` are not intended to manage production instances. .. code-block:: bash - $ echo $PASSWORD | edgedb instance link \ - --dsn $EDGEDB_DSN \ + $ echo $PASSWORD | gel instance link \ + --dsn $GEL_DSN \ --password-from-stdin \ --non-interactive \ --trust-tls-cert \ @@ -259,19 +259,19 @@ name is expected; for instance, you can open a REPL: .. code-block:: bash - $ edgedb -I gcp_instance + $ gel -I gcp_instance Or apply migrations: .. code-block:: bash - $ edgedb -I gcp_instance migrate + $ gel -I gcp_instance migrate In production ------------- -To connect to this instance in production, set the ``EDGEDB_DSN`` environment -variable wherever you deploy your application server; EdgeDB's client +To connect to this instance in production, set the :gelenv:`DSN` environment +variable wherever you deploy your application server; Gel's client libraries read the value of this variable to know how to connect to your instance. @@ -279,5 +279,5 @@ Health Checks ============= Using an HTTP client, you can perform health checks to monitor the status of -your EdgeDB instance. Learn how to use them with our :ref:`health checks guide +your Gel instance. Learn how to use them with our :ref:`health checks guide `. diff --git a/docs/guides/deployment/health_checks.rst b/docs/guides/deployment/health_checks.rst index 2f9fda44bef..a92fa914f3c 100644 --- a/docs/guides/deployment/health_checks.rst +++ b/docs/guides/deployment/health_checks.rst @@ -4,7 +4,7 @@ Health Checks ============= -You may want to monitor the status of your EdgeDB instance. Is it up? Is it +You may want to monitor the status of your Gel instance. Is it up? Is it ready to take queries? This guide will show you to perform health checks using HTTP and the ``alive`` and ``ready`` endpoints. @@ -18,7 +18,7 @@ To check if the instance is alive, make a request to this endpoint: http://:/server/status/alive -To find your ````, you can run ``edgedb instance list`` to see a table of +To find your ````, you can run :gelcmd:`instance list` to see a table of all your instances along with their port numbers. The endpoint will respond with a ``200`` status code and ``"OK"`` as the @@ -35,7 +35,7 @@ To check if the instance is ready, make a request to this endpoint: http://:/server/status/ready As with the ``alive`` endpoint, you can find your ```` by running -``edgedb instance list`` to see a table of all your instances along with their +:gelcmd:`instance list` to see a table of all your instances along with their port numbers. The endpoint will respond with a ``200`` status code and ``"OK"`` as the diff --git a/docs/guides/deployment/heroku.rst b/docs/guides/deployment/heroku.rst index 7358c4e6312..bc7a4f22d55 100644 --- a/docs/guides/deployment/heroku.rst +++ b/docs/guides/deployment/heroku.rst @@ -4,15 +4,15 @@ Heroku ====== -:edb-alt-title: Deploying EdgeDB to Heroku +:edb-alt-title: Deploying Gel to Heroku -In this guide we show how to deploy EdgeDB to Heroku using a Heroku PostgreSQL +In this guide we show how to deploy Gel to Heroku using a Heroku PostgreSQL add-on as the backend. -Because of Heroku's architecture EdgeDB must be deployed with a web app on +Because of Heroku's architecture Gel must be deployed with a web app on Heroku. For this guide we will use a `todo app written in Node `_. -.. _todo-repo: https://github.com/edgedb/simpletodo/tree/main +.. _todo-repo: https://github.com/geldata/simpletodo/tree/main Prerequisites @@ -36,21 +36,21 @@ First copy the code, initialize a new git repo, and create a new heroku app. .. code-block:: bash - $ npx degit 'edgedb/simpletodo#main' simpletodo-heroku + $ npx degit 'geldata/simpletodo#main' simpletodo-heroku $ cd simpletodo-heroku $ git init --initial-branch main $ heroku apps:create --buildpack heroku/nodejs - $ edgedb project init --non-interactive + $ gel project init --non-interactive -If you are using the :ref:`JS query builder for EdgeDB ` then +If you are using the :ref:`JS query builder for Gel ` then you will need to check the ``dbschema/edgeql-js`` directory in to your git repo after running ``yarn edgeql-js``. The ``edgeql-js`` command cannot be run during the build step on Heroku because it needs access to a running -EdgeDB instance which is not available at build time on Heroku. +|Gel| instance which is not available at build time on Heroku. .. code-block:: bash - $ yarn install && npx @edgedb/generate edgeql-js + $ yarn install && npx @gel/generate edgeql-js The ``dbschema/edgeql-js`` directory was added to the ``.gitignore`` in the upstream project so we'll remove it here. @@ -64,7 +64,7 @@ Create a PostgreSQL Add-on ========================== Heroku's smallest PostgreSQL plan, Hobby Dev, limits the number of rows to -10,000, but EdgeDB's standard library uses more than 20,000 rows so we need to +10,000, but Gel's standard library uses more than 20,000 rows so we need to use a different plan. We'll use the `Standard 0 plan `_ for this guide. @@ -75,32 +75,32 @@ this guide. $ heroku addons:create --wait heroku-postgresql:standard-0 -Add the EdgeDB Buildpack -======================== +Add the Gel Buildpack +===================== -To run EdgeDB on Heroku we'll add the `EdgeDB buildpack `_. +To run Gel on Heroku we'll add the `Gel buildpack `_. -.. _buildpack: https://github.com/edgedb/heroku-buildpack-edgedb +.. _buildpack: https://github.com/geldata/heroku-buildpack-gel .. code-block:: bash $ heroku buildpacks:add \ --index 1 \ - https://github.com/edgedb/heroku-buildpack-edgedb.git + https://github.com/geldata/heroku-buildpack-gel.git -Use ``start-edgedb`` in the Procfile -==================================== +Use ``start-gel`` in the Procfile +================================= -To make EdgeDB available to a process prepend the command with ``start-edgedb`` -which is provided by the EdgeDB buildpack. For the sample application in this +To make Gel available to a process prepend the command with ``start-gel`` +which is provided by the Gel buildpack. For the sample application in this guide, the web process is started with the command ``npm start``. If you have other processes in your application besides/instead of web that need to access -EdgeDB those process commands should be prepended with ``start-edgedb`` too. +|Gel| those process commands should be prepended with ``start-gel`` too. .. code-block:: bash - $ echo "web: start-edgedb npm start" > Procfile + $ echo "web: start-gel npm start" > Procfile Deploy the App @@ -119,7 +119,7 @@ Scale the web dyno ================== The default dyno size has 512MB of memory which is a little under powered to -run EdgeDB. Scale the dyno so that it has 1GB of memory available. +run Gel. Scale the dyno so that it has 1GB of memory available. .. code-block:: bash @@ -129,5 +129,5 @@ Health Checks ============= Using an HTTP client, you can perform health checks to monitor the status of -your EdgeDB instance. Learn how to use them with our :ref:`health checks guide +your Gel instance. Learn how to use them with our :ref:`health checks guide `. diff --git a/docs/guides/deployment/index.rst b/docs/guides/deployment/index.rst index 6d6a225758c..b8ddcd33daa 100644 --- a/docs/guides/deployment/index.rst +++ b/docs/guides/deployment/index.rst @@ -5,13 +5,13 @@ Deployment ========== -EdgeDB can be hosted on all major cloud hosting platforms. The guides below +|Gel| can be hosted on all major cloud hosting platforms. The guides below demonstrate how to spin up both a managed PostgreSQL instance and a container -running EdgeDB `in Docker `_. +running Gel `in Docker `_. .. note:: Minimum requirements - As a rule of thumb, the EdgeDB Docker container requires 1GB RAM! Images + As a rule of thumb, the Gel Docker container requires 1GB RAM! Images with insufficient RAM may experience unexpected issues during startup. .. toctree:: diff --git a/docs/guides/index.rst b/docs/guides/index.rst index 4ff9475a11d..402d109d121 100644 --- a/docs/guides/index.rst +++ b/docs/guides/index.rst @@ -6,22 +6,20 @@ Guides ====== -These guides contain tutorials introducing EdgeDB to newcomers and +These guides contain tutorials introducing Gel to newcomers and how-tos providing more experienced users with examples and advice for tackling some common tasks. -If you are new to EdgeDB check out our :ref:`Quickstart ` +If you are new to Gel check out our :ref:`Quickstart ` guide! .. toctree:: :maxdepth: 1 - cloud/index deployment/index datamigrations/index tutorials/index auth/index migrations/index contributing/index - Cheatsheets diff --git a/docs/guides/migrations/guide.rst b/docs/guides/migrations/guide.rst index cff239554ba..ee835abd886 100644 --- a/docs/guides/migrations/guide.rst +++ b/docs/guides/migrations/guide.rst @@ -8,7 +8,7 @@ Basics EdgeQL is a strongly-typed language, which means that it moves checks and verification of your code to compile time as much as possible -instead of performing them at run time. EdgeDB's view is that a schema +instead of performing them at run time. Gel's view is that a schema should allow you to set types, constraints, expressions, and more so that you can confidently know what sort of behavior to expect from your data. Laying a type-safe foundation means a bit more thinking up front, but saves @@ -20,36 +20,36 @@ When you *do* eventually need to make a change, you'll need to migrate your schema from its current state to a new state. The basics of creating a project, modifying its schema, and migrating -it in EdgeDB are pretty easy: +it in Gel are pretty easy: -- Type ``edgedb project init`` to start a project, -- Open the newly created empty schema at ``dbschema/default.esdl`` and add +- Type :gelcmd:`project init` to start a project, +- Open the newly created empty schema at :dotgel:`dbschema/default` and add a simple type like ``SomeType { name: str; }`` inside the empty ``module`` -- Run ``edgedb migration create``, type ``y`` to confirm the change, - then run ``edgedb migrate``, and you are done! You can now +- Run :gelcmd:`migration create`, type ``y`` to confirm the change, + then run :gelcmd:`migrate`, and you are done! You can now ``insert SomeType;`` in your database to your heart's content. .. note:: If you ever feel like outright removing and creating an instance anew during this migration guide, you can use the command - ``edgedb instance destroy -I --force``. And if you want to + :gelcmd:`instance destroy -I --force`. And if you want to remove all existing migrations as well, you can manually delete them inside your ``/migrations`` folder (otherwise, the CLI will try to apply the migrations again when you recreate your instance with - ``edgedb migration create``). Once that is done, you will have a blank + :gelcmd:`migration create`). Once that is done, you will have a blank slate on which to start over again. -But many EdgeDB users have needs that go beyond these basics. In addition, +But many Gel users have needs that go beyond these basics. In addition, schema migrations are pretty interesting and teach you a lot about -what EdgeDB does behind the scenes. This guide will turn you from +what Gel does behind the scenes. This guide will turn you from a casual migration user into one with a lot more tools at hand, along -with a deeper understanding of the internals of EdgeDB at the same +with a deeper understanding of the internals of Gel at the same time. -EdgeDB's built-in tools are what make schema migrations easy, and +|Gel's| built-in tools are what make schema migrations easy, and the way they work is through a pretty interesting interaction between -EdgeDB's SDL (Schema Definition Language) and DDL (Data Definition +Gel's SDL (Schema Definition Language) and DDL (Data Definition Language). The first thing to understand about migrations is the difference between SDL and DDL, and how they are used. @@ -57,7 +57,7 @@ SDL: For humans =============== SDL, not DDL, is the primary way for you to create and migrate your -schema in EdgeDB. You don't need to work with DDL to use EdgeDB any +schema in Gel. You don't need to work with DDL to use Gel any more than you need to know how to change a tire to drive a car. SDL is built for humans to read, which is why it is said to be *declarative*. @@ -68,7 +68,7 @@ real life would be telling a friend to show up at your house at 6416 Riverside Way. You've declared what the final result should be, but it's up to your friend to find how to achieve it. -Now let's look at some real SDL and think about its role in EdgeDB. +Now let's look at some real SDL and think about its role in Gel. Here is a simple example of a schema: .. code-block:: sdl @@ -79,18 +79,18 @@ Here is a simple example of a schema: } } -If you have EdgeDB installed and want to follow along, type ``edgedb -project init`` and copy the above schema into your ``default.esdl`` +If you have Gel installed and want to follow along, run +:gelcmd:` project init` and copy the above schema into your :dotgel:`default` file inside the ``/dbschema`` folder it creates. Then save the file. .. note:: - While schema is usually contained inside the ``default.esdl`` file, - you can divide a schema over multiple files if you like. EdgeDB will - combine all ``.esdl`` files inside the ``/dbschema`` folder into a + While schema is usually contained inside the :dotgel:`default` file, + you can divide a schema over multiple files if you like. Gel will + combine all |.gel| files inside the ``/dbschema`` folder into a single schema. -Type ``edgedb`` to start the EdgeDB REPL, and, into the REPL, type +Type |gelcmd| to start the Gel REPL, and, into the REPL, type ``describe schema as sdl``. The output will be ``{'module default{};'}`` β€” nothing more than the empty ``default`` module. What happened? Our ``type User`` is nowhere to be found. @@ -100,12 +100,12 @@ person's house, it doesn't *do* anything on its own. With SDL you are declaring what you want the final result to be: a schema containing a single type called ``User``, with a property of type ``str`` called ``name``. -In order for a migration to happen, the EdgeDB server needs to receive +In order for a migration to happen, the Gel server needs to receive DDL statements telling it what changes to make, in the exact same way that you give instructions like "turn right at the next intersection" -to your friend who is trying to find your house. In EdgeDB's case, +to your friend who is trying to find your house. In Gel's case, these commands will start with words like ``create`` and ``drop`` -and ``alter`` to tell it what changes to make. EdgeDB accomplishes +and ``alter`` to tell it what changes to make. Gel accomplishes these changes by knowing how to turn your declarative SDL into a schema migration file that contains the DDL statements to accomplish the necessary changes. @@ -113,9 +113,9 @@ necessary changes. DDL: For computers (mostly) =========================== -To see what a schema migration file looks like, type ``edgedb migration -create``. Now look inside your ``/dbschema/migrations`` folder. You should -see a file called ``00001.esdl`` with the following, our first view into +To see what a schema migration file looks like, type :gelcmd:`migration +create`. Now look inside your ``/dbschema/migrations`` folder. You should +see a file called ``00001.edgeql`` with the following, our first view into what DDL looks like. .. code-block:: @@ -133,7 +133,7 @@ at all that doesn't already have a type called ``User``. Let's try one more small migration, in which we decide that we don't want the ``name`` property anymore. Once again, we are declaring the -final state: a ``User`` type with nothing inside. Update your ``default.esdl`` +final state: a ``User`` type with nothing inside. Update your :dotgel:`default` to look like this: .. code-block:: sdl @@ -142,7 +142,7 @@ to look like this: type User; } -As before, typing ``edgedb migration create`` will create a DDL statement to +As before, typing :gelcmd:`migration create` will create a DDL statement to change the schema from the current state to the one we have declared. This time we aren't starting from a blank schema, so the stakes are a bit higher. After all, dropping a property from a type will also drop all existing data @@ -174,7 +174,7 @@ a property called ``name`` anymore. .. note:: - EdgeDB commands inside the REPL use a backslash instead of the ``edgedb`` + Gel commands inside the REPL use a backslash instead of the |gelcmd| command, so you can migrate your schema inside the REPL by typing ``\migration create`` , followed by ``\migrate``. Not only are the comands shorter, but they also execute faster. This is because the database client @@ -194,7 +194,7 @@ Similarly, if you want add a property to an existing type and the property's type is a new scalar type, the database will need to create the new scalar type first. -Let's take a look at this by first getting EdgeDB to describe our +Let's take a look at this by first getting Gel to describe our schema to us. Typing ``describe schema;`` inside the REPL will display the following DDL statements: @@ -264,7 +264,7 @@ It's SDL, but the order matches that of the DDL statements. }; Although the schema produced with ``describe schema as sdl;`` may not match -the schema you've written inside ``default.esdl``, it will +the schema you've written inside :dotgel:`default`, it will show you the order in which statements were needed to reach this final schema. @@ -280,13 +280,13 @@ has no properties. type User; } -Creating a migration with ``edgedb migration create`` will result +Creating a migration with :gelcmd:`migration create` will result in two questions, one to confirm that we wanted to drop the ``name`` property, and another to drop the ``Name`` type. .. code-block:: bash - $ edgedb migration create + $ gel migration create did you drop property 'name' of object type 'default::User'? [y,n,l,c,b,s,q,?] > y @@ -302,7 +302,7 @@ First go into your ``/dbschema/migrations`` folder and delete the most recent ``.edgeql`` file that drops the property ``name`` and the scalar type ``Name``. Don't worry - the migration hasn't been applied yet, so you won't confuse the database by deleting it at this -point. And now type ``edgedb migration create --non-interactive``. +point. And now type :gelcmd:`migration create --non-interactive`. You'll see the same file generated, except that this time there weren't any questions to answer. A non-interactive migration will work as @@ -325,7 +325,7 @@ a single letter. Can you spot the difference? } The only difference from the current schema is that we would like -to change the property name ``name`` to ``nam``, but this time EdgeDB isn't +to change the property name ``name`` to ``nam``, but this time Gel isn't sure what change we wanted to make. Did we intend to: - Change ``name`` to ``nam`` and keep the existing data? @@ -338,14 +338,14 @@ some pretty helpful output: .. code-block:: edgeql-repl db> \migration create --non-interactive - EdgeDB intended to apply the following migration: + Gel intended to apply the following migration: ALTER TYPE default::User { ALTER PROPERTY name { RENAME TO nam; }; }; But confidence is 0.67, below minimum threshold of 0.99999 - Error executing command: EdgeDB is unable to make a decision. + Error executing command: Gel is unable to make a decision. Please run in interactive mode to confirm changes, or use `--allow-unsafe` @@ -392,7 +392,7 @@ look like this: This migration will alter the ``User`` type by creating a new property and dropping the old one. If that is what we wanted, then we can now type -``\migrate`` in the REPL or ``edgedb migrate`` at the command line to complete +``\migrate`` in the REPL or :gelcmd:`migrate` at the command line to complete the migration. Questions from the CLI @@ -456,7 +456,7 @@ Here is what that would look like: > y did you create object type 'default::User'? [y,n,l,c,b,s,q,?] > n - Error executing command: EdgeDB could not resolve migration with + Error executing command: Gel could not resolve migration with the provided answers. Please retry with different answers. ``l`` (or ``list``) @@ -503,7 +503,7 @@ The following two keys will stop the migration, but in different ways: This is also known as a 'split'. Pressing ``s`` will complete the migration at the current point. Any statements that you have applied will be applied, but the schema will not yet match the schema in your -``.esdl`` file(s). You can easily start another migration to complete +|.gel| file(s). You can easily start another migration to complete the remaining changes once you have applied the migration that was just created. This effectively splits the migration into two or more files. @@ -522,13 +522,13 @@ Sometimes you may want to initialize a database with some default data, or add some data to a migration that you have just created before you apply it. -EdgeDB assumes by default that a migration involves a change to your +|Gel| assumes by default that a migration involves a change to your schema, so it won't create a migration for you if it doesn't see a schema change: .. code-block:: bash - $ edgedb migration create + $ gel migration create No schema changes detected. So how do you create a migration with only data? To do this, just @@ -536,7 +536,7 @@ add ``--allow-empty`` to the command: .. code-block:: bash - $ edgedb migration create --allow-empty + $ gel migration create --allow-empty Created myproject/dbschema/migrations/00002.edgeql, id: m1xseswmheqzxutr55cu66ko4oracannpddujg7gkna2zsjpqm2g3a @@ -564,7 +564,7 @@ such as the following: delete User filter .name = 'User 2'; }; -The problem is, if you save that migration and run ``edgedb migrate``, the CLI +The problem is, if you save that migration and run :gelcmd:`migrate`, the CLI will complain that the migration hash doesn't match what it is supposed to be. However, it helpfully provides the reason: "Migration names are computed from the hash of the migration contents." @@ -594,9 +594,9 @@ will need to be: If you change the statement to read in exactly the way the output suggests, the migration will now work. -That's the manual way to do a data migration, but EdgeDB also has an -``edgedb migration edit`` command that will automate the process for you. -Using ``edgedb migration edit`` will open up the most recent migration for +That's the manual way to do a data migration, but Gel also has an +:gelcmd:`migration edit` command that will automate the process for you. +Using :gelcmd:`migration edit` will open up the most recent migration for you to change, and update the migration hash when you close the window. Aside from exclusive data migrations, you can also create a migration that @@ -604,15 +604,15 @@ combines schema changes *and* data. This is even easier, since it doesn't even require appending ``--allow-empty`` to the command. Just do the following: 1. Change your schema -2. Type ``edgedb migration create`` and respond to the CLI's questions +2. Type :gelcmd:`migration create` and respond to the CLI's questions 3. Add your queries to the file (best done on the bottom after the DDL statements have changed the schema) either manually or using - ``edgedb migration edit`` -4. Type ``edgedb migrate`` to migrate the schema. If you have changed the + :gelcmd:`migration edit` +4. Type :gelcmd:`migrate` to migrate the schema. If you have changed the schema file manually, copy the suggested name into the migration hash - and type ``edgedb migrate`` again. + and type :gelcmd:`migrate` again. -The `EdgeDB tutorial `_ is a good example of a database +The Gel tutorial is a good example of a database set up with both a schema migration and a data migration. Setting up a database with `schema changes in one file and default data in a second file `_ is a nice way to separate the two operations @@ -623,7 +623,7 @@ Squashing migrations Users often end up making many changes to their schema because of how effortless it is to do. (And in the next section we will learn -about ``edgedb watch``, which is even more effortless!) This leads to +about :gelcmd:`watch`, which is even more effortless!) This leads to an interesting side effect: lots of ``.edgeql`` files, many of which represent trials and approaches that don't end up making it to the final schema. @@ -637,7 +637,7 @@ to work through: .. code-block:: - Initializing EdgeDB instance... + Initializing Gel instance... Applying migrations... Applied m13brvdizqpva6icpcvmsc3fee2yt5j267uba6jugy6iugcbs2djkq (00001.edgeql) @@ -650,7 +650,7 @@ to work through: ...and so on... Project initialized. -To squash your migrations, just run ``edgedb migration create`` with the +To squash your migrations, just run :gelcmd:`migration create` with the ``--squash`` option. Running this command will first display some helpful info to keep in mind before committing to the operation: @@ -666,7 +666,7 @@ info to keep in mind before committing to the operation: 2. Ensure that other users of the database have the revision above or can create database from scratch. To check a specific instance, run: - edgedb -I migration log --from-db --newest-first --limit 1 + gel -I migration log --from-db --newest-first --limit 1 1. Merge version control branches that contain schema changes if possible. @@ -678,7 +678,7 @@ a single file. Fixups during a squash ---------------------- -If your schema doesn't match the schema in the database, EdgeDB will +If your schema doesn't match the schema in the database, Gel will prompt you to create a *fixup* file, which can be useful to, as the CLI says, "automate upgrading other instances to a squashed revision". You'll see fixups inside ``/dbschema/fixups``. Their file names @@ -727,12 +727,12 @@ Next, change to this schema **without migrating it**: nickname: str; } -Now run ``edgedb migration create --squash``. The output is first +Now run :gelcmd:`migration create --squash`. The output is first the same as with our previous squash: .. code-block:: bash - $ edgedb migration create --squash + $ gel migration create --squash Current database revision: m16awk2tzhtbupjrzoc4fikgw5okxpfnaazupb6rxudxwin2qfgy5q While squashing migrations is non-destructive, @@ -743,7 +743,7 @@ the same as with our previous squash: 2. Ensure that other users of the database have the revision above or can create database from scratch. To check a specific instance, run: - edgedb -I migration log --from-db --newest-first --limit 1 + gel -I migration log --from-db --newest-first --limit 1 3. Merge version control branches that contain schema changes if possible. @@ -786,13 +786,13 @@ working with git after doing a squash with a fixup. git add dbschema The normal migration process will update your migration history: - edgedb migrate + gel migrate We'll take its suggestion to apply the migration: .. code-block:: bash - $ edgedb migrate + $ gel migrate Applied m1v3vqmwif4ml3ucbzi555mjgm4myxs2husqemopo2sz2m7otr22ka (m16awk2tzhtbupjrzoc4fikgw5okxpfnaazupb6rxudxwin2qfgy5q- @@ -804,24 +804,24 @@ We'll take its suggestion to apply the migration: Squashing is limited to schema changes, so queries inside data migrations will be discarded during a squash. -EdgeDB Watch -============ +Gel Watch +========= -Another option when quickly iterating over schema changes is ``edgedb watch``. +Another option when quickly iterating over schema changes is :gelcmd:`watch`. This will create a long-running process that keeps track of every time you -save an ``.esdl`` file inside your ``/migrations`` folder, letting you know -if your changes have successfully compiled or not. The ``edgedb watch`` +save an |.gel| file inside your ``/migrations`` folder, letting you know +if your changes have successfully compiled or not. The :gelcmd:`watch` command itself will show the following input when the process starts up: .. code-block:: - Connecting to EdgeDB instance 'anything' at localhost:10700... - EdgeDB Watch initialized. - Hint: Use `edgedb migration create` and `edgedb migrate --dev-mode` + Connecting to Gel instance 'anything' at localhost:10700... + Gel Watch initialized. + Hint: Use `gel migration create` and `gel migrate --dev-mode` to apply changes once done. Monitoring "/home/instancename". -Unseen to the user, ``edgedb watch`` will begin creating individual migration +Unseen to the user, :gelcmd:`watch` will begin creating individual migration scripts for every time you save a change to one of your files. These are stored as separate "dev mode" migrations, which are sort of like preliminary migrations that haven't been turned into a standalone @@ -849,7 +849,7 @@ hit after making a change to the following schema: } } -You will see a quick "calculating diff" show up as ``edgedb watch`` checks +You will see a quick "calculating diff" show up as :gelcmd:`watch` checks to see that the change we made was a valid one. As the change we made was to a valid schema, the "calculating diff" message will disappear pretty quickly. @@ -867,19 +867,19 @@ more verbose. Let's add some incorrect syntax to the existing schema: } } -Once you hit save, ``edgedb watch`` will suddenly pipe up and inform you +Once you hit save, :gelcmd:`watch` will suddenly pipe up and inform you that the schema can't be resolved: .. code-block:: error: type 'default::i32' does not exist - β”Œβ”€ myproject/dbschema/default.esdl:5:25 + β”Œβ”€ myproject/dbschema/default.gel:5:25 β”‚ 5 β”‚ wrong_property: i32; β”‚ ^^^ error Schema migration error: - cannot proceed until .esdl files are fixed + cannot proceed until .gel files are fixed Once you correct the ``i32`` type to ``int32``, you will see a message letting you know that things are okay now. @@ -891,12 +891,12 @@ letting you know that things are okay now. The process will once again quieten down, but will continue to watch your schema and apply migrations to any changes you make to your schema. -``edgedb watch`` is best run in a separate instance of your command line so +:gelcmd:`watch` is best run in a separate instance of your command line so that you can take care of other tasks β€” including officially migrating when you are satisfied with your current schema β€” without having to stop the process. -If you are curious what is happening as ``edgedb watch`` does its thing, +If you are curious what is happening as :gelcmd:`watch` does its thing, try the following query after you have made some changes. It will return a few lists of applied migrations, grouped by the way they were generated. @@ -908,7 +908,7 @@ a few lists of applied migrations, grouped by the way they were generated. } by .generated_by; Some migrations will contain nothing in their ``generated_by`` property, -while those generated by ``edgedb watch`` will have a +while those generated by :gelcmd:`watch` will have a ``MigrationGeneratedBy.DevMode``. .. note:: @@ -918,30 +918,29 @@ while those generated by ``edgedb watch`` will have a show up if you directly change your schema by using DDL, which is generally not recommended. -Once you are satisfied with your changes while running ``edgedb watch``, -just create the migration with ``edgedb migration create`` and then +Once you are satisfied with your changes while running :gelcmd:`watch`, +just create the migration with :gelcmd:`migration create` and then apply them with one small tweak to the ``migrate`` command: -``edgedb migrate --dev-mode`` to let the CLI know to apply the migrations -made during dev mode that were made by ``edgedb watch``. +:gelcmd:`migrate --dev-mode` to let the CLI know to apply the migrations +made during dev mode that were made by :gelcmd:`watch`. Branches ======== -EdgeDB's branches can be a useful part of your schema migrations, especially +|Gel's| branches can be a useful part of your schema migrations, especially when you're developing new features or prototyping experimental features. By creating a new branch, you can isolate schema changes from your other branches. -Imagine a scenario in which your main branch is called ``main`` (which is the -default name for the initial branch) and your feature branch is called -``feature``. This is the ideal workflow for using an EdgeDB branch alongside a feature -branch in your VCS to develop a new feature: +Imagine a scenario in which your main branch is |main| and your feature branch +is called ``feature``. This is the ideal workflow for using an Gel branch +alongside a feature branch in your VCS to develop a new feature: -1. Create a new feature branch with :ref:`ref_cli_edgedb_branch_create` +1. Create a new feature branch with :ref:`ref_cli_gel_branch_create` 2. Build your feature -3. Pull any changes on ``main`` -4. Rebase your feature branch on ``main`` with - :ref:`ref_cli_edgedb_branch_rebase` -5. Merge ``feature`` onto ``main`` with :ref:`ref_cli_edgedb_branch_merge` +3. Pull any changes on |main| +4. Rebase your feature branch on |main| with + :ref:`ref_cli_gel_branch_rebase` +5. Merge ``feature`` onto |main| with :ref:`ref_cli_gel_branch_merge` The workflow is outlined in detail in :ref:`the branches guide in our "Get started" section `. @@ -951,11 +950,11 @@ started" section `. How rebasing works ------------------ -Rebasing the branch in step 4 above happens with a single command β€” ``edgedb -branch rebase main`` β€” but that one command has quite a bit going on under the -hood. Here's how it works: +Rebasing the branch in step 4 above happens with a single command β€” +:gelcmd:`branch rebase main` β€” but that one command has quite a bit going on +under the hood. Here's how it works: -1. The CLI first clones the ``main`` branch with the data into a ``temp`` +1. The CLI first clones the |main| branch with the data into a ``temp`` branch. 2. It introspects the migration histories of ``temp`` and the ``feature`` branch to establish where they diverge. @@ -972,7 +971,7 @@ So, you really want to use DDL? =============================== You might have a good reason to use a direct DDL statement or two -to change your schema. How do you make that happen? EdgeDB disables +to change your schema. How do you make that happen? Gel disables the usage of DDL by default if you have already carried out a migration through the recommended migration commands, so this attempt to use DDL will not work: @@ -988,7 +987,7 @@ will not work: β”‚ ^^^^^^^^^^^^^^^^^^ Use the migration commands instead. β”‚ = The `allow_bare_ddl` configuration variable is set to - 'NeverAllow'. The `edgedb migrate` command normally sets + 'NeverAllow'. The `gel migrate` command normally sets this to avoid accidental schema changes outside of the migration flow. @@ -1060,7 +1059,7 @@ you try to apply the change: Error executing command: Database must be updated to the last migration on the filesystem for `migration create`. Run: - edgedb migrate + gel migrate db> \migrate Error executing command: database applied migration @@ -1093,20 +1092,20 @@ see it with the following query: } Fortunately, the fix is not too hard: we can use the command -``edgedb migration extract``. This command will retrieve the migration(s) +:gelcmd:`migration extract`. This command will retrieve the migration(s) created using DDL and assign each of them a proper file name and hash inside the ``/dbschema/migrations`` folder, effectively giving them a proper position inside the migration flow. -Note that at this point your ``.esdl`` schema will still not match -the database schema, so if you were to type ``edgedb migration create`` +Note that at this point your |.gel| schema will still not match +the database schema, so if you were to type :gelcmd:`migration create` the CLI would then ask you if you want to drop the type that you just created - because it doesn't exist inside there. So be sure to change your schema to match the schema inside the database that you have manually changed via DDL. If in doubt, use ``describe schema as sdl`` -to compare or use ``edgedb migration create`` and check the output. +to compare or use :gelcmd:`migration create` and check the output. If the CLI is asking you if you want to drop a type, that means that -you forgot to add it to the schema inside your ``.esdl`` file(s). +you forgot to add it to the schema inside your |.gel| file(s). Multiple migrations to keep data @@ -1154,7 +1153,7 @@ make each ``User`` friends with all of the others: Now what happens if we now want to change ``multi friends`` to an ``array``? If we were simply changing a scalar property to another -property it would be easy, because EdgeDB would prompt us for a conversion +property it would be easy, because Gel would prompt us for a conversion expression, but a change from a link to a property is different: .. code-block:: sdl @@ -1184,11 +1183,11 @@ we will keep the ``friends`` link, while adding a new property called } } -Upon using ``edgedb migration create``, the CLI will simply ask us if we +Upon using :gelcmd:`migration create`, the CLI will simply ask us if we created a property called ``friend_names``. We haven't applied the migration yet, so we might as well put the data inside the same migration. A simple ``update`` will do the job! As we learned previously, -``edgedb migration edit`` is the easiest way to add data to a migration. Or +:gelcmd:`migration edit` is the easiest way to add data to a migration. Or you can manually add the ``update``, try to apply the migration, and change the migration hash to the output suggested by the CLI. @@ -1242,13 +1241,13 @@ We've now reached the most optional part of the migrations tutorial, but an interesting one for those curious about what goes on behind the scenes during a migration. -Migrations in EdgeDB before the advent of the ``edgedb project`` flow +Migrations in Gel before the advent of the :gelcmd:`project` flow were still automated but required more manual work if you didn't want to accept all of the suggestions provided by the server. This process is in fact still used to migrate even today; the CLI just facilitates it by making it easy to respond to the generated suggestions. -:ref:`Early EdgeDB migrations took place inside a transaction ` +:ref:`Early Gel migrations took place inside a transaction ` handled by the user that essentially went like this: .. code-block:: @@ -1268,7 +1267,7 @@ are going to have some fun with. You can see It is *very* finicky compared to the CLI, resulting in a failed transaction if any step along the way is different from the expected behavior, but is an entertaining challenge to try to get right if you want to -truly understand how migrations work in EdgeDB. +truly understand how migrations work in Gel. This process requires looking at the server's proposed solutions every step of the way, and these steps are best seen in JSON format. We can make @@ -1279,7 +1278,7 @@ this format as readable as possible with the following command: db> \set output-format json-pretty First, let's begin with the same same simple schema used in the previous -examples, via the regular ``edgedb migration create`` and ``edgedb migrate`` +examples, via the regular :gelcmd:`migration create` and :gelcmd:`migrate` commands. .. code-block:: sdl @@ -1392,10 +1391,10 @@ will be complete. OK: COMMIT MIGRATION Since this migration was created using direct DDL statements, -you will need to use ``edgedb migration extract`` to extract the latest +you will need to use :gelcmd:`migration extract` to extract the latest migration and give it a proper ``.edgeql`` file in the same way we did above in the "So you really wanted to use DDL but now regret it?" section. -.. _rfc: https://github.com/edgedb/rfcs/blob/master/text/1000-migrations.rst -.. _tutorial_files: https://github.com/edgedb/website/tree/main/content/tutorial/dbschema/migrations +.. _rfc: https://github.com/geldata/rfcs/blob/master/text/1000-migrations.rst +.. _tutorial_files: https://github.com/geldata/website/tree/main/content/tutorial/dbschema/migrations diff --git a/docs/guides/migrations/index.rst b/docs/guides/migrations/index.rst index d822aa11265..602f1a31d83 100644 --- a/docs/guides/migrations/index.rst +++ b/docs/guides/migrations/index.rst @@ -4,7 +4,7 @@ Schema migrations ================= -Welcome to the guide to EdgeDB migrations! Let's get started. +Welcome to the guide to Gel migrations! Let's get started. .. toctree:: :maxdepth: 2 diff --git a/docs/guides/migrations/tips.rst b/docs/guides/migrations/tips.rst index d2fe5500689..6c697ddd753 100644 --- a/docs/guides/migrations/tips.rst +++ b/docs/guides/migrations/tips.rst @@ -15,16 +15,6 @@ events. We'll start with this schema: -.. code-block:: sdl - :version-lt: 3.0 - - type Event { - required property name -> str; - link prev -> Event; - - # ... more properties and links - } - .. code-block:: sdl type Event { @@ -42,12 +32,12 @@ file we proceed with our first migration: .. code-block:: bash - $ edgedb migration create + $ gel migration create did you create object type 'default::Event'? [y,n,l,c,b,s,q,?] > y Created ./dbschema/migrations/00001.edgeql, id: m1v3ahcx5f43y6mlsdmlz2agnf6msbc7rt3zstiqmezaqx4ev2qovq - $ edgedb migrate + $ gel migrate Applied m1v3ahcx5f43y6mlsdmlz2agnf6msbc7rt3zstiqmezaqx4ev2qovq (00001.edgeql) @@ -70,26 +60,6 @@ It seems like having a ``next`` link would be useful, too. So we can define it as a computed link by using :ref:`backlink ` notation: -.. code-block:: sdl - :version-lt: 3.0 - - type Event { - required property name -> str; - - link prev -> Event; - link next := . y Created ./dbschema/migrations/00002.edgeql, id: m1qpukyvw2m4lmomoseni7vdmevk4wzgsbviojacyrqgiyqjp5sdsa - $ edgedb migrate + $ gel migrate Applied m1qpukyvw2m4lmomoseni7vdmevk4wzgsbviojacyrqgiyqjp5sdsa (00002.edgeql) @@ -146,30 +116,6 @@ many-to-one and so ``next`` is one-to-many, making it a *multi* link. Let's fix that by making the link ``prev`` a one-to-one, after all we're interested in building event chains, not trees. -.. code-block:: sdl - :version-lt: 3.0 - - type Event { - required property name -> str; - - link prev -> Event { - constraint exclusive; - }; - link next := . y Created ./dbschema/migrations/00003.edgeql, id: m17or2bfywuckdqeornjmjh7c2voxgatspcewyefcd4p2vbdepimoa - $ edgedb migrate + $ gel migrate Applied m17or2bfywuckdqeornjmjh7c2voxgatspcewyefcd4p2vbdepimoa (00003.edgeql) @@ -225,13 +171,6 @@ as the needs of the project evolve. We'll start with a fairly simple schema: -.. code-block:: sdl - :version-lt: 3.0 - - type User { - property name -> str; - } - .. code-block:: sdl type User { @@ -244,12 +183,12 @@ way of identifying users. .. code-block:: bash - $ edgedb migration create + $ gel migration create did you create object type 'default::User'? [y,n,l,c,b,s,q,?] > y Created ./dbschema/migrations/00001.edgeql, id: m14gwyorqqipfg7riexvbdq5dhgv7x6buqw2jaaulilcmywinmakzq - $ edgedb migrate + $ gel migrate Applied m14gwyorqqipfg7riexvbdq5dhgv7x6buqw2jaaulilcmywinmakzq (00001.edgeql) @@ -258,13 +197,6 @@ that for a little while we realize that we want to make ``name`` a *required property*. So we make the following change in the schema file: -.. code-block:: sdl - :version-lt: 3.0 - - type User { - required property name -> str; - } - .. code-block:: sdl type User { @@ -275,7 +207,7 @@ Next we try to migrate: .. code-block:: bash - $ edgedb migration create + $ gel migration create did you make property 'name' of object type 'default::User' required? [y,n,l,c,b,s,q,?] > y @@ -291,7 +223,7 @@ different from specifying a ``default`` value since it will be applied to *existing* objects, whereas the ``default`` applies to *new ones*. Unseen to us (unless we take a look at the automatically generated -``.edgeql`` files inside our ``/dbschema`` folder), EdgeDB has created +``.edgeql`` files inside our ``/dbschema`` folder), Gel has created a migration script that includes the following command to make our schema change happen. @@ -303,21 +235,12 @@ schema change happen. }; }; -We then run :ref:`ref_cli_edgedb_migrate` to apply the changes. +We then run :ref:`ref_cli_gel_migrate` to apply the changes. Next we realize that we actually want to make names unique, perhaps to avoid confusion or to use them as reliable human-readable identifiers (unlike ``id``). We update the schema again: -.. code-block:: sdl - :version-lt: 3.0 - - type User { - required property name -> str { - constraint exclusive; - } - } - .. code-block:: sdl type User { @@ -330,14 +253,14 @@ Now we proceed with the migration: .. code-block:: bash - $ edgedb migration create + $ gel migration create did you create constraint 'std::exclusive' of property 'name'? [y,n,l,c,b,s,q,?] > y Created ./dbschema/migrations/00003.edgeql, id: m1dxs3xbk4f3vhmqh6mjzetojafddtwlphp5a3kfbfuyvupjafevya - $ edgedb migrate - edgedb error: ConstraintViolationError: name violates exclusivity + $ gel migrate + gel error: ConstraintViolationError: name violates exclusivity constraint Some objects must have the same ``name``, so the migration can't be @@ -384,8 +307,8 @@ And then we apply the migration: .. code-block:: bash - $ edgedb migrate - edgedb error: could not read migrations in ./dbschema/migrations: could not + $ gel migrate + gel error: could not read migrations in ./dbschema/migrations: could not read migration file ./dbschema/migrations/00003.edgeql: migration name should be `m1t6slgcfne35vir2lcgnqkmaxsxylzvn2hanr6mijbj5esefsp7za` but ` m1dxs3xbk4f3vhmqh6mjzetojafddtwlphp5a3kfbfuyvupjafevya` is used instead. @@ -400,12 +323,12 @@ The migration tool detected that we've altered the file and asks us to update the migration name (acting as a checksum) if this was deliberate. This is done as a precaution against accidental changes. Since we've done this on purpose, we can update the file and run -:ref:`ref_cli_edgedb_migrate` again. +:ref:`ref_cli_gel_migrate` again. Finally, we evolved our schema all the way from having an optional property ``name`` all the way to making it both *required* and -*exclusive*. We've worked with the EdgeDB :ref:`migration tools -` to iron out the kinks throughout the +*exclusive*. We've worked with the Gel :ref:`migration tools +` to iron out the kinks throughout the migration process. At this point we take a quick look at the way duplicate ``User`` objects were resolved to decide whether we need to do anything more. We can use :eql:func:`re_test` to find names that @@ -435,16 +358,6 @@ character in an adventure game as the type of data we will evolve. Let's start with this schema: -.. code-block:: sdl - :version-lt: 3.0 - - scalar type CharacterClass extending enum; - - type Character { - required property name -> str; - required property class -> CharacterClass; - } - .. code-block:: sdl scalar type CharacterClass extending enum; @@ -458,14 +371,14 @@ We edit the schema file and perform our first migration: .. code-block:: bash - $ edgedb migration create + $ gel migration create did you create scalar type 'default::CharacterClass'? [y,n,l,c,b,s,q,?] > y did you create object type 'default::Character'? [y,n,l,c,b,s,q,?] > y Created ./dbschema/migrations/00001.edgeql, id: m1fg76t7fbvguwhkmzrx7jwki6jxr6dvkswzeepd5v66oxg27ymkcq - $ edgedb migrate + $ gel migrate Applied m1fg76t7fbvguwhkmzrx7jwki6jxr6dvkswzeepd5v66oxg27ymkcq (00001.edgeql) @@ -488,22 +401,6 @@ This way instead of a property ``class`` we want to end up with a link between the two explicitly. This means that we will need to have both the old and the new "class" information to begin with: -.. code-block:: sdl - :version-lt: 3.0 - - scalar type CharacterClass extending enum; - - type NewClass { - required property name -> str; - multi property skills -> str; - } - - type Character { - required property name -> str; - required property class -> CharacterClass; - link new_class -> NewClass; - } - .. code-block:: sdl scalar type CharacterClass extending enum; @@ -523,7 +420,7 @@ We update the schema file and migrate to the new state: .. code-block:: bash - $ edgedb migration create + $ gel migration create did you create object type 'default::NewClass'? [y,n,l,c,b,s,q,?] > y did you create link 'new_class' of object type 'default::Character'? @@ -531,7 +428,7 @@ We update the schema file and migrate to the new state: > y Created ./dbschema/migrations/00002.edgeql, id: m1uttd6f7fpiwiwikhdh6qyijb6pcji747ccg2cyt5357i3wsj3l3q - $ edgedb migrate + $ gel migrate Applied m1uttd6f7fpiwiwikhdh6qyijb6pcji747ccg2cyt5357i3wsj3l3q (00002.edgeql) @@ -542,7 +439,7 @@ empty migration: .. code-block:: bash - $ edgedb migration create --allow-empty + $ gel migration create --allow-empty Created ./dbschema/migrations/00003.edgeql, id: m1iztxroh3ifoeqmvxncy77whnaei6tp5j3sewyxtrfysronjkxgga @@ -580,8 +477,8 @@ reminder: .. code-block:: bash - $ edgedb migrate - edgedb error: could not read migrations in ./dbschema/migrations: + $ gel migrate + gel error: could not read migrations in ./dbschema/migrations: could not read migration file ./dbschema/migrations/00003.edgeql: migration name should be `m1e3d3eg3j2pr7acie4n5rrhaddyhkiy5kgckd5l7h5ysrpmgwxl5a` but @@ -598,7 +495,7 @@ The migration tool detected that we've altered the file and asks us to update the migration name (acting as a checksum) if this was deliberate. This is done as a precaution against accidental changes. Since we've done this on purpose, we can update the file and run -:ref:`ref_cli_edgedb_migrate` again. +:ref:`ref_cli_gel_migrate` again. We can see the changes after the data migration is complete: @@ -632,19 +529,6 @@ We can see the changes after the data migration is complete: Everything seems to be in order. It is time to clean up the old property and ``CharacterClass`` :eql:type:`enum`: -.. code-block:: sdl - :version-lt: 3.0 - - type NewClass { - required property name -> str; - multi property skills -> str; - } - - type Character { - required property name -> str; - link new_class -> NewClass; - } - .. code-block:: sdl type NewClass { @@ -662,7 +546,7 @@ just removed: .. code-block:: bash - $ edgedb migration create + $ gel migration create did you drop property 'class' of object type 'default::Character'? [y,n,l,c,b,s,q,?] > y @@ -670,7 +554,7 @@ just removed: > y Created ./dbschema/migrations/00004.edgeql, id: m1jdnz5bxjj6kjz2pylvudli5rvw4jyr2ilpb4hit3yutwi3bq34ha - $ edgedb migrate + $ gel migrate Applied m1jdnz5bxjj6kjz2pylvudli5rvw4jyr2ilpb4hit3yutwi3bq34ha (00004.edgeql) @@ -678,19 +562,6 @@ Now that the original property and scalar type are gone, we can rename the "new" components, so that they become ``class`` link and ``CharacterClass`` type, respectively: -.. code-block:: sdl - :version-lt: 3.0 - - type CharacterClass { - required property name -> str; - multi property skills -> str; - } - - type Character { - required property name -> str; - link class -> CharacterClass; - } - .. code-block:: sdl type CharacterClass { @@ -711,7 +582,7 @@ and deleting of closely interacting entities in the same migration. .. code-block:: bash - $ edgedb migration create + $ gel migration create did you rename object type 'default::NewClass' to 'default::CharacterClass'? [y,n,l,c,b,s,q,?] > y @@ -720,7 +591,7 @@ and deleting of closely interacting entities in the same migration. > y Created ./dbschema/migrations/00005.edgeql, id: m1ra4fhx2erkygbhi7qjxt27yup5aw5hkr5bekn5y5jeam5yn57vsa - $ edgedb migrate + $ gel migrate Applied m1ra4fhx2erkygbhi7qjxt27yup5aw5hkr5bekn5y5jeam5yn57vsa (00005.edgeql) @@ -767,14 +638,6 @@ character in an adventure game as the type of data we will evolve. Let's start with this schema: -.. code-block:: sdl - :version-lt: 3.0 - - type Character { - required property name -> str; - required property description -> str; - } - .. code-block:: sdl type Character { @@ -786,12 +649,12 @@ We edit the schema file and perform our first migration: .. code-block:: bash - $ edgedb migration create + $ gel migration create did you create object type 'default::Character'? [y,n,l,c,b,s,q,?] > y Created ./dbschema/migrations/00001.edgeql, id: m1paw3ogpsdtxaoywd6pl6beg2g64zj4ykhd43zby4eqh64yjad47a - $ edgedb migrate + $ gel migrate Applied m1paw3ogpsdtxaoywd6pl6beg2g64zj4ykhd43zby4eqh64yjad47a (00001.edgeql) @@ -812,14 +675,6 @@ However, as we keep developing our game it becomes apparent that this is less of a "description" and more of a "character class", so at first we just rename the property to reflect that: -.. code-block:: sdl - :version-lt: 3.0 - - type Character { - required property name -> str; - required property class -> str; - } - .. code-block:: sdl type Character { @@ -831,17 +686,17 @@ The migration gives us this: .. code-block:: bash - $ edgedb migration create + $ gel migration create did you rename property 'description' of object type 'default::Character' to 'class'? [y,n,l,c,b,s,q,?] > y Created ./dbschema/migrations/00002.edgeql, id: m1ljrgrofsqkvo5hsxc62mnztdhlerxp6ucdto262se6dinhuj4mqq - $ edgedb migrate + $ gel migrate Applied m1ljrgrofsqkvo5hsxc62mnztdhlerxp6ucdto262se6dinhuj4mqq (00002.edgeql) -EdgeDB detected that the change looked like a property was being +|Gel| detected that the change looked like a property was being renamed, which we confirmed. Since this was an existing property being renamed, the data is all preserved: @@ -861,7 +716,7 @@ applied across several developers, we will make it in the form of a .. code-block:: bash - $ edgedb migration create --allow-empty + $ gel migration create --allow-empty Created ./dbschema/migrations/00003.edgeql, id: m1qv2pdksjxxzlnujfed4b6to2ppuodj3xqax4p3r75yfef7kd7jna @@ -885,8 +740,8 @@ We're ready to apply the migration: .. code-block:: bash - $ edgedb migrate - edgedb error: could not read migrations in ./dbschema/migrations: + $ gel migrate + gel error: could not read migrations in ./dbschema/migrations: could not read migration file ./dbschema/migrations/00003.edgeql: migration name should be `m1ryafvp24g5eqjeu65zr4bqf6m3qath3lckfdhoecfncmr7zshehq` @@ -903,22 +758,12 @@ The migration tool detected that we've altered the file and asks us to update the migration name (acting as a checksum) if this was deliberate. This is done as a precaution against accidental changes. Since we've done this on purpose, we can update the file and run -:ref:`ref_cli_edgedb_migrate` again. +:ref:`ref_cli_gel_migrate` again. As the game becomes more stable there's no reason for the ``class`` to be a :eql:type:`str` anymore, instead we can use an :eql:type:`enum` to make sure that we don't accidentally use some invalid value for it. -.. code-block:: sdl - :version-lt: 3.0 - - scalar type CharacterClass extending enum; - - type Character { - required property name -> str; - required property class -> CharacterClass; - } - .. code-block:: sdl scalar type CharacterClass extending enum; @@ -935,7 +780,7 @@ order for the type change to work. .. code-block:: bash - $ edgedb migration create + $ gel migration create did you create scalar type 'default::CharacterClass'? [y,n,l,c,b,s,q,?] > y did you alter the type of property 'class' of object type @@ -943,7 +788,7 @@ order for the type change to work. > y Created ./dbschema/migrations/00004.edgeql, id: m1hc4yynkejef2hh7fvymvg3f26nmynpffksg7yvfksqufif6lulgq - $ edgedb migrate + $ gel migrate Applied m1hc4yynkejef2hh7fvymvg3f26nmynpffksg7yvfksqufif6lulgq (00004.edgeql) @@ -966,13 +811,6 @@ character in an adventure game as the type of data we will evolve. Let's start with this schema: -.. code-block:: sdl - :version-lt: 3.0 - - type Character { - required property name -> str; - } - .. code-block:: sdl type Character { @@ -983,12 +821,12 @@ We edit the schema file and perform our first migration: .. code-block:: bash - $ edgedb migration create + $ gel migration create did you create object type 'default::Character'? [y,n,l,c,b,s,q,?] > y Created ./dbschema/migrations/00001.edgeql, id: m1xvu7o4z5f5xfwuun2vee2cryvvzh5lfilwgkulmqpifo5m3dnd6a - $ edgedb migrate + $ gel migrate Applied m1xvu7o4z5f5xfwuun2vee2cryvvzh5lfilwgkulmqpifo5m3dnd6a (00001.edgeql) @@ -998,7 +836,7 @@ and fill it out as we like: .. code-block:: bash - $ edgedb migration create --allow-empty + $ gel migration create --allow-empty Created ./dbschema/migrations/00002.edgeql, id: m1lclvwdpwitjj4xqm45wp74y4wjyadljct5o6bsctlnh5xbto74iq @@ -1024,8 +862,8 @@ reminder: .. code-block:: bash - $ edgedb migrate - edgedb error: could not read migrations in ./dbschema/migrations: + $ gel migrate + gel error: could not read migrations in ./dbschema/migrations: could not read migration file ./dbschema/migrations/00002.edgeql: migration name should be `m1juin65wriqmb4vwg23fiyajjxlzj2jyjv5qp36uxenit5y63g2iq` but @@ -1041,7 +879,7 @@ The migration tool detected that we've altered the file and asks us to update the migration name (acting as a checksum) if this was deliberate. This is done as a precaution against accidental changes. Since we've done this on purpose, we can update the file and run -:ref:`ref_cli_edgedb_migrate` again. +:ref:`ref_cli_gel_migrate` again. .. code-block:: edgeql-diff @@ -1071,19 +909,6 @@ to a link, we will add the ``required link class`` right away, without any intermediate properties. So we end up with a schema like this: -.. code-block:: sdl - :version-lt: 3.0 - - type CharacterClass { - required property name -> str; - multi property skills -> str; - } - - type Character { - required property name -> str; - required link class -> CharacterClass; - } - .. code-block:: sdl type CharacterClass { @@ -1100,7 +925,7 @@ We go ahead and try to apply this new schema: .. code-block:: bash - $ edgedb migration create + $ gel migration create did you create object type 'default::CharacterClass'? [y,n,l,c,b,s,q,?] > y did you create link 'class' of object type 'default::Character'? @@ -1117,19 +942,6 @@ our strategy. We need a separate step where the ``class`` link is not *required* so that we can write some custom queries to handle the character classes: -.. code-block:: sdl - :version-lt: 3.0 - - type CharacterClass { - required property name -> str; - multi property skills -> str; - } - - type Character { - required property name -> str; - link class -> CharacterClass; - } - .. code-block:: sdl type CharacterClass { @@ -1147,7 +959,7 @@ it right away: .. code-block:: bash - $ edgedb migration create + $ gel migration create did you create object type 'default::CharacterClass'? [y,n,l,c,b,s,q,?] > y did you create link 'class' of object type 'default::Character'? @@ -1256,19 +1068,6 @@ classes: We're finally ready to make the ``class`` link *required*. We update the schema: -.. code-block:: sdl - :version-lt: 3.0 - - type CharacterClass { - required property name -> str; - multi property skills -> str; - } - - type Character { - required property name -> str; - required link class -> CharacterClass; - } - .. code-block:: sdl type CharacterClass { @@ -1285,7 +1084,7 @@ And we perform our final migration: .. code-block:: bash - $ edgedb migration create + $ gel migration create did you make link 'class' of object type 'default::Character' required? [y,n,l,c,b,s,q,?] > y @@ -1319,8 +1118,8 @@ Our attempt at migrating fails as we expected: .. code-block:: bash - $ edgedb migrate - edgedb error: MissingRequiredError: missing value for required link + $ gel migrate + gel error: MissingRequiredError: missing value for required link 'class' of object type 'default::Character' Detail: Failing object id is 'ee604992-c1b1-11ec-ad59-4f878963769f'. @@ -1328,7 +1127,7 @@ After removing the bugged ``Character``, we can migrate without any problems: .. code-block:: bash - $ edgedb migrate + $ gel migrate Applied m14yblybdo77c7bjtm6nugiy5cs6pl6rnuzo5b27gamy4zhuwjifia (00004.edgeql) @@ -1337,7 +1136,7 @@ Recovering lost migrations You can recover lost migration files, writing the database's current migration history to ``/dbschema/migrations`` by using the -:ref:`ref_cli_edgedb_migration_extract`. +:ref:`ref_cli_gel_migration_extract`. Getting the current migration ----------------------------- diff --git a/docs/guides/tutorials/chatgpt_bot.rst b/docs/guides/tutorials/chatgpt_bot.rst index 03bbdf08856..0f065baf909 100644 --- a/docs/guides/tutorials/chatgpt_bot.rst +++ b/docs/guides/tutorials/chatgpt_bot.rst @@ -4,21 +4,21 @@ ChatGPT ======= -:edb-alt-title: Build your own documentation chatbot with ChatGPT and EdgeDB +:edb-alt-title: Build your own documentation chatbot with ChatGPT and Gel *For additional context, check out* `our blog post about why and how we use ChatGPT via embeddings`_ *to create our β€œAsk AI” bot which answers questions -related to the EdgeDB docs.* +related to the Gel docs.* .. lint-off .. _our blog post about why and how we use ChatGPT via embeddings: - https://www.edgedb.com/blog/chit-chatting-with-edgedb-docs-via-chatgpt-and-pgvector + https://www.geldata.com/blog/chit-chatting-with-edgedb-docs-via-chatgpt-and-pgvector .. lint-on In this tutorial we're going to build a documentation chatbot with -`Next.js `_, `OpenAI `_, and EdgeDB. +`Next.js `_, `OpenAI `_, and Gel. .. warning:: @@ -81,7 +81,7 @@ Embedding generation requires two steps: 1. create embeddings for each section using `OpenAI's embeddings API `_ -2. store the embeddings data in EdgeDB using pgvector +2. store the embeddings data in Gel using pgvector Each time a user asks a question, our app will: @@ -185,69 +185,45 @@ will make it easier to import them. .. lint-on -Now, we'll create an instance of EdgeDB for our project, but first, we need to -install EdgeDB! +Now, we'll create an instance of Gel for our project. -Install the EdgeDB CLI ----------------------- +Create a local Gel instance +--------------------------- -*If you already have EdgeDB installed, you can skip to creating an instance.* - -Before we can create an instance for our project, we need to install the EdgeDB -CLI. On Linux or MacOS, run the following in your terminal and follow the -on-screen instructions: - -.. code-block:: bash - - $ curl --proto '=https' --tlsv1.2 -sSf https://sh.edgedb.com | sh - -Windows Powershell users can use this command: - -.. code-block:: powershell - - PS> iwr https://ps1.edgedb.com -useb | iex - -For other installation scenarios, see the "Additional installation methods" -section of `our "Install" page `_. - - -Create a local EdgeDB instance ------------------------------- - -To create our instance, let's initialize our project as an EdgeDB project. Run +To create our instance, let's initialize our project as an Gel project. Run the following in the root of the project: .. code-block:: bash - $ edgedb project init - No `edgedb.toml` found in `////docs-chatbot` + $ npx gel project init + No `gel.toml` found in `////docs-chatbot` or above Do you want to initialize a new project? [Y/n] > Y - Specify the name of EdgeDB instance to use with this project + Specify the name of Gel instance to use with this project [default: docs_chatbot]: > docs_chatbot - Checking EdgeDB versions... - Specify the version of EdgeDB to use with this project + Checking Gel versions... + Specify the version of Gel to use with this project [default: 3.2]: > 3.2 -The CLI should set up an EdgeDB project, an instance, and a default branch on +The CLI should set up an Gel project, an instance, and a default branch on that instance. -- Confirm project creation by checking for an ``edgedb.toml`` file and a +- Confirm project creation by checking for an |gel.toml| file and a ``dbschema`` directory in the project root. -- Confirm the instance is running with the ``edgedb instance list`` command. +- Confirm the instance is running with the :gelcmd:`instance list` command. Search for the name of the instance you've just created (``docs_chatbot`` if you're following along) and check the status. (Don't worry if the status is "inactive"; the status will change to "running" automatically when you connect to the instance.) -- Confirm you can connect to the created instance by running ``edgedb`` in the - terminal to connect to it via REPL or by running ``edgedb ui`` to connect +- Confirm you can connect to the created instance by running |gelcmd| in the + terminal to connect to it via REPL or by running :gelcmd:`ui` to connect using the UI. @@ -260,33 +236,33 @@ Create a ``.env.local`` file in the root of your new Next.js project. $ touch .env.local -We're going to add a couple of variables to that file to configure the EdgeDB +We're going to add a couple of variables to that file to configure the Gel client. We'll need to run a command on our new instance to get the value for one of those. Since we'll be using the `Edge runtime `_ in our Next.js project, the -edgedb-js client won't be able to access the Node.js filesystem APIs it usually +gel-js client won't be able to access the Node.js filesystem APIs it usually uses to automatically find your instance, so we need to provide the DSN for the instance instead. To get that, run this command: .. code-block:: bash - $ edgedb instance credentials --insecure-dsn + $ npx gel instance credentials --insecure-dsn Copy what it logs out. Open the ``.env.local`` file in your text editor and add this to it: .. code-block:: typescript - EDGEDB_DSN= - EDGEDB_CLIENT_TLS_SECURITY="insecure" + GEL_DSN= + GEL_CLIENT_TLS_SECURITY="insecure" Replace ```` with the value you copied earlier. -We're going to be using the EdgeDB HTTP client a bit later to connect to our +We're going to be using the Gel HTTP client a bit later to connect to our database, but it requires a trusted TLS/SSL certificate. Local development instances use self signed certificates, and using HTTPS with these certificates will result in an error. To work around this error, we allow the client to -ignore TLS by setting the ``EDGEDB_CLIENT_TLS_SECURITY`` variable to +ignore TLS by setting the :gelenv:`CLIENT_TLS_SECURITY` variable to ``"insecure"``. Bear in mind that this is only for local development, and you should always use TLS in production. @@ -313,8 +289,8 @@ Copy the new key. Re-open your ``.env.local`` file and add it like this: .. code-block:: typescript-diff - EDGEDB_DSN= - EDGEDB_CLIENT_TLS_SECURITY="insecure" + GEL_DSN= + GEL_CLIENT_TLS_SECURITY="insecure" + OPENAI_API_KEY="" Instead of ````, paste in the key you just created. @@ -366,7 +342,7 @@ since they are straightforward for OpenAI's language models to use. Create a ``docs`` folder in the root of the project. Here we will place our Markdown documentation files. You can grab the files we use from `the example project's GitHub repo -`_ or +`_ or add your own. (If you use your own, you may also want to adjust the system message we send to OpenAI later.) @@ -439,20 +415,20 @@ gives us context to feed to the LLM. We will need the token count later when calculating how many related sections fit inside the prompt context while staying under the model's token limit. -Open the empty schema file that was generated when we initialized the EdgeDB -project (located at ``dbschema/default.esdl`` from the project directory). +Open the empty schema file that was generated when we initialized the Gel +project (located at :dotgel:`dbschema/default` from the project directory). We'll walk through what we'll add to it, one step at a time. First, add this at the top of the file (above ``module default {``): .. code-block:: sdl - :caption: dbschema/default.esdl + :caption: dbschema/default.gel using extension pgvector; module default { # Schema will go here } -We are able to store embeddings and find similar embeddings in the EdgeDB +We are able to store embeddings and find similar embeddings in the Gel database because of the ``pgvector`` extension. In order to use it in our schema, we have to activate the ``ext::pgvector`` module with ``using extension pgvector`` at the beginning of the schema file. This module gives us access to @@ -465,7 +441,7 @@ Just below that, we can start building our module by creating a new scalar type. .. code-block:: sdl - :caption: dbschema/default.esdl + :caption: dbschema/default.gel using extension pgvector; module default { @@ -487,7 +463,7 @@ in our schema for this custom scalar. Now, the ``Section`` type: .. code-block:: sdl - :caption: dbschema/default.esdl + :caption: dbschema/default.gel using extension pgvector; module default { @@ -524,7 +500,7 @@ index. Put that all together, and your entire schema file should look like this: .. code-block:: sdl - :caption: dbschema/default.esdl + :caption: dbschema/default.gel using extension pgvector; @@ -546,8 +522,8 @@ We apply this schema by creating and running a migration. .. code-block:: bash - $ edgedb migration create - $ edgedb migrate + $ npx gel migration create + $ npx gel migrate .. note:: @@ -570,7 +546,7 @@ We apply this schema by creating and running a migration. to support this: .. code-block:: sdl-diff - :caption: dbschema/default.esdl + :caption: dbschema/default.gel type Section { + required path: str { @@ -593,23 +569,23 @@ libraries that will help us. .. code-block:: bash - $ npm install openai edgedb + $ npm install openai gel $ npm install \ - @edgedb/generate \ + @gel/generate \ gpt-tokenizer \ dotenv \ tsx \ --save-dev -The ``@edgedb/generate`` package provides a set of code generation tools that -are useful when developing an EdgeDB-backed applications with +The ``@gel/generate`` package provides a set of code generation tools that +are useful when developing an Gel-backed applications with TypeScript/JavaScript. We're going to write queries using our -:ref:`query builder `, but before we can, we +:ref:`query builder `, but before we can, we need to run the query builder generator. .. code-block:: bash - $ npx @edgedb/generate edgeql-js + $ npx @gel/generate edgeql-js Answer "y" when asked about adding the query builder to ``.gitignore``. @@ -642,7 +618,7 @@ tasks we need to perform. import { join } from "path"; import dotenv from "dotenv"; import { encode } from "gpt-tokenizer"; - import * as edgedb from "edgedb"; + import * as gel from "gel"; import e from "dbschema/edgeql-js"; import { initOpenAIClient } from "./utils"; @@ -811,7 +787,7 @@ Now, we generate embeddings from the content. We need to be careful about how we approach the API calls to generate the embeddings since they could have a big impact on how long generation takes, especially as your documentation grows. The simplest solution would be to make a single request to the API for -each section, but in the case of EdgeDB's documentation, which has around 3,000 +each section, but in the case of Gel's documentation, which has around 3,000 pages, this would take about half an hour. Since OpenAI's embeddings API can take not only a *single* string but also an @@ -917,7 +893,7 @@ Again, we'll break the ``storeEmbeddings`` function apart and walk through it. // … async function storeEmbeddings() { - const client = edgedb.createClient(); + const client = gel.createClient(); const sectionPaths = await walk("docs"); @@ -929,7 +905,7 @@ Again, we'll break the ``storeEmbeddings`` function apart and walk through it. } // … -We create our EdgeDB client and get our documentation paths by calling +We create our Gel client and get our documentation paths by calling ``walk``. We also log out some debug information showing how many sections were discovered. Then, we prep our ``Section`` objects by calling the ``prepareSectionsData`` function we just walked through and passing in the @@ -947,7 +923,7 @@ Next, we'll store this data. // Delete old data from the DB. await e.delete(e.Section).run(client); - // Bulk-insert all data into EdgeDB database. + // Bulk-insert all data into Gel database. const query = e.params({ sections: e.json }, ({ sections }) => { return e.for(e.json_array_unpack(sections), (section) => { return e.insert(e.Section, { @@ -976,7 +952,7 @@ Here's what the whole function looks like: // … async function storeEmbeddings() { - const client = edgedb.createClient(); + const client = gel.createClient(); const sectionPaths = await walk("docs"); @@ -987,7 +963,7 @@ Here's what the whole function looks like: // Delete old data from the DB. await e.delete(e.Section).run(client); - // Bulk-insert all data into EdgeDB database. + // Bulk-insert all data into Gel database. const query = e.params({ sections: e.json }, ({ sections }) => { return e.for(e.json_array_unpack(sections), (section) => { return e.insert(e.Section, { @@ -1017,7 +993,7 @@ into your ``generate-embeddings.ts`` file. import { join } from "path"; import dotenv from "dotenv"; import { encode } from "gpt-tokenizer"; - import * as edgedb from "edgedb"; + import * as gel from "gel"; import e from "dbschema/edgeql-js"; import { initOpenAIClient } from "@/utils"; @@ -1079,7 +1055,7 @@ into your ``generate-embeddings.ts`` file. } async function storeEmbeddings() { - const client = edgedb.createClient(); + const client = gel.createClient(); const sectionPaths = await walk("docs"); @@ -1090,7 +1066,7 @@ into your ``generate-embeddings.ts`` file. // Delete old data from the DB. await e.delete(e.Section).run(client); - // Bulk-insert all data into EdgeDB database. + // Bulk-insert all data into Gel database. const query = e.params({ sections: e.json }, ({ sections }) => { return e.for(e.json_array_unpack(sections), (section) => { return e.insert(e.Section, { @@ -1116,6 +1092,7 @@ Running the script Let's add a script to ``package.json`` that will invoke and execute ``generate-embeddings.ts``. +.. XXX gel version - fix .. code-block:: json-diff { @@ -1131,7 +1108,7 @@ Let's add a script to ``package.json`` that will invoke and execute + "embeddings": "tsx generate-embeddings.ts" }, "dependencies": { - "edgedb": "^1.3.5", + "gel": "^1.3.5", "next": "^13.4.19", "openai": "^4.0.1", "react": "18.2.0", @@ -1139,7 +1116,7 @@ Let's add a script to ``package.json`` that will invoke and execute "typescript": "5.1.6" }, "devDependencies": { - "@edgedb/generate": "^0.3.3", + "@gel/generate": "^0.3.3", "@types/node": "20.4.8", "@types/react": "18.2.18", "@types/react-dom": "18.2.7", @@ -1161,11 +1138,11 @@ a simple command: $ npm run embeddings -After the script finishes, open the EdgeDB UI. +After the script finishes, open the Gel UI. .. code-block:: bash - $ edgedb ui + $ npx gel ui Open your "main" branch and switch to the Data Explorer tab. You should see that the database has been updated with the embeddings and other relevant data. @@ -1234,7 +1211,7 @@ when we create the prompt from user's question and related sections. Let's talk briefly about runtimes. In the context of Next.js, "runtime" refers to the set of libraries, APIs, and general functionality available to your code during execution. Next.js supports `Node.js and Edge runtimes`_. (The "Edge" -runtime is coincidentally named but is not related to EdgeDB.) +runtime is coincidentally named but is not related to Gel.) Streaming is supported within both runtimes, but the implementation is a bit simpler when using Edge, so that's what we will use here. The Edge runtime is @@ -1260,7 +1237,7 @@ writing some configuration. :caption: app/api/generate-answer/route.ts import { stripIndents, oneLineTrim } from "common-tags"; - import * as edgedb from "edgedb"; + import * as gel from "gel"; import e from "dbschema/edgeql-js"; import { errors } from "../../constants"; import { initOpenAIClient } from "@/utils"; @@ -1269,7 +1246,7 @@ writing some configuration. const openai = initOpenAIClient(); - const client = edgedb.createHttpClient(); + const client = gel.createHttpClient(); export async function POST(req: Request) { // … @@ -1279,7 +1256,7 @@ writing some configuration. The first imports are templates from the ``common-tags`` library we installed -earlier. Then, we import the EdgeDB binding. The third import is the query +earlier. Then, we import the Gel binding. The third import is the query builder we described previously. We also import our errors and our OpenAI API client initializer function. @@ -1342,7 +1319,7 @@ build toward an answer. 2. If the query fails, we throw. If it passes, we generate embeddings for it using the OpenAI embedding API. This is handled by our ``getEmbedding`` function. -3. We get related documentation sections from the EdgeDB database. This is +3. We get related documentation sections from the Gel database. This is handled by ``getContext``. 4. We create the full prompt as our input to the chat completions API by combining the question, related documentation sections, and a system @@ -1473,7 +1450,7 @@ a variable named ``getSectionsQuery``. } ); -In the above code, we use EdgeDB's TypeScript query builder to create a query. +In the above code, we use Gel's TypeScript query builder to create a query. The query takes a few parameters: * ``target``: Embedding array to compare against to find related sections. In @@ -1494,7 +1471,7 @@ ordering, and limit clause. We use the ``cosine_distance`` function to calculate the similarity between the user's question and our documentation sections. We have access to this function -through EdgeDB's pgvector extension. We then filter on that property by +through Gel's pgvector extension. We then filter on that property by comparing it to the ``matchThreshold`` value we will pass when executing the query. @@ -1580,8 +1557,8 @@ response. We'll combine all of these parts in a function called function createFullPrompt(query: string, context: string) { const systemMessage = ` - As an enthusiastic EdgeDB expert keen to assist, - respond to questions referencing the given EdgeDB + As an enthusiastic Gel expert keen to assist, + respond to questions referencing the given Gel sections. If unable to help based on documentation, respond @@ -1590,7 +1567,7 @@ response. We'll combine all of these parts in a function called return stripIndents` ${oneLineTrim`${systemMessage}`} - EdgeDB sections: """ + Gel sections: """ ${context} """ @@ -1664,7 +1641,7 @@ Now, let's take a look at the whole thing. Copy and paste this into your :caption: app/api/generate-answer/route.ts import { stripIndents, oneLineTrim } from "common-tags"; - import * as edgedb from "edgedb"; + import * as gel from "gel"; import e from "dbschema/edgeql-js"; import { errors } from "../../constants"; import { initOpenAIClient } from "@/utils"; @@ -1673,7 +1650,7 @@ Now, let's take a look at the whole thing. Copy and paste this into your const openai = initOpenAIClient(); - const client = edgedb.createHttpClient(); + const client = gel.createHttpClient(); export async function POST(req: Request) { try { @@ -1795,8 +1772,8 @@ Now, let's take a look at the whole thing. Copy and paste this into your function createFullPrompt(query: string, context: string) { const systemMessage = ` - As an enthusiastic EdgeDB expert keen to assist, - respond to questions referencing the given EdgeDB + As an enthusiastic Gel expert keen to assist, + respond to questions referencing the given Gel sections. If unable to help based on documentation, respond @@ -1805,7 +1782,7 @@ Now, let's take a look at the whole thing. Copy and paste this into your return stripIndents` ${oneLineTrim`${systemMessage}`} - EdgeDB sections: """ + Gel sections: """ ${context} """ @@ -2294,15 +2271,15 @@ try tweaking: function in ``app/api/generate-answer/route.ts`` You can see the finished source code for this build in `our examples repo on -GitHub `_. +GitHub `_. You might also find our actual implementation interesting. You'll find it in -`our website repo `_. Pay close attention to +`our website repo `_. Pay close attention to the contents of `buildTools/gpt -`_, where the +`_, where the embedding generation happens and `components/gpt -`_, which contains +`_, which contains most of the UI for our chatbot. -If you have trouble with the build or just want to hang out with other EdgeDB +If you have trouble with the build or just want to hang out with other Gel users, please join `our awesome community on Discord `_! diff --git a/docs/guides/tutorials/cloudflare_workers.rst b/docs/guides/tutorials/cloudflare_workers.rst index 0c920b4484b..48edf1d5750 100644 --- a/docs/guides/tutorials/cloudflare_workers.rst +++ b/docs/guides/tutorials/cloudflare_workers.rst @@ -4,20 +4,20 @@ Cloudflare Workers ================== -:edb-alt-title: Using EdgeDB in Cloudflare Workers +:edb-alt-title: Using Gel in Cloudflare Workers -This guide demonstrates how to integrate EdgeDB with Cloudflare Workers to -build serverless applications that can interact with EdgeDB. +This guide demonstrates how to integrate Gel with Cloudflare Workers to +build serverless applications that can interact with Gel. It covers the following: - Setting up a new Cloudflare Worker project -- Configuring EdgeDB -- Using EdgeDB in a Cloudflare Worker +- Configuring Gel +- Using Gel in a Cloudflare Worker - Deploying the Worker to Cloudflare -You can use this project as a reference: `EdgeDB Cloudflare Workers Example`_. +You can use this project as a reference: `Gel Cloudflare Workers Example`_. Prerequisites ------------- @@ -27,7 +27,7 @@ Prerequisites Ensure you have the following installed: - `Node.js`_ -- :ref:`EdgeDB CLI ` +- :ref:`Gel CLI ` or juse ``$ npx gel`` .. _Sign up for a Cloudflare account: https://dash.cloudflare.com/sign-up .. _Node.js: https://nodejs.org/en/ @@ -51,61 +51,64 @@ Use the `create-cloudflare`_ package to create a new Cloudflare Worker project. Answer the prompts to create a new project. Pick the *"Hello World" Worker* template to get started. - + You'll be asked if you want to put your project on Cloudflare. -If you say yes, you'll need to sign in (if you haven't already). -If you don't want to deploy right away, switch to the project folder -you just made to start writing your code. When you're ready to deploy your +If you say yes, you'll need to sign in (if you haven't already). +If you don't want to deploy right away, switch to the project folder +you just made to start writing your code. When you're ready to deploy your project on Cloudflare, you can run ``npx wrangler deploy`` to push it. .. note:: Using Wrangler CLI - If you prefer using `Wrangler`_ to set up your worker, you can use the + If you prefer using `Wrangler`_ to set up your worker, you can use the :code:`wrangler generate` command to create a new project. .. _Wrangler: https://developers.cloudflare.com/workers/cli-wrangler -Configure EdgeDB -================= +Configure Gel +============= -You can use `EdgeDB Cloud`_ for a managed service or run EdgeDB locally. +You can use `Gel Cloud`_ for a managed service or run Gel locally. -.. _`EdgeDB Cloud`: https://www.edgedb.com/cloud +.. _`Gel Cloud`: https://www.geldata.com/cloud -**Local EdgeDB Setup (Optional for EdgeDB Cloud Users)** +**Local Gel Setup (Optional for Gel Cloud Users)** -If you're running EdgeDB locally, you can use the following command +If you're running Gel locally, you can use the following command to create a new instance: .. code-block:: bash - $ edgedb project init + $ gel project init -It creates an :code:`edgedb.toml` config file and a schema file -:code:`dbschema/default.esdl`. +It creates an |gel.toml| config file and a schema file +:code:`dbschema/default.gel`. -It also spins up an EdgeDB instance and associates it with the current +It also spins up an Gel instance and associates it with the current directory. -As long as you’re inside the project directory, all CLI commands will +As long as you're inside the project directory, all CLI commands will be executed against this instance. -You can run :code:`edgedb` in your terminal to open an -interactive REPL to your instance. +You can run |gelcmd| in your terminal to open an interactive REPL to your +instance. .. code-block:: bash - $ edgedb + $ gel + + # or + $ npx gel -**Install the EdgeDB npm package** +**Install the Gel npm package** .. code-block:: bash - $ npm install edgedb # or pnpm, yarn, bun + $ npm install gel # or pnpm, yarn, bun **Extend The Default Schema (Optional)** -You can extend the default schema, :code:`dbschema/default.esdl`, to define +You can extend the default schema, :code:`dbschema/default.gel`, to define your data model, and then try it out in the Cloudflare Worker code. Add new types to the schema file: @@ -125,24 +128,24 @@ Add new types to the schema file: } } -Then apply the schema schema to your EdgeDB instance: +Then apply the schema schema to your Gel instance: .. code-block:: bash - $ edgedb migration create - $ edgedb migrate + $ gel migration create + $ gel migrate -Using EdgeDB in a Cloudflare Worker -==================================== +Using Gel in a Cloudflare Worker +================================ -Open the :code:`index.ts` file from the :code:`src` directory in your project, +Open the :code:`index.ts` file from the :code:`src` directory in your project, and remove the default code. -To interact with your **local EdgeDB instance**, use the following code: +To interact with your **local Gel instance**, use the following code: .. code-block:: typescript - import * as edgedb from "edgedb"; + import * as gel from "gel"; export default { async fetch( @@ -150,9 +153,9 @@ To interact with your **local EdgeDB instance**, use the following code: env: Env, ctx: ExecutionContext, ): Promise { - const client = edgedb.createHttpClient({ + const client = gel.createHttpClient({ tlsSecurity: "insecure", - dsn: "", + dsn: "", }); const movies = await client.query(`select Movie { title }`); return new Response(JSON.stringify(movies, null, 2), { @@ -164,39 +167,39 @@ To interact with your **local EdgeDB instance**, use the following code: } satisfies ExportedHandler; -.. note:: EdgeDB DSN +.. note:: Gel DSN - Replace :code:`` with your EdgeDB DSN. - You can obtain your EdgeDB DSN from the command line by running: + Replace :code:`` with your Gel DSN. + You can obtain your Gel DSN from the command line by running: .. code-block:: bash - $ edgedb instance credentials --insecure-dsn + $ gel instance credentials --insecure-dsn .. note:: tlsSecurity - The :code:`tlsSecurity` option is set to :code:`insecure` to allow - connections to a local EdgeDB instance. This lets you test your + The :code:`tlsSecurity` option is set to :code:`insecure` to allow + connections to a local Gel instance. This lets you test your Cloudflare Worker locally. **Don't use this option in production.** -**Client Setup with EdgeDB Cloud** +**Client Setup with Gel Cloud** -If you're using EdgeDB Cloud, you can instead use the following code to +If you're using Gel Cloud, you can instead use the following code to set up the client: .. code-block:: typescript - const client = edgedb.createHttpClient({ - instanceName: env.EDGEDB_INSTANCE, - secretKey: env.EDGEDB_SECRET_KEY, + const client = gel.createHttpClient({ + instanceName: env.GEL_INSTANCE, + secretKey: env.GEL_SECRET_KEY, }); .. note:: Environment variables - You can obtain :code:`EDGEDB_INSTANCE` and :code:`EDGEDB_SECRET_KEY` - values from the EdgeDB Cloud dashboard. + You can obtain :gelenv:`INSTANCE` and :gelenv:`SECRET_KEY` + values from the Gel Cloud dashboard. -You will need to set the :code:`EDGEDB_INSTANCE` and :code:`EDGEDB_SECRET` +You will need to set the :gelenv:`INSTANCE` and :gelenv:`SECRET_KEY` environment variables in your Cloudflare Worker project. Add the following to your :code:`wrangler.toml` file: @@ -204,19 +207,19 @@ Add the following to your :code:`wrangler.toml` file: .. code-block:: toml [vars] - EDGEDB_INSTANCE = "your-edgedb-instance" - EDGEDB_SECRET_KEY = "your-edgedb-secret-key" + GEL_INSTANCE = "your-gel-instance" + GEL_SECRET_KEY = "your-gel-secret-key" Next, you can run :code:`wrangler types` to generate the types for your environment variables. **Running the Worker** -.. note:: Adding polyfills for Node.js +.. note:: Adding polyfills for Node.js - The :code:`edgedb` package currently uses Node.js built-in modules - that are not available in the Cloudflare Worker environment. - You have to add the following line to your :code:`wrangler.toml` file + The :code:`gel` package currently uses Node.js built-in modules + that are not available in the Cloudflare Worker environment. + You have to add the following line to your :code:`wrangler.toml` file to include the polyfills: .. code-block:: toml @@ -229,7 +232,7 @@ To run the worker locally, use the following command: $ npm run dev # or pnpm, yarn, bun -This will start a local server at :code:`http://localhost:8787`. +This will start a local server at :code:`http://localhost:8787`. Run :code:`curl http://localhost:8787` to see the response. **Deploying the Worker to Cloudflare** @@ -240,22 +243,22 @@ To deploy the worker to Cloudflare, use the following command: $ npm run deploy # or pnpm, yarn, bun -This will deploy the worker to Cloudflare and provide you with a URL +This will deploy the worker to Cloudflare and provide you with a URL to access your worker. Wrapping up =========== -Congratulations! You have successfully integrated EdgeDB with +Congratulations! You have successfully integrated Gel with Cloudflare Workers. -Here's a minimal starter project that you can use as a -reference: `EdgeDB Cloudflare Workers Example`_. +Here's a minimal starter project that you can use as a +reference: `Gel Cloudflare Workers Example`_. -Check out the `Cloudflare Workers documentation`_ for more information and +Check out the `Cloudflare Workers documentation`_ for more information and to learn about the various features and capabilities of Cloudflare Workers. -.. _`EdgeDB Cloudflare Workers Example`: - https://github.com/edgedb/edgedb-examples/tree/main/cloudflare-workers +.. _`Gel Cloudflare Workers Example`: + https://github.com/geldata/gel-examples/tree/main/cloudflare-workers .. _`Cloudflare Workers documentation`: https://developers.cloudflare.com/workers diff --git a/docs/guides/tutorials/django.rst b/docs/guides/tutorials/django.rst new file mode 100644 index 00000000000..25caa220891 --- /dev/null +++ b/docs/guides/tutorials/django.rst @@ -0,0 +1,285 @@ +.. _ref_guide_django: + +====== +Django +====== + +|Gel| supports SQL protocol for communicating with the database. This makes it possible to use it with Django by matching a Django schema to the |Gel| schema. You don't even need to figure out the conversion yourself because we have an automated tool for that. + +This tool becomes available when you install ``gel`` Python package. Once you have you |Gel| project setup, you can generate the Django schema with this command: + +.. code-block:: bash + + $ gel-orm django --out models.py + +The ``--out`` indicates the output file for the newly generated Django module. You will also need to include ``'gel.orm.django.gelmodels.apps.GelPGModel'`` into the ``INSTALLED_APPS`` for your Django app. + +Even though Django and |Gel| both view the schema as a bunch of types with fields and interconnections, there are still some differences between what |Gel| and Django can represent. + + +Properties +========== + +Property types must match the basic Postgres types supported by Django, so avoid any custom types as they will be skipped. Currently we support the following: + +* :eql:type:`std::uuid` - ``UUIDField`` +* :eql:type:`std::bigint` - ``DecimalField`` +* :eql:type:`std::bool` - ``BooleanField`` +* :eql:type:`std::bytes` - ``BinaryField`` +* :eql:type:`std::decimal` - ``DecimalField`` +* :eql:type:`std::float32` - ``FloatField`` +* :eql:type:`std::float64` - ``FloatField`` +* :eql:type:`std::int16` - ``SmallIntegerField`` +* :eql:type:`std::int32` - ``IntegerField`` +* :eql:type:`std::int64` - ``BigIntegerField`` +* :eql:type:`std::json` - ``JSONField`` +* :eql:type:`std::str` - ``TextField`` +* :eql:type:`std::datetime` - ``DateTimeField`` +* :eql:type:`cal::local_date` - ``DateField`` +* :eql:type:`cal::local_datetime` - ``DateTimeField`` +* :eql:type:`cal::local_time` - ``TimeField`` + +Extreme caution is needed for datetime field, the TZ aware and naive values are controlled in Django via settings (``USE_TZ``) and are mutually exclusive in the same app under default circumstances. + +Array properties are supported for all of the above types as well. + +Multi properties cannot be represented as they have no primary key at all. If you needs to reflect multi properties, consider replacing them with a single array property. + + +Links +===== + +Plain single links are reflected as a ``ForeignKey``. + +Multi links can be represented as link tables in Django schema and used as an implicit intermediary table. Creation and deletion of implicit intermediary table entries works. During creation both ``source`` and ``target`` are specified. While during deletion we rely on |Gel's| machinery to correctly handle deletion based on the target. + +Django is quite opinionated about the underlying SQL tables. One such important detail is that it requires a table to have a primary key (PK). Therefore, if a link has link properties we cannot reflect it at all because Django single column PK limits the ability to correctly update the link table. + +If you need to include these types of structures, you will need to make them as explicit intermediate objects connected with single links (which by default represent an N-to-1 relationship, so they are multi links in the reverse direction). + +Links with link properties can become objects in their own right: + +.. code-block:: sdl + + type User { + name: str; + # ... + } + + type UserGroup { + name: str; + # ... + + # Replace this kind of link with an explicit object + # multi link members: User; + } + + # this would replace a multi link members + type Members { + required source: UserGroup + required target: User + + # ... possibly additional payload that used + # to be link properties + } + +All links automatically generate the ``related_name`` relationships as well. The name of these back-links takes the format of ``_linkname_SourceName``, which mimics the EdgeQL version of backlinks ``.``. + +Properties +---------- + +The |Gel| schema declares a few properties: ``name`` for ``User`` and ``UserGroup`` as well as ``body`` for ``Post``. These get reflected as ``TextField`` in the corresponding models. As long as a property has a valid corresponding Django ``Field`` type it will be reflected in this manner. + +Links +----- + +Let's first look at the ``Post`` declaration in |Gel|. A ``Post`` has a link ``author`` pointing to a ``User``. So the reflected type ``Post`` has a ``ForeignKeys`` ``author`` which targets ``'User'``. + +Each reflected relationship also automatically declares a back-link via ``related_name``. The naming format is ``__``. For the ``author`` link the name of the back-link is ``_author_Post``. + +The ``User`` model has no links of its own just like in the |Gel| schema. + +``UserGroup`` model has a many-to-many relationship with ``User``. The model declares ``users`` as a ``ManyToManyField`` pointing to ``'User'``. The ``through`` relationship is ``UserGroupUsers``. The rules for ``related_name`` are the same as for ``ForeignKey`` and so ``_users_UserGroup`` is declared to be the back-link. + +App Settings +------------ + +In order to use these generated models in your Django app there are a couple of things that need to be added to the settings (typically found in ``settings.py``). + +First, we must add ``'gel_pg_models.apps.GelPGModel'`` to ``INSTALLED_APPS``. This will ensure that the |Gel| models are handled correctly, such as making ``id`` and ``gel_type_id`` read-only and managed by |Gel|. + +Second, we must configure the ``DATABASES`` to include the connection information for our |Gel| database (using PostgreSQL endpoint). + +Running :gelcmd:`instance credentials --json` command produces something like this: + +.. code-block:: bash + + $ gel instance credentials --json + { + "host": "localhost", + "port": 10715, + "user": "admin", + "password": "h632hKRuss6i9uQeMgEvRsuQ", + "database": "main", + "branch": "main", + "tls_cert_data": "-----BEGIN CERTIFICATE----- <...>", + "tls_ca": "-----BEGIN CERTIFICATE-----<...>", + "tls_security": "default" + } + +So we can use that to create the following ``DATABASES`` entry: + +.. code-block:: python + + DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.postgresql', + 'NAME': 'main', + 'USER': 'admin', + 'PASSWORD': 'h632hKRuss6i9uQeMgEvRsuQ', + 'HOST': 'localhost', + 'PORT': '10715', + } + } diff --git a/docs/guides/tutorials/graphql_apis_with_strawberry.rst b/docs/guides/tutorials/graphql_apis_with_strawberry.rst index 572bfceb75b..88466b53d99 100644 --- a/docs/guides/tutorials/graphql_apis_with_strawberry.rst +++ b/docs/guides/tutorials/graphql_apis_with_strawberry.rst @@ -2,17 +2,17 @@ Strawberry ========== -:edb-alt-title: Building a GraphQL API with EdgeDB and Strawberry +:edb-alt-title: Building a GraphQL API with Gel and Strawberry -EdgeDB allows you to query your database with GraphQL via the built-in GraphQL +|Gel| allows you to query your database with GraphQL via the built-in GraphQL extension. It enables you to expose GraphQL-driven CRUD APIs for all object types, their properties, links, and aliases. This opens up the scope for creating backend-less applications where the users will directly communicate with the database. You can learn more about that in the :ref:`GraphQL ` section of the docs. -However, as of now, EdgeDB is not ready to be used as a standalone backend. You -shouldn't expose your EdgeDB instance directly to the application’s frontend; +However, as of now, Gel is not ready to be used as a standalone backend. You +shouldn't expose your Gel instance directly to the application's frontend; this is insecure and will give all users full read/write access to your database. So, in this tutorial, we'll see how you can quickly create a simple GraphQL API without using the built-in extension, which will give the users @@ -28,9 +28,9 @@ and expose the objects and relationships as a GraphQL API. Using the GraphQL interface, you'll be able to fetch, create, update, and delete movie and actor objects in the database. `Strawberry `_ is a Python library that takes a code-first approach where you'll write your object schema -as Python classes. This allows us to focus more on how you can integrate EdgeDB +as Python classes. This allows us to focus more on how you can integrate Gel into your workflow and less on the idiosyncrasies of GraphQL itself. We'll also -use the EdgeDB client to communicate with the database, +use the Gel client to communicate with the database, `FastAPI `_ to build the authentication layer, and Uvicorn as the webserver. @@ -38,10 +38,10 @@ Prerequisites ============= Before we start, make sure you have :ref:`installed ` the -``edgedb`` command-line tool. Here, we'll use Python 3.10 and a few of its +|gelcmd| command-line tool. Here, we'll use Python 3.10 and a few of its latest features while building the APIs. A working version of this tutorial can be found `on Github -`_. +`_. Install the dependencies @@ -53,8 +53,8 @@ directory. .. code-block:: bash - $ git clone git@github.com:edgedb/edgedb-examples.git - $ cd edgedb-examples/strawberry-gql + $ git clone git@github.com:geldata/gel-examples.git + $ cd gel-examples/strawberry-gql Create a Python 3.10 virtual environment, activate it, and install the dependencies with this command: @@ -63,28 +63,28 @@ dependencies with this command: $ python3.10 -m venv .venv $ source .venv/bin/activate - $ pip install edgedb fastapi strawberry-graphql uvicorn[standard] + $ pip install gel fastapi strawberry-graphql uvicorn[standard] Initialize the database ^^^^^^^^^^^^^^^^^^^^^^^ -Now, let's initialize an EdgeDB project. From the project's root directory: +Now, let's initialize an Gel project. From the project's root directory: .. code-block:: bash - $ edgedb project init + $ gel project init Initializing project... - Specify the name of EdgeDB instance to use with this project + Specify the name of Gel instance to use with this project [default: strawberry_crud]: > strawberry_crud Do you want to start instance automatically on login? [y/n] > y - Checking EdgeDB versions... + Checking Gel versions... -Once you've answered the prompts, a new EdgeDB instance called +Once you've answered the prompts, a new Gel instance called ``strawberry_crud`` will be created and started. @@ -95,16 +95,16 @@ Let's test that we can connect to the newly started instance. To do so, run: .. code-block:: bash - $ edgedb + $ gel You should be connected to the database instance and able to see a prompt similar to this: :: - EdgeDB 2.x (repl 2.x) + Gel x.x (repl x.x) Type \help for help, \quit to quit. - edgedb> + gel> You can start writing queries here. However, the database is currently empty. Let's start designing the data model. @@ -117,14 +117,14 @@ The movie organization system will have two object typesβ€”**movies** and create a GraphQL API suite that'll allow us to fetch, create, update, and delete the objects while maintaining their relationships. -EdgeDB allows us to declaratively define the structure of the objects. The -schema lives inside ``.esdl`` file in the ``dbschema`` directory. It's -common to declare the entire schema in a single file ``dbschema/default.esdl``. +|Gel| allows us to declaratively define the structure of the objects. The +schema lives inside |.gel| file in the ``dbschema`` directory. It's +common to declare the entire schema in a single file :dotgel:`dbschema/default`. This is how our datatypes look: .. code-block:: sdl - # dbschema/default.esdl + # dbschema/default.gel module default { abstract type Auditable { @@ -161,7 +161,7 @@ This is how our datatypes look: Here, we've defined an ``abstract`` type called ``Auditable`` to take advantage -of EdgeDB's schema mixin system. This allows us to add a ``created_at`` +of Gel's schema mixin system. This allows us to add a ``created_at`` property to multiple types without repeating ourselves. The ``Actor`` type extends ``Auditable`` and inherits the ``created_at`` @@ -200,7 +200,7 @@ layer, and exposes the API to the webserver. Write the GraphQL schema ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Along with the database schema, to expose EdgeDB's object relational model as a +Along with the database schema, to expose Gel's object relational model as a GraphQL API, you'll also have to define a GraphQL schema that mirrors the object structure in the database. Strawberry allows us to express this schema via type annotated Python classes. We define the Strawberry schema in the @@ -213,10 +213,10 @@ via type annotated Python classes. We define the Strawberry schema in the import json # will be used later for serialization - import edgedb + import gel import strawberry - client = edgedb.create_async_client() + client = gel.create_async_client() @strawberry.type @@ -233,7 +233,7 @@ via type annotated Python classes. We define the Strawberry schema in the actors: list[Actor] | None = None Here, the GraphQL schema mimics our database schema. Similar to the ``Actor`` -and ``Movie`` types in the EdgeDB schema, here, both the ``Actor`` and +and ``Movie`` types in the Gel schema, here, both the ``Actor`` and ``Movie`` models have three attributes. Likewise, the ``actors`` attribute in the ``Movie`` model represents the link between movies and actors. @@ -290,7 +290,7 @@ is built in the ``schema.py`` file as follows: Here, the ``get_actors`` resolver method accepts an optional ``filter_name`` parameter and returns a list of ``Actor`` type objects. The optional ``filter_name`` parameter allows us to build the capability of filtering the -actor objects by name. Inside the method, we use the EdgeDB client to +actor objects by name. Inside the method, we use the Gel client to asynchronously query the data. The ``client.query_json`` method returns JSON serialized data which we use to create the ``Actor`` instances. Finally, we return the list of actor instances and the rest of the work is done by @@ -738,7 +738,7 @@ more insights into the implementation details of those mutations. Conclusion ========== -In this tutorial, you've seen how can use Strawberry and EdgeDB together to +In this tutorial, you've seen how can use Strawberry and Gel together to quickly build a fully-featured GraphQL API. Also, you have seen how FastAPI allows you add an authentication layer and serve the API in a secure manner. One thing to keep in mind here is, ideally, you'd only use GraphQL if you're diff --git a/docs/guides/tutorials/index.rst b/docs/guides/tutorials/index.rst index 6b7ce2f1a8d..ca2035a7df3 100644 --- a/docs/guides/tutorials/index.rst +++ b/docs/guides/tutorials/index.rst @@ -1,9 +1,9 @@ .. _ref_guide_tutorials: -==================== -Using EdgeDB with... -==================== +================= +Using Gel with... +================= .. toctree:: :maxdepth: 1 @@ -13,9 +13,12 @@ Using EdgeDB with... rest_apis_with_fastapi rest_apis_with_flask jupyter_notebook - phoenix_github_oauth graphql_apis_with_strawberry chatgpt_bot cloudflare_workers trpc + sqlalchemy + sqlmodel + django + prisma Bun diff --git a/docs/guides/tutorials/jupyter_notebook.rst b/docs/guides/tutorials/jupyter_notebook.rst index 493e099b8aa..926a31869b7 100644 --- a/docs/guides/tutorials/jupyter_notebook.rst +++ b/docs/guides/tutorials/jupyter_notebook.rst @@ -4,50 +4,49 @@ Jupyter Notebook ================ -:edb-alt-title: Using EdgeDB with Jupyter Notebook +:edb-alt-title: Using Gel with Jupyter Notebook 1. `Install Jupyter Notebook `__ -2. Install the EdgeDB Python library with ``pip install edgedb`` +2. Install the Gel Python library with ``pip install gel`` -3. Set the appropriate `connection environment variables - `__ required for your - EdgeDB instance +3. Set the appropriate :ref:`connection environment variables + ` required for your + Gel instance - **For EdgeDB Cloud instances** + **For Gel Cloud instances** - - ``EDGEDB_INSTANCE``- your instance name (``/``) - - ``EDGEDB_SECRET_KEY``- a secret key with permissions for the selected instance. + - :gelenv:`INSTANCE`- your instance name (``/``) + - :gelenv:`SECRET_KEY`- a secret key with permissions for the selected instance. .. note:: - You may create a secret key with the CLI by running ``edgedb cloud - secretkey create`` or in the `EdgeDB Cloud UI - `__. + You may create a secret key with the CLI by running :gelcmd:`cloud + secretkey create` or in the `Gel Cloud UI + `__. **For other remote instances** - - ``EDGEDB_DSN``- the DSN of your remote instance + - :gelenv:`DSN`- the DSN of your remote instance .. note:: DSNs take the following format: - ``edgedb://:@:/``. - Omit any segment, and EdgeDB will fall back to a default value listed - in `our DSN specification - `__ + :geluri:`:@:/`. + Omit any segment, and Gel will fall back to a default value listed + in :ref:`our DSN specification ` - **For local EdgeDB instances** + **For local Gel instances** - - ``EDGEDB_INSTANCE``- your instance name - - ``EDGEDB_USER`` & ``EDGEDB_PASSWORD`` + - :gelenv:`INSTANCE`- your instance name + - :gelenv:`USER` & :gelenv:`PASSWORD` .. note :: Usernames and passwords - EdgeDB creates an ``edgedb`` user by default, but the password is + Gel creates an |admin| user by default, but the password is randomized. You may set the password for this role by running ``alter - role edgedb { set password := ''; };`` or you may create a new + role admin { set password := ''; };`` or you may create a new role using ``create superuser role { set password := ''; };``. @@ -56,13 +55,13 @@ Jupyter Notebook 5. Create a new notebook. -6. In one of your notebook's blocks, import the EdgeDB library and run a query. +6. In one of your notebook's blocks, import the Gel library and run a query. .. code-block:: python - import edgedb + import gel - client = edgedb.create_client() + client = gel.create_client() def main(): query = "SELECT 1 + 1;" # Swap in any query you want diff --git a/docs/guides/tutorials/nextjs_app_router.rst b/docs/guides/tutorials/nextjs_app_router.rst index df876746eb5..48e4a28cef4 100644 --- a/docs/guides/tutorials/nextjs_app_router.rst +++ b/docs/guides/tutorials/nextjs_app_router.rst @@ -5,15 +5,15 @@ Next.js (App Router) ==================== :edb-alt-title: Building a simple blog application with - EdgeDB and Next.js (App Router) + Gel and Next.js (App Router) We're going to build a simple blog application with -`Next.js `_ and EdgeDB. Let's start by scaffolding our +`Next.js `_ and Gel. Let's start by scaffolding our app with Next.js's ``create-next-app`` tool. -You'll be prompted to provide a name (we'll use ``nextjs-blog``) for your -app and choose project options. For this tutorial, we'll go with the -recommended settings including TypeScript, App Router, and +You'll be prompted to provide a name (we'll use ``nextjs-blog``) for your +app and choose project options. For this tutorial, we'll go with the +recommended settings including TypeScript, App Router, and **opt-ing out** of the ``src/`` directory. .. code-block:: bash @@ -26,8 +26,8 @@ recommended settings including TypeScript, App Router, and βœ” Would you like to use App Router? (recommended) Yes βœ” Would you like to customize the default import alias (@/*) Yes -The scaffolding tool will create a simple Next.js app and install its -dependencies. Once it's done, you can navigate to the app's directory and +The scaffolding tool will create a simple Next.js app and install its +dependencies. Once it's done, you can navigate to the app's directory and start the development server. .. code-block:: bash @@ -35,8 +35,8 @@ start the development server. $ cd nextjs-blog $ npm dev # or yarn dev or pnpm dev or bun run dev -When the dev server starts, it will log out a local URL. -Visit that URL to see the default Next.js homepage. At this +When the dev server starts, it will log out a local URL. +Visit that URL to see the default Next.js homepage. At this point the app's file structure looks like this: .. code-block:: @@ -57,14 +57,14 @@ point the app's file structure looks like this: β”œβ”€β”€ next.tsx └── vercel.svg -There's an async function ``Home`` defined in ``app/page.tsx`` that renders -the homepage. It's a +There's an async function ``Home`` defined in ``app/page.tsx`` that renders +the homepage. It's a `Server Component `_ -which lets you integrate server-side logic directly -into your React components. Server Components are executed on the server and -can fetch data from a database or an API. We'll use this feature to load blog -posts from an EdgeDB database. +rendering/server-components>`_ +which lets you integrate server-side logic directly +into your React components. Server Components are executed on the server and +can fetch data from a database or an API. We'll use this feature to load blog +posts from an Gel database. Updating the homepage --------------------- @@ -88,11 +88,11 @@ static data. Replace the contents of ``app/page.tsx`` with the following. { id: 'post1', title: 'This one weird trick makes using databases fun', - content: 'Use EdgeDB', + content: 'Use Gel', }, { id: 'post2', - title: 'How to build a blog with EdgeDB and Next.js', + title: 'How to build a blog with Gel and Next.js', content: "Let's start by scaffolding our app with `create-next-app`.", }, ] @@ -124,57 +124,56 @@ After saving, you can refresh the page to see the blog posts. Clicking on a post title will take you to a page that doesn't exist yet. We'll create that page later in the tutorial. -Initializing EdgeDB -------------------- +Initializing Gel +---------------- -Now let's spin up a database for the app. You have two options to initialize -an EdgeDB project: using ``npx edgedb`` without installing the CLI, or -installing the edgedb CLI directly. In this tutorial, we'll use the first -option. If you prefer to install the CLI, see the -`EdgeDB CLI installation guide `_ -for more information. +Now let's spin up a database for the app. You have two options to initialize +an Gel project: using ``$ npx gel`` without installing the CLI, or +installing the gel CLI directly. In this tutorial, we'll use the first +option. If you prefer to install the CLI, see the +:ref:`Gel CLI guide ` for more information. From the application's root directory, run the following command: .. code-block:: bash - $ npx edgedb project init - No `edgedb.toml` found in `~/nextjs-blog` or above + $ npx gel project init + No `gel.toml` found in `~/nextjs-blog` or above Do you want to initialize a new project? [Y/n] > Y - Specify the name of EdgeDB instance to use with this project [default: + Specify the name of Gel instance to use with this project [default: nextjs_blog]: > nextjs_blog - Checking EdgeDB versions... - Specify the version of EdgeDB to use with this project [default: x.x]: + Checking Gel versions... + Specify the version of Gel to use with this project [default: x.x]: > β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Project directory β”‚ ~/nextjs-blog β”‚ - β”‚ Project config β”‚ ~/nextjs-blog/edgedb.toml β”‚ + β”‚ Project config β”‚ ~/nextjs-blog/gel.toml β”‚ β”‚ Schema dir (empty) β”‚ ~/nextjs-blog/dbschema β”‚ β”‚ Installation method β”‚ portable package β”‚ β”‚ Start configuration β”‚ manual β”‚ β”‚ Version β”‚ x.x β”‚ β”‚ Instance name β”‚ nextjs_blog β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - Initializing EdgeDB instance... + Initializing Gel instance... Applying migrations... Everything is up to date. Revision initial. Project initialized. -This process has spun up an EdgeDB instance called ``nextjs_blog`` and +This process has spun up an Gel instance called ``nextjs_blog`` and associated it with your current directory. As long as you're inside that directory, CLI commands and client libraries will be able to connect to the linked instance automatically, without additional configuration. -To test this, run the ``edgedb`` command to open a REPL to the linked instance. +To test this, run the |gelcmd| command to open a REPL to the linked instance. .. code-block:: bash - $ edgedb - EdgeDB x.x (repl x.x) + $ gel + Gel x.x (repl x.x) Type \help for help, \quit to quit. - edgedb> select 2 + 2; + gel> select 2 + 2; {4} > @@ -184,20 +183,20 @@ change that. The project initialization process also created a new subdirectory in our project called ``dbschema``. This is folder that contains everything -pertaining to EdgeDB. Currently it looks like this: +pertaining to Gel. Currently it looks like this: .. code-block:: dbschema - β”œβ”€β”€ default.esdl + β”œβ”€β”€ default.gel └── migrations -The ``default.esdl`` file will contain our schema. The ``migrations`` +The :dotgel:`default` file will contain our schema. The ``migrations`` directory is currently empty, but will contain our migration files. Let's -update the contents of ``default.esdl`` with the following simple blog schema. +update the contents of :dotgel:`default` with the following simple blog schema. .. code-block:: sdl - :caption: dbschema/default.esdl + :caption: dbschema/default.gel module default { type BlogPost { @@ -210,14 +209,14 @@ update the contents of ``default.esdl`` with the following simple blog schema. .. note:: - EdgeDB lets you split up your schema into different ``modules`` but it's + Gel lets you split up your schema into different ``modules`` but it's common to keep your entire schema in the ``default`` module. Save the file, then let's create our first migration. .. code-block:: bash - $ npx edgedb migration create + $ npx gel migration create did you create object type 'default::BlogPost'? [y,n,l,c,b,s,q,?] > y Created ./dbschema/migrations/00001.edgeql @@ -228,62 +227,62 @@ our database. Let's do that. .. code-block:: bash - $ npx edgedb migrate + $ npx gel migrate Applied m1fee6oypqpjrreleos5hmivgfqg6zfkgbrowx7sw5jvnicm73hqdq (00001.edgeql) Our database now has a schema consisting of the ``BlogPost`` type. We can -create some sample data from the REPL. Run the ``edgedb`` command to re-open +create some sample data from the REPL. Run the |gelcmd| command to re-open the REPL. .. code-block:: bash - $ edgedb - EdgeDB 4.x (repl 4.x) + $ gel + Gel x.x (repl x.x) Type \help for help, \quit to quit. - edgedb> + gel> Then execute the following ``insert`` statements. .. code-block:: edgeql-repl - edgedb> insert BlogPost { - ....... title := "This one weird trick makes using databases fun", - ....... content := "Use EdgeDB" - ....... }; + gel> insert BlogPost { + .... title := "This one weird trick makes using databases fun", + .... content := "Use Gel" + .... }; {default::BlogPost {id: 7f301d02-c780-11ec-8a1a-a34776e884a0}} - edgedb> insert BlogPost { - ....... title := "How to build a blog with EdgeDB and Next.js", - ....... content := "Let's start by scaffolding our app..." - ....... }; + gel> insert BlogPost { + .... title := "How to build a blog with Gel and Next.js", + .... content := "Let's start by scaffolding our app..." + .... }; {default::BlogPost {id: 88c800e6-c780-11ec-8a1a-b3a3020189dd}} Loading posts with React Server Components ------------------------------------------ -Now that we have a couple posts in the database, let's load them into our +Now that we have a couple posts in the database, let's load them into our Next.js app. -To do that, we'll need the ``edgedb`` client library. Let's install that from +To do that, we'll need the ``gel`` client library. Let's install that from NPM: .. code-block:: bash - $ npm install edgedb - # or yarn add edgedb or pnpm add edgedb or bun add edgedb + $ npm install gel + # or 'yarn add gel' or 'pnpm add gel' or 'bun add gel' Then go to the ``app/page.tsx`` file to replace the static data with the blogposts fetched from the database. -To fetch these from the homepage, we'll create an EdgeDB client and use the -``.query()`` method to fetch all the posts in the database with a +To fetch these from the homepage, we'll create an Gel client and use the +``.query()`` method to fetch all the posts in the database with a ``select`` statement. .. code-block:: tsx-diff :caption: app/page.tsx import Link from 'next/link' - + import { createClient } from 'edgedb'; + + import { createClient } from 'gel'; type Post = { id: string @@ -297,11 +296,11 @@ To fetch these from the homepage, we'll create an EdgeDB client and use the - { - id: 'post1', - title: 'This one weird trick makes using databases fun', - - content: 'Use EdgeDB', + - content: 'Use Gel', - }, - { - id: 'post2', - - title: 'How to build a blog with EdgeDB and Next.js', + - title: 'How to build a blog with Gel and Next.js', - content: "Start by scaffolding our app with `create-next-app`.", - }, - ] @@ -339,7 +338,7 @@ When you refresh the page, you should see the blog posts. Generating the query builder ---------------------------- -Since we're using TypeScript, it makes sense to use EdgeDB's powerful query +Since we're using TypeScript, it makes sense to use Gel's powerful query builder. This provides a schema-aware client API that makes writing strongly typed EdgeQL queries easy and painless. The result type of our queries will be automatically inferred, so we won't need to manually type something like @@ -349,20 +348,20 @@ First, install the generator to your project. .. code-block:: bash - $ npm install --save-dev @edgedb/generate - $ # or yarn add --dev @edgedb/generate - $ # or pnpm add --dev @edgedb/generate - $ # or bun add --dev @edgedb/generate + $ npm install --save-dev @gel/generate + $ # or yarn add --dev @gel/generate + $ # or pnpm add --dev @gel/generate + $ # or bun add --dev @gel/generate Then generate the query builder with the following command. .. code-block:: bash - $ npx @edgedb/generate edgeql-js + $ npx @gel/generate edgeql-js Generating query builder... Detected tsconfig.json, generating TypeScript files. To override this, use the --target flag. - Run `npx @edgedb/generate --help` for full options. + Run `npx @gel/generate --help` for full options. Introspecting database schema... Writing files to ./dbschema/edgeql-js Generation complete! 🀘 @@ -388,7 +387,7 @@ instead. :caption: app/page.tsx import Link from 'next/link' - import { createClient } from 'edgedb'; + import { createClient } from 'gel'; + import e from '@/dbschema/edgeql-js'; - type Post = { @@ -411,7 +410,7 @@ instead. + content: true, + })); + const posts = await selectPosts.run(client); - + return (

Posts

@@ -458,8 +457,8 @@ Add the following code in ``app/post/[id]/page.tsx``: .. code-block:: tsx :caption: app/post/[id]/page.tsx - - import { createClient } from 'edgedb' + + import { createClient } from 'gel' import e from '@/dbschema/edgeql-js' import Link from 'next/link' @@ -496,9 +495,9 @@ Add the following code in ``app/post/[id]/page.tsx``: ) } -We are again using a Server Component to fetch the post from the database. -This time, we're using the ``filter_single`` method to filter the -``BlogPost`` type by its ``id``. We're also using the ``uuid`` function +We are again using a Server Component to fetch the post from the database. +This time, we're using the ``filter_single`` method to filter the +``BlogPost`` type by its ``id``. We're also using the ``uuid`` function from the query builder to convert the ``id`` parameter to a UUID. Now, click on one of the blog post links on the homepage. This should bring @@ -507,46 +506,46 @@ you to ``/post/``. Deploying to Vercel ------------------- -You can deploy an EdgeDB instance on the EdgeDB Cloud or +You can deploy an Gel instance on the Gel Cloud or on your preferred cloud provider. We'll cover both options here. -With EdgeDB Cloud -================= +With Gel Cloud +============== -**#1 Deploy EdgeDB** +**#1 Deploy Gel** -First, sign up for an account at -`cloud.edgedb.com `_ and create a new instance. -Create and make note of a secret key for your EdgeDB Cloud instance. You -can create a new secret key from the "Secret Keys" tab in the EdgeDB Cloud +First, sign up for an account at +`cloud.geldata.com `_ and create a new instance. +Create and make note of a secret key for your Gel Cloud instance. You +can create a new secret key from the "Secret Keys" tab in the Gel Cloud console. We'll need this later to connect to the database from Vercel. -Run the following command to migrate the project to the EdgeDB Cloud: +Run the following command to migrate the project to the Gel Cloud: .. code-block:: bash - $ npx edgedb migrate -I / + $ npx gel migrate -I / .. note:: - Alternatively, if you want to restore your data from a local instance to - the cloud, you can use the ``edgedb dump`` and ``edgedb restore`` commands. + Alternatively, if you want to restore your data from a local instance to + the cloud, you can use the :gelcmd:`dump` and :gelcmd:`restore` commands. .. code-block:: bash - $ npx edgedb dump - $ npx edgedb restore -I / + $ npx gel dump + $ npx gel restore -I / -The migrations and schema will be automatically applied to the +The migrations and schema will be automatically applied to the cloud instance. **#2 Set up a `prebuild` script** Add the following ``prebuild`` script to your ``package.json``. When Vercel initializes the build, it will trigger this script which will generate the -query builder. The ``npx @edgedb/generate edgeql-js`` command will read the -value of the ``EDGEDB_SECRET_KEY`` and ``EDGEDB_INSTANCE`` variables, -connect to the database, and generate the query builder before Vercel +query builder. The ``npx @gel/generate edgeql-js`` command will read the +value of the :gelenv:`SECRET_KEY` and :gelenv:`INSTANCE` variables, +connect to the database, and generate the query builder before Vercel starts building the project. .. code-block:: javascript-diff @@ -557,27 +556,29 @@ starts building the project. "build": "next build", "start": "next start", "lint": "next lint", - + "prebuild": "npx @edgedb/generate edgeql-js" + + "prebuild": "npx @gel/generate edgeql-js" }, **#3 Deploy to Vercel** -Push your project to GitHub or some other Git remote repository. Then deploy +Push your project to GitHub or some other Git remote repository. Then deploy this app to Vercel with the button below. + +.. XXX -- update URL .. lint-off .. image:: https://vercel.com/button :width: 150px - :target: https://vercel.com/new/git/external?repository-url=https://github.com/edgedb/edgedb-examples/tree/main/nextjs-blog&project-name=nextjs-edgedb-blog&repository-name=nextjs-edgedb-blog&env=EDGEDB_DSN,EDGEDB_CLIENT_TLS_SECURITY + :target: https://vercel.com/new/git/external?repository-url=https://github.com/geldata/gel-examples/tree/main/nextjs-blog&project-name=nextjs-edgedb-blog&repository-name=nextjs-edgedb-blog&env=EDGEDB_DSN,EDGEDB_CLIENT_TLS_SECURITY .. lint-on In "Configure Project," expand "Environment Variables" to add two variables: -- ``EDGEDB_INSTANCE`` containing your EdgeDB Cloud instance name (in +- :gelenv:`INSTANCE` containing your Gel Cloud instance name (in ``/`` format) -- ``EDGEDB_SECRET_KEY`` containing the secret key you created and noted +- :gelenv:`SECRET_KEY` containing the secret key you created and noted previously. **#4 View the application** @@ -588,23 +589,23 @@ supplied by Vercel. With other cloud providers =========================== -**#1 Deploy EdgeDB** +**#1 Deploy Gel** -Check out the following guides for deploying EdgeDB to your preferred cloud +Check out the following guides for deploying Gel to your preferred cloud provider: -- `AWS `_ -- `Google Cloud `_ -- `Azure `_ -- `DigitalOcean `_ -- `Fly.io `_ -- `Docker `_ +- :ref:`AWS ` +- :ref:`Google Cloud ` +- :ref:`Azure ` +- :ref:`DigitalOcean ` +- :ref:`Fly.io ` +- :ref:`Docker ` (cloud-agnostic) **#2 Find your instance's DSN** The DSN is also known as a connection string. It will have the format -``edgedb://username:password@hostname:port``. The exact instructions for this +:geluri:`username:password@hostname:port`. The exact instructions for this depend on which cloud you are deploying to. **#3 Apply migrations** @@ -613,11 +614,11 @@ Use the DSN to apply migrations against your remote instance. .. code-block:: bash - $ npx edgedb migrate --dsn --tls-security insecure + $ npx gel migrate --dsn --tls-security insecure .. note:: - You have to disable TLS checks with ``--tls-security insecure``. All EdgeDB + You have to disable TLS checks with ``--tls-security insecure``. All Gel instances use TLS by default, but configuring it is out of scope of this project. @@ -626,10 +627,10 @@ database. Open a REPL and ``insert`` some blog posts: .. code-block:: bash - $ npx edgedb --dsn --tls-security insecure - EdgeDB x.x (repl x.x) + $ npx gel --dsn --tls-security insecure + Gel x.x (repl x.x) Type \help for help, \quit to quit. - edgedb> insert BlogPost { title := "Test post" }; + gel> insert BlogPost { title := "Test post" }; {default::BlogPost {id: c00f2c9a-cbf5-11ec-8ecb-4f8e702e5789}} @@ -637,8 +638,8 @@ database. Open a REPL and ``insert`` some blog posts: Add the following ``prebuild`` script to your ``package.json``. When Vercel initializes the build, it will trigger this script which will generate the -query builder. The ``npx @edgedb/generate edgeql-js`` command will read the -value of the ``EDGEDB_DSN`` variable, connect to the database, and generate +query builder. The ``npx @gel/generate edgeql-js`` command will read the +value of the :gelenv:`DSN` variable, connect to the database, and generate the query builder before Vercel starts building the project. .. code-block:: javascript-diff @@ -649,7 +650,7 @@ the query builder before Vercel starts building the project. "build": "next build", "start": "next start", "lint": "next lint", - + "prebuild": "npx @edgedb/generate edgeql-js" + + "prebuild": "npx @gel/generate edgeql-js" }, **#5 Deploy to Vercel** @@ -660,19 +661,21 @@ Deploy this app to Vercel with the button below. .. image:: https://vercel.com/button :width: 150px - :target: https://vercel.com/new/git/external?repository-url=https://github.com/edgedb/edgedb-examples/tree/main/nextjs-blog&project-name=nextjs-edgedb-blog&repository-name=nextjs-edgedb-blog&env=EDGEDB_DSN,EDGEDB_CLIENT_TLS_SECURITY + :target: https://vercel.com/new/git/external?repository-url=https://github.com/geldata/gel-examples/tree/main/nextjs-blog&project-name=nextjs-edgedb-blog&repository-name=nextjs-edgedb-blog&env=EDGEDB_DSN,EDGEDB_CLIENT_TLS_SECURITY .. lint-on When prompted: -- Set ``EDGEDB_DSN`` to your database's DSN -- Set ``EDGEDB_CLIENT_TLS_SECURITY`` to ``insecure``. This will disable - EdgeDB's default TLS checks; configuring TLS is beyond the scope of this +- Set :gelenv:`DSN` to your database's DSN +- Set :gelenv:`CLIENT_TLS_SECURITY` to ``insecure``. This will disable + Gel's default TLS checks; configuring TLS is beyond the scope of this tutorial. +.. XXX -- update URL + .. image:: - https://www.edgedb.com/docs/tutorials/nextjs/env.png + https://www.geldata.com/docs/tutorials/nextjs/env.png :alt: Setting environment variables in Vercel :width: 100% @@ -685,16 +688,16 @@ supplied by Vercel. Wrapping up ----------- -This tutorial demonstrates how to work with EdgeDB in a -Next.js app, using the App Router. We've created a simple blog application -that loads posts from a database and displays them on the homepage. -We've also created a dynamic route that fetches a single post from the +This tutorial demonstrates how to work with Gel in a +Next.js app, using the App Router. We've created a simple blog application +that loads posts from a database and displays them on the homepage. +We've also created a dynamic route that fetches a single post from the database and displays it on a separate page. The next step is to add a ``/newpost`` page with a form for writing new blog -posts and saving them into EdgeDB. That's left as an exercise for the reader. +posts and saving them into Gel. That's left as an exercise for the reader. -To see the final code for this tutorial, refer to -`github.com/edgedb/edgedb-examples/tree/main/nextjs-blog -`_. diff --git a/docs/guides/tutorials/nextjs_pages_router.rst b/docs/guides/tutorials/nextjs_pages_router.rst index 8503b1eb6ac..6475fcfeee7 100644 --- a/docs/guides/tutorials/nextjs_pages_router.rst +++ b/docs/guides/tutorials/nextjs_pages_router.rst @@ -4,11 +4,11 @@ Next.js (Pages Router) ====================== -:edb-alt-title: Building a simple blog application with EdgeDB and +:edb-alt-title: Building a simple blog application with Gel and Next.js (Pages Router) We're going to build a simple blog application with -`Next.js `_ and EdgeDB. Let's start by scaffolding our +`Next.js `_ and Gel. Let's start by scaffolding our app with Next.js's ``create-next-app`` tool. We'll be using TypeScript for this tutorial. @@ -38,7 +38,7 @@ homepage. At this point the app's file structure looks like this: pages β”œβ”€β”€ _app.tsx β”œβ”€β”€ api - β”‚Β  └── hello.ts + β”‚ └── hello.ts └── index.tsx public β”œβ”€β”€ favicon.ico @@ -77,11 +77,11 @@ static data. Replace the contents of ``pages/index.tsx`` with the following. { id: 'post1', title: 'This one weird trick makes using databases fun', - content: 'Use EdgeDB', + content: 'Use Gel', }, { id: 'post2', - title: 'How to build a blog with EdgeDB and Next.js', + title: 'How to build a blog with Gel and Next.js', content: "Let's start by scaffolding our app with `create-next-app`.", }, ]; @@ -122,57 +122,55 @@ something like this. :alt: Basic blog homepage with static content :width: 100% -Initializing EdgeDB -------------------- - -Now let's spin up a database for the app. You have two options to initialize -an EdgeDB project: using ``npx edgedb`` without installing the CLI, or -installing the edgedb CLI directly. In this tutorial, we'll use the first -option. If you prefer to install the CLI, see the -`EdgeDB CLI installation guide `_ -for more information. +Initializing Gel +---------------- +Now let's spin up a database for the app. You have two options to initialize +an Gel project: using ``$ npx gel`` without installing the CLI, or +installing the gel CLI directly. In this tutorial, we'll use the first +option. If you prefer to install the CLI, see the +:ref:`Gel CLI guide ` for more information. From the application's root directory, run the following command: .. code-block:: bash - $ npx edgedb project init - No `edgedb.toml` found in `~/nextjs-blog` or above + $ npx gel project init + No `gel.toml` found in `~/nextjs-blog` or above Do you want to initialize a new project? [Y/n] > Y - Specify the name of EdgeDB instance to use with this project [default: + Specify the name of Gel instance to use with this project [default: nextjs_blog]: > nextjs_blog - Checking EdgeDB versions... - Specify the version of EdgeDB to use with this project [default: x.x]: + Checking Gel versions... + Specify the version of Gel to use with this project [default: x.x]: > β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Project directory β”‚ ~/nextjs-blog β”‚ - β”‚ Project config β”‚ ~/nextjs-blog/edgedb.toml β”‚ + β”‚ Project config β”‚ ~/nextjs-blog/gel.toml β”‚ β”‚ Schema dir (empty) β”‚ ~/nextjs-blog/dbschema β”‚ β”‚ Installation method β”‚ portable package β”‚ β”‚ Start configuration β”‚ manual β”‚ β”‚ Version β”‚ x.x β”‚ β”‚ Instance name β”‚ nextjs_blog β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - Initializing EdgeDB instance... + Initializing Gel instance... Applying migrations... Everything is up to date. Revision initial. Project initialized. -This process has spun up an EdgeDB instance called ``nextjs-blog`` and +This process has spun up an Gel instance called ``nextjs-blog`` and "linked" it with your current directory. As long as you're inside that directory, CLI commands and client libraries will be able to connect to the linked instance automatically, without additional configuration. -To test this, run the ``edgedb`` command to open a REPL to the linked instance. +To test this, run the |gelcmd| command to open a REPL to the linked instance. .. code-block:: bash - $ edgedb - EdgeDB 2.x (repl 2.x) + $ gel + Gel x.x (repl x.x) Type \help for help, \quit to quit. - edgedb> select 2 + 2; + gel> select 2 + 2; {4} > @@ -182,21 +180,21 @@ change that. The project initialization process also created a new subdirectory in our project called ``dbschema``. This is folder that contains everything -pertaining to EdgeDB. Currently it looks like this: +pertaining to Gel. Currently it looks like this: .. code-block:: dbschema - β”œβ”€β”€ default.esdl + β”œβ”€β”€ default.gel └── migrations -The ``default.esdl`` file will contain our schema. The ``migrations`` +The :dotgel:`default` file will contain our schema. The ``migrations`` directory is currently empty, but will contain our migration files. Let's -update the contents of ``default.esdl`` with the following simple blog schema. +update the contents of :dotgel:`default` with the following simple blog schema. .. code-block:: sdl - # dbschema/default.esdl + # dbschema/default.gel module default { type BlogPost { @@ -209,14 +207,14 @@ update the contents of ``default.esdl`` with the following simple blog schema. .. note:: - EdgeDB lets you split up your schema into different ``modules`` but it's + Gel lets you split up your schema into different ``modules`` but it's common to keep your entire schema in the ``default`` module. Save the file, then let's create our first migration. .. code-block:: bash - $ npx edgedb migration create + $ npx gel migration create did you create object type 'default::BlogPost'? [y,n,l,c,b,s,q,?] > y Created ./dbschema/migrations/00001.edgeql @@ -227,34 +225,34 @@ our database. Let's do that. .. code-block:: bash - $ npx edgedb migrate + $ npx gel migrate Applied m1fee6oypqpjrreleos5hmivgfqg6zfkgbrowx7sw5jvnicm73hqdq (00001.edgeql) Our database now has a schema consisting of the ``BlogPost`` type. We can -create some sample data from the REPL. Run the ``edgedb`` command to re-open +create some sample data from the REPL. Run the |gelcmd| command to re-open the REPL. .. code-block:: bash - $ edgedb - EdgeDB 2.x (repl 2.x) + $ gel + Gel x.x (repl x.x) Type \help for help, \quit to quit. - edgedb> + gel> Then execute the following ``insert`` statements. .. code-block:: edgeql-repl - edgedb> insert BlogPost { - ....... title := "This one weird trick makes using databases fun", - ....... content := "Use EdgeDB" - ....... }; + gel> insert BlogPost { + .... title := "This one weird trick makes using databases fun", + .... content := "Use Gel" + .... }; {default::BlogPost {id: 7f301d02-c780-11ec-8a1a-a34776e884a0}} - edgedb> insert BlogPost { - ....... title := "How to build a blog with EdgeDB and Next.js", - ....... content := "Let's start by scaffolding our app..." - ....... }; + gel> insert BlogPost { + .... title := "How to build a blog with Gel and Next.js", + .... content := "Let's start by scaffolding our app..." + .... }; {default::BlogPost {id: 88c800e6-c780-11ec-8a1a-b3a3020189dd}} @@ -263,12 +261,12 @@ Loading posts with an API route Now that we have a couple posts in the database, let's load them dynamically with a Next.js `API route `_. -To do that, we'll need the ``edgedb`` client library. Let's install that from +To do that, we'll need the ``gel`` client library. Let's install that from NPM: .. code-block:: bash - $ npm install edgedb + $ npm install gel Then create a new file at ``pages/api/post.ts`` and copy in the following code. @@ -277,7 +275,7 @@ Then create a new file at ``pages/api/post.ts`` and copy in the following code. // pages/api/post.ts import type {NextApiRequest, NextApiResponse} from 'next'; - import {createClient} from 'edgedb'; + import {createClient} from 'gel'; export const client = createClient(); @@ -293,7 +291,7 @@ Then create a new file at ``pages/api/post.ts`` and copy in the following code. res.status(200).json(posts); } -This file initializes an EdgeDB client, which manages a pool of connections to +This file initializes an Gel client, which manages a pool of connections to the database and provides an API for executing queries. We're using the ``.query()`` method to fetch all the posts in the database with a simple ``select`` statement. @@ -322,11 +320,11 @@ the built-in ``fetch`` API. At the top of the ``HomePage`` component in - { - id: 'post1', - title: 'This one weird trick makes using databases fun', - - content: 'Use EdgeDB', + - content: 'Use Gel', - }, - { - id: 'post2', - - title: 'How to build a blog with EdgeDB and Next.js', + - title: 'How to build a blog with Gel and Next.js', - content: "Let's start by scaffolding our app...", - }, - ]; @@ -348,7 +346,7 @@ before the homepage renders the (dynamically loaded!) blog posts. Generating the query builder ---------------------------- -Since we're using TypeScript, it makes sense to use EdgeDB's powerful query +Since we're using TypeScript, it makes sense to use Gel's powerful query builder. This provides a schema-aware client API that makes writing strongly typed EdgeQL queries easy and painless. The result type of our queries will be automatically inferred, so we won't need to manually type something like @@ -358,17 +356,17 @@ First, install the generator to your project. .. code-block:: bash - $ yarn add --dev @edgedb/generate + $ yarn add --dev @gel/generate Then generate the query builder with the following command. .. code-block:: bash - $ npx @edgedb/generate edgeql-js + $ npx @gel/generate edgeql-js Generating query builder... Detected tsconfig.json, generating TypeScript files. To override this, use the --target flag. - Run `npx @edgedb/generate --help` for full options. + Run `npx @gel/generate --help` for full options. Introspecting database schema... Writing files to ./dbschema/edgeql-js Generation complete! 🀘 @@ -395,7 +393,7 @@ instead. // pages/api/post.ts import type {NextApiRequest, NextApiResponse} from 'next'; - import {createClient} from 'edgedb'; + import {createClient} from 'gel'; + import e, {$infer} from '../../dbschema/edgeql-js'; export const client = createClient(); @@ -545,9 +543,9 @@ you to ``/post/``, which should display something like this: Deploying to Vercel ------------------- -**#1 Deploy EdgeDB** +**#1 Deploy Gel** -First deploy an EdgeDB instance on your preferred cloud provider: +First deploy an Gel instance on your preferred cloud provider: - :ref:`AWS ` - :ref:`Azure ` @@ -564,7 +562,7 @@ or use a cloud-agnostic deployment method: **#2. Find your instance's DSN** The DSN is also known as a connection string. It will have the format -``edgedb://username:password@hostname:port``. The exact instructions for this +:geluri:`username:password@hostname:port`. The exact instructions for this depend on which cloud you are deploying to. **#3 Apply migrations** @@ -573,11 +571,11 @@ Use the DSN to apply migrations against your remote instance. .. code-block:: bash - $ npx edgedb migrate --dsn --tls-security insecure + $ npx gel migrate --dsn --tls-security insecure .. note:: - You have to disable TLS checks with ``--tls-security insecure``. All EdgeDB + You have to disable TLS checks with ``--tls-security insecure``. All Gel instances use TLS by default, but configuring it is out of scope of this project. @@ -586,10 +584,10 @@ database. Open a REPL and ``insert`` some blog posts: .. code-block:: bash - $ npx edgedb --dsn --tls-security insecure - EdgeDB 2.x (repl 2.x) + $ npx gel --dsn --tls-security insecure + Gel x.x (repl x.x) Type \help for help, \quit to quit. - edgedb> insert BlogPost { title := "Test post" }; + gel> insert BlogPost { title := "Test post" }; {default::BlogPost {id: c00f2c9a-cbf5-11ec-8ecb-4f8e702e5789}} @@ -597,8 +595,8 @@ database. Open a REPL and ``insert`` some blog posts: Add the following ``prebuild`` script to your ``package.json``. When Vercel initializes the build, it will trigger this script which will generate the -query builder. The ``npx @edgedb/generate edgeql-js`` command will read the -value of the ``EDGEDB_DSN`` variable, connect to the database, and generate the +query builder. The ``npx @gel/generate edgeql-js`` command will read the +value of the :gelenv:`DSN` variable, connect to the database, and generate the query builder before Vercel starts building the project. .. code-block:: javascript-diff @@ -609,26 +607,27 @@ query builder before Vercel starts building the project. "build": "next build", "start": "next start", "lint": "next lint", - + "prebuild": "npx @edgedb/generate edgeql-js" + + "prebuild": "npx @gel/generate edgeql-js" }, **#5 Deploy to Vercel** Deploy this app to Vercel with the button below. +.. XXX -- update URL .. lint-off .. image:: https://vercel.com/button :width: 150px - :target: https://vercel.com/new/git/external?repository-url=https://github.com/edgedb/edgedb-examples/tree/main/nextjs-blog&project-name=nextjs-edgedb-blog&repository-name=nextjs-edgedb-blog&env=EDGEDB_DSN,EDGEDB_CLIENT_TLS_SECURITY + :target: https://vercel.com/new/git/external?repository-url=https://github.com/geldata/gel-examples/tree/main/nextjs-blog&project-name=nextjs-edgedb-blog&repository-name=nextjs-edgedb-blog&env=GEL_DSN,GEL_CLIENT_TLS_SECURITY .. lint-on When prompted: -- Set ``EDGEDB_DSN`` to your database's DSN -- Set ``EDGEDB_CLIENT_TLS_SECURITY`` to ``insecure``. This will disable - EdgeDB's default TLS checks; configuring TLS is beyond the scope of this +- Set :gelenv:`DSN` to your database's DSN +- Set :gelenv:`CLIENT_TLS_SECURITY` to ``insecure``. This will disable + Gel's default TLS checks; configuring TLS is beyond the scope of this tutorial. .. image:: @@ -646,13 +645,13 @@ Wrapping up ----------- Admittedly this isn't the prettiest blog of all time, or the most -feature-complete. But this tutorial demonstrates how to work with EdgeDB in a +feature-complete. But this tutorial demonstrates how to work with Gel in a Next.js app, including data fetching with API routes and ``getServerSideProps``. The next step is to add a ``/newpost`` page with a form for writing new blog -posts and saving them into EdgeDB. That's left as an exercise for the reader. +posts and saving them into Gel. That's left as an exercise for the reader. To see the final code for this tutorial, refer to -`github.com/edgedb/edgedb-examples/tree/main/nextjs-blog -`_. +`github.com/geldata/gel-examples/tree/main/nextjs-blog +`_. diff --git a/docs/guides/tutorials/phoenix_github_oauth.rst b/docs/guides/tutorials/phoenix_github_oauth.rst deleted file mode 100644 index 5c09f020771..00000000000 --- a/docs/guides/tutorials/phoenix_github_oauth.rst +++ /dev/null @@ -1,834 +0,0 @@ -.. _ref_guide_phoenix_github_oauth: - -======= -Phoenix -======= - -:edb-alt-title: Building a GitHub OAuth application - - -In this tutorial, we'll look at -how you can create an application with authorization through GitHub using -`Phoenix `_ and :ref:`the official EdgeDB Elixir -driver `. - -This tutorial is a simplified version of the `LiveBeats -`_ application from -`fly.io `_ with EdgeDB instead of PostgreSQL, which focuses on -implementing authorization via GitHub. The completed implementation of this -example can be found `on GitHub `_. The full version -of LiveBeats version on EdgeDB can also be found `on GitHub -`_ - -.. _repository: - https://github.com/edgedb/edgedb-examples/tree/main/phoenix-github-oauth - -.. _prerequisites: - -Prerequisites -============= - -For this tutorial we will need: - -* EdgeDB CLI. -* Elixir version 1.13 or higher. -* Phoenix framework version 1.6 or higher. -* `GitHub OAuth application `_. - -.. _gh-oauth-guide: - https://docs.github.com/ - en/developers/apps/building-oauth-apps/creating-an-oauth-app - -Before discussing the project database schema, let's generate a skeleton for -our application. We will make sure that it will use binary IDs for the Ecto -schemas because EdgeDB uses UUIDs as primary IDs, which in Elixir are -represented as strings, and since it is basically a plain JSON API application, -we will disable all the built-in Phoenix integrations. - -.. code-block:: bash - - $ mix phx.new phoenix-github_oauth --app github_oauth --module GitHubOAuth \ - > --no-html --no-gettext --no-dashboard --no-live --no-mailer --binary-id - $ cd phoenix-github_oauth/ - -Let's also get rid of some default things that were created by Phoenix and -won't be used by us. - -.. code-block:: bash - - $ # remove the module Ecto.Repo and the directory for Ecto migrations, - $ # because they will not be used - $ rm -r lib/github_oauth/repo.ex priv/repo/ - -And then add the EdgeDB driver, the ``Ecto`` helper for it and the ``Mint`` -HTTP client for GitHub OAuth client as project dependencies to ``mix.exs``. - -.. code-block:: elixir - - defmodule GitHubOAuth.MixProject do - # ... - - defp deps do - [ - {:phoenix, "~> 1.6.9"}, - {:phoenix_ecto, "~> 4.4"}, - {:esbuild, "~> 0.4", runtime: Mix.env() == :dev}, - {:telemetry_metrics, "~> 0.6"}, - {:telemetry_poller, "~> 1.0"}, - {:jason, "~> 1.2"}, - {:plug_cowboy, "~> 2.5"}, - {:edgedb, "~> 0.3.0"}, - {:edgedb_ecto, git: "https://github.com/nsidnev/edgedb_ecto"}, - {:mint, "~> 1.0"} # we need mint to write the GitHub client - ] - end - - # ... - end - -Now we need to download new dependencies. - -.. code-block:: bash - - $ mix deps.get - -Next, we will create a module in ``lib/github_oauth/edgedb.ex`` which will -define a child specification for the EdgeDB driver and use the ``EdgeDBEcto`` -helper, which will inspect the queries that will be stored in the -``priv/edgeql/`` directory and generate Elixir code for them. - -.. code-block:: elixir - - defmodule GitHubOAuth.EdgeDB do - use EdgeDBEcto, - name: __MODULE__, - queries: true, - otp_app: :github_oauth - - def child_spec(_opts \\ []) do - %{ - id: __MODULE__, - start: {EdgeDB, :start_link, [[name: __MODULE__]]} - } - end - end - -Now we need to add ``GitHubOAuth.EdgeDB`` as a child for our application in -``lib/github_oauth/application.ex`` (at the same time removing the child -definition for ``Ecto.Repo`` from there). - -.. code-block:: elixir - - defmodule GitHubOAuth.Application do - # ... - - @impl true - def start(_type, _args) do - children = [ - # Start the EdgeDB driver - GitHubOAuth.EdgeDB, - # Start the Telemetry supervisor - GitHubOAuthWeb.Telemetry, - # Start the PubSub system - {Phoenix.PubSub, name: GitHubOAuth.PubSub}, - # Start the Endpoint (http/https) - GitHubOAuthWeb.Endpoint - # Start a worker by calling: GitHubOAuth.Worker.start_link(arg) - # {GitHubOAuth.Worker, arg} - ] - - # ... - end - - # ... - end - - -Now we are ready to start working with EdgeDB! First, let's initialize a new -project for this application. - -.. code-block:: bash - - $ edgedb project init - No `edgedb.toml` found in `/home//phoenix-github_oauth` or above - - Do you want to initialize a new project? [Y/n] - > Y - - Specify the name of EdgeDB instance to use with this project - [default: phoenix_github_oauth]: - > github_oauth - - Checking EdgeDB versions... - Specify the version of EdgeDB to use with this project [default: 2.x]: - > 2.x - - Do you want to start instance automatically on login? [y/n] - > y - -Great! Now we are ready to develop the database schema for the application. - -Schema design -============= - -This application will have 2 types: ``User`` and ``Identity``. The -``default::User`` represents the system user and the ``default::Identity`` -represents the way the user logs in to the application (in this example via -GitHub OAuth). - -This schema will be stored in a single EdgeDB module inside the -``dbschema/default.esdl`` file. - -.. code-block:: sdl - - module default { - type User { - property name -> str; - required property username -> str; - required property email -> cistr; - - property profile_tagline -> str; - - property avatar_url -> str; - property external_homepage_url -> str; - - required property inserted_at -> cal::local_datetime { - default := cal::to_local_datetime(datetime_current(), 'UTC'); - } - - required property updated_at -> cal::local_datetime { - default := cal::to_local_datetime(datetime_current(), 'UTC'); - } - - index on (.email); - index on (.username); - } - - type Identity { - required property provider -> str; - required property provider_token -> str; - required property provider_login -> str; - required property provider_email -> str; - required property provider_id -> str; - - required property provider_meta -> json { - default := "{}"; - } - - required property inserted_at -> cal::local_datetime { - default := cal::to_local_datetime(datetime_current(), 'UTC'); - } - - required property updated_at -> cal::local_datetime { - default := cal::to_local_datetime(datetime_current(), 'UTC'); - } - - required link user -> User { - on target delete delete source; - } - - index on (.provider); - constraint exclusive on ((.user, .provider)); - } - } - -After saving the file, we can create a migration for the schema and apply the -generated migration. - -.. code-block:: bash - - $ edgedb migration create - did you create object type 'default::User'? [y,n,l,c,b,s,q,?] - > y - - did you create object type 'default::Identity'? [y,n,l,c,b,s,q,?] - > y - - Created ./dbschema/migrations/00001.edgeql, id: - m1yehm3jhj6jqwguelek54jzp4wqvvqgrcnvncxwb7676ult7nmcta - - $ edgedb migrate - -Ecto schemas -============ - -In this tutorial we will define 2 ``Ecto.Schema`` modules, for -``default::User`` and ``default::Identity`` types, so that we can work with -EdgeDB in a more convenient way that is familiar to the world of Elixir. - -Here is the definition for the user in the ``lib/accounts/user.ex`` file. - -.. code-block:: elixir - - defmodule GitHubOAuth.Accounts.User do - use Ecto.Schema - use EdgeDBEcto.Mapper - - alias GitHubOAuth.Accounts.Identity - - @primary_key {:id, :binary_id, autogenerate: false} - - schema "default::User" do - field :email, :string - field :name, :string - field :username, :string - field :avatar_url, :string - field :external_homepage_url, :string - - has_many :identities, Identity - - timestamps() - end - end - -And here for identity in ``lib/accounts/identity.ex``. - -.. code-block:: elixir - - defmodule GitHubOAuth.Accounts.Identity do - use Ecto.Schema - use EdgeDBEcto.Mapper - - alias GitHubOAuth.Accounts.User - - @primary_key {:id, :binary_id, autogenerate: false} - - schema "default::Identity" do - field :provider, :string - field :provider_token, :string - field :provider_email, :string - field :provider_login, :string - field :provider_name, :string, virtual: true - field :provider_id, :string - field :provider_meta, :map - - belongs_to :user, User - - timestamps() - end - end - -User authentication via GitHub -================================== - -This part will be pretty big, as we'll talk about using ``Ecto.Changeset`` -with the EdgeDB driver, as well as modules and queries related to user -registration via GitHub OAuth. - -``Ecto`` provides "changesets" (via ``Ecto.Changeset``), which are convenient -to use when working with ``Ecto.Schema`` to validate external parameters. We -could use them via ``EdgeDBEcto`` instead, though not quite as fully as we can -with the full-featured adapters for ``Ecto``. - -First, we will update the ``GitHubOAuth.Accounts.Identity`` module so that it -checks all the necessary parameters when we are creating a user via a GitHub -registration. - -.. code-block:: elixir - - defmodule GitHubOAuth.Accounts.Identity do - # ... - import Ecto.Changeset - - alias GitHubOAuth.Accounts.{Identity, User} - - @github "github" - - # ... - - def github_registration_changeset(info, primary_email, emails, token) do - params = %{ - "provider_token" => token, - "provider_id" => to_string(info["id"]), - "provider_login" => info["login"], - "provider_name" => info["name"] || info["login"], - "provider_email" => primary_email - } - - %Identity{} - |> cast(params, [ - :provider_token, - :provider_email, - :provider_login, - :provider_name, - :provider_id - ]) - |> put_change(:provider, @github) - |> put_change(:provider_meta, %{"user" => info, "emails" => emails}) - |> validate_required([ - :provider_token, - :provider_email, - :provider_name, - :provider_id - ]) - end - end - -And now let's define a changeset for user registration, which will use an -already defined changeset from ``GitHubOAuth.Accounts.Identity``. - -.. code-block:: elixir - - defmodule GitHubOAuth.Accounts.User do - # ... - - import Ecto.Changeset - - alias GitHubOAuth.Accounts.{User, Identity} - - # ... - - def github_registration_changeset(info, primary_email, emails, token) do - %{ - "login" => username, - "avatar_url" => avatar_url, - "html_url" => external_homepage_url - } = info - - identity_changeset = - Identity.github_registration_changeset( - info, - primary_email, - emails, - token - ) - - if identity_changeset.valid? do - params = %{ - "username" => username, - "email" => primary_email, - "name" => get_change(identity_changeset, :provider_name), - "avatar_url" => avatar_url, - "external_homepage_url" => external_homepage_url - } - - %User{} - |> cast(params, [ - :email, - :name, - :username, - :avatar_url, - :external_homepage_url - ]) - |> validate_required([:email, :name, :username]) - |> validate_username() - |> validate_email() - |> put_assoc(:identities, [identity_changeset]) - else - %User{} - |> change() - |> Map.put(:valid?, false) - |> put_assoc(:identities, [identity_changeset]) - end - end - - defp validate_email(changeset) do - changeset - |> validate_required([:email]) - |> validate_format( - :email, - ~r/^[^\s]+@[^\s]+$/, - message: "must have the @ sign and no spaces" - ) - |> validate_length(:email, max: 160) - end - - defp validate_username(changeset) do - validate_format(changeset, :username, ~r/^[a-zA-Z0-9_-]{2,32}$/) - end - end - -Now that we have the schemas and changesets defined, let's define a set of the -EdgeQL queries we need for the login process. - -There are 5 queries that we will need: - -1. Search for a user by user ID. - -2. Search for a user by email and by identity provider. - -3. Update the identity token if the user from the 1st query exists. - -4. Registering a user along with his identity data, if the 1st request did not - return the user. - -5. Querying a user identity before updating its token. - -Before writing the queries themselves, let's create a context module -``lib/github_oauth/accounts.ex`` that will use these queries, and the module -itself will be used by Phoenix controllers. - -.. code-block:: elixir - - defmodule GitHubOAuth.Accounts do - import Ecto.Changeset - - alias GitHubOAuth.Accounts.{User, Identity} - - def get_user(id) do - GitHubOAuth.EdgeDB.Accounts.get_user_by_id(id: id) - end - - def register_github_user(primary_email, info, emails, token) do - if user = get_user_by_provider(:github, primary_email) do - update_github_token(user, token) - else - info - |> User.github_registration_changeset(primary_email, emails, token) - |> EdgeDBEcto.insert( - &GitHubOAuth.EdgeDB.Accounts.register_github_user/1, - nested: true - ) - end - end - - def get_user_by_provider(provider, email) when provider in [:github] do - GitHubOAuth.EdgeDB.Accounts.get_user_by_provider( - provider: to_string(provider), - email: String.downcase(email) - ) - end - - defp update_github_token(%User{} = user, new_token) do - identity = - GitHubOAuth.EdgeDB.Accounts.get_identity_for_user( - user_id: user.id, - provider: "github" - ) - - {:ok, _} = - identity - |> change() - |> put_change(:provider_token, new_token) - |> EdgeDBEcto.update( - &GitHubOAuth.EdgeDB.Accounts.update_identity_token/1 - ) - - identity = %Identity{identity | provider_token: new_token} - {:ok, %User{user | identities: [identity]}} - end - end - -Note that updating a token with a single query is quite easy, but we will use -two separate queries, to show how to work with ``Ecto.Changeset`` in different -ways. - -Now that all the preparations are complete, we can start writing EdgeQL -queries. - -We start with the ``priv/edgeql/accounts/get_user_by_provider.edgeql`` file, -which defines a query to find an user with a specified email provider. - -.. code-block:: edgeql - - # edgedb = :query_single! - # mapper = GitHubOAuth.Accounts.User - - select User { - id, - name, - username, - email, - avatar_url, - external_homepage_url, - inserted_at, - updated_at, - } - filter - .$provider - and - str_lower(.email) = str_lower($email) - limit 1 - -It is worth noting the ``# edgedb = :query_single!`` and -``# mapper = GitHubOAuth.Accounts.User`` comments. Both are special comments -that will be used by ``EdgeDBEcto`` when generating query functions. The -``edgedb`` comment defines the driver function for requesting data. -Information on all supported features can be found in the driver -`documentation `_. -The ``mapper`` comment is used to define the module that will be used to map -the result from EdgeDB to some other form. Our ``Ecto.Schema`` schemas support -this with ``use EdgeDBEcto.Mapper`` expression at the top of the module -definition. - -The queries for `getting the identity `_ and -`getting the user by ID `_ are quite similar to the -above, so we will omit them here. You can find these queries in the -`example repository `_. - -.. _get-identity-query: - https://github.com/edgedb/edgedb-examples/blob/main/ - phoenix-github-oauth/priv/edgeql/accounts/get_identity_for_user.edgeql - -.. _get-user-by-id-query: - https://github.com/edgedb/edgedb-examples/blob/main/ - phoenix-github-oauth/priv/edgeql/accounts/get_user_by_id.edgeql - -Instead, let's look at how to update the user identity. This will be described -in the ``priv/edgeql/accounts/update_identity_token.edgeql`` file. - -.. code-block:: edgeql - - # edgedb = :query_required_single - - with params := $params - update Identity - filter .id = params["id"] - set { - provider_token := ( - json_get(params, "provider_token") ?? .provider_token - ), - updated_at := cal::to_local_datetime(datetime_current(), 'UTC'), - } - -As you can see, this query uses the named parameter ``$params`` instead of two -separate parameters such as ``$id`` and ``$provider_token``. This is because -to update our identity we use the changeset in the module -``GitHubOAuth.Accounts``, which automatically monitors changes to the schema -and will not give back the parameters, which will not affect the state of the -schema in update. So ``EdgeDBEcto`` automatically converts data from -changesets when it is an update or insert operation into a named ``$params`` -parameter of type JSON. It also helps to work with nested changesets, as we -will see in the next query, which is defined in the -``priv/edgeql/accounts/register_github_user.edgeql`` file. - -.. code-block:: edgeql - - # edgedb = :query_single! - # mapper = GitHubOAuth.Accounts.User - - with - params := $params, - identities_params := params["identities"], - user := ( - insert User { - email := params["email"], - name := params["name"], - username := params["username"], - avatar_url := json_get(params, "avatar_url"), - external_homepage_url := ( - json_get(params, "external_homepage_url") - ), - } - ), - identites := ( - for identity_params in json_array_unpack(identities_params) union ( - insert Identity { - provider := identity_params["provider"], - provider_token := identity_params["provider_token"], - provider_email := identity_params["provider_email"], - provider_login := identity_params["provider_login"], - provider_id := identity_params["provider_id"], - provider_meta := identity_params["provider_meta"], - user := user, - } - ) - ) - select user { - id, - name, - username, - email, - avatar_url, - external_homepage_url, - inserted_at, - updated_at, - identities := identites, - } - -Awesome! We're almost done with our application! - -As a final step in this tutorial, we will add 2 routes for the web -application. The first will redirect the user to the GitHub OAuth page if -they're not already logged in or will show their username otherwise. The second -is for logging into the application through GitHub. - -Save the GitHub OAuth credentials from the `prerequisites `_ -step as ``GITHUB_CLIENT_ID`` and ``GITHUB_CLIENT_SECRET`` environment -variables. - -And then modify your ``config/dev.exs`` configuration file to use them. - -.. code-block:: elixir - - # ... - - config :github_oauth, :github, - client_id: System.fetch_env!("GITHUB_CLIENT_ID"), - client_secret: System.fetch_env!("GITHUB_CLIENT_SECRET") - - # ... - -First we create a file ``lib/github_oauth_web/controllers/user_controller.ex`` -with a controller which will show the name of the logged in user or redirect -to the authentication page otherwise. - -.. code-block:: elixir - - defmodule GitHubOAuthWeb.UserController do - use GitHubOAuthWeb, :controller - - alias GitHubOAuth.Accounts - - plug :fetch_current_user - - def index(conn, _params) do - if conn.assigns.current_user do - json(conn, %{name: conn.assigns.current_user.name}) - else - redirect(conn, external: GitHubOAuth.GitHub.authorize_url()) - end - end - - defp fetch_current_user(conn, _opts) do - user_id = get_session(conn, :user_id) - user = user_id && Accounts.get_user(user_id) - assign(conn, :current_user, user) - end - end - -Note that the implementation of the ``GitHubOAuth.GitHub`` module is not given -here because it is relatively big and not a necessary part of this guide. If -you want to explore its internals, you can check out its implementation `on -GitHub `_. - -.. _gh-client: - https://github.com/edgedb/edgedb-examples/blob/main/ - phoenix-github-oauth/lib/github_oauth/github.ex - -Now add an authentication controller in -``lib/github_oauth_web/controllers/oauth_callback_controller.ex``. - -.. code-block:: elixir - - defmodule GitHubOAuthWeb.OAuthCallbackController do - use GitHubOAuthWeb, :controller - - alias GitHubOAuth.Accounts - - require Logger - - def new( - conn, - %{"provider" => "github", "code" => code, "state" => state} - ) do - client = github_client(conn) - - with {:ok, info} <- - client.exchange_access_token(code: code, state: state), - %{ - info: info, - primary_email: primary, - emails: emails, - token: token - } = info, - {:ok, user} <- - Accounts.register_github_user(primary, info, emails, token) do - conn - |> log_in_user(user) - |> redirect(to: "/") - else - {:error, %Ecto.Changeset{} = changeset} -> - Logger.debug("failed GitHub insert #{inspect(changeset.errors)}") - - error = - "We were unable to fetch the necessary information from " <> - "your GitHub account" - - json(conn, %{error: error}) - - {:error, reason} -> - Logger.debug("failed GitHub exchange #{inspect(reason)}") - - json(conn, %{ - error: "We were unable to contact GitHub. Please try again later" - }) - end - end - - def new(conn, %{"provider" => "github", "error" => "access_denied"}) do - json(conn, %{error: "Access denied"}) - end - - defp github_client(conn) do - conn.assigns[:github_client] || GitHubOAuth.GitHub - end - - defp log_in_user(conn, user) do - conn - |> assign(:current_user, user) - |> configure_session(renew: true) - |> clear_session() - |> put_session(:user_id, user.id) - end - end - -Finally, we need to change ``lib/github_oauth_web/router.ex`` and add new -controllers there. - -.. code-block:: elixir - - defmodule GitHubOAuthWeb.Router do - # ... - - pipeline :api do - # ... - plug :fetch_session - end - - scope "/", GitHubOAuthWeb do - pipe_through :api - - get "/", UserController, :index - get "/oauth/callbacks/:provider", OAuthCallbackController, :new - end - - # ... - end - - -Running web server -================== - -That's it! Now we are ready to run our application and check if everything -works as expected. - -.. code-block:: bash - - $ mix phx.server - Generated github_oauth app - [info] Running GitHubOAuthWeb.Endpoint with cowboy 2.9.0 at 127.0.0.1:4000 - (http) - - [info] Access GitHubOAuthWeb.Endpoint at http://localhost:4000 - -After going to http://localhost:4000, we will be greeted by the GitHub -authentication page. And after confirming the login we will be automatically -redirected back to our local server, which will save the received user in the -session and return the obtained user name in the JSON response. - -We can also verify that everything is saved correctly by manually checking -the database data. - -.. code-block:: edgeql-repl - - edgedb> select User { - ....... name, - ....... username, - ....... avatar_url, - ....... external_homepage_url, - ....... }; - { - default::User { - name: 'Nik', - username: 'nsidnev', - avatar_url: 'https://avatars.githubusercontent.com/u/22559461?v=4', - external_homepage_url: 'https://github.com/nsidnev' - }, - } - edgedb> select Identity { - ....... provider, - ....... provider_login - ....... } - ....... filter .user.username = 'nsidnev'; - {default::Identity {provider: 'github', provider_login: 'nsidnev'}} diff --git a/docs/guides/tutorials/prisma.rst b/docs/guides/tutorials/prisma.rst new file mode 100644 index 00000000000..c1f59543f05 --- /dev/null +++ b/docs/guides/tutorials/prisma.rst @@ -0,0 +1,214 @@ +.. _ref_guide_prisma: + +====== +Prisma +====== + +|Gel| supports SQL protocol for communicating with the database. This makes it possible to use it with Prisma by matching a Prisma schema to the |Gel| schema. You don't even need to figure out the conversion yourself because we have an automated tool for that. + +This tool becomes available when you install ``gel`` JavaScript/TypeScript package. Once you have you |Gel| project setup, you can generate the Prisma schema with this command: + +.. code-block:: bash + + $ npx @gel/generate prisma --file schema.prisma + +The ``--file`` indicates the output file for the newly generated Prisma schema. + +Even though Prisma and |Gel| both view the schema as a bunch of types with fields and interconnections, there are still some differences between what |Gel| and Prisma can represent. + + +Properties +========== + +Property types must match the basic Postgres types supported by Prisma, so avoid any custom types as they will be skipped. Currently we support the following: + +* :eql:type:`std::uuid` - ``String @db.Uuid`` +* :eql:type:`std::bigint` - ``Decimal`` +* :eql:type:`std::bool` - ``Boolean`` +* :eql:type:`std::bytes` - ``Bytes`` +* :eql:type:`std::decimal` - ``Decimal`` +* :eql:type:`std::float32` - ``Float`` +* :eql:type:`std::float64` - ``Float`` +* :eql:type:`std::int16` - ``Int`` +* :eql:type:`std::int32` - ``Int`` +* :eql:type:`std::int64` - ``BigInt`` +* :eql:type:`std::json` - ``Json`` +* :eql:type:`std::str` - ``String`` +* :eql:type:`std::datetime` - ``DateTime`` + +Array properties are supported for all of the above types as well. + +Multi properties cannot be represented as they have no primary key and therefore rows cannot be uniquely identified. That means that the schema generator will omit them from the schema. If you needs to reflect multi properties, consider replacing them with a single array property. + + +Links +===== + +Plain single links are reflected as a relation. + +Multi links get represented as a many-to-many relationship with an implicit intermediary table. + +Prisma is quite opinionated about the underlying SQL tables. It has a strict naming requirement for implicit link tables (they **must** start with an ``_``). This means that the way |Gel| exposes link tables is incompatible with the implicit naming requirement. So multi links and links with link properties have to reflected as explicit intermediate objects in a Prisma schema. These intermediary objects have ``source`` and ``target`` relations to the end points of the link. The link properties (if any) then become the fields of this link object. + +All links automatically generate the backward relations as well. The name of these back-links takes the format of ``bk_linkname_SourceName``, which mimics the EdgeQL version of backlinks ``._``. + +Properties +---------- + +The |Gel| schema declares a few properties: ``name`` for ``User`` and ``UserGroup`` as well as ``body`` for ``Post``. These get reflected as ``String`` in the corresponding models. As long as a property has a valid corresponding Prisma field type it will be reflected in this manner. + +Links +----- + +Let's first look at the ``Post`` declaration in |Gel|. A ``Post`` has a link ``author`` pointing to a ``User``. So the reflected type ``Post`` has a field ``author_id`` and the corresponding relation ``author``. + +Each reflected relation also automatically declares a back-link. In order to correctly map links and back-links every relation needs a name. We simply use the name of the back-link as the name of the relation. The naming format is ``bk__``. For the ``author`` link the name of the back-link is ``bk_author_Post`` and so is the name of the relation. + +We can look at the ``User`` model and find ``bk_author_Post`` relation used as a back-link of the same name. This relation is pointing back to ``Post[]``. + +``User`` model also has a many-to-many relationship with ``UserGroup``. Both ``User`` and ``UserGroup`` are connected by the ``UserGroup_users`` model. The relation names for ``UserGroup`` is the same as in the original |Gel| schema - ``users``. On the other hand the ``User`` model follows the back-link naming convention for this relation - ``bk_users_UserGroup``. + +Finally, ``UserGroup_users`` model has the last part of the many-to-many relationship declaration. The ``source`` relation pointing to ``UserGroup`` and the ``target`` relation pointing to ``User``. + +Connection +---------- + +In order to use these generated models in your Prisma app you need to setup the ``DATABASE_URL``. Typically this is done in the ``.env`` file. + +Running :gelcmd:`instance credentials --insecure-dsn` command produces something like this: + +.. code-block:: bash + + $ gel instance credentials --insecure-dsn + gel://admin:h632hKRuss6i9uQeMgEvRsuQ@localhost:10715/main + +All we have to do is replace the protocol with ``postgresql`` and add the following to ``.env``: + +.. code-block:: + + DATABASE_URL="postgresql://admin:h632hKRuss6i9uQeMgEvRsuQ@localhost:10715/main" diff --git a/docs/guides/tutorials/rest_apis_with_fastapi.rst b/docs/guides/tutorials/rest_apis_with_fastapi.rst index 62ab990cf9c..db387c6dc15 100644 --- a/docs/guides/tutorials/rest_apis_with_fastapi.rst +++ b/docs/guides/tutorials/rest_apis_with_fastapi.rst @@ -4,17 +4,17 @@ FastAPI ======= -:edb-alt-title: Building a REST API with EdgeDB and FastAPI +:edb-alt-title: Building a REST API with Gel and FastAPI Because FastAPI encourages and facilitates strong typing, it's a natural -pairing with EdgeDB. Our Python code generation generates not only typed +pairing with Gel. Our Python code generation generates not only typed query functions but result types you can use to annotate your endpoint handler functions. -EdgeDB can help you quickly build REST APIs in Python without getting into the +|Gel| can help you quickly build REST APIs in Python without getting into the rigmarole of using ORM libraries to handle your data effectively. Here, we'll be using `FastAPI `_ to expose the API endpoints -and EdgeDB to store the content. +and Gel to store the content. We'll build a simple event management system where you'll be able to fetch, create, update, and delete *events* and *event hosts* via RESTful API @@ -29,15 +29,15 @@ Prerequisites ============= Before we start, make sure you've :ref:`installed ` the -``edgedb`` command line tool. For this tutorial, we'll use Python 3.10 to -take advantage of the asynchronous I/O paradigm to communicate with the -database more efficiently. You can use newer versions of Python if you prefer, -but you may need to adjust the code accordingly. If you want to skip ahead, +|gelcmd| command line tool. For this tutorial, we'll use Python 3.10 to +take advantage of the asynchronous I/O paradigm to communicate with the +database more efficiently. You can use newer versions of Python if you prefer, +but you may need to adjust the code accordingly. If you want to skip ahead, the completed source code for this API can be found `in our examples repo -`_. If you -want to check out an example with EdgeDB Auth, you can find that in the same +`_. If you +want to check out an example with Gel Auth, you can find that in the same repo in the `fastapi-crud-auth folder -`_. +`_. Create a project directory @@ -62,7 +62,7 @@ note for help with Windows): $ python -m venv myvenv $ source myvenv/bin/activate - $ pip install edgedb fastapi 'httpx[cli]' uvicorn + $ pip install gel fastapi 'httpx[cli]' uvicorn .. note:: @@ -83,22 +83,22 @@ note for help with Windows): Initialize the database ^^^^^^^^^^^^^^^^^^^^^^^ -Now, let's initialize an EdgeDB project. From the project's root directory: +Now, let's initialize an Gel project. From the project's root directory: .. code-block:: bash - $ edgedb project init - No `edgedb.toml` found in `` or above + $ gel project init + No `gel.toml` found in `` or above Do you want to initialize a new project? [Y/n] > Y - Specify the name of EdgeDB instance to use with this project [default: + Specify the name of Gel instance to use with this project [default: fastapi_crud]: > fastapi_crud - Checking EdgeDB versions... - Specify the version of EdgeDB to use with this project [default: 2.7]: + Checking Gel versions... + Specify the version of Gel to use with this project [default: 2.7]: > 2.7 -Once you've answered the prompts, a new EdgeDB instance called ``fastapi_crud`` +Once you've answered the prompts, a new Gel instance called ``fastapi_crud`` will be created and started. If you see ``Project initialized``, you're ready. @@ -109,16 +109,16 @@ Let's test that we can connect to the newly started instance. To do so, run: .. code-block:: bash - $ edgedb + $ gel You should see this prompt indicating you are now connected to your new database instance: :: - EdgeDB 2.x (repl 2.x) + Gel x.x (repl x.x) Type \help for help, \quit to quit. - edgedb> + gel> You can start writing queries here. Since this database is empty, that won't get you very far, so let's start designing our data model instead. @@ -131,19 +131,19 @@ Each *event* can have an optional link to a *user* who is that event's host. The goal is to create API endpoints that'll allow us to fetch, create, update, and delete the entities while maintaining their relationships. -EdgeDB allows us to declaratively define the structure of the entities. If +|Gel| allows us to declaratively define the structure of the entities. If you've worked with SQLAlchemy or Django ORM, you might refer to these -declarative schema definitions as *models*. In EdgeDB we call them +declarative schema definitions as *models*. In Gel we call them "object types". -The schema lives inside ``.esdl`` files in the ``dbschema`` directory. It's +The schema lives inside |.gel| files in the ``dbschema`` directory. It's common to declare the entire schema in a single file -``dbschema/default.esdl``. This file is created for you when you run ``edgedb -project init``, but you'll need to fill it with your schema. This is what our -datatypes look like: +:dotgel:`dbschema/default`. This file is created for you when you run +:gelcmd:`project init`, but you'll need to fill it with your schema. +This is what our datatypes look like: .. code-block:: sdl - :caption: dbschema/default.esdl + :caption: dbschema/default.gel module default { abstract type Auditable { @@ -172,7 +172,7 @@ datatypes look like: } Here, we've defined an ``abstract`` type called ``Auditable`` to take advantage -of EdgeDB's schema mixin system. This allows us to add a ``created_at`` +of Gel's schema mixin system. This allows us to add a ``created_at`` property to multiple types without repeating ourselves. Abstract types don't have any concrete footprints in the database, as they don't hold any actual data. Their only job is to propagate properties, links, and constraints @@ -198,7 +198,7 @@ migration. .. code-block:: bash - $ edgedb migration create + $ gel migration create When this step is successful, you'll see ``Created dbschema/migrations/00001.edgeql``. @@ -207,18 +207,18 @@ Now run the migration we just created. .. code-block:: bash - $ edgedb migrate + $ gel migrate Once this is done, you'll see ``Applied`` along with the migration's ID. I like to go one step further in verifying success and see the schema applied to my -database. To do that, first fire up the EdgeDB console: +database. To do that, first fire up the Gel console: .. code-block:: bash - $ edgedb + $ gel In the console, type ``\ds`` (for "describe schema"). If everything worked, we -should output very close to the schema we added in the ``default.esdl`` file: +should output very close to the schema we added in the :dotgel:`default` file: :: @@ -281,7 +281,7 @@ simple text files containing the queries we want our app to be able to run. The code generator will search through our project for all files with the ``.edgeql`` extension and generate those functions for us as individual Python -modules. When you installed the EdgeDB client (via ``pip install edgedb``), the +modules. When you installed the Gel client (via ``pip install gel``), the code generator was installed alongside it, so you're already ready to go. We just need to write those queries! @@ -310,8 +310,8 @@ Save that file and get ready to kick off the magic that is code generation! πŸͺ„ .. code-block:: bash - $ edgedb-py - Found EdgeDB project: + $ gel-py + Found Gel project: Processing /app/queries/get_user_by_name.edgeql Processing /app/queries/get_users.edgeql Generating /app/queries/get_user_by_name.py @@ -336,7 +336,7 @@ the following code: from http import HTTPStatus from typing import List - import edgedb + import gel from fastapi import APIRouter, HTTPException, Query from pydantic import BaseModel @@ -344,7 +344,7 @@ the following code: from .queries import get_users_async_edgeql as get_users_qry router = APIRouter() - client = edgedb.create_async_client() + client = gel.create_async_client() class RequestData(BaseModel): @@ -369,13 +369,13 @@ We've imported the generated code and aliased it (using ``as ``) to make the module names we use in our code a bit neater. The ``APIRouter`` instance does the actual work of exposing the API. We also -create an async EdgeDB client instance to communicate with the database. +create an async Gel client instance to communicate with the database. By default, this API will return a list of all users, but you can also filter the user objects by name. We have the ``RequestData`` class to handle the data an API consumer will need to send in case they want to get only a single user. The types we're using in the return annotation have been generated by the -EdgeDB code generation based on the queries we wrote and our database's schema. +|Gel| code generation based on the queries we wrote and our database's schema. Note that we're also calling the appropriate generated function based on whether or not the API consumer passes an argument for ``name``. @@ -410,7 +410,7 @@ will send the 404 (not found) response to the user. .. lint-on To summarize, in the ``get_users`` function, we use our generated code to -perform asynchronous queries via the ``edgedb`` client. Then we return the +perform asynchronous queries via the ``gel`` client. Then we return the query results. Afterward, the JSON serialization part is taken care of by FastAPI. @@ -507,7 +507,7 @@ Create and open ``app/queries/create_user.edgeql`` and fill it with this query: the ``name`` and ``created_at`` properties. If we just ran the ``insert`` bare, it would return only the ``id``. -Save the file and run ``edgedb-py`` to generate the new function. Now, +Save the file and run ``gel-py`` to generate the new function. Now, we're ready to open ``app/users.py`` again and add the POST endpoint. First, import the generated function for the new query: @@ -533,7 +533,7 @@ Then write the endpoint to call that function: try: created_user = await create_user_qry.create_user(client, name=user.name) - except edgedb.errors.ConstraintViolationError: + except gel.errors.ConstraintViolationError: raise HTTPException( status_code=HTTPStatus.BAD_REQUEST, detail={"error": f"Username '{user.name}' already exists."}, @@ -602,7 +602,7 @@ We'll start again with the query. Create a new file in ``app/queries`` named set {name := $new_name} ) {name, created_at}; -Save the file and generate again using ``edgedb-py``. Now, we'll import that +Save the file and generate again using ``gel-py``. Now, we'll import that and add the endpoint over in ``app/users.py``. .. lint-off @@ -626,7 +626,7 @@ and add the endpoint over in ``app/users.py``. new_name=user.name, current_name=current_name, ) - except edgedb.errors.ConstraintViolationError: + except gel.errors.ConstraintViolationError: raise HTTPException( status_code=HTTPStatus.BAD_REQUEST, detail={"error": f"Username '{user.name}' already exists."}, @@ -711,7 +711,7 @@ query: delete User filter .name = $name ) {name, created_at}; -Generate the new function by again running ``edgedb-py``. Then re-open +Generate the new function by again running ``gel-py``. Then re-open ``app/users.py``. This endpoint's code will look similar to the endpoints we've already written: @@ -734,7 +734,7 @@ we've already written: client, name=name, ) - except edgedb.errors.ConstraintViolationError: + except gel.errors.ConstraintViolationError: raise HTTPException( status_code=HTTPStatus.BAD_REQUEST, detail={"error": "User attached to an event. Cannot delete."}, @@ -804,7 +804,7 @@ drop this query into it: } ) {name, address, schedule, host: {name}}; -Run ``edgedb-py`` to generate a function from that query. +Run ``gel-py`` to generate a function from that query. Create a file in ``app`` named ``events.py`` and open it in your editor. It's time to code up the endpoint to use that freshly generated query. @@ -819,14 +819,14 @@ time to code up the endpoint to use that freshly generated query. from http import HTTPStatus from typing import List - import edgedb + import gel from fastapi import APIRouter, HTTPException, Query from pydantic import BaseModel from .queries import create_event_async_edgeql as create_event_qry router = APIRouter() - client = edgedb.create_async_client() + client = gel.create_async_client() class RequestData(BaseModel): @@ -847,7 +847,7 @@ time to code up the endpoint to use that freshly generated query. host_name=event.host_name, ) - except edgedb.errors.InvalidValueError: + except gel.errors.InvalidValueError: raise HTTPException( status_code=HTTPStatus.BAD_REQUEST, detail={ @@ -857,7 +857,7 @@ time to code up the endpoint to use that freshly generated query. }, ) - except edgedb.errors.ConstraintViolationError: + except gel.errors.ConstraintViolationError: raise HTTPException( status_code=HTTPStatus.BAD_REQUEST, detail=f"Event name '{event.name}' already exists,", @@ -981,7 +981,7 @@ That query will handle PUT requests. The last method left is DELETE. Create delete Event filter .name = $name ) {name, address, schedule, host : {name}}; -Run ``edgedb-py`` to generate the new functions. Open ``app/events.py`` +Run ``gel-py`` to generate the new functions. Open ``app/events.py`` so we can start getting these functions implemented in the API! We'll start by coding GET. Import the newly generated queries and write the GET endpoint in ``events.py``: @@ -1093,7 +1093,7 @@ Let's finish off the events API with the PUT and DELETE endpoints. Open host_name=event.host_name, ) - except edgedb.errors.InvalidValueError: + except gel.errors.InvalidValueError: raise HTTPException( status_code=HTTPStatus.BAD_REQUEST, detail={ @@ -1102,7 +1102,7 @@ Let's finish off the events API with the PUT and DELETE endpoints. Open }, ) - except edgedb.errors.ConstraintViolationError: + except gel.errors.ConstraintViolationError: raise HTTPException( status_code=HTTPStatus.BAD_REQUEST, detail={"error": f"Event name '{event.name}' already exists."}, @@ -1170,40 +1170,40 @@ payload: You can do the same to test ``DELETE /events``, just make sure you give it whatever name you set for the event in your previous test of the PUT method. -Integrating EdgeDB Auth -======================= +Integrating Gel Auth +==================== -EdgeDB Auth provides a built-in authentication solution that is deeply -integrated with the EdgeDB server. This section outlines how to enable and -configure EdgeDB Auth in your application schema, manage authentication +|Gel| Auth provides a built-in authentication solution that is deeply +integrated with the Gel server. This section outlines how to enable and +configure Gel Auth in your application schema, manage authentication providers, and set key configuration parameters. -Setting up EdgeDB Auth -^^^^^^^^^^^^^^^^^^^^^^^ +Setting up Gel Auth +^^^^^^^^^^^^^^^^^^^ -To start using EdgeDB Auth, you must first enable it in your schema. Add the +To start using Gel Auth, you must first enable it in your schema. Add the following to your schema definition: .. code-block:: sdl - using extension auth; + using extension auth; Once added, make sure to apply the schema changes by migrating your database schema. .. code-block:: bash - $ edgedb migration create - $ edgedb migrate + $ gel migration create + $ gel migrate -Configuring EdgeDB Auth ------------------------ +Configuring Gel Auth +-------------------- -The configuration of EdgeDB Auth involves setting various parameters to secure +The configuration of Gel Auth involves setting various parameters to secure and tailor authentication to your needs. For now, we'll focus on the essential -parameters to get started. You can configure these settings through a Python -script, which is recommended for scalability, or you can use the EdgeDB UI for +parameters to get started. You can configure these settings through a Python +script, which is recommended for scalability, or you can use the Gel UI for a more user-friendly approach. **Auth Signing Key** @@ -1226,7 +1226,7 @@ Using Python: import secrets print(secrets.token_urlsafe(32)) -Once you have generated your key, configure it in EdgeDB like this: +Once you have generated your key, configure it in Gel like this: .. code-block:: edgeql @@ -1253,10 +1253,10 @@ To configure this in your application: Enabling authentication providers --------------------------------- -You need to configure at least one authentication provider to use EdgeDB Auth. -This can be done via the EdgeDB UI or directly through queries. +You need to configure at least one authentication provider to use Gel Auth. +This can be done via the Gel UI or directly through queries. -In this example, we'll configure a email and password provider. You can add +In this example, we'll configure a email and password provider. You can add it with the following query: .. code-block:: edgeql @@ -1268,14 +1268,14 @@ it with the following query: .. note:: - ``require_verification`` defaults to ``true``. In this example, we're - setting it to ``false`` to simplify the setup. In a production environment, - you should set it to ``true`` to ensure that users verify their email + ``require_verification`` defaults to ``true``. In this example, we're + setting it to ``false`` to simplify the setup. In a production environment, + you should set it to ``true`` to ensure that users verify their email addresses before they can log in. If you use the Email and Password provider, in addition to the -``require_verification`` configuration, you’ll need to configure SMTP to allow -EdgeDB to send email verification and password reset emails on your behalf. +``require_verification`` configuration, you'll need to configure SMTP to allow +|Gel| to send email verification and password reset emails on your behalf. Here is an example of setting a local SMTP server, in this case using a product called `Mailpit `__ which is @@ -1298,7 +1298,7 @@ great for testing in development: CONFIGURE CURRENT BRANCH SET ext::auth::SMTPConfig::validate_certs := false; -You can query the database configuration to discover which providers are +You can query the database configuration to discover which providers are configured with the following query: .. code-block:: edgeql @@ -1356,10 +1356,10 @@ Next, we're going to create endpoints in FastAPI to handle user registration import httpx router = APIRouter() - + # Value should be: # {protocol}://${host}:${port}/branch/${branch}/ext/auth/ - EDGEDB_AUTH_BASE_URL = os.getenv('EDGEDB_AUTH_BASE_URL') + GEL_AUTH_BASE_URL = os.getenv('GEL_AUTH_BASE_URL') @router.post("/auth/signup") async def handle_signup(request: Request): @@ -1371,7 +1371,7 @@ Next, we're going to create endpoints in FastAPI to handle user registration raise HTTPException(status_code=400, detail="Missing email or password") verifier, challenge = generate_pkce() - register_url = f"{EDGEDB_AUTH_BASE_URL}/register" + register_url = f"{GEL_AUTH_BASE_URL}/register" register_response = httpx.post(register_url, json={ "challenge": challenge, "email": email, @@ -1384,7 +1384,7 @@ Next, we're going to create endpoints in FastAPI to handle user registration return JSONResponse(status_code=400, content={"message": "Registration failed"}) code = register_response.json().get("code") - token_url = f"{EDGEDB_AUTH_BASE_URL}/token" + token_url = f"{GEL_AUTH_BASE_URL}/token" token_response = httpx.get(token_url, params={"code": code, "verifier": verifier}) if token_response.status_code != 200: @@ -1393,10 +1393,10 @@ Next, we're going to create endpoints in FastAPI to handle user registration auth_token = token_response.json().get("auth_token") response = JSONResponse(content={"message": "User registered"}) - response.set_cookie(key="edgedb-auth-token", value=auth_token, httponly=True, secure=True, samesite='strict') + response.set_cookie(key="gel-auth-token", value=auth_token, httponly=True, secure=True, samesite='strict') return response -The sign-up endpoint sends a POST request to the EdgeDB Auth server to register +The sign-up endpoint sends a POST request to the Gel Auth server to register a new user. It also sets the auth token as an HttpOnly cookie in the response. **Sign-in endpoint** @@ -1415,7 +1415,7 @@ a new user. It also sets the auth token as an HttpOnly cookie in the response. raise HTTPException(status_code=400, detail="Missing email, password, or provider.") verifier, challenge = generate_pkce() - authenticate_url = f"{EDGEDB_AUTH_BASE_URL}/authenticate" + authenticate_url = f"{GEL_AUTH_BASE_URL}/authenticate" response = httpx.post(authenticate_url, json={ "challenge": challenge, "email": email, @@ -1427,7 +1427,7 @@ a new user. It also sets the auth token as an HttpOnly cookie in the response. return JSONResponse(status_code=400, content={"message": "Authentication failed"}) code = response.json().get("code") - token_url = f"{EDGEDB_AUTH_BASE_URL}/token" + token_url = f"{GEL_AUTH_BASE_URL}/token" token_response = httpx.get(token_url, params={"code": code, "verifier": verifier}) if token_response.status_code != 200: @@ -1435,11 +1435,11 @@ a new user. It also sets the auth token as an HttpOnly cookie in the response. auth_token = token_response.json().get("auth_token") response = JSONResponse(content={"message": "Authentication successful"}) - response.set_cookie(key="edgedb-auth-token", value=auth_token, httponly=True, secure=True, samesite='strict') + response.set_cookie(key="gel-auth-token", value=auth_token, httponly=True, secure=True, samesite='strict') return response -The sign-in endpoint sends a POST request to the EdgeDB Auth server to authenticate -a user. It then retrieves the code from the response and exchanges it for an auth +The sign-in endpoint sends a POST request to the Gel Auth server to authenticate +a user. It then retrieves the code from the response and exchanges it for an auth token. The token is set as an HttpOnly cookie in the response. **Add the auth endpoints to the FastAPI application** @@ -1455,23 +1455,23 @@ Creating a new user in the sign-up endpoint ------------------------------------------- Now, let's automatically create a new user in the database when a user signs up. -We'll use the ``create_user_async_edgeql`` query we generated earlier +We'll use the ``create_user_async_edgeql`` query we generated earlier to achieve this, but we'll need to modify it slightly to link it to the -EdgeDB Auth identity. +|Gel| Auth identity. -First, let's update the EdgeDB schema to include a new field in the User type -to store the EdgeDB Auth identity and a new ``current_user`` type. +First, let's update the Gel schema to include a new field in the User type +to store the Gel Auth identity and a new ``current_user`` type. .. code-block:: sdl-diff - :caption: dbschema/default.esdl - + :caption: dbschema/default.gel + + global current_user := assert_single( + (( + select User + filter .identity = global ext::auth::ClientTokenIdentity + )) + ); - + type User extending Auditable { + required identity: ext::auth::Identity; required name: str { @@ -1484,8 +1484,8 @@ After updating the schema, run the following command to apply the changes: .. code-block:: bash - $ edgedb migration create - $ edgedb migrate + $ gel migration create + $ gel migrate Next, update the ``create_user_async_edgeql`` query to include the identity: @@ -1501,14 +1501,14 @@ Next, update the ``create_user_async_edgeql`` query to include the identity: created_at, }; -Run ``edgedb-py`` to generate the new function. Now, let's update the sign-up +Run ``gel-py`` to generate the new function. Now, let's update the sign-up endpoint to create a new user in the database. We need to do a few things: -1. Import ``edgedb``. +1. Import ``gel``. -2. Create an EdgeDB client. +2. Create an Gel client. -3. Get the identity ID from the EdgeDB Auth server response. +3. Get the identity ID from the Gel Auth server response. 4. Create a new user in the database using the ``create_user_async_edgeql`` query. @@ -1516,8 +1516,8 @@ endpoint to create a new user in the database. We need to do a few things: .. code-block:: python-diff - + import edgedb - + client = edgedb.create_async_client() + + import gel + + client = gel.create_async_client() @router.post("/auth/signup") async def handle_signup(request: Request): @@ -1530,9 +1530,9 @@ endpoint to create a new user in the database. We need to do a few things: + if not email or not password or not name: - raise HTTPException(status_code=400, detail="Missing email or password.") + raise HTTPException(status_code=400, detail="Missing email, password, or name.") - + verifier, challenge = generate_pkce() - register_url = f"{EDGEDB_AUTH_BASE_URL}/register" + register_url = f"{GEL_AUTH_BASE_URL}/register" register_response = httpx.post(register_url, json={ "challenge": challenge, "email": email, @@ -1540,14 +1540,14 @@ endpoint to create a new user in the database. We need to do a few things: "provider": "builtin::local_emailpassword", "verify_url": "http://localhost:8000/auth/verify", }) - + if register_response.status_code != 200 and register_response.status_code != 201: return JSONResponse(status_code=400, content={"message": "Registration failed"}) - + code = register_response.json().get("code") - token_url = f"{EDGEDB_AUTH_BASE_URL}/token" + token_url = f"{GEL_AUTH_BASE_URL}/token" token_response = httpx.get(token_url, params={"code": code, "verifier": verifier}) - + if token_response.status_code != 200: return JSONResponse(status_code=400, content={"message": "Token exchange failed"}) @@ -1555,14 +1555,14 @@ endpoint to create a new user in the database. We need to do a few things: + identity_id = token_response.json().get("identity_id") + try: + created_user = await create_user_qry.create_user(client, name=name, identity_id=identity_id) - + except edgedb.errors.ConstraintViolationError: + + except gel.errors.ConstraintViolationError: + raise HTTPException( + status_code=400, + detail={"error": f"User with email '{email}' already exists."}, + ) - + response = JSONResponse(content={"message": "User registered"}) - response.set_cookie(key="edgedb-auth-token", value=auth_token, httponly=True, secure=True, samesite='strict') + response.set_cookie(key="gel-auth-token", value=auth_token, httponly=True, secure=True, samesite='strict') return response You can now test the sign-up endpoint by sending a POST request to @@ -1578,24 +1578,19 @@ You can now test the sign-up endpoint by sending a POST request to If the request is successful, you should see a response with the message ``User registered``. - + Wrapping up =========== -Now you have a fully functioning events API in FastAPI backed by EdgeDB. If you +Now you have a fully functioning events API in FastAPI backed by Gel. If you want to see all the source code for the completed project, you'll find it in `our examples repo -`_. We also -have a separate example that demonstrates how to integrate EdgeDB Auth with -FastAPI in the same repo. Check it out -`here `_. -If you're stuck or if you just want to show off what you've built, come talk -to us `on Discord `_. It's a great community of -helpful folks, all passionate about being part of the next generation of +`_. We also +have a separate example that demonstrates how to integrate Gel Auth with +FastAPI in the same repo. Check it out +`here `_. +If you're stuck or if you just want to show off what you've built, come talk +to us `on Discord `_. It's a great community of +helpful folks, all passionate about being part of the next generation of databases. - -If you like what you see and want to dive deeper into EdgeDB and what it can -do, check out our `Easy EdgeDB book `_. In -it, you'll get to learn more about EdgeDB as we build an imaginary role-playing -game based on Bram Stoker's Dracula. diff --git a/docs/guides/tutorials/rest_apis_with_flask.rst b/docs/guides/tutorials/rest_apis_with_flask.rst index d6adf4d3e7a..3ba95a1abad 100644 --- a/docs/guides/tutorials/rest_apis_with_flask.rst +++ b/docs/guides/tutorials/rest_apis_with_flask.rst @@ -4,12 +4,12 @@ Flask ===== -:edb-alt-title: Building a REST API with EdgeDB and Flask +:edb-alt-title: Building a REST API with Gel and Flask -The EdgeDB Python client makes it easy to integrate EdgeDB into your preferred +The Gel Python client makes it easy to integrate Gel into your preferred web development stack. In this tutorial, we'll see how you can quickly start building RESTful APIs with `Flask `_ and -EdgeDB. +|Gel|. We'll build a simple movie organization system where you'll be able to fetch, create, update, and delete *movies* and *movie actors* via RESTful API @@ -19,10 +19,10 @@ Prerequisites ============= Before we start, make sure you've :ref:`installed ` the -``edgedb`` command-line tool. Here, we'll use Python 3.10 and a few of its +|gelcmd| command-line tool. Here, we'll use Python 3.10 and a few of its latest features while building the APIs. A working version of this tutorial can be found `on Github -`_. +`_. Install the dependencies @@ -34,8 +34,8 @@ directory. .. code-block:: bash - $ git clone git@github.com:edgedb/edgedb-examples.git - $ cd edgedb-examples/flask-crud + $ git clone git@github.com:geldata/gel-examples.git + $ cd gel-examples/flask-crud Create a Python 3.10 virtual environment, activate it, and install the dependencies with this command: @@ -44,28 +44,28 @@ dependencies with this command: $ python -m venv myvenv $ source myvenv/bin/activate - $ pip install edgedb flask 'httpx[cli]' + $ pip install gel flask 'httpx[cli]' Initialize the database ^^^^^^^^^^^^^^^^^^^^^^^ -Now, let's initialize an EdgeDB project. From the project's root directory: +Now, let's initialize an Gel project. From the project's root directory: .. code-block:: bash - $ edgedb project init + $ gel project init Initializing project... - Specify the name of EdgeDB instance to use with this project + Specify the name of Gel instance to use with this project [default: flask_crud]: > flask_crud Do you want to start instance automatically on login? [y/n] > y - Checking EdgeDB versions... + Checking Gel versions... -Once you've answered the prompts, a new EdgeDB instance called ``flask_crud`` +Once you've answered the prompts, a new Gel instance called ``flask_crud`` will be created and started. @@ -76,16 +76,16 @@ Let's test that we can connect to the newly started instance. To do so, run: .. code-block:: bash - $ edgedb + $ gel You should be connected to the database instance and able to see a prompt similar to this: :: - EdgeDB 2.x (repl 2.x) + Gel x.x (repl x.x) Type \help for help, \quit to quit. - edgedb> + gel> You can start writing queries here. However, the database is currently empty. Let's start designing the data model. @@ -98,14 +98,14 @@ The movie organization system will have two object typesβ€”**movies** and create API endpoints that'll allow us to fetch, create, update, and delete the objects while maintaining their relationships. -EdgeDB allows us to declaratively define the structure of the objects. The -schema lives inside ``.esdl`` file in the ``dbschema`` directory. It's -common to declare the entire schema in a single file ``dbschema/default.esdl``. +|Gel| allows us to declaratively define the structure of the objects. The +schema lives inside |.gel| file in the ``dbschema`` directory. It's +common to declare the entire schema in a single file :dotgel:`dbschema/default`. This is how our datatypes look: .. code-block:: sdl - # dbschema/default.esdl + # dbschema/default.gel module default { abstract type Auditable { @@ -142,7 +142,7 @@ This is how our datatypes look: Here, we've defined an ``abstract`` type called ``Auditable`` to take advantage -of EdgeDB's schema mixin system. This allows us to add a ``created_at`` +of Gel's schema mixin system. This allows us to add a ``created_at`` property to multiple types without repeating ourselves. The ``Actor`` type extends ``Auditable`` and inherits the ``created_at`` @@ -192,11 +192,11 @@ objects saved in the database. You can create the API in Flask like this: import json from http import HTTPStatus - import edgedb + import gel from flask import Blueprint, request actor = Blueprint("actor", __name__) - client = edgedb.create_client() + client = gel.create_client() @actor.route("/actors", methods=["GET"]) @@ -231,12 +231,12 @@ objects saved in the database. You can create the API in Flask like this: The ``Blueprint`` instance does the actual work of exposing the API. We also -create a blocking EdgeDB client instance to communicate with the database. By +create a blocking Gel client instance to communicate with the database. By default, this API will return a list of actors, but you can also filter the objects by name. In the ``get_actors`` function, we perform the database query via the -``edgedb`` client. Here, the ``client.query_json`` method conveniently returns +``gel`` client. Here, the ``client.query_json`` method conveniently returns ``JSON`` serialized objects. We deserialize the returned data in the ``response_payload`` dictionary and then return it. Afterward, the final JSON serialization part is taken care of by Flask. This endpoint is exposed to the @@ -591,7 +591,7 @@ looks similar to the ones you've already seen: """, filter_name=filter_name, ) - except edgedb.errors.ConstraintViolationError: + except gel.errors.ConstraintViolationError: return ( { "error": f"Cannot delete '{filter_name}. " @@ -645,11 +645,11 @@ Here's how we'll implement the ``POST /movie`` endpoint: import json from http import HTTPStatus - import edgedb + import gel from flask import Blueprint, request movie = Blueprint("movie", __name__) - client = edgedb.create_client() + client = gel.create_client() @movie.route("/movies", methods=["POST"]) def post_movie() -> tuple[dict, int]: @@ -796,7 +796,7 @@ That'll return: Conclusion ========== -While building REST APIs, the EdgeDB client allows you to leverage EdgeDB with +While building REST APIs, the Gel client allows you to leverage Gel with any microframework of your choice. Whether it's `FastAPI `_, `Flask `_, diff --git a/docs/guides/tutorials/sqlalchemy.rst b/docs/guides/tutorials/sqlalchemy.rst new file mode 100644 index 00000000000..6c1e14b71e2 --- /dev/null +++ b/docs/guides/tutorials/sqlalchemy.rst @@ -0,0 +1,294 @@ +.. _ref_guide_sqlalchemy: + +========== +SQLAlchemy +========== + +|Gel| supports SQL protocol for communicating with the database. This makes it possible to use it with SQLAlchemy by matching a SQLAlchemy schema to the |Gel| schema. You don't even need to figure out the conversion yourself because we have an automated tool for that. + +This tool becomes available when you install ``gel`` Python package. Once you have you |Gel| project setup, you can generate the SQLAlchemy schema with this command: + +.. code-block:: bash + + $ gel-orm sqlalchemy --mod sqlaschema --out sqlaschema + +The ``--mod`` is required and specifies the name of the root Python module that will be generated (the name will be referenced in the generated code). The ``--out`` indicates the output directory (which will be created if it doesn't exist) for the newly generated module. + +Even though SQLAlchemy and |Gel| both view the schema as a bunch of types with fields and interconnections, there are still some differences between what |Gel| and SQLAlchemy can represent. + + +Properties +========== + +Property types must match the basic Postgres types supported by SQLAlchemy, so avoid any custom types as they will be skipped. Currently we support the following: + +* :eql:type:`std::bool` +* :eql:type:`std::str` +* :eql:type:`std::int16` +* :eql:type:`std::int32` +* :eql:type:`std::int64` +* :eql:type:`std::float32` +* :eql:type:`std::float64` +* :eql:type:`std::uuid` +* :eql:type:`std::bytes` +* :eql:type:`cal::local_date` +* :eql:type:`cal::local_time` +* :eql:type:`cal::local_datetime` +* :eql:type:`std::datetime` + +Array properties are supported for all of the above types as well. + +Multi properties do not have a uniqueness condition that would be true for every row in an exposed SQL table, so they cannot be properly reflected into a SQLAlchemy schema. That means that the schema generator will omit them from the schema. If you needs to reflect multi properties, consider replacing them with a single array property. + + +Links +===== + +Plain single links are reflected as a relationship. + +Multi links get represented as a many-to-many relationship with an implicit intermediary table. + +Links that have link properties are reflected as intermediary objects with a ``source`` and ``target`` relationships to the end points of the link. The link properties then become the fields of this link object. + +All links automatically generate the ``back_populates`` relationships as well. The name of these back-links takes the format of ``_linkname_SourceName``, which mimics the EdgeQL version of backlinks ``.__table``. + +Finally, the file containing SQLAlchemy models is ``default.py`` (named after the ``default`` |Gel| module). It contains ``Post``, ``User``, and ``UserGroup`` model declarations. + +Let's start with what all models have in common: ``id`` and ``gel_type_id``. They refer to the unique object ``id`` and to the ``__type__.id`` in the |Gel| schema. These two UUID fields are managed automatically by |Gel| and should not be directly modified. Effectively they are supposed to be treated as read-only fields. + +Properties +---------- + +The |Gel| schema declares a few properties: ``name`` for ``User`` and ``UserGroup`` as well as ``body`` for ``Post``. These get reflected as string mapped columns in the corresponding SQLAlchemy models. As long as a property has a valid corresponding SQLAlchemy type it will be reflected in this manner. + +Links +----- + +Let's first look at the ``Post`` declaration in |Gel|. A ``Post`` has a link ``author`` pointing to a ``User``. So the reflected class ``Post`` has a ``ForeignKey`` ``author_id`` and the corresponding relationship ``author``. + +Note that the ``author`` relationship is annotated with ``orm.Mapped['projschema.default.User']``. This annotation uses the value passed as ``--mod`` in order to correctly specify the type for the ``author`` relationship. + +Each reflected relationship also automatically declares a back-link via ``back_populates``. The naming format is ``__``. For the ``author`` link the name of the back-link is ``_author_Post``. + +We can look at the ``User`` model and find ``_author_Post`` relationship pointing back to ``'projschema.default.Post'`` and using ``author`` as the ``back_populates`` value. + +``User`` model also has a many-to-many relationship with ``UserGroup``. Since in the |Gel| schema that is represented by the multi link ``users`` that originates on the ``UserGroup`` type, the ``User`` end of this relationship is a back-link and it follows the back-link naming convention. The relationship is ``_users_UserGroup`` and in addition to ``back_populates`` it also declares the other endpoint as ``'projschema.default.UserGroup'`` and secondary link table (from ``_tables.py``) being used. + +Finally, ``UserGroup`` model has the other half of the many-to-many relationship declaration. It has the same name as the |Gel| schema: ``users``. Otherwise it mirrors the relationship declaration for ``_users_UserGroup``. diff --git a/docs/guides/tutorials/sqlmodel.rst b/docs/guides/tutorials/sqlmodel.rst new file mode 100644 index 00000000000..07b7872a57d --- /dev/null +++ b/docs/guides/tutorials/sqlmodel.rst @@ -0,0 +1,273 @@ +.. _ref_guide_sqlmodel: + +======== +SQLModel +======== + +|Gel| supports SQL protocol for communicating with the database. This makes it possible to use it with SQLModel by matching a SQLModel schema to the |Gel| schema. You don't even need to figure out the conversion yourself because we have an automated tool for that. + +This tool becomes available when you install ``gel`` Python package. Once you have you |Gel| project setup, you can generate the SQLModel schema with this command: + +.. code-block:: bash + + $ gel-orm sqlmodel --mod sqlmschema --out sqlmschema + +The ``--mod`` is required and specifies the name of the root Python module that will be generated (the name will be referenced in the generated code). The ``--out`` indicates the output directory (which will be created if it doesn't exist) for the newly generated module. + +Even though SQLModel and |Gel| both view the schema as a bunch of types with fields and interconnections, there are still some differences between what |Gel| and SQLModel can represent. + + +Properties +========== + +Property types must match the basic Postgres types supported by SQLModel, so avoid any custom types as they will be skipped. Currently we support the following: + +* :eql:type:`std::bool` +* :eql:type:`std::str` +* :eql:type:`std::int16` +* :eql:type:`std::int32` +* :eql:type:`std::int64` +* :eql:type:`std::float32` +* :eql:type:`std::float64` +* :eql:type:`std::uuid` +* :eql:type:`std::bytes` +* :eql:type:`cal::local_date` +* :eql:type:`cal::local_time` +* :eql:type:`cal::local_datetime` +* :eql:type:`std::datetime` + +Array properties are supported for all of the above types as well. + +Multi properties do not have a uniqueness condition that would be true for every row in an exposed SQL table, so they cannot be properly reflected into a SQLModel schema. That means that the schema generator will omit them from the schema. If you needs to reflect multi properties, consider replacing them with a single array property. + + +Links +===== + +Plain single links are reflected as a relationship. + +Multi links get represented as a many-to-many relationship with an implicit intermediary table. + +Links that have link properties are reflected as intermediary objects with a ``source`` and ``target`` relationships to the end points of the link. The link properties then become the fields of this link object. + +All links automatically generate the ``back_populates`` relationships as well. The name of these back-links takes the format of ``_linkname_SourceName``, which mimics the EdgeQL version of backlinks ``.__table``. + +Finally, the file containing SQLModel models is ``default.py`` (named after the ``default`` |Gel| module). It contains ``Post``, ``User``, and ``UserGroup`` model declarations. + +Let's start with what all models have in common: ``id`` and ``gel_type_id``. They refer to the unique object ``id`` and to the ``__type__.id`` in the |Gel| schema. These two UUID fields are managed automatically by |Gel| and should not be directly modified. Effectively they are supposed to be treated as read-only fields. + +Properties +---------- + +The |Gel| schema declares a few properties: ``name`` for ``User`` and ``UserGroup`` as well as ``body`` for ``Post``. These get reflected as ``str`` fields in the corresponding models. As long as a property has a valid corresponding SQLModel ``Field`` type it will be reflected in this manner. + +Links +----- + +Let's first look at the ``Post`` declaration in |Gel|. A ``Post`` has a link ``author`` pointing to a ``User``. So the reflected class ``Post`` has a UUID ``Field`` ``author_id`` which is a foreign key. There is also the corresponding ``author`` ``Relationship``. The target type of ``author`` is annotated to be ``'User'``. + +Each reflected ``Relationship`` also automatically declares a back-link via ``back_populates``. The naming format is ``__``. For the ``author`` link the name of the back-link is ``_author_Post``. + +We can look at the ``User`` model and find ``_author_Post`` ``Relationship`` pointing back to ``list['Post']`` and using ``author`` as the ``back_populates`` value. + +``User`` model also has a many-to-many relationship with ``UserGroup``. Since in the |Gel| schema that is represented by the multi link ``users`` that originates on the ``UserGroup`` type, the ``User`` end of this relationship is a back-link and it follows the back-link naming convention. The relationship is ``_users_UserGroup`` and in addition to ``back_populates`` it also declares the other endpoint as ``list['UserGroup']`` and the ``link_model`` ``UserGroup_users_table`` from ``_tables.py`` is used. + +Finally, ``UserGroup`` model has the other half of the many-to-many relationship declaration. It has the same name as the |Gel| schema: ``users``. Otherwise it mirrors the ``Relationship`` declaration for ``_users_UserGroup``. diff --git a/docs/guides/tutorials/trpc.rst b/docs/guides/tutorials/trpc.rst index 4dab003f33a..ab6356f9425 100644 --- a/docs/guides/tutorials/trpc.rst +++ b/docs/guides/tutorials/trpc.rst @@ -4,47 +4,47 @@ tRPC ==== -:edb-alt-title: Integrating EdgeDB with tRPC +:edb-alt-title: Integrating Gel with tRPC -This guide explains how to integrate **EdgeDB** with **tRPC** for a modern, -type-safe API. We'll cover setting up database interactions, API routing, -and implementing authentication, all while ensuring type safety across the +This guide explains how to integrate **Gel** with **tRPC** for a modern, +type-safe API. We'll cover setting up database interactions, API routing, +and implementing authentication, all while ensuring type safety across the client and server. You can reference the following repositories for more context: -- `create-t3-turbo-edgedb `_ - - A monorepo template using the `T3 stack `_, - `Turborepo `_, and EdgeDB. -- `LookFeel Project `_ - A real-world - example using **EdgeDB** and **tRPC**. +- `create-t3-turbo-gel `_ - + A monorepo template using the `T3 stack `_, + `Turborepo `_, and Gel. +- `LookFeel Project `_ - A real-world + example using **Gel** and **tRPC**. -Step 1: EdgeDB setup -==================== +Step 1: Gel setup +================= -EdgeDB will serve as the database layer for your application. +|Gel| will serve as the database layer for your application. -Install and initialize EdgeDB ------------------------------ +Install and initialize Gel +-------------------------- -To initialize **EdgeDB**, run the following command using your preferred +To initialize **Gel**, run the following command using your preferred package manager: .. code-block:: bash - $ pnpm dlx edgedb project init # or npx edgedb project init + $ pnpm dlx gel project init # or `npx gel project init` -This will create an EdgeDB project and set up a schema to start with. +This will create an Gel project and set up a schema to start with. -Define the EdgeDB Schema ------------------------- +Define the Gel Schema +--------------------- The previous command generated a schema file in the ``dbschema`` directory. -Here’s an example schema that defines a ``User`` model: +Here's an example schema that defines a ``User`` model: .. code-block:: sdl - :caption: dbschema/default.esdl + :caption: dbschema/default.gel module default { type User { @@ -60,43 +60,43 @@ Once schema changes are made, apply migrations with: .. code-block:: bash - $ pnpm dlx edgedb migration create # or npx edgedb migration create - $ pnpm dlx edgedb migration apply # or npx edgedb migration apply + $ pnpm dlx gel migration create # or npx gel migration create + $ pnpm dlx gel migration apply # or npx gel migration apply -Step 2: Configure EdgeDB Client -=============================== +Step 2: Configure Gel Client +============================ -To interact with **EdgeDB** from your application, you need to configure the +To interact with **Gel** from your application, you need to configure the client. -Install EdgeDB Client ---------------------- +Install Gel Client +------------------ -First, install the **EdgeDB** client using your package manager: +First, install the **Gel** client using your package manager: .. code-block:: bash - $ pnpm add edgedb - $ # or yarn add edgedb - $ # or npm install edgedb - $ # or bun add edgedb + $ pnpm add gel + $ # or yarn add gel + $ # or npm install gel + $ # or bun add gel -Then, create a client instance in a ``edgedb.ts`` file: +Then, create a client instance in a ``gel.ts`` file: .. code-block:: typescript - :caption: src/edgedb.ts + :caption: src/gel.ts - import { createClient } from 'edgedb'; + import { createClient } from 'gel'; - const edgedbClient = createClient(); - export default edgedbClient; + const gelClient = createClient(); + export default gelClient; This client will be used to interact with the database and execute queries. Step 3: tRPC setup ================== -**tRPC** enables type-safe communication between the frontend and +**tRPC** enables type-safe communication between the frontend and backend. Install tRPC dependencies @@ -111,7 +111,7 @@ Install the required tRPC dependencies: $ # or npm install @trpc/server @trpc/client $ # or bun add @trpc/server @trpc/client -If you're using React and would like to use React Query with tRPC, also +If you're using React and would like to use React Query with tRPC, also install a wrapper around the `@tanstack/react-query `_. .. code-block:: bash @@ -124,26 +124,26 @@ install a wrapper around the `@tanstack/react-query { - const users = await edgedbClient.query('SELECT User { name, email }'); + const users = await gelClient.query('SELECT User { name, email }'); return users; }), }); export type AppRouter = typeof appRouter; -This example defines a query that fetches user data from EdgeDB, ensuring +This example defines a query that fetches user data from Gel, ensuring type safety in both the query and response. Step 4: Use tRPC Client @@ -156,12 +156,12 @@ the API from the frontend. We will demonstrate how to integrate tRPC with With Next.js ------------ -If you're working with **Next.js**, here’s how to integrate **tRPC**: +If you're working with **Next.js**, here's how to integrate **tRPC**: Create a tRPC API Handler ~~~~~~~~~~~~~~~~~~~~~~~~~ -Inside ``api/trpc/[trpc].ts``, create the following handler to connect +Inside ``api/trpc/[trpc].ts``, create the following handler to connect **tRPC** with Next.js: .. code-block:: typescript @@ -222,7 +222,7 @@ If you're not using **Next.js**, here's how you can integrate **tRPC** with Set up Express server with tRPC ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Here’s how you can create an Express server and integrate **tRPC**: +Here's how you can create an Express server and integrate **tRPC**: .. code-block:: typescript @@ -266,34 +266,34 @@ In non-Next.js apps, use the tRPC client to interact with the server: console.log(users); } -Step 5: Set up authentication with EdgeDB Auth -============================================== +Step 5: Set up authentication with Gel Auth +=========================================== -In this section, we will cover how to integrate **EdgeDB Auth** with **tRPC** -and context in both **Next.js** and **Express** environments. This will ensure -that user authentication is handled securely and that both server-side and -client-side tRPC calls can access the user’s session. +In this section, we will cover how to integrate **Gel Auth** with **tRPC** +and context in both **Next.js** and **Express** environments. This will ensure +that user authentication is handled securely and that both server-side and +client-side tRPC calls can access the user's session. -EdgeDB Auth with tRPC and tRPC context in Next.js -------------------------------------------------- +Gel Auth with tRPC and tRPC context in Next.js +---------------------------------------------- -In **Next.js**, integrating **EdgeDB Auth** with **tRPC** involves creating a -context that provides the user session and EdgeDB client to the tRPC API. +In **Next.js**, integrating **Gel Auth** with **tRPC** involves creating a +context that provides the user session and Gel client to the tRPC API. -1. **Initialize EdgeDB Client and Auth** +1. **Initialize Gel Client and Auth** - First, initialize the **EdgeDB** client and **EdgeDB Auth**: + First, initialize the **Gel** client and **Gel Auth**: .. code-block:: typescript - import { createClient } from "edgedb"; - import createAuth from "@edgedb/auth-nextjs/app"; + import { createClient } from "gel"; + import createAuth from "@gel/auth-nextjs/app"; - // Initialize EdgeDB client - export const edgedbClient = createClient(); + // Initialize Gel client + export const gelClient = createClient(); - // Initialize EdgeDB Auth - export const auth = createAuth(edgedbClient, { + // Initialize Gel Auth + export const auth = createAuth(gelClient, { baseUrl: process.env.VERCEL_ENV === "production" ? "https://production.yourapp.com" : "http://localhost:3000", @@ -301,7 +301,7 @@ context that provides the user session and EdgeDB client to the tRPC API. 2. **Create tRPC Context** - The **tRPC** context provides the EdgeDB Auth session to the tRPC + The **tRPC** context provides the Gel Auth session to the tRPC procedures: .. code-block:: typescript @@ -309,11 +309,11 @@ context that provides the user session and EdgeDB client to the tRPC API. import { initTRPC } from '@trpc/server'; import { headers } from "next/headers"; - import { auth } from "src/edgedb.ts"; + import { auth } from "src/gel.ts"; - // Create tRPC context with session and EdgeDB client + // Create tRPC context with session and Gel client export const createTRPCContext = async () => { - const session = await auth.getSession(); // Retrieve session from EdgeDB Auth + const session = await auth.getSession(); // Retrieve session from Gel Auth return { session, // Pass the session to the context @@ -325,7 +325,7 @@ context that provides the user session and EdgeDB client to the tRPC API. 3. **Use tRPC Context in API Handler** - In **Next.js**, set up an API handler to connect your **tRPC router** with + In **Next.js**, set up an API handler to connect your **tRPC router** with the context: .. code-block:: typescript @@ -342,8 +342,8 @@ context that provides the user session and EdgeDB client to the tRPC API. 4. **Example tRPC Procedure** - You can now write procedures in your tRPC router, making use of the - **EdgeDB Auth** session and the **EdgeDB** client: + You can now write procedures in your tRPC router, making use of the + **Gel Auth** session and the **Gel** client: .. code-block:: typescript @@ -352,7 +352,7 @@ context that provides the user session and EdgeDB client to the tRPC API. if (!(await ctx.session.isSignedIn())) { throw new Error("Not authenticated"); } - // Fetch data from EdgeDB using the authenticated client + // Fetch data from Gel using the authenticated client const userData = await ctx.session.client.query(` select User { name, email } `); @@ -361,34 +361,34 @@ context that provides the user session and EdgeDB client to the tRPC API. }), }); -EdgeDB Auth with tRPC and Context in Express --------------------------------------------- +Gel Auth with tRPC and Context in Express +----------------------------------------- -In **Express**, the process involves setting up middleware to manage the +In **Express**, the process involves setting up middleware to manage the authentication and context for tRPC procedures. -1. **Initialize EdgeDB Client and Auth for Express** +1. **Initialize Gel Client and Auth for Express** - Just like in **Next.js**, you first initialize the **EdgeDB** client and - **EdgeDB Auth**: + Just like in **Next.js**, you first initialize the **Gel** client and + **Gel Auth**: .. code-block:: typescript - import { createClient } from "edgedb"; - import createExpressAuth from "@edgedb/auth-express"; + import { createClient } from "gel"; + import createExpressAuth from "@gel/auth-express"; - // Initialize EdgeDB client - const edgedbClient = createClient(); + // Initialize Gel client + const gelClient = createClient(); - // Initialize EdgeDB Auth for Express - export const auth = createExpressAuth(edgedbClient, { + // Initialize Gel Auth for Express + export const auth = createExpressAuth(gelClient, { baseUrl: `http://localhost:${process.env.PORT || 3000}`, }); 2. **Create tRPC Context Middleware for Express** - In **Express**, create middleware to pass the authenticated session and - EdgeDB client to the tRPC context: + In **Express**, create middleware to pass the authenticated session and + Gel client to the tRPC context: .. code-block:: typescript @@ -403,15 +403,15 @@ authentication and context for tRPC procedures. const session = req.auth?.session(); // Get authenticated session req.context = { session, // Add session to context - edgedbClient, // Add EdgeDB client to context + gelClient, // Add Gel client to context }; next(); }; 3. **Set up tRPC Router in Express** - Use the **tRPC router** in **Express** by including the context middleware - and **EdgeDB Auth** middleware: + Use the **tRPC router** in **Express** by including the context middleware + and **Gel Auth** middleware: .. code-block:: typescript @@ -423,7 +423,7 @@ authentication and context for tRPC procedures. const app = express(); - // EdgeDB Auth middleware to handle sessions + // Gel Auth middleware to handle sessions app.use(auth.middleware); // Custom middleware to pass tRPC context @@ -444,8 +444,8 @@ authentication and context for tRPC procedures. 4. **Example tRPC Procedure in Express** - Once the context is set, you can define tRPC procedures that use both the - session and EdgeDB client: + Once the context is set, you can define tRPC procedures that use both the + session and Gel client: .. code-block:: typescript @@ -454,7 +454,7 @@ authentication and context for tRPC procedures. if (!(await ctx.session.isSignedIn())) { throw new Error("Not authenticated"); } - // Fetch data from EdgeDB using the authenticated client + // Fetch data from Gel using the authenticated client const userData = await ctx.session.client.query(` select User { name, email } `); @@ -466,14 +466,14 @@ authentication and context for tRPC procedures. Conclusion ---------- -By integrating **EdgeDB Auth** into the tRPC context, you ensure that -authenticated sessions are securely passed to API procedures, enabling +By integrating **Gel Auth** into the tRPC context, you ensure that +authenticated sessions are securely passed to API procedures, enabling user authentication and protecting routes. You can also reference these projects for further examples: -- `create-t3-turbo-edgedb `_ - - A monorepo template using the `T3 stack `_, - `Turborepo `_, and EdgeDB. -- `LookFeel Project `_ - A real-world - example using **EdgeDB** and **tRPC**. +- `create-t3-turbo-gel `_ - + A monorepo template using the `T3 stack `_, + `Turborepo `_, and Gel. +- `LookFeel Project `_ - A real-world + example using **Gel** and **tRPC**. diff --git a/docs/index.rst b/docs/index.rst index b9a8f914ab1..ce82fdc02ad 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,11 +1,11 @@ .. _index_toplevel: -==================== -EdgeDB documentation -==================== +================= +Gel documentation +================= -Welcome to the EdgeDB |version| documentation. +Welcome to the |Gel| |version| documentation. .. !!! DO NOT CHANGE :maxdepth: egdedb.com/docs depends on it !!! @@ -24,3 +24,4 @@ Welcome to the EdgeDB |version| documentation. reference/index cheatsheets/index changelog/index + cloud/index diff --git a/docs/intro/branches.rst b/docs/intro/branches.rst index ffd288e5c4d..c770b6e71e4 100644 --- a/docs/intro/branches.rst +++ b/docs/intro/branches.rst @@ -4,18 +4,18 @@ Branches ======== -EdgeDB's branches make it easy to prototype app features that impact your +|Gel's| branches make it easy to prototype app features that impact your database schema, even in cases where those features are never released. You can -create a branch in your EdgeDB database that corresponds to a feature branch in -your VCS. When you're done, either :ref:`merge ` -that branch into your main branch or :ref:`drop ` +create a branch in your Gel database that corresponds to a feature branch in +your VCS. When you're done, either :ref:`merge ` +that branch into your main branch or :ref:`drop ` it leaving your original schema intact. .. note:: The procedure we will describe should be adaptable to any VCS offering branching and rebasing, but in order to make the examples concrete and - easy-to-follow, we'll be demonstrating how EdgeDB branches interact with + easy-to-follow, we'll be demonstrating how Gel branches interact with Git branches. You may adapt these examples to your VCS of choice. @@ -23,20 +23,20 @@ it leaving your original schema intact. ------------------------------ Create a feature branch in your VCS and switch to it. Then, create and switch -to a corresponding branch in EdgeDB using the CLI. +to a corresponding branch in Gel using the CLI. .. code-block:: bash - $ edgedb branch create feature + $ gel branch create feature Creating branch 'feature'... OK: CREATE BRANCH - $ edgedb branch switch feature + $ gel branch switch feature Switching from 'main' to 'feature' .. note:: - You can alternatively create and switch in one shot using ``edgedb branch - switch -c feature``. + You can alternatively create and switch in one shot using :gelcmd:`branch + switch -c feature`. 2. Build your feature @@ -45,34 +45,34 @@ to a corresponding branch in EdgeDB using the CLI. Write your code and make any schema changes your feature requires. -3. Pull any changes on ``main`` -------------------------------- +3. Pull any changes on "main" +----------------------------- .. note:: - This step is optional. If you know your ``main`` code branch is current and + This step is optional. If you know your |main| code branch is current and all migrations in that code branch have already been applied to your - ``main`` database branch, feel free to skip it. + |main| database branch, feel free to skip it. -We need to make sure that merging our feature branch onto ``main`` is a simple +We need to make sure that merging our feature branch onto |main| is a simple fast-forward. The next two steps take care of that. -Switch back to your ``main`` code branch. Run ``git pull`` to pull down any new -changes. If any of these are schema changes, use ``edgedb branch switch main`` -to switch back to your ``main`` database branch and apply the new schema with -``edgedb migrate``. +Switch back to your |main| code branch. Run ``git pull`` to pull down any new +changes. If any of these are schema changes, use :gelcmd:`branch switch main` +to switch back to your |main| database branch and apply the new schema with +:gelcmd:`migrate`. Once this is done, you can switch back to your feature branches in your VCS and -EdgeDB. +|Gel|. -4. Rebase your feature branch on ``main`` ------------------------------------------ +4. Rebase your feature branch on "main" +--------------------------------------- .. note:: If you skipped the previous step, you can skip this one too. This is only - necessary if you had to pull down new changes on ``main``. + necessary if you had to pull down new changes on |main|. For your code branch, first make sure you're on ``feature`` and then run the rebase: @@ -85,13 +85,13 @@ Now, do the same for your database, also from ``feature``: .. code-block:: bash - $ edgedb branch rebase main + $ gel branch rebase main -5. Merge ``feature`` onto ``main`` ----------------------------------- +5. Merge ``feature`` onto "main" +-------------------------------- -Switch back to both ``main`` branches and merge ``feature``. +Switch back to both |main| branches and merge ``feature``. .. code-block:: bash @@ -102,9 +102,9 @@ Switch back to both ``main`` branches and merge ``feature``. .. code-block:: bash - $ edgedb branch switch main + $ gel branch switch main Switching from 'feature' to 'main' - $ edgedb branch merge feature + $ gel branch merge feature Now, your feature and its schema have been successfully merged! πŸŽ‰ @@ -112,8 +112,8 @@ Now, your feature and its schema have been successfully merged! πŸŽ‰ Further reading ^^^^^^^^^^^^^^^ -- :ref:`Branches CLI ` +- :ref:`Branches CLI ` Further information can be found in the `branches RFC -`_, +`_, which describes the design of the migration system. diff --git a/docs/intro/cli.rst b/docs/intro/cli.rst index 437fdb425f2..9b2fce60dc3 100644 --- a/docs/intro/cli.rst +++ b/docs/intro/cli.rst @@ -6,61 +6,55 @@ The CLI ======= -The ``edgedb`` command line tool is an integral part of the developer workflow -of building with EdgeDB. Below are instructions for installing it. +The |gelcmd| command line tool is an integral part of the developer workflow +of building with Gel. Below are instructions for installing it. Installation ------------ -To get started with EdgeDB, the first step is install the ``edgedb`` CLI. +To get started with Gel, the first step is install the |gelcmd| CLI. **Linux or macOS** .. code-block:: bash - $ curl --proto '=https' --tlsv1.2 -sSf https://sh.edgedb.com | sh + $ curl --proto '=https' --tlsv1.2 -sSf https://geldata.com/sh | sh **Windows Powershell** .. note:: - EdgeDB on Windows requires WSL 2 because the EdgeDB server runs on Linux. + Gel on Windows requires WSL 2 because the Gel server runs on Linux. .. code-block:: powershell - PS> iwr https://ps1.edgedb.com -useb | iex + PS> iwr https://geldata.com/ps1 -useb | iex Follow the prompts on screen to complete the installation. The script will -download the ``edgedb`` command built for your OS and add a path to it to your +download the |gelcmd| command built for your OS and add a path to it to your shell environment. Then test the installation: .. code-block:: bash - $ edgedb --version - EdgeDB CLI 4.x+abcdefg + $ gel --version + Gel CLI x.x+abcdefg .. note:: If you encounter a ``command not found`` error, you may need to open a fresh shell window. -.. note:: - - To install the CLI with a package manager, refer to the "Additional - methods" section of the `Install `_ page - for instructions. - See ``help`` commands --------------------- -The entire CLI is self-documenting. Once it's installed, run ``edgedb --help`` +The entire CLI is self-documenting. Once it's installed, run :gelcmd:`--help` to see a breakdown of all the commands and options. .. code-block:: bash - $ edgedb --help - Usage: edgedb [OPTIONS] [COMMAND] + $ gel --help + Usage: gel [OPTIONS] [COMMAND] Commands: @@ -68,59 +62,59 @@ to see a breakdown of all the commands and options. Options: - Connection Options (edgedb --help-connect to see full list): + Connection Options (gel --help-connect to see full list): Cloud Connection Options: -The majority of CLI commands perform some action against a *particular* EdgeDB +The majority of CLI commands perform some action against a *particular* Gel instance. As such, there are a standard set of flags that are used to specify *which instance* should be the target of the command, plus additional information like TLS certificates. The following command documents these flags. .. code-block:: bash - $ edgedb --help-connect + $ gel --help-connect Connection Options (full list): -I, --instance - Instance name (use `edgedb instance list` to list local, remote and + Instance name (use `gel instance list` to list local, remote and Cloud instances available to you) --dsn - DSN for EdgeDB to connect to (overrides all other options except + DSN for Gel to connect to (overrides all other options except password) --credentials-file Path to JSON file to read credentials from -H, --host - EdgeDB instance host + Gel instance host -P, --port - Port to connect to EdgeDB + Port to connect to Gel --unix-path - A path to a Unix socket for EdgeDB connection + A path to a Unix socket for Gel connection When the supplied path is a directory, the actual path will be computed using the `--port` and `--admin` parameters. ... -If you ever want to see documentation for a particular command (``edgedb -migration create``) or group of commands (``edgedb instance``), just append -the ``--help`` flag. +If you ever want to see documentation for a particular command ( +:gelcmd:`migration create`) or group of commands (:gelcmd:`instance`), +just append the ``--help`` flag. .. code-block:: bash - $ edgedb instance --help - Manage local EdgeDB instances + $ gel instance --help + Manage local Gel instances - Usage: edgedb instance + Usage: gel instance Commands: - create Initialize a new EdgeDB instance + create Initialize a new Gel instance list Show all instances status Show status of an instance start Start an instance @@ -134,4 +128,4 @@ To upgrade to the latest version: .. code-block:: bash - $ edgedb cli upgrade + $ gel cli upgrade diff --git a/docs/intro/clients.rst b/docs/intro/clients.rst index 3f56d57b254..83c5f1b409d 100644 --- a/docs/intro/clients.rst +++ b/docs/intro/clients.rst @@ -4,25 +4,25 @@ Client Libraries ================ -EdgeDB implements libraries for popular languages that make it easier to work -with EdgeDB. These libraries provide a common set of functionality. +|Gel| implements libraries for popular languages that make it easier to work +with Gel. These libraries provide a common set of functionality. - *Instantiating clients.* Most libraries implement a ``Client`` class that - internally manages a pool of physical connections to your EdgeDB instance. + internally manages a pool of physical connections to your Gel instance. - *Resolving connections.* All client libraries implement a standard protocol for determining how to connect to your database. In most cases, this will - involve checking for special environment variables like ``EDGEDB_DSN`` or, in - the case of EdgeDB Cloud instances, ``EDGEDB_INSTANCE`` and - ``EDGEDB_SECRET_KEY``. + involve checking for special environment variables like :gelenv:`DSN` or, in + the case of Gel Cloud instances, :gelenv:`INSTANCE` and + :gelenv:`SECRET_KEY`. (More on this in :ref:`the Connection section below `.) - *Executing queries.* A ``Client`` will provide some methods for executing queries against your database. Under the hood, this query is executed using - EdgeDB's efficient binary protocol. + Gel's efficient binary protocol. .. note:: - For some use cases, you may not need a client library. EdgeDB allows you to + For some use cases, you may not need a client library. Gel allows you to execute :ref:`queries over HTTP `. This is slower than the binary protocol and lacks support for transactions and rich data types, but may be suitable if a client library isn't available for your language of @@ -31,17 +31,19 @@ with EdgeDB. These libraries provide a common set of functionality. Available libraries =================== -To execute queries from your application code, use one of EdgeDB's *client +To execute queries from your application code, use one of Gel's *client libraries* for the following languages. -- :ref:`JavaScript/TypeScript ` -- :ref:`Go ` -- :ref:`Python ` -- :ref:`Rust ` -- :ref:`C# and F# ` -- :ref:`Java ` -- :ref:`Dart ` -- :ref:`Elixir ` +- :ref:`JavaScript/TypeScript ` +- :ref:`Go ` +- :ref:`Python ` + +.. XXX: link to third-party doc websites +.. - :ref:`Rust ` +.. - :ref:`C# and F# ` +.. - :ref:`Java ` +.. - :ref:`Dart ` +.. - :ref:`Elixir ` Usage ===== @@ -53,7 +55,7 @@ initialize a project. $ mydir myproject $ cd myproject - $ edgedb project init + $ gel project init Configure the environment as needed for your preferred language. @@ -94,30 +96,16 @@ Configure the environment as needed for your preferred language. $ dotnet new console -o . -f net6.0 - .. code-tab:: bash - :caption: Maven (Java) - - $ touch Main.java - .. code-tab:: bash - :caption: Gradle (Java) - - $ touch Main.java - - .. code-tab:: bash - :caption: Elixir - - $ mix new edgedb_quickstart - -Install the EdgeDB client library. +Install the Gel client library. .. tabs:: .. code-tab:: bash :caption: Node.js - $ npm install edgedb # npm - $ yarn add edgedb # yarn + $ npm install gel # npm + $ yarn add gel # yarn .. code-tab:: txt :caption: Deno @@ -127,7 +115,7 @@ Install the EdgeDB client library. .. code-tab:: bash :caption: Python - $ pip install edgedb + $ pip install gel .. code-tab:: toml :caption: Rust @@ -135,40 +123,20 @@ Install the EdgeDB client library. # Cargo.toml [dependencies] - edgedb-tokio = "0.5.0" + gel-tokio = "0.5.0" # Additional dependency tokio = { version = "1.28.1", features = ["macros", "rt-multi-thread"] } .. code-tab:: bash :caption: Go - $ go get github.com/edgedb/edgedb-go + $ go get github.com/geldata/gel-go .. code-tab:: bash :caption: .NET - $ dotnet add package EdgeDB.Net.Driver - - .. code-tab:: xml - :caption: Maven (Java) + $ dotnet add package Gel.Net.Driver - // pom.xml - - com.edgedb - driver - - - .. code-tab:: - :caption: Gradle (Java) - - // build.gradle - implementation 'com.edgedb:driver' - - .. code-tab:: elixir - :caption: Elixir - - # mix.exs - {:edgedb, "~> 0.6.0"} Copy and paste the following simple script. This script initializes a ``Client`` instance. Clients manage an internal pool of connections to your @@ -189,7 +157,7 @@ database and provide a set of methods for executing queries. .. code-tab:: typescript :caption: Node.js - import {createClient} from 'edgedb'; + import {createClient} from 'gel'; const client = createClient(); @@ -198,19 +166,9 @@ database and provide a set of methods for executing queries. }); - .. code-tab:: typescript - :caption: Deno - - import {createClient} from 'https://deno.land/x/edgedb/mod.ts'; - - const client = createClient(); - - const result = await client.querySingle(`select random()`); - console.log(result); - .. code-tab:: python - from edgedb import create_client + from gel import create_client client = create_client() @@ -222,7 +180,7 @@ database and provide a set of methods for executing queries. // src/main.rs #[tokio::main] async fn main() { - let conn = edgedb_tokio::create_client() + let conn = gel_tokio::create_client() .await .expect("Client initiation"); let val = conn @@ -242,12 +200,12 @@ database and provide a set of methods for executing queries. "fmt" "log" - "github.com/edgedb/edgedb-go" + "github.com/geldata/gel-go" ) func main() { ctx := context.Background() - client, err := edgedb.CreateClient(ctx, edgedb.Options{}) + client, err := gel.CreateClient(ctx, gel.Options{}) if err != nil { log.Fatal(err) } @@ -266,52 +224,20 @@ database and provide a set of methods for executing queries. .. code-tab:: csharp :caption: .NET - using EdgeDB; + using Gel; - var client = new EdgeDBClient(); + var client = new GelClient(); var result = await client.QuerySingleAsync("select random();"); Console.WriteLine(result); - .. code-tab:: java - :caption: Futures (Java) - - import com.edgedb.driver.EdgeDBClient; - import java.util.concurrent.CompletableFuture; - - public class Main { - public static void main(String[] args) { - var client = new EdgeDBClient(); - - client.querySingle(String.class, "select random();") - .thenAccept(System.out::println) - .toCompletableFuture().get(); - } - } - - .. code-tab:: java - :caption: Reactor (Java) - - import com.edgedb.driver.EdgeDBClient; - import reactor.core.publisher.Mono; - - public class Main { - public static void main(String[] args) { - var client = new EdgeDBClient(); - - Mono.fromFuture(client.querySingle(String.class, "select random();")) - .doOnNext(System.out::println) - .block(); - } - } - .. code-tab:: elixir :caption: Elixir - # lib/edgedb_quickstart.ex - defmodule EdgeDBQuickstart do + # lib/gel_quickstart.ex + defmodule GelQuickstart do def run do - {:ok, client} = EdgeDB.start_link() - result = EdgeDB.query_single!(client, "select random()") + {:ok, client} = Gel.start_link() + result = Gel.query_single!(client, "select random()") IO.inspect(result) end end @@ -353,19 +279,13 @@ Finally, execute the file. $ dotnet run - .. code-tab:: bash - :caption: Java - - $ javac Main.java - $ java Main - .. code-tab:: bash :caption: Elixir - $ mix run -e EdgeDBQuickstart.run + $ mix run -e GelQuickstart.run You should see a random number get printed to the console. This number was -generated inside your EdgeDB instance using EdgeQL's built-in +generated inside your Gel instance using EdgeQL's built-in :eql:func:`random` function. .. _ref_intro_clients_connection: @@ -384,7 +304,7 @@ project ` in the root of your codebase. .. code-block:: bash - $ edgedb project init + $ gel project init Once the project is initialized, any code that uses an official client library will automatically connect to the project-linked instanceβ€”no need for @@ -396,39 +316,36 @@ Using environment variables .. _ref_intro_clients_connection_cloud: -For EdgeDB Cloud -^^^^^^^^^^^^^^^^ +For Gel Cloud +^^^^^^^^^^^^^ In production, connection information can be securely passed to the client -library via environment variables. For EdgeDB Cloud instances, the recommended -variables to set are ``EDGEDB_INSTANCE`` and ``EDGEDB_SECRET_KEY``. +library via environment variables. For Gel Cloud instances, the recommended +variables to set are :gelenv:`INSTANCE` and :gelenv:`SECRET_KEY`. -Set ``EDGEDB_INSTANCE`` to ``/`` where -```` is the name you set when you created the EdgeDB Cloud +Set :gelenv:`INSTANCE` to ``/`` where +```` is the name you set when you created the Gel Cloud instance. -If you have not yet created a secret key, you can do so in the EdgeDB Cloud UI -or by running :ref:`ref_cli_edgedb_cloud_secretkey_create` via the CLI. +If you have not yet created a secret key, you can do so in the Gel Cloud UI +or by running :ref:`ref_cli_gel_cloud_secretkey_create` via the CLI. For self-hosted instances ^^^^^^^^^^^^^^^^^^^^^^^^^ Most commonly for self-hosted remote instances, you set a value for the -``EDGEDB_DSN`` environment variable. +:gelenv:`DSN` environment variable. .. note:: - If environment variables like ``EDGEDB_DSN`` are defined inside a project + If environment variables like :gelenv:`DSN` are defined inside a project directory, the environment variables will take precedence. A DSN is also known as a "connection string" and takes the -following form. - -.. code-block:: +following form: :geluri:`:@:`. - edgedb://:@: -Each element of the DSN is optional; in fact ``edgedb://`` is a technically a +Each element of the DSN is optional; in fact |geluri| is a technically a valid DSN. Any unspecified element will default to the following values. .. list-table:: @@ -438,15 +355,12 @@ valid DSN. Any unspecified element will default to the following values. * - ```` - ``5656`` * - ```` - - ``edgedb`` + - |admin| * - ```` - ``null`` A typical DSN may look like this: - -.. code-block:: - - edgedb://username:pas$$word@db.domain.com:8080 +:geluri:`admin:PASSWORD@db.domain.com:8080`. DSNs can also contain the following query parameters. @@ -454,7 +368,7 @@ DSNs can also contain the following query parameters. * - ``branch`` - The database branch to connect to within the given instance. Defaults to - ``main``. + |main|. * - ``tls_security`` - The TLS security mode. Accepts the following values. @@ -469,11 +383,8 @@ DSNs can also contain the following query parameters. self-signed certificate. These parameters can be added to any DSN using web-standard query string -notation. - -.. code-block:: +notation: :geluri:`user:pass@example.com:8080?branch=my_branch&tls_security=insecure`. - edgedb://user:pass@example.com:8080?branch=my_branch&tls_security=insecure For a more comprehensive guide to DSNs, see the :ref:`DSN Specification `. @@ -484,22 +395,22 @@ Using multiple environment variables If needed for your deployment pipeline, each element of the DSN can be specified independently. -- ``EDGEDB_HOST`` -- ``EDGEDB_PORT`` -- ``EDGEDB_USER`` -- ``EDGEDB_PASSWORD`` -- ``EDGEDB_BRANCH`` -- ``EDGEDB_TLS_CA_FILE`` -- ``EDGEDB_CLIENT_TLS_SECURITY`` +- :gelenv:`HOST` +- :gelenv:`PORT` +- :gelenv:`USER` +- :gelenv:`PASSWORD` +- :gelenv:`BRANCH` +- :gelenv:`TLS_CA_FILE` +- :gelenv:`CLIENT_TLS_SECURITY` .. note:: - If a value for ``EDGEDB_DSN`` is defined, it will override these variables! + If a value for :gelenv:`DSN` is defined, it will override these variables! Other mechanisms ---------------- -``EDGEDB_CREDENTIALS_FILE`` +:gelenv:`CREDENTIALS_FILE` A path to a ``.json`` file containing connection information. In some scenarios (including local Docker development) its useful to represent connection information with files. @@ -515,18 +426,18 @@ Other mechanisms "tls_cert_data": "-----BEGIN CERTIFICATE-----\nabcdef..." } -``EDGEDB_INSTANCE`` (local/EdgeDB Cloud only) - The name of an instance. Useful only for local or EdgeDB Cloud instances. +:gelenv:`INSTANCE` (local/Gel Cloud only) + The name of an instance. Useful only for local or Gel Cloud instances. .. note:: - For more on EdgeDB Cloud instances, see the :ref:`EdgeDB Cloud instance + For more on Gel Cloud instances, see the :ref:`Gel Cloud instance connection section ` above. Reference --------- -These are the most common ways to connect to an instance, however EdgeDB +These are the most common ways to connect to an instance, however Gel supports several other options for advanced use cases. For a complete reference on connection configuration, see :ref:`Reference > Connection Parameters `. diff --git a/docs/intro/edgeql.rst b/docs/intro/edgeql.rst index 93384b5daa6..b7fc846911f 100644 --- a/docs/intro/edgeql.rst +++ b/docs/intro/edgeql.rst @@ -3,26 +3,23 @@ EdgeQL ====== -EdgeQL is the query language of EdgeDB. It's intended as a spiritual successor +EdgeQL is the query language of Gel. It's intended as a spiritual successor to SQL that solves some of its biggest design limitations. This page is intended as a rapid-fire overview so you can hit the ground running with -EdgeDB. Refer to the linked pages for more in-depth documentation. +|Gel|. Refer to the linked pages for more in-depth documentation. -Want to follow along with the queries below? Open the `Interactive -Tutorial `_ in a separate tab. Copy and paste the queries below and -execute them directly from the browser. .. note:: The examples below also demonstrate how to express the query with the - :ref:`TypeScript client's ` query builder, which lets you + :ref:`TypeScript client's ` query builder, which lets you express arbitrary EdgeQL queries in a code-first, typesafe way. Scalar literals ^^^^^^^^^^^^^^^ -EdgeDB has a rich primitive type system consisting of the following data types. +|Gel| has a rich primitive type system consisting of the following data types. .. list-table:: @@ -31,7 +28,7 @@ EdgeDB has a rich primitive type system consisting of the following data types. * - Booleans - ``bool`` * - Numbers - - ``int16`` ``int32`` ``int64`` ``float32`` ``float64`` + - ``int16`` ``int32`` ``int64`` ``float32`` ``float64`` ``bigint`` ``decimal`` * - UUID - ``uuid`` @@ -55,8 +52,8 @@ Basic literals can be declared using familiar syntax. .. code-tab:: edgeql-repl - db> select "i ❀️ edgedb"; # str - {'i ❀️ edgedb'} + db> select "I ❀️ EdgeQL"; # str + {'U ❀️ EdgeQL'} db> select false; # bool {false} db> select 42; # int64 @@ -73,7 +70,7 @@ Basic literals can be declared using familiar syntax. .. code-tab:: typescript - e.str("i ❀️ edgedb") + e.str("I ❀️ EdgeQL") // string e.bool(false) // boolean @@ -112,9 +109,9 @@ structured string. e.datetime("1999-03-31T15:17:00Z") // Date e.duration("5 hours 4 minutes 3 seconds") - // edgedb.Duration (custom class) + // gel.Duration (custom class) e.cal.relative_duration("2 years 18 days") - // edgedb.RelativeDuration (custom class) + // gel.RelativeDuration (custom class) Primitive data can be composed into arrays and tuples, which can themselves be nested. @@ -144,7 +141,7 @@ nested. // unknown -EdgeDB also supports a special ``json`` type for representing unstructured +|Gel| also supports a special ``json`` type for representing unstructured data. Primitive data structures can be converted to JSON using a type cast (````). Alternatively, a properly JSON-encoded string can be converted to ``json`` with the built-in ``to_json`` function. Indexing a ``json`` value @@ -154,13 +151,13 @@ returns another ``json`` value. .. code-tab:: edgeql-repl - edgedb> select 5; + gel> select 5; {"5"} - edgedb> select [1,2,3]; + gel> select [1,2,3]; {"[1, 2, 3]"} - edgedb> select to_json('[{ "name": "Peter Parker" }]'); + gel> select to_json('[{ "name": "Peter Parker" }]'); {"[{\"name\": \"Peter Parker\"}]"} - edgedb> select to_json('[{ "name": "Peter Parker" }]')[0]['name']; + gel> select to_json('[{ "name": "Peter Parker" }]')[0]['name']; {"\"Peter Parker\""} .. code-tab:: typescript @@ -180,7 +177,7 @@ Refer to :ref:`Docs > EdgeQL > Literals ` for complete docs. Functions and operators ^^^^^^^^^^^^^^^^^^^^^^^ -EdgeDB provides a rich standard library of functions to operate and manipulate +|Gel| provides a rich standard library of functions to operate and manipulate various data types. .. tabs:: @@ -669,7 +666,7 @@ executing a query. .. code-tab:: javascript - import {createClient} from "edgedb"; + import {createClient} from "gel"; const client = createClient(); const result = await client.query(`select $param`, { @@ -679,9 +676,9 @@ executing a query. .. code-tab:: python - import edgedb + import gel - client = edgedb.create_async_client() + client = gel.create_async_client() async def main(): result = await client.query("select $param", param="Play it, Sam") @@ -695,12 +692,12 @@ executing a query. "context" "log" - "github.com/edgedb/edgedb-go" + "github.com/geldata/gel-go" ) func main() { ctx := context.Background() - client, err := edgedb.CreateClient(ctx, edgedb.Options{}) + client, err := gel.CreateClient(ctx, gel.Options{}) if err != nil { log.Fatal(err) } @@ -719,12 +716,12 @@ executing a query. .. code-tab:: rust // [dependencies] - // edgedb-tokio = "0.5.0" + // gel-tokio = "0.5.0" // tokio = { version = "1.28.1", features = ["macros", "rt-multi-thread"] } #[tokio::main] async fn main() { - let conn = edgedb_tokio::create_client() + let conn = gel_tokio::create_client() .await .expect("Client initiation"); let param = "Play it, Sam."; @@ -817,21 +814,6 @@ Polymorphic queries Consider the following schema. -.. code-block:: sdl - :version-lt: 3.0 - - abstract type Content { - required property title -> str; - } - - type Movie extending Content { - property release_year -> int64; - } - - type TVShow extending Content { - property num_seasons -> int64; - } - .. code-block:: sdl abstract type Content { diff --git a/docs/intro/index.rst b/docs/intro/index.rst index 24ab8234c8b..f07e30fe31c 100644 --- a/docs/intro/index.rst +++ b/docs/intro/index.rst @@ -9,7 +9,7 @@ Get Started :maxdepth: 3 :hidden: - quickstart + quickstart/index cli instances projects @@ -18,16 +18,14 @@ Get Started branches edgeql clients - Live tutorial - Easy EdgeDB book -EdgeDB is a next-generation `graph-relational database -`_ designed +|Gel| is a next-generation `graph-relational database +`_ designed as a spiritual successor to the relational database. It inherits the strengths of SQL databases: type safety, performance, reliability, and transactionality. But instead of modeling data in a -relational (tabular) way, EdgeDB represents data with *object types* +relational (tabular) way, Gel represents data with *object types* containing *properties* and *links* to other objects. It leverages this object-oriented model to provide a superpowered query language that solves some of SQL's biggest usability problems. @@ -35,40 +33,40 @@ solves some of SQL's biggest usability problems. How to read the docs ^^^^^^^^^^^^^^^^^^^^ -EdgeDB is a complex system, but we've structured the documentation so you can +|Gel| is a complex system, but we've structured the documentation so you can learn it in "phases". You only need to learn as much as you need to start building your application. - **Get Started** β€” Start with the :ref:`quickstart `. It walks - through EdgeDB's core workflows: how to install EdgeDB, create an instance, + through Gel's core workflows: how to install Gel, create an instance, write a simple schema, execute a migration, write some simple queries, and use the client libraries. The rest of the section goes deeper on each of these subjects. - **Schema** β€” - A set of pages that break down the concepts of syntax of EdgeDB's schema - definition language (SDL). This starts with a rundown of EdgeDB's primitive + A set of pages that break down the concepts of syntax of Gel's schema + definition language (SDL). This starts with a rundown of Gel's primitive type system (:ref:`Primitives `), followed by a description of (:ref:`Object Types `) and the things they can contain: links, properties, indexes, access policies, and more. - **EdgeQL** β€” - A set of pages that break down EdgeDB's query language, EdgeQL. It starts + A set of pages that break down Gel's query language, EdgeQL. It starts with a rundown of how to declare :ref:`literal values `, then introduces some key EdgeQL concepts like sets, paths, and type casts. With the basics established, it proceeds to break down all of EdgeQL's top-level statements: ``select``, ``insert``, and so on. - **Guides** β€” - Contains collections of guides on topics that are peripheral to EdgeDB + Contains collections of guides on topics that are peripheral to Gel itself: how to deploy to various cloud providers, how to integrate with various frameworks, and how to introspect the schema to build - code-generation tools on top of EdgeDB. + code-generation tools on top of Gel. - **Standard Library** β€” - This section contains an encyclopedic breakdown of EdgeDB's built-in types + This section contains an encyclopedic breakdown of Gel's built-in types and the functions/operators that can be used with them. We didn't want to \ clutter the **EdgeQL** section with all the nitty-gritty on each of these. If you're looking for a particular function (say, a ``replace``), go to the @@ -77,33 +75,33 @@ building your application. (:eql:func:`str_replace`). - **Client Libraries** - The documentation for EdgeDB's set of official client libraries for + The documentation for Gel's set of official client libraries for JavaScript/TypeScript, Python, Go, and Rust. All client libraries implement - EdgeDB's binary protocol and provide a standard interface for executing + Gel's binary protocol and provide a standard interface for executing queries. If you're using another language, you can execute queries :ref:`over HTTP `. This section also includes - documentation for EdgeDB's :ref:`GraphQL ` endpoint. + documentation for Gel's :ref:`GraphQL ` endpoint. - **CLI** - Complete reference for the ``edgedb`` command-line tool. The CLI is + Complete reference for the |gelcmd| command-line tool. The CLI is self-documentingβ€”add the ``--help`` flag after any command to print the relevant documentationβ€”so you shouldn't need to reference this section often. - **Reference** - The *Reference* section contains a complete breakdown of EdgeDB's *syntax* + The *Reference* section contains a complete breakdown of Gel's *syntax* (for both EdgeQL and SDL), *internals* (like the binary protocol and dump file format), and *configuration settings*. Usually you'll only need to reference these once you're an advanced user. - **Changelog** - Detailed changelogs for each successive version of EdgeDB, including any + Detailed changelogs for each successive version of Gel, including any breaking changes, new features, bigfixes, and links to Tooling ^^^^^^^ -To actually build apps with EdgeDB, you'll need to know more than SDL and +To actually build apps with Gel, you'll need to know more than SDL and EdgeQL. - **CLI** β€” @@ -117,16 +115,16 @@ EdgeQL. To actually execute queries, you'll use one of our client libraries for JavaScript, Go, or Python; find your preferred library under :ref:`Client Libraries `. If you're using another language, you can - still use EdgeDB! You can execute :ref:`queries via HTTP `. + still use Gel! You can execute :ref:`queries via HTTP `. - **Deployment** β€” - To publish an EdgeDB-backed application, you'll need to deploy EdgeDB. Refer + To publish an Gel-backed application, you'll need to deploy Gel. Refer to :ref:`Guides > Deployment ` for step-by-step deployment guides for all major cloud hosting platforms, as well as instructions for self-hosting with Docker. .. eql:react-element:: DocsNavTable -EdgeDB features: +|Gel| features: .. class:: ticklist @@ -135,13 +133,13 @@ EdgeDB features: - ability to easily work with complex hierarchical data; - built-in support for schema migrations. -EdgeDB is not a graph database: the data is stored and queried using -relational database techniques. Unlike most graph databases, EdgeDB +|Gel| is not a graph database: the data is stored and queried using +relational database techniques. Unlike most graph databases, Gel maintains a strict schema. -EdgeDB is not a document database, but inserting and querying hierarchical +|Gel| is not a document database, but inserting and querying hierarchical document-like data is trivial. -EdgeDB is not a traditional object database, despite the classification, +|Gel| is not a traditional object database, despite the classification, it is not an implementation of OOP persistence. diff --git a/docs/intro/instances.rst b/docs/intro/instances.rst index 47c475e2982..7980124bb41 100644 --- a/docs/intro/instances.rst +++ b/docs/intro/instances.rst @@ -4,29 +4,29 @@ Instances ========= -Let's get to the good stuff. You can spin up an EdgeDB instance with a single +Let's get to the good stuff. You can spin up an Gel instance with a single command. .. code-block:: bash - $ edgedb instance create my_instance + $ gel instance create my_instance This creates a new instance named ``my_instance`` that runs the latest stable -version of EdgeDB. (EdgeDB itself will be automatically installed if it isn't +version of Gel. (Gel itself will be automatically installed if it isn't already.) Alternatively you can specify a specific version with ``--version``. .. code-block:: bash - $ edgedb instance create my_instance --version 2.1 - $ edgedb instance create my_instance --version nightly + $ gel instance create my_instance --version 6.1 + $ gel instance create my_instance --version nightly -We can execute a query against our new instance with ``edgedb query``. Specify +We can execute a query against our new instance with :gelcmd:`query`. Specify which instance to connect to by passing an instance name into the ``-I`` flag. .. code-block:: bash - $ edgedb query "select 3.14" -I my_instance + $ gel query "select 3.14" -I my_instance 3.14 Managing instances @@ -35,10 +35,10 @@ Instances can be stopped, started, restarted, and destroyed. .. code-block:: bash - $ edgedb instance stop -I my_instance - $ edgedb instance start -I my_instance - $ edgedb instance restart -I my_instance - $ edgedb instance destroy -I my_instance + $ gel instance stop -I my_instance + $ gel instance start -I my_instance + $ gel instance restart -I my_instance + $ gel instance destroy -I my_instance Listing instances @@ -48,22 +48,22 @@ To list all instances on your machine: .. code-block:: bash - $ edgedb instance list + $ gel instance list β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Kind β”‚ Name β”‚ Port β”‚ Version β”‚ Status β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ - β”‚ local β”‚ my_instance β”‚ 10700 β”‚ 4.x+cc4f3b5 β”‚ active β”‚ - β”‚ local β”‚ my_instance_2 β”‚ 10701 β”‚ 4.x+cc4f3b5 β”‚ active β”‚ - β”‚ local β”‚ my_instance_3 β”‚ 10702 β”‚ 4.x+cc4f3b5 β”‚ active β”‚ + β”‚ local β”‚ my_instance β”‚ 10700 β”‚ x.x+cc4f3b5 β”‚ active β”‚ + β”‚ local β”‚ my_instance_2 β”‚ 10701 β”‚ x.x+cc4f3b5 β”‚ active β”‚ + β”‚ local β”‚ my_instance_3 β”‚ 10702 β”‚ x.x+cc4f3b5 β”‚ active β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ Further reference ^^^^^^^^^^^^^^^^^ For complete documentation on managing instances with the CLI (upgrading, -viewing logs, etc.), refer to the :ref:`edgedb instance -` reference or view the help text in your shell: +viewing logs, etc.), refer to the :ref:`gel instance +` reference or view the help text in your shell: .. code-block:: bash - $ edgedb instance --help + $ gel instance --help diff --git a/docs/intro/migrations.rst b/docs/intro/migrations.rst index db844230a1c..7f7903d81a0 100644 --- a/docs/intro/migrations.rst +++ b/docs/intro/migrations.rst @@ -6,9 +6,9 @@ Migrations :index: migrations fill_expr cast_expr -EdgeDB’s baked-in migration system lets you painlessly evolve your schema +|Gel's| baked-in migration system lets you painlessly evolve your schema throughout the development process. If you want to work along with this guide, -start a new project with :ref:`ref_cli_edgedb_project_init`. This will create a +start a new project with :ref:`ref_cli_gel_project_init`. This will create a new instance and some empty schema files to get you started. .. edb:youtube-embed:: _IUSPBm2xEA @@ -17,14 +17,14 @@ new instance and some empty schema files to get you started. 1. Start the ``watch`` command ------------------------------ -The easiest way to work with your schema in development is by running ``edgedb -watch``. This long-running task will monitor your schema files and +The easiest way to work with your schema in development is by running +:gelcmd:`watch`. This long-running task will monitor your schema files and automatically apply schema changes in your database as you work. .. code-block:: bash - $ edgedb watch - Initialized. Monitoring "/projects/my-edgedb-project". + $ gel watch + Initialized. Monitoring "/projects/my-gel-project". If you get output similar to the output above, you're ready to get started! @@ -32,7 +32,7 @@ If you get output similar to the output above, you're ready to get started! 2. Write an initial schema -------------------------- -By convention, your EdgeDB schema is defined inside one or more ``.esdl`` +By convention, your Gel schema is defined inside one or more |.gel| files that live in a directory called ``dbschema`` in the root directory of your codebase. @@ -40,11 +40,11 @@ your codebase. . β”œβ”€β”€ dbschema - β”‚ └── default.esdl # schema file (written by you) - └── edgedb.toml + β”‚ └── default.gel # schema file (written by you) + └── gel.toml -The schema itself is written using EdgeDB's schema definition language. Edit -your ``dbschema/default.esdl`` and add the following schema inside your +The schema itself is written using Gel's schema definition language. Edit +your :dotgel:`dbschema/default` and add the following schema inside your ``module default`` block: .. code-block:: sdl @@ -60,8 +60,8 @@ your ``dbschema/default.esdl`` and add the following schema inside your It's common to keep your entire schema in a single file, and many users use -this ``default.esdl`` that is created when you start a project. However it's -also possible to split their schemas across a number of ``.esdl`` files. +this :dotgel:`default` that is created when you start a project. However it's +also possible to split their schemas across a number of |.gel| files. Once you save your initial schema, assuming it is valid, the ``watch`` command will pick it up and apply it to your database. @@ -71,7 +71,7 @@ will pick it up and apply it to your database. ------------------------- As your application evolves, directly edit your schema files to reflect your -desired data model. Try updating your ``dbschema/default.esdl`` to add a +desired data model. Try updating your :dotgel:`dbschema/default` to add a ``Comment`` type: .. code-block:: sdl-diff @@ -109,15 +109,15 @@ and commit it to version control, it's time to generate a migration. 4. Generate a migration ----------------------- -To generate a migration that reflects all your changes, run ``edgedb migration -create``. +To generate a migration that reflects all your changes, run :gelcmd:`migration +create`. .. code-block:: bash - $ edgedb migration create + $ gel migration create -The CLI reads your schema file and sends it to the active EdgeDB instance. The +The CLI reads your schema file and sends it to the active Gel instance. The instance compares the file's contents to its current schema state and determines a migration plan. **The migration plan is generated by the database itself.** @@ -130,7 +130,7 @@ advanced options. .. code-block:: bash - $ edgedb migration create + $ gel migration create did you create object type 'default::Comment'? [y,n,l,c,b,s,q,?] > y did you create object type 'default::User'? [y,n,l,c,b,s,q,?] @@ -147,21 +147,21 @@ Migration without iteration If you want to change the schema, but you already know exactly what you want to change and don't need to iterate on your schema β€” you want to lock in the -migration right away β€” ``edgedb watch`` might not be the tool you reach for. +migration right away β€” :gelcmd:`watch` might not be the tool you reach for. Instead, you might use this method: 1. Edit your schema files -2. Create your migration with ``edgedb migration create`` -3. Apply your migration with ``edgedb migrate`` +2. Create your migration with :gelcmd:`migration create` +3. Apply your migration with :gelcmd:`migrate` Since you're not using ``watch``, the schema changes are not applied when you save your schema files. As a result, we need to tack an extra step on the end -of the process of applying the migration. That's handled by ``edgedb migrate``. +of the process of applying the migration. That's handled by :gelcmd:`migrate`. .. code-block:: bash - $ edgedb migrate + $ gel migrate Applied m1virjowa... (00002.edgeql) Once your migration is applied, you'll see the schema changes reflected in your @@ -172,7 +172,7 @@ Data migrations --------------- Depending on how the schema was changed, data in your database may prevent -EdgeDB from applying your schema changes. Imagine we added a required ``body`` +|Gel| from applying your schema changes. Imagine we added a required ``body`` property to our ``Post`` type: .. code-block:: sdl-diff @@ -207,18 +207,18 @@ We have a couple of options here. We could delete all the offending objects. default::Post {id: cc051bea-d9f5-11ed-a26d-2b64b6b273a4} } -Now, if we save the schema again, ``edgedb watch`` will be able to apply it. If +Now, if we save the schema again, :gelcmd:`watch` will be able to apply it. If we have data in here we don't want to lose though, that's not a good option. In that case, we might drop back to creating and applying the migration outside of -``edgedb watch``. +:gelcmd:`watch`. -To start, run ``edgedb migration create``. The interactive plan generator will +To start, run :gelcmd:`migration create`. The interactive plan generator will ask you for an EdgeQL expression to map the contents of your database to the new schema. .. code-block:: bash - $ edgedb migration create + $ gel migration create did you create property 'body' of object type 'default::Post'? [y,n,l,c,b,s,q,?] > y @@ -263,7 +263,7 @@ following EdgeQL features are often useful: .. list-table:: * - ``assert_exists`` - - This is an "escape hatch" function that tells EdgeDB to assume the input + - This is an "escape hatch" function that tells Gel to assume the input has *at least* one element. .. code-block:: @@ -275,7 +275,7 @@ following EdgeQL features are often useful: otherwise it will fail. * - ``assert_single`` - - This tells EdgeDB to assume the input has *at most* one element. This + - This tells Gel to assume the input has *at most* one element. This will throw an error if the argument is a set containing more than one element. This is useful is you are changing a property from ``multi`` to ``single``. @@ -299,6 +299,6 @@ Further reading - :ref:`Migration tips ` Further information can be found in the :ref:`CLI -reference ` or the `Beta 1 blog post -`_, -which describes the design of the migration system. \ No newline at end of file +reference ` or the `Beta 1 blog post +`_, +which describes the design of the migration system. diff --git a/docs/intro/projects.rst b/docs/intro/projects.rst index 0885abb3012..f0bbad87deb 100644 --- a/docs/intro/projects.rst +++ b/docs/intro/projects.rst @@ -9,16 +9,16 @@ CLI command. .. code-block:: bash - $ edgedb migration create -I my_instance + $ gel migration create -I my_instance -That's one of the reasons we introduced the concept of an *EdgeDB +That's one of the reasons we introduced the concept of an *Gel project*. A project is a directory on your file system that is associated -("linked") with an EdgeDB instance. +("linked") with an Gel instance. .. note:: Projects are intended to make *local development* easier! They only exist on - your local machine and are managed with the CLI. When deploying EdgeDB for + your local machine and are managed with the CLI. When deploying Gel for production, you will typically pass connection information to the client library using environment variables. @@ -27,17 +27,17 @@ When you're inside a project, all CLI commands will be applied against the .. code-block:: bash - $ edgedb migration create + $ gel migration create -The same is true for all EdgeDB client libraries (discussed in more depth in +The same is true for all Gel client libraries (discussed in more depth in the :ref:`Clients ` section). If the following file lives -inside an EdgeDB project directory, ``createClient`` will discover the project +inside an Gel project directory, ``createClient`` will discover the project and connect to its linked instance with no additional configuration. .. code-block:: typescript // clientTest.js - import {createClient} from 'edgedb'; + import {createClient} from 'gel'; const client = createClient(); await client.query("select 5"); @@ -45,54 +45,53 @@ and connect to its linked instance with no additional configuration. Initializing ^^^^^^^^^^^^ -To initialize a project, create a new directory and run ``edgedb -project init`` inside it. You'll see something like this: +To initialize a project, create a new directory and run :gelcmd:`project init` +inside it. You'll see something like this: .. code-block:: bash - $ edgedb project init - No `edgedb.toml` found in this repo or above. + $ gel project init + No `gel.toml` found in this repo or above. Do you want to initialize a new project? [Y/n] > Y - Specify the name of EdgeDB instance to use with this project + Specify the name of Gel instance to use with this project [default: my_instance]: > my_instance - Checking EdgeDB versions... - Specify the version of EdgeDB to use with this project [default: 4.x]: + Checking Gel versions... + Specify the version of Gel to use with this project [default: x.x]: > # (left blank for default) ... - Successfully installed 4.x+cc4f3b5 - Initializing EdgeDB instance... + Successfully installed x.x+cc4f3b5 + Initializing Gel instance... Applying migrations... Everything is up to date. Revision initial Project initialized. - To connect to my_instance, run `edgedb` + To connect to my_instance, run `gel` This command does a couple important things. -1. It spins up a new EdgeDB instance called ``my_instance``. -2. If no ``edgedb.toml`` file exists, it will create one. This is a - configuration file that marks a given directory as an EdgeDB project. Learn - more about it in :ref:`our edgedb.toml reference - `. +1. It spins up a new Gel instance called ``my_instance``. +2. If no |gel.toml| file exists, it will create one. This is a + configuration file that marks a given directory as an Gel project. Learn + more about it in the :ref:`gel.toml reference `. .. code-block:: toml - [edgedb] - server-version = "4.1" + [instance] + server-version = "6.0" 3. If no ``dbschema`` directory exists, it will be created, along with an - empty ``default.esdl`` file which will contain your schema. If a + empty :dotgel:`default` file which will contain your schema. If a ``dbschema`` directory exists and contains a subdirectory called ``migrations``, those migrations will be applied against the new instance. -Every project maps one-to-one to a particular EdgeDB instance. From -inside a project directory, you can run ``edgedb project info`` to see +Every project maps one-to-one to a particular Gel instance. From +inside a project directory, you can run :gelcmd:`project info` to see information about the current project. .. code-block:: bash - $ edgedb project info + $ gel project info β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Instance name β”‚ my_instance β”‚ β”‚ Project root β”‚ /path/to/project β”‚ @@ -104,14 +103,14 @@ Connection As long as you are inside the project directory, all CLI commands will be executed against the project-linked instance. For instance, you can simply run -``edgedb`` to open a REPL. +|gelcmd| to open a REPL. .. code-block:: bash - $ edgedb - EdgeDB 4.x+cc4f3b5 (repl 4.x+da2788e) + $ gel + Gel x.x+cc4f3b5 (repl x.x+da2788e) Type \help for help, \quit to quit. - my_instance:edgedb> select "Hello world!"; + my_instance:main> select "Hello world!"; By contrast, if you leave the project directory, the CLI will no longer know which instance to connect to. You can solve this by specifing an instance name @@ -120,14 +119,14 @@ with the ``-I`` flag. .. code-block:: bash $ cd ~ - $ edgedb - edgedb error: no `edgedb.toml` found and no connection options are specified - Hint: Run `edgedb project init` or use any of `-H`, `-P`, `-I` arguments to + $ gel + gel error: no `gel.toml` found and no connection options are specified + Hint: Run `gel project init` or use any of `-H`, `-P`, `-I` arguments to specify connection parameters. See `--help` for details - $ edgedb -I my_instance - EdgeDB 4.x+cc4f3b5 (repl 4.x+da2788e) + $ gel -I my_instance + Gel x.x+cc4f3b5 (repl x.x+da2788e) Type \help for help, \quit to quit. - my_instance:edgedb> + my_instance:main> Similarly, client libraries will auto-connect to the project's linked instance without additional configuration. @@ -135,32 +134,32 @@ linked instance without additional configuration. Using remote instances ^^^^^^^^^^^^^^^^^^^^^^ -You may want to initialize a project that points to a remote EdgeDB instance. -This is totally a valid case and EdgeDB fully supports it! Before running -``edgedb project init``, you just need to create an alias for the remote -instance using ``edgedb instance link``, like so: +You may want to initialize a project that points to a remote Gel instance. +This is totally a valid case and Gel fully supports it! Before running +:gelcmd:`project init`, you just need to create an alias for the remote +instance using :gelcmd:`instance link`, like so: .. lint-off .. code-block:: bash - $ edgedb instance link + $ gel instance link Specify server host [default: localhost]: > 192.168.4.2 Specify server port [default: 5656]: > 10818 - Specify database user [default: edgedb]: - > edgedb + Specify database user [default: admin]: + > admin Specify branch [default: main]: - > edgedb + > main Unknown server certificate: SHA1:c38a7a90429b033dfaf7a81e08112a9d58d97286. Trust? [y/N] > y - Password for 'edgedb': + Password for 'admin': Specify a new instance name for the remote server [default: abcd]: > staging_db Successfully linked to remote instance. To connect run: - edgedb -I staging_db + gel -I staging_db .. lint-on @@ -170,41 +169,41 @@ instance name in CLI commands. .. code-block:: - $ edgedb -I staging_db - edgedb> + $ gel -I staging_db + gel> To initialize a project that uses the remote instance, provide this alias when -prompted for an instance name during the ``edgedb project init`` workflow. +prompted for an instance name during the :gelcmd:`project init` workflow. Unlinking ^^^^^^^^^ An instance can be unlinked from a project. This leaves the instance running -but effectively "uninitializes" the project. The ``edgedb.toml`` and +but effectively "uninitializes" the project. The |gel.toml| and ``dbschema`` are left untouched. .. code-block:: bash - $ edgedb project unlink + $ gel project unlink If you wish to delete the instance as well, use the ``-D`` flag. .. code-block:: bash - $ edgedb project unlink -D + $ gel project unlink -D Upgrading ^^^^^^^^^ A standalone instance (not linked to a project) can be upgraded with the -``edgedb instance upgrade`` command. +:gelcmd:`instance upgrade` command. .. code-block:: bash - $ edgedb project upgrade --to-latest - $ edgedb project upgrade --to-nightly - $ edgedb project upgrade --to-version 4.x + $ gel project upgrade --to-latest + $ gel project upgrade --to-nightly + $ gel project upgrade --to-version x.x See info @@ -214,7 +213,7 @@ You can see the location of a project and the name of its linked instance. .. code-block:: bash - $ edgedb project info + $ gel project info β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Instance name β”‚ my_app β”‚ β”‚ Project root β”‚ /path/to/my_app β”‚ diff --git a/docs/intro/quickstart.rst b/docs/intro/quickstart.rst deleted file mode 100644 index d6121295bfd..00000000000 --- a/docs/intro/quickstart.rst +++ /dev/null @@ -1,561 +0,0 @@ -.. _ref_quickstart: - -========== -Quickstart -========== - -Welcome to EdgeDB! - -This quickstart will walk you through the entire process of creating a simple -EdgeDB-powered application: installation, defining your schema, adding some -data, and writing your first query. Let's jump in! - -.. _ref_quickstart_install: - -1. Installation -=============== - -First let's install the EdgeDB CLI. Open a terminal and run the appropriate -command below. - -.. note:: Great news for Node users! - - Skip installing and start using the EdgeDB CLI right away! Just prepend - :ref:`any CLI command ` with ``npx`` or your package - manager's equivalent. For example, to create a new project, you can use - ``npx edgedb project init``. - -Linux ------ - -.. tabs:: - - .. code-tab:: bash - :caption: Script - - $ curl https://sh.edgedb.com --proto '=https' -sSf1 | sh - - .. code-tab:: bash - :caption: APT - - $ # Import the EdgeDB packaging key - $ sudo mkdir -p /usr/local/share/keyrings && \ - sudo curl --proto '=https' --tlsv1.2 -sSf \ - -o /usr/local/share/keyrings/edgedb-keyring.gpg \ - https://packages.edgedb.com/keys/edgedb-keyring.gpg && \ - $ # Add the EdgeDB package repository - $ echo deb [signed-by=/usr/local/share/keyrings/edgedb-keyring.gpg]\ - https://packages.edgedb.com/apt \ - $(grep "VERSION_CODENAME=" /etc/os-release | cut -d= -f2) main \ - | sudo tee /etc/apt/sources.list.d/edgedb.list - $ # Install the EdgeDB package - $ sudo apt-get update && sudo apt-get install edgedb-5 - - .. code-tab:: bash - :caption: YUM - - $ # Add the EdgeDB package repository - $ sudo curl --proto '=https' --tlsv1.2 -sSfL \ - https://packages.edgedb.com/rpm/edgedb-rhel.repo \ - > /etc/yum.repos.d/edgedb.repo - $ # Install the EdgeDB package - $ sudo yum install edgedb-5 - -macOS ------ - -.. tabs:: - - .. code-tab:: bash - :caption: Script - - $ curl https://sh.edgedb.com --proto '=https' -sSf1 | sh - - .. code-tab:: bash - :caption: Homebrew - - $ # Add the EdgeDB tap to your Homebrew - $ brew tap edgedb/tap - $ # Install EdgeDB CLI - $ brew install edgedb-cli - -Windows (Powershell) --------------------- - -.. note:: - - EdgeDB on Windows requires WSL 2 to create local instances because the - EdgeDB server runs on Linux. It is *not* required if you will use the CLI - only to manage EdgeDB Cloud and/or other remote instances. This quickstart - *does* create local instances, so WSL 2 is required to complete the - quickstart. - -.. code-block:: powershell - - PS> iwr https://ps1.edgedb.com -useb | iex - -.. note:: Command prompt installation - - To install EdgeDB in the Windows Command prompt, follow these steps: - - 1. `Download the CLI `__ - - 2. Navigate to the download location in the command prompt - - 3. Run the installation command: - - .. code-block:: - - edgedb-cli.exe _self_install - -The script installation methods download and execute a bash script that -installs the ``edgedb`` CLI on your machine. You may be asked for your -password. Once the installation completes, you may need to **restart your -terminal** before you can use the ``edgedb`` command. - -Now let's set up your EdgeDB project. - -.. _ref_quickstart_createdb: - -2. Initialize a project -======================= - -In a terminal, create a new directory and ``cd`` into it. - -.. code-block:: bash - - $ mkdir quickstart - $ cd quickstart - -Then initialize your EdgeDB project: - -.. code-block:: bash - - $ edgedb project init - -This starts an interactive tool that walks you through the process of setting -up your first EdgeDB instance. You should see something like this: - -.. code-block:: bash - - $ edgedb project init - No `edgedb.toml` found in `/path/to/quickstart` or above - Do you want to initialize a new project? [Y/n] - > Y - Specify the name of EdgeDB instance to use with this project - [default: quickstart]: - > quickstart - Checking EdgeDB versions... - Specify the version of EdgeDB to use with this project [default: 5.x]: - > 5.x - Specify branch name: [default: main]: - > main - β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” - β”‚ Project directory β”‚ ~/path/to/quickstart β”‚ - β”‚ Project config β”‚ ~/path/to/quickstart/edgedb.toml β”‚ - β”‚ Schema dir (empty) β”‚ ~/path/to/quickstart/dbschema β”‚ - β”‚ Installation method β”‚ portable package β”‚ - β”‚ Version β”‚ 5.x+cc4f3b5 β”‚ - β”‚ Instance name β”‚ quickstart β”‚ - β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - Downloading package... - 00:00:01 [====================] 41.40 MiB/41.40 MiB 32.89MiB/s | ETA: 0s - Successfully installed 5.x+cc4f3b5 - Initializing EdgeDB instance... - Applying migrations... - Everything is up to date. Revision initial - Project initialized. - To connect to quickstart, run `edgedb` - - -This did a couple things. - -1. First, it scaffolded your project by creating an - :ref:`ref_reference_edgedb_toml` config file and a schema file - ``dbschema/default.esdl``. In the next section, you'll define a schema in - ``default.esdl``. - -2. Second, it spun up an EdgeDB instance called ``quickstart`` and "linked" it - to the current directory. As long as you're inside the project - directory, all CLI commands will be executed against this - instance. For more details on how EdgeDB projects work, check out the - :ref:`Managing instances ` guide. - -.. note:: - - Quick note! You can have several **instances** of EdgeDB running on your - computer simultaneously. Each instance may be **branched** many times. Each - branch may have an independent schema consisting of a number of **modules** - (though commonly your schema will be entirely defined inside the ``default`` - module). - -Let's connect to our new instance! Run ``edgedb`` in your terminal to open an -interactive REPL to your instance. You're now connected to a live EdgeDB -instance running on your computer! Try executing a simple query (``select 1 + 1;``) after the -REPL prompt (``quickstart:main>``): - -.. code-block:: edgeql-repl - - quickstart:main> select 1 + 1; - {2} - -Run ``\q`` to exit the REPL. More interesting queries are coming soon, -promise! But first we need to set up a schema. - -.. _ref_quickstart_createdb_sdl: - -3. Set up your schema -===================== - -Open the ``quickstart`` directory in your IDE or editor of choice. You should -see the following file structure. - -.. code-block:: - - /path/to/quickstart - β”œβ”€β”€ edgedb.toml - β”œβ”€β”€ dbschema - β”‚ β”œβ”€β”€ default.esdl - β”‚ β”œβ”€β”€ migrations - -EdgeDB schemas are defined with a dedicated schema definition language called -(predictably) EdgeDB SDL (or just **SDL** for short). It's an elegant, -declarative way to define your data model. - -SDL lives inside ``.esdl`` files. Commonly, your entire schema will be -declared in a file called ``default.esdl`` but you can split your schema -across several ``.esdl`` files if you prefer. - -.. note:: - - Syntax-highlighter packages/extensions for ``.esdl`` files are available - for - `Visual Studio Code `_, - `Sublime Text `_, - `Atom `_, - and `Vim `_. - -Let's build a simple movie database. We'll need to define two **object types** -(equivalent to a *table* in SQL): Movie and Person. Open -``dbschema/default.esdl`` in your editor of choice and paste the following: - -.. code-block:: sdl - :version-lt: 3.0 - - module default { - type Person { - required property name -> str; - } - - type Movie { - property title -> str; - multi link actors -> Person; - } - }; - -.. code-block:: sdl - - module default { - type Person { - required name: str; - } - - type Movie { - title: str; - multi actors: Person; - } - }; - - -A few things to note here. - -- Our types don't contain an ``id`` property; EdgeDB automatically - creates this property and assigns a unique UUID to every object inserted - into the database. -- The ``Movie`` type includes a **link** named ``actors``. In EdgeDB, links are - used to represent relationships between object types. They eliminate the need - for foreign keys; later, you'll see just how easy it is to write "deep" - queries without JOINs. -- The object types are inside a ``module`` called ``default``. You can split - up your schema into logical subunits called modules, though it's common to - define the entire schema in a single module called ``default``. - -Now we're ready to run a migration to apply this schema to the database. - -4. Run a migration -================== - -Generate a migration file with ``edgedb migration create``. This command -gathers up our ``*.esdl`` files and sends them to the database. The *database -itself* parses these files, compares them against its current schema, and -generates a migration plan! Then the database sends this plan back to the CLI, -which creates a migration file. - -.. code-block:: bash - - $ edgedb migration create - Created ./dbschema/migrations/00001.edgeql (id: ) - -.. note:: - - If you're interested, open this migration file to see what's inside! It's - a simple EdgeQL script consisting of :ref:`DDL ` commands like - ``create type``, ``alter type``, and ``create property``. - -The migration file has been *created* but we haven't *applied it* against the -database. Let's do that. - -.. code-block:: bash - - $ edgedb migrate - Applied m1k54jubcs62wlzfebn3pxwwngajvlbf6c6qfslsuagkylg2fzv2lq (00001.edgeql) - -Looking good! Let's make sure that worked by running ``edgedb list types`` on -the command line. This will print a table containing all currently-defined -object types. - -.. code-block:: bash - - $ edgedb list types - β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” - β”‚ Name β”‚ Extending β”‚ - β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ - β”‚ default::Movie β”‚ std::BaseObject, std::Object β”‚ - β”‚ default::Person β”‚ std::BaseObject, std::Object β”‚ - β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ - - -.. _ref_quickstart_migrations: - -.. _Migrate your schema: - -Before we proceed, let's try making a small change to our schema: making the -``title`` property of ``Movie`` required. First, update the schema file: - -.. code-block:: sdl-diff - :version-lt: 3.0 - - type Movie { - - property title -> str; - + required property title -> str; - multi link actors -> Person; - } - -.. code-block:: sdl-diff - - type Movie { - - title: str; - + required title: str; - multi actors: Person; - } - -Then create another migration. Because this isn't the initial migration, we -see something a little different than before. - -.. code-block:: bash - - $ edgedb migration create - did you make property 'title' of object type 'default::Movie' - required? [y,n,l,c,b,s,q,?] - > - -As before, EdgeDB parses the schema files and compared them against its -current internal schema. It correctly detects the change we made, and prompts -us to confirm it. This interactive process lets you sanity check every change -and provide guidance when a migration is ambiguous (e.g. when a property is -renamed). - -Enter ``y`` to confirm the change. - -.. code-block:: bash - - $ edgedb migration create - did you make property 'title' of object type 'default::Movie' - required? [y,n,l,c,b,s,q,?] - > y - Please specify an expression to populate existing objects in - order to make property 'title' of object type 'default::Movie' required: - fill_expr> {} - -Hm, now we're seeing another prompt. Because ``title`` is changing from -*optional* to *required*, EdgeDB is asking us what to do for all the ``Movie`` -objects that don't currently have a value for ``title`` defined. We'll just -specify a placeholder value of "Untitled". Replace the ``{}`` value -with ``"Untitled"`` and press Enter. - -.. code-block:: - - fill_expr> "Untitled" - Created dbschema/migrations/00002.edgeql (id: ) - - -If we look at the generated migration file, we see it contains the following -lines: - -.. code-block:: edgeql - - ALTER TYPE default::Movie { - ALTER PROPERTY title { - SET REQUIRED USING ('Untitled'); - }; - }; - -Let's wrap up by applying the new migration. - -.. code-block:: bash - - $ edgedb migrate - Applied m1rd2ikgwdtlj5ws7ll6rwzvyiui2xbrkzig4adsvwy2sje7kxeh3a (00002.edgeql) - -.. _ref_quickstart_insert_data: - -.. _Insert data: - -.. _Run some queries: - -5. Write some queries -===================== - -Let's write some simple queries via *EdgeDB UI*, the admin dashboard baked -into every EdgeDB instance (v2.0+ only). To open the dashboard: - -.. code-block:: bash - - $ edgedb ui - Opening URL in browser: - http://localhost:107xx/ui?authToken= - -You should see a simple landing page, as below. You'll see a card for each -branch of your instance. Remember: each instance can be branched multiple -times! - -.. image:: images/ui_landing.jpg - :width: 100% - -Currently, there's only one branch, which is simply called ``main`` by -default. Click the ``main`` card. - -.. image:: images/ui_db.jpg - :width: 100% - -Then click ``Open Editor`` so we can start writing some queries. We'll start -simple: ``select "Hello world!";``. Click ``RUN`` to execute the query. - -.. image:: images/ui_hello.jpg - :width: 100% - -The result of the query will appear on the right. - -The query will also be added to your history of previous queries, which can be -accessed via the "HISTORY" tab located on the lower left side of the editor. - -Now let's actually ``insert`` an object into our database. Copy the following -query into the query textarea and hit ``Run``. - -.. code-block:: edgeql - - insert Movie { - title := "Dune" - }; - -Nice! You've officially inserted the first object into your database! Let's -add a couple cast members with an ``update`` query. - -.. code-block:: edgeql - - update Movie - filter .title = "Dune" - set { - actors := { - (insert Person { name := "Timothee Chalamet" }), - (insert Person { name := "Zendaya" }) - } - }; - -Finally, we can run a ``select`` query to fetch all the data we just inserted. - -.. code-block:: edgeql - - select Movie { - title, - actors: { - name - } - }; - -Click the outermost ``COPY`` button in the top right of the query result area -to copy the result of this query to your clipboard as JSON. The copied text -will look something like this: - -.. code-block:: json - - [ - { - "title": "Dune", - "actors": [ - { - "name": "Timothee Chalamet" - }, - { - "name": "Zendaya" - } - ] - } - ] - -EdgeDB UI is a useful development tool, but in practice your application will -likely be using one of EdgeDB's *client libraries* to execute queries. EdgeDB -provides official libraries for many langauges: - -- :ref:`JavaScript/TypeScript ` -- :ref:`Go ` -- :ref:`Python ` -- :ref:`Rust ` -- :ref:`C# and F# ` -- :ref:`Java ` -- :ref:`Dart ` -- :ref:`Elixir ` - -Check out the :ref:`Clients -` guide to get started with the language of your choice. - -.. _ref_quickstart_onwards: - -.. _Computeds: - -Onwards and upwards -=================== - -You now know the basics of EdgeDB! You've installed the CLI and database, set -up a local project, run a couple migrations, inserted and queried some data, -and used a client library. - -- For a more in-depth exploration of each topic covered here, continue reading - the other pages in the Getting Started section, which will cover important - topics like migrations, the schema language, and EdgeQL in greater detail. - -- For guided tours of major concepts, check out the showcase pages for `Data - Modeling `_, `EdgeQL - `_, and `Migrations - `_. - -- For a deep dive into the EdgeQL query language, check out the - `Interactive Tutorial `_. - -- For an immersive, comprehensive walkthrough of EdgeDB concepts, check out - our illustrated e-book `Easy EdgeDB `_; it's designed to walk a - total beginner through EdgeDB, from the basics all the way through advanced - concepts. - -- To start building an application using the language of your choice, check out - our client libraries: - - - :ref:`JavaScript/TypeScript ` - - :ref:`Go ` - - :ref:`Python ` - - :ref:`Rust ` - - :ref:`C# and F# ` - - :ref:`Java ` - - :ref:`Dart ` - - :ref:`Elixir ` diff --git a/docs/intro/quickstart/connecting.rst b/docs/intro/quickstart/connecting.rst new file mode 100644 index 00000000000..36838dd4f01 --- /dev/null +++ b/docs/intro/quickstart/connecting.rst @@ -0,0 +1,97 @@ +.. _ref_quickstart_connecting: + +========================== +Connecting to the database +========================== + +.. edb:split-section:: + + Before diving into the application, let's take a quick look at how to connect to the database from your code. We will intialize a client and use it to make a simple, static query to the database, and log the result to the console. + + .. note:: + + Notice that the ``createClient`` function isn't being passed any connection details. With |Gel|, you do not need to come up with your own scheme for how to build the correct database connection credentials and worry about leaking them into your code. You simply use |Gel| "projects" for local development, and set the appropriate environment variables in your deployment environments, and the ``createClient`` function knows what to do! + + .. edb:split-point:: + + .. code-block:: typescript + :caption: ./test.ts + + import { createClient } from "gel"; + + const client = createClient(); + + async function main() { + console.log(await client.query("select 'Hello from Gel!';")); + } + + main().then( + () => process.exit(0), + (err) => { + console.error(err); + process.exit(1); + } + ); + + + .. code-block:: sh + + $ npx tsx test.ts + [ 'Hello from Gel!' ] + +.. edb:split-section:: + + + With TypeScript, there are three ways to run a query: use a string EdgeQL query, use the ``queries`` generator to turn a string of EdgeQL into a TypeScript function, or use the query builder API to build queries dynamically in a type-safe manner. In this tutorial, you will use the TypeScript query builder API. + + This query builder must be regenerated any time the schema changes, so a hook has been added to the ``gel.toml`` file to generate the query builder any time the schema is updated. Moving beyond this simple query, use the query builder API to insert a few ``Deck`` objects into the database, and then select them back. + + .. edb:split-point:: + + .. code-block:: typescript-diff + :caption: ./test.ts + + import { createClient } from "gel"; + + import e from "@/dbschema/edgeql-js"; + + const client = createClient(); + + async function main() { + console.log(await client.query("select 'Hello from Gel!';")); + + + await e.insert(e.Deck, { name: "I am one" }).run(client); + + + + await e.insert(e.Deck, { name: "I am two" }).run(client); + + + + const decks = await e + + .select(e.Deck, () => ({ + + id: true, + + name: true, + + })) + + .run(client); + + + + console.table(decks); + + + + await e.delete(e.Deck).run(client); + } + + main().then( + () => process.exit(0), + (err) => { + console.error(err); + process.exit(1); + } + ); + + .. code-block:: sh + + $ npx tsx test.ts + [ 'Hello from Gel!' ] + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ (index) β”‚ id β”‚ name β”‚ + β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ + β”‚ 0 β”‚ 'f4cd3e6c-ea75-11ef-83ec-037350ea8a6e' β”‚ 'I am one' β”‚ + β”‚ 1 β”‚ 'f4cf27ae-ea75-11ef-83ec-3f7b2fceab24' β”‚ 'I am two' β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + +Now that you know how to connect to the database, you will see that we have provided an initialized ``Client`` object in the ``/lib/gel.ts`` module. Throughout the rest of the tutorial, you will import this ``Client`` object and use it to make queries. diff --git a/docs/intro/quickstart/images/flashcards-import.png b/docs/intro/quickstart/images/flashcards-import.png new file mode 100644 index 00000000000..8b3d66a2f06 Binary files /dev/null and b/docs/intro/quickstart/images/flashcards-import.png differ diff --git a/docs/intro/quickstart/images/schema-ui.png b/docs/intro/quickstart/images/schema-ui.png new file mode 100644 index 00000000000..3f197e8baeb Binary files /dev/null and b/docs/intro/quickstart/images/schema-ui.png differ diff --git a/docs/intro/quickstart/images/timestamped.png b/docs/intro/quickstart/images/timestamped.png new file mode 100644 index 00000000000..5d3f523a36b Binary files /dev/null and b/docs/intro/quickstart/images/timestamped.png differ diff --git a/docs/intro/quickstart/index.rst b/docs/intro/quickstart/index.rst new file mode 100644 index 00000000000..a9dd7543131 --- /dev/null +++ b/docs/intro/quickstart/index.rst @@ -0,0 +1,62 @@ +.. _ref_quickstart: + +========== +Quickstart +========== + +.. toctree:: + :maxdepth: 1 + :hidden: + + setup + modeling + connecting + working + inheritance + + +Welcome to the quickstart tutorial! In this tutorial, you will update a simple Next.js application to use |Gel| as your data layer. The application will let users build and manage their own study decks, with each flashcard featuring customizable text on both sides - making it perfect for studying, memorization practice, or creating educational games. + +Don't worry if you're new to |Gel| - you will be up and running with a working Next.js application and a local |Gel| database in just about **5 minutes**. From there, you will replace the static mock data with a |Gel| powered data layer in roughly 30-45 minutes. + +By the end of this tutorial, you will be comfortable with: + +* Creating and updating a database schema +* Running migrations to evolve your data +* Writing EdgeQL queries in text and via a TypeScript query builder +* Building an app backed by |Gel| + +Features of the flashcards app +------------------------------ + +* Create, edit, and delete decks +* Add/remove cards with front/back content +* Simple Next.js + Tailwind UI +* Clean, type-safe schema with |Gel| + +Requirements +------------ + +Before you start, you need: + +* Basic familiarity with TypeScript, Next.js, and React +* Node.js 20+ on a Unix-like OS (Linux, macOS, or WSL) +* A code editor you love + +Why |Gel| for Next.js? +---------------------- + +* **Type Safety**: Catch data errors before runtime +* **Rich Modeling**: Use object types and links to model relations +* **Modern Tooling**: TypeScript-friendly schemas and migrations +* **Performance**: Efficient queries for complex data +* **Developer Experience**: An intuitive query language (EdgeQL) + +Need Help? +---------- + +If you run into issues while following this tutorial: + +* Check the `Gel documentation `_ +* Visit our `community Discord `_ +* File an issue on `GitHub `_ diff --git a/docs/intro/quickstart/inheritance.rst b/docs/intro/quickstart/inheritance.rst new file mode 100644 index 00000000000..520b4d33dad --- /dev/null +++ b/docs/intro/quickstart/inheritance.rst @@ -0,0 +1,113 @@ +.. _ref_quickstart_inheritance: + +======================== +Adding shared properties +======================== + +.. edb:split-section:: + + One common pattern in applications is to add shared properties to the schema that are used by multiple objects. For example, you might want to add a ``created_at`` and ``updated_at`` property to every object in your schema. You can do this by adding an abstract type and using it as a mixin for your other object types. + + .. code-block:: sdl-diff + :caption: dbschema/default.gel + + module default { + + abstract type Timestamped { + + required created_at: datetime { + + default := datetime_of_statement(); + + }; + + required updated_at: datetime { + + default := datetime_of_statement(); + + }; + + } + + + - type Deck { + + type Deck extending Timestamped { + required name: str; + description: str; + + multi cards: Card { + constraint exclusive; + on target delete allow; + }; + }; + + - type Card { + + type Card extending Timestamped { + required order: int64; + required front: str; + required back: str; + } + } + +.. edb:split-section:: + + Since you don't have historical data for when these objects were actually created or modified, the migration will fall back to the default values set in the ``Timestamped`` type. + + .. code-block:: sh + + $ npx gel migration create + did you create object type 'default::Timestamped'? [y,n,l,c,b,s,q,?] + > y + did you alter object type 'default::Card'? [y,n,l,c,b,s,q,?] + > y + did you alter object type 'default::Deck'? [y,n,l,c,b,s,q,?] + > y + Created /home/strinh/projects/flashcards/dbschema/migrations/00004-m1d2m5n.edgeql, id: m1d2m5n5ajkalyijrxdliioyginonqbtfzihvwdfdmfwodunszstya + + $ npx gel migrate + Applying m1d2m5n5ajkalyijrxdliioyginonqbtfzihvwdfdmfwodunszstya (00004-m1d2m5n.edgeql) + ... parsed + ... applied + Generating query builder... + Detected tsconfig.json, generating TypeScript files. + To override this, use the --target flag. + Run `npx @gel/generate --help` for full options. + Introspecting database schema... + Generating runtime spec... + Generating cast maps... + Generating scalars... + Generating object types... + Generating function types... + Generating operators... + Generating set impl... + Generating globals... + Generating index... + Writing files to ./dbschema/edgeql-js + Generation complete! 🀘 + +.. edb:split-section:: + + Update the ``getDecks`` query to sort the decks by ``updated_at`` in descending order. + + .. code-block:: typescript-diff + :caption: app/queries.ts + + import { client } from "@/lib/gel"; + import e from "@/dbschema/edgeql-js"; + + export async function getDecks() { + const decks = await e.select(e.Deck, (deck) => ({ + id: true, + name: true, + description: true, + cards: e.select(deck.cards, (card) => ({ + id: true, + front: true, + back: true, + order_by: card.order, + })), + + order_by: { + + expression: deck.updated_at, + + direction: e.DESC, + + }, + })).run(client); + + return decks; + } + +.. edb:split-section:: + + Now when you look at the data in the UI, you will see the new properties on each of your object types. + + .. image:: images/timestamped.png diff --git a/docs/intro/quickstart/modeling.rst b/docs/intro/quickstart/modeling.rst new file mode 100644 index 00000000000..ce54e63690d --- /dev/null +++ b/docs/intro/quickstart/modeling.rst @@ -0,0 +1,108 @@ +.. _ref_quickstart_modeling: + +================= +Modeling the data +================= + +.. edb:split-section:: + + The flashcards application has a simple data model, but it's interesting enough to utilize many unique features of the |Gel| schema language. + + Looking at the mock data in our example JSON file ``./deck-edgeql.json``, you can see this structure in the JSON. There is a ``Card`` type that describes a single flashcard, which contains two required string properties: ``front`` and ``back``. Each ``Deck`` object has a link to zero or more ``Card`` objects in an array. + + .. code-block:: typescript + + interface Card { + front: string; + back: string; + } + + interface Deck { + name: string; + description: string | null; + cards: Card[]; + } + +.. edb:split-section:: + + Starting with this simple model, add these types to the :dotgel:`dbschema/default` schema file. As you can see, the types closely mirror the JSON mock data. + + Also of note, the link between ``Card`` and ``Deck`` objects creates a "1-to-n" relationship, where each ``Deck`` object has a link to zero or more ``Card`` objects. When you query the ``Deck.cards`` link, the cards will be unordered, so the ``Card`` type needs an explicit ``order`` property to allow sorting them at query time. + + By default, when you try to delete an object that is linked to another object, the database will prevent you from doing so. We want to support removing a ``Card``, so we define a deletion policy on the ``cards`` link that allows deleting the target of this link. + + .. code-block:: sdl-diff + :caption: dbschema/default.gel + + module default { + + type Card { + + required order: int64; + + required front: str; + + required back: str; + + }; + + + + type Deck { + + required name: str; + + description: str; + + multi cards: Card { + + constraint exclusive; + + on target delete allow; + + }; + + }; + }; + +.. edb:split-section:: + + Congratulations! This first version of the data model's schema is *stored in a file on disk*. Now you need to signal the database to actually create types for ``Deck`` and ``Card`` in the database. + + To make |Gel| do that, you need to do two quick steps: + + 1. **Create a migration**: a "migration" is a file containing a set of low level instructions that define how the database schema should change. It records any additions, modifications, or deletions to your schema in a way that the database can understand. + + .. note:: + + When you are changing existing schema, the CLI migration tool might ask questions to ensure that it understands your changes exactly. Since the existing schema was empty, the CLI will skip asking any questions and simply create the migration file. + + 2. **Apply the migration**: This executes the migration file on the database, instructing |Gel| to implement the recorded changes in the database. Essentially, this step updates the database structure to match your defined schema, ensuring that the ``Deck`` and ``Card`` types are created and ready for use. + + .. note:: + + Notice that after the migration is applied, the CLI will automatically run the script to generate the query builder. This is a convenience feature that is enabled by the ``schema.update.after`` hook in the ``gel.toml`` file. + + .. code-block:: sh + + $ npx gel migration create + Created ./dbschema/migrations/00001-m125ajr.edgeql, id: m125ajrbqp7ov36s7aniefxc376ofxdlketzspy4yddd3hrh4lxmla + $ npx gel migrate + Applying m125ajrbqp7ov36s7aniefxc376ofxdlketzspy4yddd3hrh4lxmla (00001-m125ajr.edgeql) + ... parsed + ... applied + Generating query builder... + Detected tsconfig.json, generating TypeScript files. + To override this, use the --target flag. + Run `npx @gel/generate --help` for full options. + Introspecting database schema... + Generating runtime spec... + Generating cast maps... + Generating scalars... + Generating object types... + Generating function types... + Generating operators... + Generating set impl... + Generating globals... + Generating index... + Writing files to ./dbschema/edgeql-js + Generation complete! 🀘 + + +.. edb:split-section:: + + Take a look at the schema you've generated in the built-in database UI. Use this tool to visualize your data model and see the object types and links you've defined. + + .. edb:split-point:: + + .. code-block:: sh + + $ npx gel ui + + .. image:: images/schema-ui.png diff --git a/docs/intro/quickstart/setup.rst b/docs/intro/quickstart/setup.rst new file mode 100644 index 00000000000..371fb5bd57d --- /dev/null +++ b/docs/intro/quickstart/setup.rst @@ -0,0 +1,89 @@ +.. _ref_quickstart_setup: + +=========================== +Setting up your environment +=========================== + +.. edb:split-section:: + + Use git to clone `the Next.js starter template `_ into a new directory called ``flashcards``. This will create a fully configured Next.js project and a local |Gel| instance with an empty schema. You will see the database instance being created and the project being initialized. You are now ready to start building the application. + + .. code-block:: sh + + $ git clone \ + git@github.com:geldata/quickstart-nextjs.git \ + flashcards + $ cd flashcards + $ npm install + $ npx gel project init + + +.. edb:split-section:: + + Explore the empty database by starting our REPL from the project root. + + .. code-block:: sh + + $ npx gel + +.. edb:split-section:: + + Try the following queries which will work without any schema defined. + + .. code-block:: edgeql-repl + + db> select 42; + {42} + db> select sum({1, 2, 3}); + {6} + db> with cards := { + ... ( + ... front := "What is the highest mountain in the world?", + ... back := "Mount Everest", + ... ), + ... ( + ... front := "Which ocean contains the deepest trench on Earth?", + ... back := "The Pacific Ocean", + ... ), + ... } + ... select cards order by random() limit 1; + { + ( + front := "What is the highest mountain in the world?", + back := "Mount Everest", + ) + } + +.. edb:split-section:: + + Fun! You will create a proper data model for the application in the next step, but for now, take a look around the project you've just created. Most of the project files will be familiar if you've worked with Next.js before. Here are the files that integrate |Gel|: + + - ``gel.toml``: The configuration file for the Gel project instance. Notice that we have a ``hooks.migration.apply.after`` hook that will run ``npx @gel/generate edgeql-js`` after migrations are applied. This will generate the query builder code that you'll use to interact with the database. More details on that to come! + - ``dbschema/``: This directory contains the schema for the database, and later supporting files like migrations, and generated code. + - :dotgel:`dbschema/default`: The default schema file that you'll use to define your data model. It is empty for now, but you'll add your data model to this file in the next step. + - ``lib/gel.ts``: A utility module that exports the Gel client, which you'll use to interact with the database. + + .. tabs:: + + .. code-tab:: toml + :caption: gel.toml + + [instance] + server-version = 6.0 + + [hooks] + schema.update.after = "npx @gel/generate edgeql-js" + + .. code-tab:: sdl + :caption: dbschema/default.gel + + module default { + + } + + .. code-tab:: typescript + :caption: lib/gel.ts + + import { createClient } from "gel"; + + export const client = createClient(); diff --git a/docs/intro/quickstart/working.rst b/docs/intro/quickstart/working.rst new file mode 100644 index 00000000000..3aee348a036 --- /dev/null +++ b/docs/intro/quickstart/working.rst @@ -0,0 +1,635 @@ +.. _ref_quickstart_working: + +===================== +Working with the data +===================== + +In this section, you will update the existing application to use |Gel| to store and query data, instead of a static JSON file. Having a working application with mock data allows you to focus on learning how |Gel| works, without getting bogged down by the details of the application. + +Bulk importing of data +====================== + +.. edb:split-section:: + + Begin by updating the server action to import a deck with cards. Loop through each card in the deck and insert it, building an array of IDs as you go. This array of IDs will be used to set the ``cards`` link on the ``Deck`` object after all cards have been inserted. + + The array of card IDs is initially an array of strings. To satisfy the |Gel| type system, which expects the ``id`` property of ``Card`` objects to be a ``uuid`` rather than a ``str``, you need to cast the array of strings to an array of UUIDs. Use the ``e.literal(e.array(e.uuid), cardIds)`` function to perform this casting. + + The function ``e.includes(cardIdsLiteral, c.id)`` from our standard library checks if a value is present in an array and returns a boolean. When inserting the ``Deck`` object, set the ``cards`` to the result of selecting only the ``Card`` objects whose ``id`` is included in the ``cardIds`` array. + + .. code-block:: typescript-diff + :caption: app/actions.ts + + "use server"; + + - import { readFile, writeFile } from "node:fs/promises"; + + import { client } from "@/lib/gel"; + + import e from "@/dbschema/edgeql-js"; + import { revalidatePath } from "next/cache"; + - import { RawJSONDeck, Deck } from "@/lib/models"; + + import { RawJSONDeck } from "@/lib/models"; + + export async function importDeck(formData: FormData) { + const file = formData.get("file") as File; + const rawDeck = JSON.parse(await file.text()) as RawJSONDeck; + const deck = { + ...rawDeck, + - id: crypto.randomUUID(), + - cards: rawDeck.cards.map((card) => ({ + + cards: rawDeck.cards.map((card, index) => ({ + ...card, + - id: crypto.randomUUID(), + + order: index, + })), + }; + - + - const existingDecks = JSON.parse( + - await readFile("./decks.json", "utf-8") + - ) as Deck[]; + - + - await writeFile( + - "./decks.json", + - JSON.stringify([...existingDecks, deck], null, 2) + - ); + + const cardIds: string[] = []; + + for (const card of deck.cards) { + + const createdCard = await e + + .insert(e.Card, { + + front: card.front, + + back: card.back, + + order: card.order, + + }) + + .run(client); + + + + cardIds.push(createdCard.id); + + } + + + + const cardIdsLiteral = e.literal(e.array(e.uuid), cardIds); + + + + await e.insert(e.Deck, { + + name: deck.name, + + description: deck.description, + + cards: e.select(e.Card, (c) => ({ + + filter: e.contains(cardIdsLiteral, c.id), + + })), + + }).run(client); + + revalidatePath("/"); + } + +.. edb:split-section:: + + This works, but you might notice that it is not atomic. For instance, if one of the ``Card`` objects fails to insert, the entire operation will fail and the ``Deck`` will not be inserted, but some data will still linger. To make this operation atomic, update the ``importDeck`` action to use a transaction. + + .. code-block:: typescript-diff + :caption: app/actions.ts + + "use server"; + + import { client } from "@/lib/gel"; + import e from "@/dbschema/edgeql-js"; + import { revalidatePath } from "next/cache"; + import { RawJSONDeck } from "@/lib/models"; + + export async function importDeck(formData: FormData) { + const file = formData.get("file") as File; + const rawDeck = JSON.parse(await file.text()) as RawJSONDeck; + const deck = { + ...rawDeck, + cards: rawDeck.cards.map((card, index) => ({ + ...card, + order: index, + })), + }; + + await client.transaction(async (tx) => { + const cardIds: string[] = []; + for (const card of deck.cards) { + const createdCard = await e + .insert(e.Card, { + front: card.front, + back: card.back, + order: card.order, + }) + - .run(client); + + .run(tx); + + cardIds.push(createdCard.id); + } + + const cardIdsLiteral = e.literal(e.array(e.uuid), cardIds); + + await e.insert(e.Deck, { + name: deck.name, + description: deck.description, + cards: e.select(e.Card, (c) => ({ + filter: e.contains(cardIdsLiteral, c.id), + })), + - }).run(client); + + }).run(tx); + + }); + + revalidatePath("/"); + } + +.. edb:split-section:: + + You might think this is as good as it gets, and many ORMs will create a similar set of queries. However, with the query builder, you can improve this by crafting a single query that inserts the ``Deck`` and ``Card`` objects, along with their links, in one efficient query. + + The first thing to notice is that the ``e.params`` function is used to define parameters for your query instead of embedding literal values directly. This approach eliminates the need for casting, as was necessary with the ``cardIds`` array. By defining the ``cards`` parameter as an array of tuples, you ensure full type safety with both TypeScript and the database. + + Another key feature of this query builder expression is the ``e.for(e.array_unpack(params.cards), (card) => {...})`` construct. This expression converts the array of tuples into a set of tuples and generates a set containing an expression for each element. Essentially, you assign the ``Deck.cards`` set of ``Card`` objects to the result of inserting each element from the ``cards`` array. This is similar to what you were doing before by selecting all ``Card`` objects by their ``id``, but is more efficient since you are inserting the ``Deck`` and all ``Card`` objects in one query. + + .. code-block:: typescript-diff + :caption: app/actions.ts + + "use server"; + + import { client } from "@/lib/gel"; + import e from "@/dbschema/edgeql-js"; + import { revalidatePath } from "next/cache"; + import { RawJSONDeck } from "@/lib/models"; + + export async function importDeck(formData: FormData) { + const file = formData.get("file") as File; + const rawDeck = JSON.parse(await file.text()) as RawJSONDeck; + const deck = { + ...rawDeck, + cards: rawDeck.cards.map((card, index) => ({ + ...card, + order: index, + })), + }; + - await client.transaction(async (tx) => { + - const cardIds: string[] = []; + - for (const card of deck.cards) { + - const createdCard = await e + - .insert(e.Card, { + - front: card.front, + - back: card.back, + - order: card.order, + - }) + - .run(tx); + - + - cardIds.push(createdCard.id); + - } + - + - const cardIdsLiteral = e.literal(e.array(e.uuid), cardIds); + - + - await e.insert(e.Deck, { + - name: deck.name, + - description: deck.description, + - cards: e.select(e.Card, (c) => ({ + - filter: e.contains(cardIdsLiteral, c.id), + - })), + - }).run(tx); + - }); + + await e + + .params( + + { + + name: e.str, + + description: e.optional(e.str), + + cards: e.array(e.tuple({ front: e.str, back: e.str, order: e.int64 })), + + }, + + (params) => + + e.insert(e.Deck, { + + name: params.name, + + description: params.description, + + cards: e.for(e.array_unpack(params.cards), (card) => + + e.insert(e.Card, { + + front: card.front, + + back: card.back, + + order: card.order, + + }) + + ), + + }) + + ) + + .run(client, deck); + + revalidatePath("/"); + } + +Updating data +============= + +.. edb:split-section:: + + Next, you will update the Server Actions for each ``Deck`` object: ``updateDeck``, ``addCard``, and ``deleteCard``. Start with ``updateDeck``, which is the most complex because it is dynamic. You can set either the ``title`` or ``description`` fields in an update. Use the dynamic nature of the query builder to generate separate queries based on which fields are present in the form data. + + This may seem a bit intimidating at first, but the key to making this query dynamic is the ``nameSet`` and ``descriptionSet`` variables. These variables conditionally add the ``name`` or ``description`` fields to the ``set`` parameter of the ``update`` call. + + .. code-block:: typescript-diff + :caption: app/deck/[id]/actions.ts + + "use server"; + + import { revalidatePath } from "next/cache"; + import { readFile, writeFile } from "node:fs/promises"; + + import { client } from "@/lib/gel"; + + import e from "@/dbschema/edgeql-js"; + import { Deck } from "@/lib/models"; + + export async function updateDeck(formData: FormData) { + const id = formData.get("id"); + const name = formData.get("name"); + const description = formData.get("description"); + + if ( + typeof id !== "string" || + (typeof name !== "string" && + typeof description !== "string") + ) { + return; + } + + - const decks = JSON.parse( + - await readFile("./decks.json", "utf-8") + - ) as Deck[]; + - decks[index].name = name ?? decks[index].name; + + const nameSet = typeof name === "string" ? { name } : {}; + - decks[index].description = description ?? decks[index].description; + + const descriptionSet = + + typeof description === "string" ? { description: description || null } : {}; + + + await e + + .update(e.Deck, (d) => ({ + + filter_single: e.op(d.id, "=", e.uuid(id)), + + set: { + + ...nameSet, + + ...descriptionSet, + + }, + + })).run(client); + - await writeFile("./decks.json", JSON.stringify(decks, null, 2)); + revalidatePath(`/deck/${id}`); + } + + export async function addCard(formData: FormData) { + const deckId = formData.get("deckId"); + const front = formData.get("front"); + const back = formData.get("back"); + + if ( + typeof deckId !== "string" || + typeof front !== "string" || + typeof back !== "string" + ) { + return; + } + + const decks = JSON.parse(await readFile("./decks.json", "utf-8")) as Deck[]; + + const deck = decks.find((deck) => deck.id === deckId); + if (!deck) { + return; + } + + deck.cards.push({ front, back, id: crypto.randomUUID() }); + await writeFile("./decks.json", JSON.stringify(decks, null, 2)); + + revalidatePath(`/deck/${deckId}`); + } + + export async function deleteCard(formData: FormData) { + const cardId = formData.get("cardId"); + + if (typeof cardId !== "string") { + return; + } + + const decks = JSON.parse(await readFile("./decks.json", "utf-8")) as Deck[]; + const deck = decks.find((deck) => deck.cards.some((card) => card.id === cardId)); + if (!deck) { + return; + } + + deck.cards = deck.cards.filter((card) => card.id !== cardId); + await writeFile("./decks.json", JSON.stringify(decks, null, 2)); + + revalidatePath(`/`); + } + +Adding linked data +================== + +.. edb:split-section:: + + For the ``addCard`` action, you need to insert a new ``Card`` object and update the ``Deck.cards`` set to include the new ``Card`` object. Notice that the ``order`` property is set by selecting the maximum ``order`` property of this ``Deck.cards`` set and incrementing it by 1. + + The syntax for adding an object to a set of links is ``{ "+=": object }``. You can think of this as a shortcut for setting the link set to the current set plus the new object. + + .. code-block:: typescript-diff + :caption: app/deck/[id]/actions.ts + + "use server"; + + import { revalidatePath } from "next/cache"; + import { readFile, writeFile } from "node:fs/promises"; + import { client } from "@/lib/gel"; + import e from "@/dbschema/edgeql-js"; + import { Deck } from "@/lib/models"; + + export async function updateDeck(formData: FormData) { + const id = formData.get("id"); + const name = formData.get("name"); + const description = formData.get("description"); + + if ( + typeof id !== "string" || + (typeof name !== "string" && + typeof description !== "string") + ) { + return; + } + + const nameSet = typeof name === "string" ? { name } : {}; + const descriptionSet = + typeof description === "string" ? { description: description || null } : {}; + + await e + .update(e.Deck, (d) => ({ + filter_single: e.op(d.id, "=", e.uuid(id)), + set: { + ...nameSet, + ...descriptionSet, + }, + })).run(client); + revalidatePath(`/deck/${id}`); + } + + export async function addCard(formData: FormData) { + const deckId = formData.get("deckId"); + const front = formData.get("front"); + const back = formData.get("back"); + + if ( + typeof deckId !== "string" || + typeof front !== "string" || + typeof back !== "string" + ) { + return; + } + + - const decks = JSON.parse(await readFile("./decks.json", "utf-8")) as Deck[]; + - + - const deck = decks.find((deck) => deck.id === deckId); + - if (!deck) { + - return; + - } + - + - deck.cards.push({ front, back, id: crypto.randomUUID() }); + - await writeFile("./decks.json", JSON.stringify(decks, null, 2)); + + await e + + .params( + + { + + front: e.str, + + back: e.str, + + deckId: e.uuid, + + }, + + (params) => { + + const deck = e.assert_exists( + + e.select(e.Deck, (d) => ({ + + filter_single: e.op(d.id, "=", params.deckId), + + })) + + ); + + + + const order = e.cast(e.int64, e.max(deck.cards.order)); + + const card = e.insert(e.Card, { + + front: params.front, + + back: params.back, + + order: e.op(order, "+", 1), + + }); + + return e.update(deck, (d) => ({ + + set: { + + cards: { + + "+=": card + + }, + + }, + + })) + + } + + ) + + .run(client, { + + front, + + back, + + deckId, + + }); + + revalidatePath(`/deck/${deckId}`); + } + + export async function deleteCard(formData: FormData) { + const cardId = formData.get("cardId"); + + if (typeof cardId !== "string") { + return; + } + + const decks = JSON.parse(await readFile("./decks.json", "utf-8")) as Deck[]; + const deck = decks.find((deck) => deck.cards.some((card) => card.id === cardId)); + if (!deck) { + return; + } + + deck.cards = deck.cards.filter((card) => card.id !== cardId); + await writeFile("./decks.json", JSON.stringify(decks, null, 2)); + + revalidatePath(`/`); + } + +Deleting linked data +==================== + +.. edb:split-section:: + + For the ``deleteCard`` action, delete the ``Card`` object and based on the deletion policy we set up earlier in the schema, the object will be deleted from the database and removed from the ``Deck.cards`` set. + + .. code-block:: typescript-diff + :caption: app/deck/[id]/actions.ts + + "use server"; + + import { revalidatePath } from "next/cache"; + - import { readFile, writeFile } from "node:fs/promises"; + import { client } from "@/lib/gel"; + import e from "@/dbschema/edgeql-js"; + import { Deck } from "@/lib/models"; + + export async function updateDeck(formData: FormData) { + const id = formData.get("id"); + const name = formData.get("name"); + const description = formData.get("description"); + + if ( + typeof id !== "string" || + (typeof name !== "string" && + typeof description !== "string") + ) { + return; + } + + const nameSet = typeof name === "string" ? { name } : {}; + const descriptionSet = + typeof description === "string" ? { description: description || null } : {}; + + await e + .update(e.Deck, (d) => ({ + filter_single: e.op(d.id, "=", e.uuid(id)), + set: { + ...nameSet, + ...descriptionSet, + }, + })).run(client); + revalidatePath(`/deck/${id}`); + } + + export async function addCard(formData: FormData) { + const deckId = formData.get("deckId"); + const front = formData.get("front"); + const back = formData.get("back"); + + if ( + typeof deckId !== "string" || + typeof front !== "string" || + typeof back !== "string" + ) { + return; + } + + await e + .params( + { + front: e.str, + back: e.str, + deckId: e.uuid, + }, + (params) => { + const deck = e.assert_exists( + e.select(e.Deck, (d) => ({ + filter_single: e.op(d.id, "=", params.deckId), + })) + ); + + const order = e.cast(e.int64, e.max(deck.cards.order)); + const card = e.insert(e.Card, { + front: params.front, + back: params.back, + order: e.op(order, "+", 1), + }); + return e.update(deck, (d) => ({ + set: { + cards: { + "+=": card + }, + }, + })) + } + ) + .run(client, { + front, + back, + deckId, + }); + + revalidatePath(`/deck/${deckId}`); + } + + export async function deleteCard(formData: FormData) { + const cardId = formData.get("cardId"); + + if (typeof cardId !== "string") { + return; + } + + - const decks = JSON.parse(await readFile("./decks.json", "utf-8")) as Deck[]; + - const deck = decks.find((deck) => deck.cards.some((card) => card.id === cardId)); + - if (!deck) { + - return; + - } + - + - deck.cards = deck.cards.filter((card) => card.id !== cardId); + - await writeFile("./decks.json", JSON.stringify(decks, null, 2)); + + await e + + .params({ id: e.uuid }, (params) => + + e.delete(e.Card, (c) => ({ + + filter_single: e.op(c.id, "=", params.id), + + })) + + ) + + .run(client, { id: cardId }); + + + + revalidatePath(`/`); + } + +Querying data +============= + +.. edb:split-section:: + + Next, update the two ``queries.ts`` methods: ``getDecks`` and ``getDeck``. + + .. tabs:: + + .. code-tab:: typescript-diff + :caption: app/queries.ts + + - import { readFile } from "node:fs/promises"; + + import { client } from "@/lib/gel"; + + import e from "@/dbschema/edgeql-js"; + - + - import { Deck } from "@/lib/models"; + + export async function getDecks() { + - const decks = JSON.parse(await readFile("./decks.json", "utf-8")) as Deck[]; + + const decks = await e.select(e.Deck, (deck) => ({ + + id: true, + + name: true, + + description: true, + + cards: e.select(deck.cards, (card) => ({ + + id: true, + + front: true, + + back: true, + + order_by: card.order, + + })), + + })).run(client); + + return decks; + } + + .. code-tab:: typescript-diff + :caption: app/deck/[id]/queries.ts + + - import { readFile } from "node:fs/promises"; + - import { Deck } from "@/lib/models"; + + import { client } from "@/lib/gel"; + + import e from "@/dbschema/edgeql-js"; + + export async function getDeck({ id }: { id: string }) { + - const decks = JSON.parse(await readFile("./decks.json", "utf-8")) as Deck[]; + - return decks.find((deck) => deck.id === id) ?? null; + + return await e + + .select(e.Deck, (deck) => ({ + + filter_single: e.op(deck.id, "=", e.uuid(id)), + + id: true, + + name: true, + + description: true, + + cards: e.select(deck.cards, (card) => ({ + + id: true, + + front: true, + + back: true, + + order_by: card.order, + + })), + + })) + + .run(client); + } + +.. edb:split-section:: + + In a terminal, run the Next.js development server. + + .. code-block:: sh + + $ npm run dev + +.. edb:split-section:: + + A static JSON file to seed your database with a deck of trivia cards is included in the project. Open your browser and navigate to the app at ``_. Use the "Import JSON" button to import this JSON file into your database. + + .. image:: images/flashcards-import.png diff --git a/docs/intro/schema.rst b/docs/intro/schema.rst index ee7e4f9c5bc..06ba507a6df 100644 --- a/docs/intro/schema.rst +++ b/docs/intro/schema.rst @@ -5,14 +5,14 @@ Schema ====== -This page is intended as a rapid-fire overview of EdgeDB's schema definition -language (SDL) so you can hit the ground running with EdgeDB. Refer to the +This page is intended as a rapid-fire overview of Gel's schema definition +language (SDL) so you can hit the ground running with Gel. Refer to the linked pages for more in-depth documentation! Scalar types ------------ -EdgeDB implements a rigorous type system containing the following primitive +|Gel| implements a rigorous type system containing the following primitive types. .. list-table:: @@ -22,7 +22,7 @@ types. * - Booleans - ``bool`` * - Numbers - - ``int16`` ``int32`` ``int64`` ``float32`` ``float64`` + - ``int16`` ``int32`` ``int64`` ``float32`` ``float64`` ``bigint`` ``decimal`` * - UUID - ``uuid`` @@ -53,7 +53,7 @@ These primitives can be combined into arrays, tuples, and ranges. * - Ranges - ``range`` -Collectively, *primitive* and *collection* types comprise EdgeDB's *scalar +Collectively, *primitive* and *collection* types comprise Gel's *scalar type system*. Object types @@ -68,21 +68,13 @@ Properties Declare a property by naming it and setting its type. -.. code-block:: sdl - :version-lt: 3.0 - - type Movie { - property title -> str; - } - .. code-block:: sdl type Movie { title: str; } -The ``property`` keyword can be omitted for non-computed properties since -EdgeDB v3. +The ``property`` keyword can be omitted for non-computed properties. See :ref:`Schema > Object types `. @@ -92,14 +84,6 @@ Required vs optional Properties are optional by default. Use the ``required`` keyword to make them required. -.. code-block:: sdl - :version-lt: 3.0 - - type Movie { - required property title -> str; # required - property release_year -> int64; # optional - } - .. code-block:: sdl type Movie { @@ -115,17 +99,6 @@ Constraints Add a pair of curly braces after the property to define additional information, including constraints. -.. code-block:: sdl - :version-lt: 3.0 - - type Movie { - required property title -> str { - constraint exclusive; - constraint min_len_value(8); - constraint regexp(r'^[A-Za-z0-9 ]+$'); - } - } - .. code-block:: sdl type Movie { @@ -146,22 +119,6 @@ Object types can contain *computed properties* that correspond to EdgeQL expressions. This expression is dynamically computed whenever the property is queried. -.. code-block:: sdl - :version-lt: 3.0 - - type Movie { - required property title -> str; - property uppercase_title := str_upper(.title); - } - -.. code-block:: sdl - :version-lt: 4.0 - - type Movie { - required title: str; - property uppercase_title := str_upper(.title); - } - .. code-block:: sdl type Movie { @@ -176,18 +133,6 @@ Links Object types can have links to other object types. -.. code-block:: sdl - :version-lt: 3.0 - - type Movie { - required property title -> str; - link director -> Person; - } - - type Person { - required property name -> str; - } - .. code-block:: sdl type Movie { @@ -199,27 +144,11 @@ Object types can have links to other object types. required name: str; } -The ``link`` keyword can be omitted for non-computed links since EdgeDB v3. +The ``link`` keyword can be omitted for non-computed links since Gel v3. Use the ``required`` and ``multi`` keywords to specify the cardinality of the relation. -.. code-block:: sdl - :version-lt: 3.0 - - type Movie { - required property title -> str; - - link cinematographer -> Person; # zero or one - required link director -> Person; # exactly one - multi link writers -> Person; # zero or more - required multi link actors -> Person; # one or more - } - - type Person { - required property name -> str; - } - .. code-block:: sdl type Movie { @@ -237,21 +166,6 @@ relation. To define a one-to-one relation, use an ``exclusive`` constraint. -.. code-block:: sdl - :version-lt: 3.0 - - type Movie { - required property title -> str; - required link stats -> MovieStats { - constraint exclusive; - }; - } - - type MovieStats { - required property budget -> int64; - required property box_office -> int64; - } - .. code-block:: sdl type Movie { @@ -275,34 +189,6 @@ Objects can contain "computed links": stored expressions that return a set of objects. Computed links are dynamically computed when they are referenced in queries. The example below defines a backlink. -.. code-block:: sdl - :version-lt: 3.0 - - type Movie { - required property title -> str; - multi link actors -> Person; - - # returns all movies with same title - multi link same_title := ( - with t := .title - select detached Movie filter .title = t - ) - } - -.. code-block:: sdl - :version-lt: 4.0 - - type Movie { - required title: str; - multi actors: Person; - - # returns all movies with same title - multi link same_title := ( - with t := .title - select detached Movie filter .title = t - ) - } - .. code-block:: sdl type Movie { @@ -321,32 +207,6 @@ Backlinks A common use case for computed links is *backlinks*. -.. code-block:: sdl - :version-lt: 3.0 - - type Movie { - required property title -> str; - multi link actors -> Person; - } - - type Person { - required property name -> str; - multi link acted_in := . Computeds > Backlinks `. @@ -381,17 +241,6 @@ Constraints Constraints can also be defined at the *object level*. -.. code-block:: sdl - :version-lt: 3.0 - - type BlogPost { - property title -> str; - link author -> User; - - constraint exclusive on ((.title, .author)); - } - - .. code-block:: sdl type BlogPost { @@ -403,16 +252,6 @@ Constraints can also be defined at the *object level*. Constraints can contain exceptions; these are called *partial constraints*. -.. code-block:: sdl - :version-lt: 3.0 - - type BlogPost { - property title -> str; - property published -> bool; - - constraint exclusive on (.title) except (not .published); - } - .. code-block:: sdl type BlogPost { @@ -427,18 +266,6 @@ Indexes Use ``index on`` to define indexes on an object type. -.. code-block:: sdl - :version-lt: 3.0 - - type Movie { - required property title -> str; - required property release_year -> int64; - - index on (.title); # simple index - index on ((.title, .release_year)); # composite index - index on (str_trim(str_lower(.title))); # computed index - } - .. code-block:: sdl type Movie { @@ -461,21 +288,6 @@ Schema mixins Object types can be declared as ``abstract``. Non-abstract types can *extend* abstract types. -.. code-block:: sdl - :version-lt: 3.0 - - abstract type Content { - required property title -> str; - } - - type Movie extending Content { - required property release_year -> int64; - } - - type TVShow extending Content { - required property num_seasons -> int64; - } - .. code-block:: sdl abstract type Content { @@ -492,21 +304,6 @@ abstract types. Multiple inheritance is supported. -.. code-block:: sdl - :version-lt: 3.0 - - abstract type HasTitle { - required property title -> str; - } - - abstract type HasReleaseYear { - required property release_year -> int64; - } - - type Movie extending HasTitle, HasReleaseYear { - link sequel_to -> Movie; - } - .. code-block:: sdl abstract type HasTitle { @@ -529,26 +326,6 @@ Polymorphism Links can correspond to abstract types. These are known as *polymorphic links*. -.. code-block:: sdl - :version-lt: 3.0 - - abstract type Content { - required property title -> str; - } - - type Movie extending Content { - required property release_year -> int64; - } - - type TVShow extending Content { - required property num_seasons -> int64; - } - - type Franchise { - required property name -> str; - multi link entries -> Content; - } - .. code-block:: sdl abstract type Content { diff --git a/docs/redirects b/docs/redirects new file mode 100644 index 00000000000..aaa94a3809c --- /dev/null +++ b/docs/redirects @@ -0,0 +1,71 @@ +/guides/cloud -> /cloud + +/cli/edgedb -> docs/cli/gel +/cli/edgedb_analyze -> docs/cli/gel_analyze +/cli/edgedb_branch/edgedb_branch_create -> docs/cli/gel_branch/gel_branch_create +/cli/edgedb_branch/edgedb_branch_drop -> docs/cli/gel_branch/gel_branch_drop +/cli/edgedb_branch/edgedb_branch_list -> docs/cli/gel_branch/gel_branch_list +/cli/edgedb_branch/edgedb_branch_merge -> docs/cli/gel_branch/gel_branch_merge +/cli/edgedb_branch/edgedb_branch_rebase -> docs/cli/gel_branch/gel_branch_rebase +/cli/edgedb_branch/edgedb_branch_rename -> docs/cli/gel_branch/gel_branch_rename +/cli/edgedb_branch/edgedb_branch_switch -> docs/cli/gel_branch/gel_branch_switch +/cli/edgedb_branch/edgedb_branch_wipe -> docs/cli/gel_branch/gel_branch_wipe +/cli/edgedb_branch/index -> docs/cli/gel_branch/index +/cli/edgedb_cli_upgrade -> docs/cli/gel_cli_upgrade +/cli/edgedb_cloud/edgedb_cloud_login -> docs/cli/gel_cloud/gel_cloud_login +/cli/edgedb_cloud/edgedb_cloud_logout -> docs/cli/gel_cloud/gel_cloud_logout +/cli/edgedb_cloud/edgedb_cloud_secretkey/edgedb_cloud_secretkey_create -> docs/cli/gel_cloud/gel_cloud_secretkey/edgedb_cloud_secretkey_create +/cli/edgedb_cloud/edgedb_cloud_secretkey/edgedb_cloud_secretkey_list -> docs/cli/gel_cloud/gel_cloud_secretkey/edgedb_cloud_secretkey_list +/cli/edgedb_cloud/edgedb_cloud_secretkey/edgedb_cloud_secretkey_revoke -> docs/cli/gel_cloud/gel_cloud_secretkey/edgedb_cloud_secretkey_revoke +/cli/edgedb_cloud/edgedb_cloud_secretkey/index -> docs/cli/gel_cloud/gel_cloud_secretkey/index +/cli/edgedb_cloud/index -> docs/cli/gel_cloud/index +/cli/edgedb_configure -> docs/cli/gel_configure +/cli/edgedb_connopts -> docs/cli/gel_connopts +/cli/edgedb_database/edgedb_database_create -> docs/cli/gel_database/gel_database_create +/cli/edgedb_database/edgedb_database_drop -> docs/cli/gel_database/gel_database_drop +/cli/edgedb_database/edgedb_database_wipe -> docs/cli/gel_database/gel_database_wipe +/cli/edgedb_database/index -> docs/cli/gel_database/index +/cli/edgedb_describe/edgedb_describe_object -> docs/cli/gel_describe/gel_describe_object +/cli/edgedb_describe/edgedb_describe_schema -> docs/cli/gel_describe/gel_describe_schema +/cli/edgedb_describe/index -> docs/cli/gel_describe/index +/cli/edgedb_dump -> docs/cli/gel_dump +/cli/edgedb_info -> docs/cli/gel_info +/cli/edgedb_instance/edgedb_instance_create -> docs/cli/gel_instance/gel_instance_create +/cli/edgedb_instance/edgedb_instance_credentials -> docs/cli/gel_instance/gel_instance_credentials +/cli/edgedb_instance/edgedb_instance_destroy -> docs/cli/gel_instance/gel_instance_destroy +/cli/edgedb_instance/edgedb_instance_link -> docs/cli/gel_instance/gel_instance_link +/cli/edgedb_instance/edgedb_instance_list -> docs/cli/gel_instance/gel_instance_list +/cli/edgedb_instance/edgedb_instance_logs -> docs/cli/gel_instance/gel_instance_logs +/cli/edgedb_instance/edgedb_instance_reset_password -> docs/cli/gel_instance/gel_instance_reset_password +/cli/edgedb_instance/edgedb_instance_restart -> docs/cli/gel_instance/gel_instance_restart +/cli/edgedb_instance/edgedb_instance_revert -> docs/cli/gel_instance/gel_instance_revert +/cli/edgedb_instance/edgedb_instance_start -> docs/cli/gel_instance/gel_instance_start +/cli/edgedb_instance/edgedb_instance_status -> docs/cli/gel_instance/gel_instance_status +/cli/edgedb_instance/edgedb_instance_stop -> docs/cli/gel_instance/gel_instance_stop +/cli/edgedb_instance/edgedb_instance_unlink -> docs/cli/gel_instance/gel_instance_unlink +/cli/edgedb_instance/edgedb_instance_upgrade -> docs/cli/gel_instance/gel_instance_upgrade +/cli/edgedb_instance/index -> docs/cli/gel_instance/index +/cli/edgedb_list -> docs/cli/gel_list +/cli/edgedb_migrate -> docs/cli/gel_migrate +/cli/edgedb_migration/edgedb_migration_apply -> docs/cli/gel_migration/gel_migration_apply +/cli/edgedb_migration/edgedb_migration_create -> docs/cli/gel_migration/gel_migration_create +/cli/edgedb_migration/edgedb_migration_edit -> docs/cli/gel_migration/gel_migration_edit +/cli/edgedb_migration/edgedb_migration_extract -> docs/cli/gel_migration/gel_migration_extract +/cli/edgedb_migration/edgedb_migration_log -> docs/cli/gel_migration/gel_migration_log +/cli/edgedb_migration/edgedb_migration_status -> docs/cli/gel_migration/gel_migration_status +/cli/edgedb_migration/edgedb_migration_upgrade_check -> docs/cli/gel_migration/gel_migration_upgrade_check +/cli/edgedb_migration/index -> docs/cli/gel_migration/index +/cli/edgedb_project/edgedb_project_info -> docs/cli/gel_project/gel_project_info +/cli/edgedb_project/edgedb_project_init -> docs/cli/gel_project/gel_project_init +/cli/edgedb_project/edgedb_project_unlink -> docs/cli/gel_project/gel_project_unlink +/cli/edgedb_project/edgedb_project_upgrade -> docs/cli/gel_project/gel_project_upgrade +/cli/edgedb_project/index -> docs/cli/gel_project/index +/cli/edgedb_query -> docs/cli/gel_query +/cli/edgedb_restore -> docs/cli/gel_restore +/cli/edgedb_server/edgedb_server_info -> docs/cli/gel_server/gel_server_info +/cli/edgedb_server/edgedb_server_install -> docs/cli/gel_server/gel_server_install +/cli/edgedb_server/edgedb_server_list_versions -> docs/cli/gel_server/gel_server_list_versions +/cli/edgedb_server/edgedb_server_uninstall -> docs/cli/gel_server/gel_server_uninstall +/cli/edgedb_server/index -> docs/cli/gel_server/index +/cli/edgedb_ui -> docs/cli/gel_ui +/cli/edgedb_watch -> docs/cli/gel_watch diff --git a/docs/reference/admin/branches.rst b/docs/reference/admin/branches.rst index 95b3b4eb6fb..0f3d85cd8bb 100644 --- a/docs/reference/admin/branches.rst +++ b/docs/reference/admin/branches.rst @@ -27,7 +27,7 @@ Create a new branch without schema or data. Description ----------- -The command ``create empty branch`` creates a new EdgeDB branch without schema +The command ``create empty branch`` creates a new Gel branch without schema or data, aside from standard schemas. Examples @@ -54,7 +54,7 @@ Create a new branch copying the schema of an existing branch. Description ----------- -The command ``create schema branch`` creates a new EdgeDB branch with schema +The command ``create schema branch`` creates a new Gel branch with schema copied from an already existing branch. Examples @@ -81,7 +81,7 @@ Create a new branch copying the schema and data of an existing branch. Description ----------- -The command ``create data branch`` creates a new EdgeDB branch with schema and +The command ``create data branch`` creates a new Gel branch with schema and data copied from an already existing branch. Examples diff --git a/docs/reference/admin/configure.rst b/docs/reference/admin/configure.rst index 32b71ff1ec4..3ffc1d760fc 100644 --- a/docs/reference/admin/configure.rst +++ b/docs/reference/admin/configure.rst @@ -8,27 +8,20 @@ Configure ``configure`` -- change a server configuration parameter -.. versionchanged:: _default +.. eql:synopsis:: - .. eql:synopsis:: + configure {session | current branch | instance} + set := ; + configure instance insert ; + configure {session | current branch | instance} reset ; + configure {current branch | instance} + reset [ filter ] ; - configure {session | current database | instance} - set := ; - configure instance insert ; - configure {session | current database | instance} reset ; - configure {current database | instance} - reset [ filter ] ; - -.. versionchanged:: 5.0 - - .. eql:synopsis:: - - configure {session | current branch | instance} - set := ; - configure instance insert ; - configure {session | current branch | instance} reset ; - configure {current branch | instance} - reset [ filter ] ; +.. note:: + Prior to |Gel| and |EdgeDB| 5.0 *branches* were called *databases*. + ``configure current branch`` is used to be called + ``configure current database``, which is still supported for backwards + compatibility. Description @@ -41,19 +34,11 @@ current session. Some configuration parameters cannot be modified by :eql:synopsis:`configure session` and can only be set by :eql:synopsis:`configure instance`. -.. versionchanged:: _default - - :eql:synopsis:`configure current database` is used to configure an - individual EdgeDB database within a server instance with the - changes persisted across server restarts. - -.. versionchanged:: 5.0 - - :eql:synopsis:`configure current branch` is used to configure an - individual EdgeDB branch within a server instance with the - changes persisted across server restarts. +:eql:synopsis:`configure current branch` is used to configure an +individual Gel branch within a server instance with the +changes persisted across server restarts. -:eql:synopsis:`configure instance` is used to configure the entire EdgeDB +:eql:synopsis:`configure instance` is used to configure the entire Gel instance with the changes persisted across server restarts. This variant acts directly on the file system and cannot be rolled back, so it cannot be used in a transaction block. diff --git a/docs/reference/admin/databases.rst b/docs/reference/admin/databases.rst index 55336b6c6eb..849c4f23301 100644 --- a/docs/reference/admin/databases.rst +++ b/docs/reference/admin/databases.rst @@ -8,9 +8,9 @@ Database .. versionadded:: 5.0 - In EdgeDB 5.0, databases were replaced by :ref:`branches - `. If you're running EdgeDB 5.0 or later, try the - :ref:`branch administrative commands ` instead. + In |EdgeDB| 5, databases were replaced by :ref:`branches + `, use the :ref:`branch administrative commands + ` instead. This section describes the administrative commands pertaining to :ref:`databases `. @@ -30,7 +30,7 @@ Create a new database. Description ----------- -The command ``create database`` creates a new EdgeDB database. +The command ``create database`` creates a new Gel database. The new database will be created with all standard schemas prepopulated. diff --git a/docs/reference/admin/index.rst b/docs/reference/admin/index.rst index 57a096cf69f..4eb523f216e 100644 --- a/docs/reference/admin/index.rst +++ b/docs/reference/admin/index.rst @@ -3,7 +3,7 @@ Administration ============== -Administrative commands for managing EdgeDB: +Administrative commands for managing Gel: * :ref:`configure ` @@ -20,7 +20,7 @@ Administrative commands for managing EdgeDB: .. versionadded:: 5.0 - New administrative commands were added in our EdgeDB 5.0 release: + New administrative commands were added in |EdgeDB| 5 release: * :ref:`branch ` diff --git a/docs/reference/backend_ha.rst b/docs/reference/backend_ha.rst index 29deeb39760..ad7ef5fc993 100644 --- a/docs/reference/backend_ha.rst +++ b/docs/reference/backend_ha.rst @@ -4,13 +4,13 @@ Backend high-availability ========================= High availability is a sophisticated and systematic challenge, especially for -databases. To address the problem, EdgeDB server now supports selected +databases. To address the problem, Gel server now supports selected highly-available backend Postgres clusters, namely in 2 categories: * API-based HA * Adaptive HA without API -When the backend HA feature is enabled in EdgeDB, EdgeDB server will try its +When the backend HA feature is enabled in Gel, Gel server will try its best to detect and react to backend failovers, whether a proper API is available or not. @@ -23,32 +23,32 @@ connection is restored and the query can be properly resolved. API-based HA ------------ -EdgeDB server accepts different types of backends by looking into the protocol -of the ``--backend-dsn`` command-line parameter. EdgeDB supports the following +|Gel| server accepts different types of backends by looking into the protocol +of the ``--backend-dsn`` command-line parameter. Gel supports the following DSN protocols currently: * ``stolon+consul+http://`` * ``stolon+consul+https://`` -When using these protocols, EdgeDB builds the actual DSN of the cluster's +When using these protocols, Gel builds the actual DSN of the cluster's leader node by calling the corresponding API using credentials in the ``--backend-dsn`` and subscribes to that API for failover events. Once failover -is detected, EdgeDB drops all backend connections and routes all new backend +is detected, Gel drops all backend connections and routes all new backend connections to the new leader node. `Stolon `_ is an open-source cloud native -PostgreSQL manager for PostgreSQL high availability. Currently, EdgeDB supports -using a Stolon cluster as the backend in a Consul-based setup, where EdgeDB +PostgreSQL manager for PostgreSQL high availability. Currently, Gel supports +using a Stolon cluster as the backend in a Consul-based setup, where Gel acts as a Stolon proxy. This way, you only need to manage Stolon sentinels and -keepers, plus a Consul deployment. To use a Stolon cluster, run EdgeDB server +keepers, plus a Consul deployment. To use a Stolon cluster, run Gel server with a DSN, like so: .. code-block:: bash - $ edgedb-server \ + $ gel-server \ --backend-dsn stolon+consul+http://localhost:8500/my-cluster -EdgeDB will connect to the Consul HTTP service at ``localhost:8500``, and +|Gel| will connect to the Consul HTTP service at ``localhost:8500``, and subscribe to the updates of the cluster named ``my-cluster``. Using a regular ``postgres://`` DSN disables API-based HA. @@ -57,25 +57,25 @@ Using a regular ``postgres://`` DSN disables API-based HA. Adaptive HA ----------- -EdgeDB also supports DNS-based generic HA backends. This may be a cloud +|Gel| also supports DNS-based generic HA backends. This may be a cloud database with multi-AZ failover or some custom HA Postgres cluster that keeps a DNS name always resolved to the leader node. Adaptive HA can be enabled with a switch in addition to a regular backend DSN: .. code-block:: bash - $ edgedb-server \ + $ gel-server \ --backend-dsn postgres://xxx.rds.amazonaws.com \ --enable-backend-adaptive-ha -Once enabled, EdgeDB server will keep track of unusual backend events like +Once enabled, Gel server will keep track of unusual backend events like unexpected disconnects or Postgres shutdown notifications. When a threshold is -reached, EdgeDB considers the backend to be in the "failover" state. It then +reached, Gel considers the backend to be in the "failover" state. It then drops all current backend connections and try to re-establish new connections -with the same backend DSN. Because EdgeDB doesn't cache resolved DNS values, +with the same backend DSN. Because Gel doesn't cache resolved DNS values, the new connections will be established with the new leader node. -Under the hood of adaptive HA, EdgeDB maintains a state machine to avoid +Under the hood of adaptive HA, Gel maintains a state machine to avoid endless switch-overs in an unstable network. State changes only happen when certain conditions are met. @@ -94,12 +94,12 @@ certain conditions are met. ``Unhealthy`` -> ``Failover`` * More than 60% (configurable with environment variable - ``EDGEDB_SERVER_BACKEND_ADAPTIVE_HA_DISCONNECT_PERCENT``) of existing pgcons + :gelenv:`SERVER_BACKEND_ADAPTIVE_HA_DISCONNECT_PERCENT`) of existing pgcons are "unexpectedly disconnected" (number of existing pgcons is captured at the moment we change to ``Unhealthy`` state, and maintained on "expected disconnects" too). * (and) In ``Unhealthy`` state for more than 30 seconds - (``EDGEDB_SERVER_BACKEND_ADAPTIVE_HA_UNHEALTHY_MIN_TIME``). + (:gelenv:`SERVER_BACKEND_ADAPTIVE_HA_UNHEALTHY_MIN_TIME`). * (and) sys_pgcon is down. * (or) Postgres shutdown/hot-standby notification received. @@ -117,4 +117,4 @@ certain conditions are met. * (and) sys_pgcon is healthy. ("pgcon" is a code name for backend connections, and "sys_pgcon" is a special -backend connection which EdgeDB uses to talk to the "EdgeDB system database".) +backend connection which Gel uses to talk to the "Gel system database".) diff --git a/docs/reference/bindings/datetime.rst b/docs/reference/bindings/datetime.rst index 521ff07d5bc..8f7cb70effd 100644 --- a/docs/reference/bindings/datetime.rst +++ b/docs/reference/bindings/datetime.rst @@ -4,7 +4,7 @@ Date/Time Handling ================== -EdgeDB has 6 types related to date and time handling: +|Gel| has 6 types related to date and time handling: * :eql:type:`datetime` (:ref:`binary format `) * :eql:type:`duration` (:ref:`binary format `) @@ -21,7 +21,7 @@ Usually we try to map those types to the respective language-native types, with the following caveats: * The type in standard library -* It has enough range (EdgeDB has timestamps from year 1 to 9999) +* It has enough range (Gel has timestamps from year 1 to 9999) * And it has good enough precision (at least microseconds) If any of the above criteria is not met, we usually provide a custom type in @@ -40,7 +40,7 @@ Precision This means that if language-native type have a bigger precision such as nanosecond, client library has to round that timestamp when encoding it for -EdgeDB. +|Gel|. We use **rouding to the nearest even** for that operation. Here are some examples of timetamps with high precision, and how they are stored in the @@ -68,8 +68,7 @@ database:: Note as described in :ref:`datetime protocol documentation ` the value is encoded as a *signed* microseconds delta since a fixed time. Some care must be taken when rounding negative -microsecond values. See `tests for Rust implementation`_ for a good set of -test cases. +microsecond values. Rounding to the nearest even applies to all operations that client libraries perform, in particular: @@ -80,13 +79,7 @@ perform, in particular: 2. Decoding timestamps *and* time deltas from the binary format is precision of native type is lower than microseconds (applies for JavaScript for example) -3. Converting from EdgeDB specific type (if there is one) to native type and +3. Converting from Gel specific type (if there is one) to native type and back (depending on the difference in precision) -4. Parsing a string to an EdgeDB specific type (this operation is optional to +4. Parsing a string to an Gel specific type (this operation is optional to implement, but if it is implemented, it must obey the rules) - -.. lint-off - -.. _tests for Rust implementation: https://github.com/edgedb/edgedb-rust/tree/master/edgedb-protocol/tests/datetime_chrono.rs - -.. lint-on diff --git a/docs/reference/bindings/index.rst b/docs/reference/bindings/index.rst index aa2ec17f9fa..7b0729ef9fc 100644 --- a/docs/reference/bindings/index.rst +++ b/docs/reference/bindings/index.rst @@ -4,7 +4,7 @@ Client Libraries ================ -EdgeDB client libraries are a bit higher level than usual database bindings. +|Gel| client libraries are a bit higher level than usual database bindings. In particular, they contain: * Structured data retrieval @@ -17,7 +17,7 @@ Additionally, client libraries might provide: * Query builder This is a **work-in-progress** reference for writing client libraries for -EdgeDB. +|Gel|. External Links: @@ -35,6 +35,6 @@ Contents: .. lint-off -.. _RFC 1004: https://github.com/edgedb/rfcs/blob/master/text/1004-transactions-api.rst +.. _RFC 1004: https://github.com/geldata/rfcs/blob/master/text/1004-transactions-api.rst .. lint-on diff --git a/docs/reference/configuration.rst b/docs/reference/configuration.rst index 2179cd93054..0003ad2e94c 100644 --- a/docs/reference/configuration.rst +++ b/docs/reference/configuration.rst @@ -4,7 +4,7 @@ Server configuration ==================== -EdgeDB exposes a number of configuration parameters that affect its +|Gel| exposes a number of configuration parameters that affect its behavior. In this section we review the ways to change the server configuration, as well as detail each available configuration parameter. @@ -20,18 +20,18 @@ configuration parameters using EdgeQL. For example: .. code-block:: edgeql-repl - edgedb> configure instance set listen_addresses := {'127.0.0.1', '::1'}; + gel> configure instance set listen_addresses := {'127.0.0.1', '::1'}; CONFIGURE: OK CLI --- -The :ref:`ref_cli_edgedb_configure` command allows modifying the system +The :ref:`ref_cli_gel_configure` command allows modifying the system configuration from a terminal: .. code-block:: bash - $ edgedb configure set listen_addresses 127.0.0.1 ::1 + $ gel configure set listen_addresses 127.0.0.1 ::1 Available settings @@ -108,8 +108,8 @@ Query behavior .. note:: This setting can also be conveniently accessed via the "Config" dropdown - menu at the top of the EdgeDB UI (accessible by running the CLI command - ``edgedb ui`` from within a project). The setting will apply only to your + menu at the top of the Gel UI (accessible by running the CLI command + :gelcmd:`ui` from within a project). The setting will apply only to your UI session, so you won't have to remember to re-enable it when you're done. diff --git a/docs/reference/connection.rst b/docs/reference/connection.rst index 65383c0cdbc..23bd1db1246 100644 --- a/docs/reference/connection.rst +++ b/docs/reference/connection.rst @@ -10,7 +10,7 @@ Connection parameters The CLI and client libraries (collectively referred to as "clients" below) must -connect to an EdgeDB instance to run queries or commands. There are several +connect to an Gel instance to run queries or commands. There are several connection parameters, each of which can be specified in several ways. .. _ref_reference_connection_instance: @@ -18,7 +18,7 @@ connection parameters, each of which can be specified in several ways. Specifying an instance ---------------------- -There are several ways to uniquely identify an EdgeDB instance. +There are several ways to uniquely identify an Gel instance. .. list-table:: @@ -27,22 +27,22 @@ There are several ways to uniquely identify an EdgeDB instance. - **Environment variable** * - Instance name - ``--instance/-I `` - - ``EDGEDB_INSTANCE`` - * - Secret key (required in some EdgeDB Cloud scenarios; see description) + - :gelenv:`INSTANCE` + * - Secret key (required in some Gel Cloud scenarios; see description) - ``--secret-key`` - - ``EDGEDB_SECRET_KEY`` + - :gelenv:`SECRET_KEY` * - DSN - ``--dsn `` - - ``EDGEDB_DSN`` + - :gelenv:`DSN` * - Host and port - .. code-block:: --host/-H --port/-P - - ``EDGEDB_HOST`` and ``EDGEDB_PORT`` + - :gelenv:`HOST` and :gelenv:`PORT` * - Credentials file - ``--credentials-file `` - - ``EDGEDB_CREDENTIALS_FILE`` + - :gelenv:`CREDENTIALS_FILE` * - *Project linking* - *N/A* - *N/A* @@ -56,33 +56,33 @@ Let's dig into each of these a bit more. All local instances (instances created on your local machine using the CLI) are associated with a name. This name is what's needed to connect; under the hood, the CLI stores the instance credentials (username, password, etc) on - your file system in the EdgeDB :ref:`config directory - `. The CLI and client libraries look up these + your file system in the Gel :ref:`config directory + `. The CLI and client libraries look up these credentials to connect. - You can also assign names to remote instances using :ref:`edgedb instance - link `. The CLI will save the credentials + You can also assign names to remote instances using :ref:`gel instance + link `. The CLI will save the credentials locally, so you can connect to a remote instance using just its name, just like a local instance. - If you have authenticated with EdgeDB Cloud in the CLI using the - :ref:`ref_cli_edgedb_cloud_login` command, you can address your own EdgeDB + If you have authenticated with Gel Cloud in the CLI using the + :ref:`ref_cli_gel_cloud_login` command, you can address your own Gel Cloud instances using the instance name format ``/``. If you are not authenticated, .. _ref_reference_connection_secret_key: **Secret key** - If you want to connect to an EdgeDB Cloud instance in either of these + If you want to connect to an Gel Cloud instance in either of these scenarios: - from a client binding - from the CLI to an instance not belonging to the currently authenticated - EdgeDB Cloud user + Gel Cloud user you will need to provide a secret key in addition to the instance name. Generate a dedicated secret key for the instance via the CLI with - :ref:`ref_cli_edgedb_cloud_secretkey_create` or via the web UI's "Secret + :ref:`ref_cli_gel_cloud_secretkey_create` or via the web UI's "Secret Keys" pane in your instance dashboard. **DSN** @@ -90,46 +90,17 @@ Let's dig into each of these a bit more. convenient and flexible way to specify connection information with a simple string. It takes the following form: - .. versionchanged:: _default + * :geluri:`USERNAME:PASSWORD@HOSTNAME:PORT/BRANCH` + * e.g.: :geluri:`alice:pa$$w0rd@example.com:1234/my_branch` - .. code-block:: - - edgedb://USERNAME:PASSWORD@HOSTNAME:PORT/DATABASE - - # example - edgedb://alice:pa$$w0rd@example.com:1234/my_db - - .. versionchanged:: 5.0 - - .. code-block:: - - edgedb://USERNAME:PASSWORD@HOSTNAME:PORT/BRANCH - - # example - edgedb://alice:pa$$w0rd@example.com:1234/my_branch - - All components of the DSN are optional; technically ``edgedb://`` is a valid + All components of the DSN are optional; technically |geluri| is a valid DSN. The unspecified values will fall back to their defaults: - .. versionchanged:: _default - - .. code-block:: - - Host: "localhost" - Port: 5656 - User: "edgedb" - Password: null - Database name: "edgedb" - - .. versionchanged:: 5.0 - - .. code-block:: - - Host: "localhost" - Port: 5656 - User: "edgedb" - Password: null - Branch name: "main" + * Host: ``"localhost"`` + * Port: ``5656`` + * User: |admin| + * Password: ``null`` + * Branch name: |main| DSNs also accept query parameters to support advanced use cases. Read the :ref:`DSN Specification ` reference for details. @@ -149,55 +120,40 @@ Let's dig into each of these a bit more. file into version control could present a security risk and is not recommended. - .. versionchanged:: _default - - .. code-block:: json + .. code-block:: json - { - "host": "localhost", - "port": 10702, - "user": "testuser", - "password": "testpassword", - "database": "edgedb", - "tls_cert_data": "-----BEGIN CERTIFICATE-----\nabcdef..." - } - - .. versionchanged:: 5.0 - - .. code-block:: json - - { - "host": "localhost", - "port": 10702, - "user": "testuser", - "password": "testpassword", - "branch": "main", - "tls_cert_data": "-----BEGIN CERTIFICATE-----\nabcdef..." - } + { + "host": "localhost", + "port": 10702, + "user": "testuser", + "password": "testpassword", + "branch": "main", + "tls_cert_data": "-----BEGIN CERTIFICATE-----\nabcdef..." + } Relative paths are resolved relative to the current working directory. **Project-linked instances** - When you run ``edgedb project init`` in a given directory, EdgeDB creates an + When you run :gelcmd:`project init` in a given directory, Gel creates an instance and "links" it to that directory. There's nothing magical about this - link; it's just a bit of metadata that gets stored in the EdgeDB config + link; it's just a bit of metadata that gets stored in the Gel config directory. When you use the client libraries or run a CLI command inside a project-linked directory, the library/CLI can detect this, look up the linked instance's credentials, and connect automatically. For more information on how this works, check out the `release post - `_ for ``edgedb project``. + `_ for :gelcmd:`project`. .. _ref_reference_connection_priority: Priority levels --------------- -The section above describes the various ways of specifying an EdgeDB instance. +The section above describes the various ways of specifying an Gel instance. There are also several ways to provide this configuration information to the client. From highest to lowest priority, you can pass them explicitly as parameters/flags (useful for debugging), use environment variables (recommended -for production), or rely on ``edgedb project`` (recommended for development). +for production), or rely on :gelcmd:`project` (recommended for development). 1. **Explicit connection parameters**. For security reasons, hard-coding connection information or credentials in your codebase is not @@ -210,9 +166,9 @@ for production), or rely on ``edgedb project`` (recommended for development). .. code-block:: javascript - import * as edgedb from "edgedb"; + import * as gel from "gel"; - const pool = await edgedb.createClient({ + const pool = await gel.createClient({ instance: "my_instance" }); @@ -221,22 +177,22 @@ for production), or rely on ``edgedb project`` (recommended for development). .. code-block:: bash - $ edgedb --instance my_instance - EdgeDB 2.x + $ gel --instance my_instance + Gel x.x Type \help for help, \quit to quit. - edgedb> + gel> 2. **Environment variables**. This is the recommended mechanism for providing connection information to - your EdgeDB client, especially in production or when running EdgeDB inside a + your Gel client, especially in production or when running Gel inside a container. All clients read the following variables from the environment: - - ``EDGEDB_DSN`` - - ``EDGEDB_INSTANCE`` - - ``EDGEDB_CREDENTIALS_FILE`` - - ``EDGEDB_HOST`` / ``EDGEDB_PORT`` + - :gelenv:`DSN` + - :gelenv:`INSTANCE` + - :gelenv:`CREDENTIALS_FILE` + - :gelenv:`HOST` / :gelenv:`PORT` When one of these environment variables is defined, there's no need to pass any additional information to the client. The CLI and client libraries will @@ -245,16 +201,16 @@ for production), or rely on ``edgedb project`` (recommended for development). .. code-block:: bash - $ edgedb # no flags needed - EdgeDB 2.x + $ gel # no flags needed + Gel x.x Type \help for help, \quit to quit. - edgedb> + gel> Using the JavaScript client library: .. code-block:: javascript - import { createClient } from "edgedb"; + import { createClient } from "gel"; const client = createClient(); const result = await client.querySingle("select 2 + 2;"); @@ -263,18 +219,18 @@ for production), or rely on ``edgedb project`` (recommended for development). .. warning:: Ambiguity is not permitted. For instance, specifying both - ``EDGEDB_INSTANCE`` and ``EDGEDB_DSN`` will result in an error. You *can* - use ``EDGEDB_HOST`` and ``EDGEDB_PORT`` simultaneously. + :gelenv:`INSTANCE` and :gelenv:`DSN` will result in an error. You *can* + use :gelenv:`HOST` and :gelenv:`PORT` simultaneously. 3. **Project-linked credentials** - If you are using ``edgedb project`` (which we recommend!) and haven't + If you are using :gelcmd:`project` (which we recommend!) and haven't otherwise specified any connection parameters, the CLI and client libraries will connect to the instance that's been linked to your project. - This makes it easy to get up and running with EdgeDB. Once you've run - ``edgedb project init``, the CLI and client libraries will be able to + This makes it easy to get up and running with Gel. Once you've run + :gelcmd:`project init`, the CLI and client libraries will be able to connect to your database without any explicit flags or parameters, as long as you're inside the project directory. @@ -286,7 +242,7 @@ connection fails. Within a given priority level, you cannot specify multiple instances of "instance selection parameters" simultaneously. For instance, specifying - both ``EDGEDB_INSTANCE`` and ``EDGEDB_DSN`` environment variables will + both :gelenv:`INSTANCE` and :gelenv:`DSN` environment variables will result in an error. @@ -304,64 +260,40 @@ configuration. The following "granular" parameters will override any value set by the instance-level configuration object. -.. versionchanged:: _default - - .. list-table:: - - * - **Environment variable** - - **CLI flag** - * - ``EDGEDB_DATABASE`` - - ``--database/-d `` - * - ``EDGEDB_USER`` - - ``--user/-u `` - * - ``EDGEDB_PASSWORD`` - - ``--password `` - * - ``EDGEDB_TLS_CA_FILE`` - - ``--tls-ca-file `` - * - ``EDGEDB_CLIENT_TLS_SECURITY`` - - ``--tls-security`` - * - ``EDGEDB_CLIENT_SECURITY`` - - N/A - - **EDGEDB_DATABASE** - Each EdgeDB *instance* can contain multiple *databases*. When an instance is - created, a default database named ``edgedb`` is created. Unless otherwise - specified, all incoming connections connect to the ``edgedb`` database. - - -.. versionchanged:: 5.0 - - .. list-table:: - - * - **Environment variable** - - **CLI flag** - * - ``EDGEDB_BRANCH`` - - ``--branch/-b `` - * - ``EDGEDB_USER`` - - ``--user/-u `` - * - ``EDGEDB_PASSWORD`` - - ``--password `` - * - ``EDGEDB_TLS_CA_FILE`` - - ``--tls-ca-file `` - * - ``EDGEDB_TLS_SERVER_NAME`` - - ``--tls-server-name`` - * - ``EDGEDB_CLIENT_TLS_SECURITY`` - - ``--tls-security`` - * - ``EDGEDB_CLIENT_SECURITY`` - - N/A - - **EDGEDB_BRANCH** - Each EdgeDB *instance* can be branched multiple times. When an instance is - created, a default branch named ``main`` is created. For CLI-managed - instances, connections are made to the currently active branch. In other - cases, incoming connections connect to the ``main`` branch by default. - -**EDGEDB_USER/EDGEDB_PASSWORD** +.. list-table:: + + * - **Environment variable** + - **CLI flag** + * - :gelenv:`BRANCH` + - ``--branch/-b `` + * - :gelenv:`USER` + - ``--user/-u `` + * - :gelenv:`PASSWORD` + - ``--password `` + * - :gelenv:`TLS_CA_FILE` + - ``--tls-ca-file `` + * - :gelenv:`TLS_SERVER_NAME` + - ``--tls-server-name`` + * - :gelenv:`CLIENT_TLS_SECURITY` + - ``--tls-security`` + * - :gelenv:`CLIENT_SECURITY` + - N/A + +* :gelenv:`BRANCH` + + Each Gel *instance* can be branched multiple times. When an instance is + created, a default branch named |main| is created. For CLI-managed + instances, connections are made to the currently active branch. In other + cases, incoming connections connect to the |main| branch by default. + +* :gelenv:`USER` / :gelenv:`PASSWORD` + These are the credentials of the database user account to connect to the - EdgeDB instance. + Gel instance. + +* :gelenv:`TLS_CA_FILE` -**EDGEDB_TLS_CA_FILE** - TLS is required to connect to any EdgeDB instance. To do so, the client needs + TLS is required to connect to any Gel instance. To do so, the client needs a reference to the root certificate of your instance's certificate chain. Typically this will be handled for you when you create a local instance or ``link`` a remote one. @@ -375,29 +307,32 @@ instance-level configuration object. and provide a path to its location on the filesystem. Otherwise TLS will fail to connect. -**EDGEDB_TLS_SERVER_NAME (SNI)** +* :gelenv:`TLS_SERVER_NAME` (SNI) + If for some reason target instance IP address can't be resolved from the hostname, you can provide SNI. -**EDGEDB_CLIENT_TLS_SECURITY** +* :gelenv:`CLIENT_TLS_SECURITY` + Sets the TLS security mode. Determines whether certificate and hostname verification is enabled. Possible values: - ``"strict"`` (**default**) β€” certificates and hostnames will be verified - ``"no_host_verification"`` β€” verify certificates but not hostnames - - ``"insecure"`` β€”Β client libraries will trust self-signed TLS certificates. + - ``"insecure"`` β€” client libraries will trust self-signed TLS certificates. Useful for self-signed or custom certificates. This setting defaults to ``"strict"`` unless a custom certificate is supplied, in which case it is set to ``"no_host_verification"``. -**EDGEDB_CLIENT_SECURITY** +* :gelenv:`CLIENT_SECURITY` + Provides some simple "security presets". Currently there is only one valid value: ``insecure_dev_mode``. Setting - ``EDGEDB_CLIENT_SECURITY=insecure_dev_mode`` disables all TLS security + :gelenv:`CLIENT_SECURITY=insecure_dev_mode` disables all TLS security measures. Currently it is equivalent to setting - ``EDGEDB_CLIENT_TLS_SECURITY=insecure`` but it may encompass additional + :gelenv:`CLIENT_TLS_SECURITY=insecure` but it may encompass additional configuration settings later. This is most commonly used when developing locally with Docker. @@ -407,20 +342,19 @@ instance-level configuration object. Override behavior ^^^^^^^^^^^^^^^^^ -When specified, the connection parameters (user, password, and -:versionreplace:`database;5.0:branch`) will *override* the corresponding -element of a DSN, credentials file, etc. For instance, consider the following -environment variables: +When specified, the connection parameters (user, password, and |branch|) +will *override* the corresponding element of a DSN, credentials file, etc. +For instance, consider the following environment variables: .. code-block:: - EDGEDB_DSN=edgedb://olduser:oldpass@hostname.com:5656 - EDGEDB_USER=newuser - EDGEDB_PASSWORD=newpass + GEL_DSN=gel://olduser:oldpass@hostname.com:5656 + GEL_USER=newuser + GEL_PASSWORD=newpass In this scenario, ``newuser`` will override ``olduser`` and ``newpass`` will override ``oldpass``. The client library will try to connect using this -modified DSN: ``edgedb://newuser:newpass@hostname.com:5656``. +modified DSN: :geluri:`newuser:newpass@hostname.com:5656`. Overriding across priority levels ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -428,17 +362,18 @@ Overriding across priority levels Override behavior can only happen at the *same or lower priority level*. For instance: -- ``EDGEDB_PASSWORD`` **will** override the password specified in - ``EDGEDB_DSN`` -- ``EDGEDB_PASSWORD`` **will be ignored** if a DSN is passed +- :gelenv:`PASSWORD` **will** override the password specified in + :gelenv:`DSN` + +- :gelenv:`PASSWORD` **will be ignored** if a DSN is passed explicitly using the ``--dsn`` flag. Explicit parameters take precedence over environment variables. To override the password of an explicit DSN, you need to pass it explicitly as well: .. code-block:: bash - $ edgedb --dsn edgedb://username:oldpass@hostname.com --password qwerty - # connects to edgedb://username:qwerty@hostname.com + $ gel --dsn gel://username:oldpass@hostname.com --password qwerty + # connects to gel://username:qwerty@hostname.com -- ``EDGEDB_PASSWORD`` **will** override the stored password associated +- :gelenv:`PASSWORD` **will** override the stored password associated with a project-linked instance. (This is unlikely to be desirable.) diff --git a/docs/reference/ddl/access_policies.rst b/docs/reference/ddl/access_policies.rst deleted file mode 100644 index 1f06651847b..00000000000 --- a/docs/reference/ddl/access_policies.rst +++ /dev/null @@ -1,277 +0,0 @@ -.. versionadded:: 2.0 - -.. _ref_eql_ddl_access_policies: - -=============== -Access Policies -=============== - -This section describes the DDL commands pertaining to access policies. - -Create access policy -==================== - -:eql-statement: - -:ref:`Declare ` a new object access policy. - -.. eql:synopsis:: - :version-lt: 3.0 - - [ with [, ...] ] - { create | alter } type "{" - [ ... ] - create access policy - [ when () ; ] - { allow | deny } [, ... ; ] - [ using () ; ] - [ "{" - [ set errmessage := value ; ] - [ create annotation annotation-name := value ; ] - "}" ] - "}" - - # where is one of - all - select - insert - delete - update [{ read | write }] - -.. eql:synopsis:: - - [ with [, ...] ] - { create | alter } type "{" - [ ... ] - create access policy - [ when () ; ] - { allow | deny } action [, action ... ; ] - [ using () ; ] - [ "{" - [ set errmessage := value ; ] - [ create annotation annotation-name := value ; ] - "}" ] - "}" - - # where is one of - all - select - insert - delete - update [{ read | write }] - - -Description ------------ - -The combination :eql:synopsis:`{create | alter} type ... create access policy` -defines a new access policy for a given object type. - -Parameters ----------- - -Most sub-commands and options of this command are identical to the -:ref:`SDL access policy declaration `. - -:eql:synopsis:`` - The name of the access policy. - -:eql:synopsis:`when ()` - Specifies which objects this policy applies to. The - :eql:synopsis:`` has to be a :eql:type:`bool` expression. - - When omitted, it is assumed that this policy applies to all objects of a - given type. - -:eql:synopsis:`allow` - Indicates that qualifying objects should allow access under this policy. - -:eql:synopsis:`deny` - Indicates that qualifying objects should *not* allow access under this - policy. This flavor supersedes any :eql:synopsis:`allow` policy and can - be used to selectively deny access to a subset of objects that otherwise - explicitly allows accessing them. - -:eql:synopsis:`all` - Apply the policy to all actions. It is exactly equivalent to listing - :eql:synopsis:`select`, :eql:synopsis:`insert`, :eql:synopsis:`delete`, - :eql:synopsis:`update` actions explicitly. - -:eql:synopsis:`select` - Apply the policy to all selection queries. Note that any object that - cannot be selected, cannot be modified either. This makes - :eql:synopsis:`select` the most basic "visibility" policy. - -:eql:synopsis:`insert` - Apply the policy to all inserted objects. If a newly inserted object would - violate this policy, an error is produced instead. - -:eql:synopsis:`delete` - Apply the policy to all objects about to be deleted. If an object does not - allow access under this kind of policy, it is not going to be considered - by any :eql:stmt:`delete` command. - - Note that any object that cannot be selected, cannot be modified either. - -:eql:synopsis:`update read` - Apply the policy to all objects selected for an update. If an object does - not allow access under this kind of policy, it is not visible cannot be - updated. - - Note that any object that cannot be selected, cannot be modified either. - -:eql:synopsis:`update write` - Apply the policy to all objects at the end of an update. If an updated - object violates this policy, an error is produced instead. - - Note that any object that cannot be selected, cannot be modified either. - -:eql:synopsis:`update` - This is just a shorthand for :eql:synopsis:`update read` and - :eql:synopsis:`update write`. - - Note that any object that cannot be selected, cannot be modified either. - -:eql:synopsis:`using ` - Specifies what the policy is with respect to a given eligible (based on - :eql:synopsis:`when` clause) object. The :eql:synopsis:`` has to be - a :eql:type:`bool` expression. The specific meaning of this value also - depends on whether this policy flavor is :eql:synopsis:`allow` or - :eql:synopsis:`deny`. - - When omitted, it is assumed that this policy applies to all eligible - objects of a given type. - -The following subcommands are allowed in the ``create access policy`` block: - -.. versionadded:: 3.0 - - :eql:synopsis:`set errmessage := ` - Set a custom error message of :eql:synopsis:`` that is displayed - when this access policy prevents a write action. - -:eql:synopsis:`create annotation := ` - Set access policy annotation :eql:synopsis:`` to - :eql:synopsis:``. - - See :eql:stmt:`create annotation` for details. - -Alter access policy -==================== - -:eql-statement: - -:ref:`Declare ` a new object access policy. - -.. eql:synopsis:: - :version-lt: 3.0 - - [ with [, ...] ] - alter type "{" - [ ... ] - alter access policy "{" - [ when () ; ] - [ reset when ; ] - { allow | deny } [, ... ; ] - [ using () ; ] - [ reset expression ; ] - [ create annotation := ; ] - [ alter annotation := ; ] - [ drop annotation ; ] - "}" - "}" - - # where is one of - all - select - insert - delete - update [{ read | write }] - -.. eql:synopsis:: - - [ with [, ...] ] - alter type "{" - [ ... ] - alter access policy "{" - [ when () ; ] - [ reset when ; ] - { allow | deny } [, ... ; ] - [ using () ; ] - [ set errmessage := value ; ] - [ reset expression ; ] - [ create annotation := ; ] - [ alter annotation := ; ] - [ drop annotation ; ] - "}" - "}" - - # where is one of - all - select - insert - delete - update [{ read | write }] - -Description ------------ - -The combination :eql:synopsis:`{create | alter} type ... create access policy` -defines a new access policy for a given object type. - -Parameters ----------- - -The parameters describing the action policy are identical to the parameters -used by ``create action policy``. There are a handful of additional -subcommands that are allowed in the ``create access policy`` block: - -:eql:synopsis:`reset when` - Clear the :eql:synopsis:`when ()` so that the policy applies to - all objects of a given type. This is equivalent to ``when (true)``. - -:eql:synopsis:`reset expression` - Clear the :eql:synopsis:`using ()` so that the policy always - passes. This is equivalent to ``using (true)``. - -:eql:synopsis:`alter annotation ;` - Alter access policy annotation :eql:synopsis:``. - See :eql:stmt:`alter annotation` for details. - -:eql:synopsis:`drop annotation ;` - Remove access policy annotation :eql:synopsis:``. - See :eql:stmt:`drop annotation` for details. - - -All the subcommands allowed in the ``create access policy`` block are also -valid subcommands for ``alter access policy`` block. - - -Drop access policy -================== - -:eql-statement: - -Remove an access policy from an object type. - -.. eql:synopsis:: - - [ with [, ...] ] - alter type "{" - [ ... ] - drop access policy ; - "}" - -Description ------------ - -The combination :eql:synopsis:`alter type ... drop access policy` -removes the specified access policy from a given object type. - - -.. list-table:: - :class: seealso - - * - **See also** - * - :ref:`Schema > Access policies ` - * - :ref:`SDL > Access policies ` diff --git a/docs/reference/ddl/aliases.rst b/docs/reference/ddl/aliases.rst deleted file mode 100644 index 60404397836..00000000000 --- a/docs/reference/ddl/aliases.rst +++ /dev/null @@ -1,123 +0,0 @@ -.. _ref_eql_ddl_aliases: - -======= -Aliases -======= - -This section describes the DDL commands pertaining to -:ref:`expression aliases `. - - -Create alias -============ - -:eql-statement: -:eql-haswith: - -:ref:`Define ` a new expression alias in the schema. - -.. eql:synopsis:: - - [ with [, ...] ] - create alias := ; - - [ with [, ...] ] - create alias "{" - using ; - [ create annotation := ; ... ] - "}" ; - - # where is: - - [ := ] module - - -Description ------------ - -The command ``create alias`` defines a new expression alias in the schema. -The schema-level expression aliases are functionally equivalent -to expression aliases defined in a statement :ref:`with block -`, but are available to all queries using the schema -and can be introspected. - -If *name* is qualified with a module name, then the alias is created -in that module, otherwise it is created in the current module. -The alias name must be distinct from that of any existing schema item -in the module. - - -Parameters ----------- - -Most sub-commands and options of this command are identical to the -:ref:`SDL alias declaration `, with some -additional features listed below: - -:eql:synopsis:`[ := ] module ` - An optional list of module alias declarations to be used in the - alias definition. - -:eql:synopsis:`create annotation := ;` - An optional list of annotation values for the alias. - See :eql:stmt:`create annotation` for details. - - -Example -------- - -Create a new alias: - -.. code-block:: edgeql - - create alias Superusers := ( - select User filter User.groups.name = 'Superusers' - ); - - -Drop alias -========== - -:eql-statement: -:eql-haswith: - - -Remove an expression alias from the schema. - -.. eql:synopsis:: - - [ with [, ...] ] - drop alias ; - - -Description ------------ - -The command ``drop alias`` removes an expression alias from the schema. - - -Parameters ----------- - -*alias-name* - The name (optionally qualified with a module name) of an existing - expression alias. - - -Example -------- - -Remove an alias: - -.. code-block:: edgeql - - drop alias SuperUsers; - - -.. list-table:: - :class: seealso - - * - **See also** - * - :ref:`Schema > Aliases ` - * - :ref:`SDL > Aliases ` - * - :ref:`Cheatsheets > Aliases ` diff --git a/docs/reference/ddl/annotations.rst b/docs/reference/ddl/annotations.rst deleted file mode 100644 index 0a7cafe9a50..00000000000 --- a/docs/reference/ddl/annotations.rst +++ /dev/null @@ -1,279 +0,0 @@ -.. _ref_eql_ddl_annotations: - -=========== -Annotations -=========== - -This section describes the DDL commands pertaining to -:ref:`annotations `. - - -Create abstract annotation -========================== - -:eql-statement: - -:ref:`Define ` a new annotation. - -.. eql:synopsis:: - - [ with [, ...] ] - create abstract [ inheritable ] annotation - [ "{" - create annotation := ; - [...] - "}" ] ; - - -Description ------------ - -The command ``create abstract annotation`` defines a new annotation -for use in the current :versionreplace:`database;5.0:branch`. - -If *name* is qualified with a module name, then the annotation is created -in that module, otherwise it is created in the current module. -The annotation name must be distinct from that of any existing schema item -in the module. - -The annotations are non-inheritable by default. That is, if a schema item -has an annotation defined on it, the descendants of that schema item will -not automatically inherit the annotation. Normal inheritance behavior can -be turned on by declaring the annotation with the ``inheritable`` qualifier. - -Most sub-commands and options of this command are identical to the -:ref:`SDL annotation declaration `. -There's only one subcommand that is allowed in the ``create -annotation`` block: - -:eql:synopsis:`create annotation := ` - Annotations can also have annotations. Set the - :eql:synopsis:`` of the - enclosing annotation to a specific :eql:synopsis:``. - See :eql:stmt:`create annotation` for details. - - -Example -------- - -Declare an annotation ``extrainfo``. - -.. code-block:: edgeql - - create abstract annotation extrainfo; - - -Alter abstract annotation -========================= - -:eql-statement: - - -Change the definition of an :ref:`annotation `. - -.. eql:synopsis:: - - alter abstract annotation - [ "{" ] ; [...] [ "}" ]; - - # where is one of - - rename to - create annotation := - alter annotation := - drop annotation - - -Description ------------ - -:eql:synopsis:`alter abstract annotation` changes the definition of an abstract -annotation. - - -Parameters ----------- - -:eql:synopsis:`` - The name (optionally module-qualified) of the annotation to alter. - -The following subcommands are allowed in the ``alter abstract annotation`` -block: - -:eql:synopsis:`rename to ` - Change the name of the annotation to :eql:synopsis:``. - -:eql:synopsis:`alter annotation ;` - Annotations can also have annotations. Change - :eql:synopsis:`` to a specific - :eql:synopsis:``. See :eql:stmt:`alter annotation` for - details. - -:eql:synopsis:`drop annotation ;` - Annotations can also have annotations. Remove annotation - :eql:synopsis:``. - See :eql:stmt:`drop annotation` for details. - -All the subcommands allowed in the ``create abstract annotation`` -block are also valid subcommands for ``alter annotation`` block. - - -Examples --------- - -Rename an annotation: - -.. code-block:: edgeql - - alter abstract annotation extrainfo - rename to extra_info; - - -Drop abstract annotation -======================== - -:eql-statement: - -Remove a :ref:`schema annotation `. - -.. eql:synopsis:: - - [ with [, ...] ] - drop abstract annotation ; - -Description ------------ - -The command ``drop abstract annotation`` removes an existing schema -annotation from the database schema. Note that the ``inheritable`` -qualifier is not necessary in this statement. - -Example -------- - -Drop the annotation ``extra_info``: - -.. code-block:: edgeql - - drop abstract annotation extra_info; - - -Create annotation -================= - -:eql-statement: - -Define an annotation value for a given schema item. - -.. eql:synopsis:: - - create annotation := - -Description ------------ - -The command ``create annotation`` defines an annotation for a schema item. - -:eql:synopsis:`` refers to the name of a defined annotation, -and :eql:synopsis:`` must be a constant EdgeQL expression -evaluating into a string. - -This statement can only be used as a subcommand in another -DDL statement. - - -Example -------- - -Create an object type ``User`` and set its ``title`` annotation to -``"User type"``. - -.. code-block:: edgeql - - create type User { - create annotation title := "User type"; - }; - - -Alter annotation -================ - -:eql-statement: - -Alter an annotation value for a given schema item. - -.. eql:synopsis:: - - alter annotation := - -Description ------------ - -The command ``alter annotation`` alters an annotation value on a schema item. - -:eql:synopsis:`` refers to the name of a defined annotation, -and :eql:synopsis:`` must be a constant EdgeQL expression -evaluating into a string. - -This statement can only be used as a subcommand in another -DDL statement. - - -Example -------- - -Alter an object type ``User`` and alter the value of its previously set -``title`` annotation to ``"User type"``. - -.. code-block:: edgeql - - alter type User { - alter annotation title := "User type"; - }; - - -Drop annotation -=============== - -:eql-statement: - - -Remove an annotation from a given schema item. - -.. eql:synopsis:: - - drop annotation ; - -Description ------------ - -The command ``drop annotation`` removes an annotation value from a schema item. - -:eql:synopsis:`` refers to the name of a defined annotation. -The annotation value does not have to exist on a schema item. - -This statement can only be used as a subcommand in another -DDL statement. - - -Example -------- - -Drop the ``title`` annotation from the ``User`` object type: - -.. code-block:: edgeql - - alter type User { - drop annotation title; - }; - - -.. list-table:: - :class: seealso - - * - **See also** - * - :ref:`Schema > Annotations ` - * - :ref:`SDL > Annotations ` - * - :ref:`Cheatsheets > Annotations ` - * - :ref:`Introspection > Object types - ` diff --git a/docs/reference/ddl/constraints.rst b/docs/reference/ddl/constraints.rst deleted file mode 100644 index 0736de2a273..00000000000 --- a/docs/reference/ddl/constraints.rst +++ /dev/null @@ -1,482 +0,0 @@ -.. _ref_eql_ddl_constraints: - -=========== -Constraints -=========== - -This section describes the DDL commands pertaining to -:ref:`constraints `. - - -Create abstract constraint -========================== - -:eql-statement: -:eql-haswith: - -:ref:`Define ` a new abstract constraint. - -.. eql:synopsis:: - - [ with [ := ] module ] - create abstract constraint [ ( [] [, ...] ) ] - [ on ( ) ] - [ extending [, ...] ] - "{" ; [...] "}" ; - - # where is: - - [ : ] - - # where is one of - - using - set errmessage := - create annotation := - - -Description ------------ - -The command ``create abstract constraint`` defines a new abstract constraint. - -If *name* is qualified with a module name, then the constraint is -created in that module, otherwise it is created in the current module. -The constraint name must be distinct from that of any existing schema item -in the module. - - -Parameters ----------- - -Most sub-commands and options of this command are identical to the -:ref:`SDL constraint declaration `, -with some additional features listed below: - -:eql:synopsis:`[ := ] module ` - An optional list of module alias declarations to be used in the - migration definition. When *module-alias* is not specified, - *module-name* becomes the effective current module and is used - to resolve all unqualified names. - -:eql:synopsis:`set errmessage := ` - An optional string literal defining the error message template - that is raised when the constraint is violated. Other than a - slight syntactical difference this is the same as the - corresponding SDL declaration. - -:eql:synopsis:`create annotation := ;` - Set constraint :eql:synopsis:`` to - :eql:synopsis:``. - - See :eql:stmt:`create annotation` for details. - - -Example -------- - -Create an abstract constraint "uppercase" which checks if the subject -is a string in upper case. - -.. code-block:: edgeql - - create abstract constraint uppercase { - create annotation title := "Upper case constraint"; - using (str_upper(__subject__) = __subject__); - set errmessage := "{__subject__} is not in upper case"; - }; - - -Alter abstract constraint -========================= - -:eql-statement: -:eql-haswith: - -Alter the definition of an -:ref:`abstract constraint `. - -.. eql:synopsis:: - - [ with [ := ] module ] - alter abstract constraint - "{" ; [...] "}" ; - - # where is one of - - rename to - using - set errmessage := - reset errmessage - create annotation := - alter annotation := - drop annotation - - -Description ------------ - -The command ``alter abstract constraint`` changes the definition of an -abstract constraint item. *name* must be a name of an existing -abstract constraint, optionally qualified with a module name. - - -Parameters ----------- - -:eql:synopsis:`[ := ] module ` - An optional list of module alias declarations to be used in the - migration definition. When *module-alias* is not specified, - *module-name* becomes the effective current module and is used - to resolve all unqualified names. - -:eql:synopsis:`` - The name (optionally module-qualified) of the constraint to alter. - -The following subcommands are allowed in the ``alter abstract -constraint`` block: - -:eql:synopsis:`rename to ` - Change the name of the constraint to *newname*. All concrete - constraints inheriting from this constraint are also renamed. - -:eql:synopsis:`alter annotation ;` - Alter constraint :eql:synopsis:``. - See :eql:stmt:`alter annotation` for details. - -:eql:synopsis:`drop annotation ;` - Remove constraint :eql:synopsis:``. - See :eql:stmt:`drop annotation` for details. - -:eql:synopsis:`reset errmessage;` - Remove the error message from this abstract constraint. - The error message specified in the base abstract constraint - will be used instead. - -All the subcommands allowed in a ``create abstract constraint`` block -are also valid subcommands for an ``alter abstract constraint`` block. - - -Example -------- - -Rename the abstract constraint "uppercase" to "upper_case": - -.. code-block:: edgeql - - alter abstract constraint uppercase rename to upper_case; - - -Drop abstract constraint -======================== - -:eql-statement: -:eql-haswith: - - -Remove an :ref:`abstract constraint ` -from the schema. - -.. eql:synopsis:: - - [ with [ := ] module ] - drop abstract constraint ; - - -Description ------------ - -The command ``drop abstract constraint`` removes an existing abstract -constraint item from the database schema. If any schema items -depending on this constraint exist, the operation is refused. - - -Parameters ----------- - -:eql:synopsis:`[ := ] module ` - An optional list of module alias declarations to be used in the - migration definition. When *module-alias* is not specified, - *module-name* becomes the effective current module and is used - to resolve all unqualified names. - -:eql:synopsis:`` - The name (optionally module-qualified) of the constraint to remove. - - -Example -------- - -Drop abstract constraint ``upper_case``: - -.. code-block:: edgeql - - drop abstract constraint upper_case; - - -Create constraint -================= - -:eql-statement: - -Define a concrete constraint on the specified schema item. - -.. eql:synopsis:: - - [ with [ := ] module ] - create [ delegated ] constraint - [ ( [] [, ...] ) ] - [ on ( ) ] - [ except ( ) ] - "{" ; [...] "}" ; - - # where is: - - [ : ] - - # where is one of - - set errmessage := - create annotation := - - -Description ------------ - -The command ``create constraint`` defines a new concrete constraint. -It can only be used in the context of :eql:stmt:`create scalar type`, -:eql:stmt:`alter scalar type`, :eql:stmt:`create property`, -:eql:stmt:`alter property`, :eql:stmt:`create link`, or -:eql:Stmt:`alter link`. - -*name* must be a name (optionally module-qualified) of previously defined -abstract constraint. - - -Parameters ----------- - -Most sub-commands and options of this command are identical to the -:ref:`SDL constraint declaration `, -with some additional features listed below: - -:eql:synopsis:`[ := ] module ` - An optional list of module alias declarations to be used in the - migration definition. When *module-alias* is not specified, - *module-name* becomes the effective current module and is used - to resolve all unqualified names. - -:eql:synopsis:`set errmessage := ` - An optional string literal defining the error message template - that is raised when the constraint is violated. Other than a - slight syntactical difference this is the same as the - corresponding SDL declaration. - -:eql:synopsis:`create annotation := ;` - An optional list of annotations for the constraint. - See :eql:stmt:`create annotation` for details. - - -Example -------- - -Create a "score" property on the "User" type with a minimum value -constraint: - -.. code-block:: edgeql - - alter type User create property score -> int64 { - create constraint min_value(0) - }; - -Create a Vector with a maximum magnitude: - -.. code-block:: edgeql - - create type Vector { - create required property x -> float64; - create required property y -> float64; - create constraint expression ON ( - __subject__.x^2 + __subject__.y^2 < 25 - ); - } - - -Alter constraint -================ - -:eql-statement: - -Alter the definition of a concrete constraint on the specified schema item. - -.. eql:synopsis:: - - [ with [ := ] module [, ...] ] - alter constraint - [ ( [] [, ...] ) ] - [ on ( ) ] - [ except ( ) ] - "{" ; [ ... ] "}" ; - - # -- or -- - - [ with [ := ] module [, ...] ] - alter constraint - [ ( [] [, ...] ) ] - [ on ( ) ] - ; - - # where is one of: - - set delegated - set not delegated - set errmessage := - reset errmessage - create annotation := - alter annotation - drop annotation - - -Description ------------ - -The command ``alter constraint`` changes the definition of a concrete -constraint. As for most ``alter`` commands, both single- and -multi-command forms are supported. - - -Parameters ----------- - -:eql:synopsis:`[ := ] module ` - An optional list of module alias declarations to be used in the - migration definition. When *module-alias* is not specified, - *module-name* becomes the effective current module and is used - to resolve all unqualified names. - -:eql:synopsis:`` - The name (optionally module-qualified) of the concrete constraint - that is being altered. - -:eql:synopsis:`` - A list of constraint arguments as specified at the time of - ``create constraint``. - -:eql:synopsis:`on ( )` - A expression defining the *subject* of the constraint as specified - at the time of ``create constraint``. - - -The following subcommands are allowed in the ``alter constraint`` block: - -:eql:synopsis:`set delegated` - If set, the constraint is defined as *delegated*, which means that it will - not be enforced on the type it's declared on, and the enforcement will be - delegated to the subtypes of this type. This is particularly useful for - :eql:constraint:`exclusive` constraints in abstract types. This is only - valid for *concrete constraints*. - -:eql:synopsis:`set not delegated` - If set, the constraint is defined as *not delegated*, which means that it - will be enforced globally across the type it's declared on and any - extending types. - -:eql:synopsis:`rename to ` - Change the name of the constraint to :eql:synopsis:``. - -:eql:synopsis:`alter annotation ;` - Alter constraint :eql:synopsis:``. - See :eql:stmt:`alter annotation` for details. - -:eql:synopsis:`drop annotation ;` - Remove an *annotation*. See :eql:stmt:`drop annotation` for details. - -:eql:synopsis:`reset errmessage;` - Remove the error message from this constraint. The error message - specified in the abstract constraint will be used instead. - -All the subcommands allowed in the ``create constraint`` block are also -valid subcommands for ``alter constraint`` block. - -Example -------- - -Change the error message on the minimum value constraint on the property -"score" of the "User" type: - -.. code-block:: edgeql - - alter type User alter property score - alter constraint min_value(0) - set errmessage := 'Score cannot be negative'; - - -Drop constraint -=============== - -:eql-statement: -:eql-haswith: - -Remove a concrete constraint from the specified schema item. - -.. eql:synopsis:: - - [ with [ := ] module [, ...] ] - drop constraint - [ ( [] [, ...] ) ] - [ on ( ) ] - [ except ( ) ] ; - - -Description ------------ - -The command ``drop constraint`` removes the specified constraint from -its containing schema item. - - -Parameters ----------- - -:eql:synopsis:`[ := ] module ` - An optional list of module alias declarations to be used in the - migration definition. When *module-alias* is not specified, - *module-name* becomes the effective current module and is used - to resolve all unqualified names. - -:eql:synopsis:`` - The name (optionally module-qualified) of the concrete constraint - to remove. - -:eql:synopsis:`` - A list of constraint arguments as specified at the time of - ``create constraint``. - -:eql:synopsis:`on ( )` - A expression defining the *subject* of the constraint as specified - at the time of ``create constraint``. - - -Example -------- - -Remove constraint "min_value" from the property "score" of the -"User" type: - -.. code-block:: edgeql - - alter type User alter property score - drop constraint min_value(0); - - -.. list-table:: - :class: seealso - - * - **See also** - * - :ref:`Schema > Constraints ` - * - :ref:`SDL > Constraints ` - * - :ref:`Introspection > Constraints - ` - * - :ref:`Standard Library > Constraints ` - * - `Tutorial > Advanced EdgeQL > Constraints - `_ diff --git a/docs/reference/ddl/extensions.rst b/docs/reference/ddl/extensions.rst deleted file mode 100644 index 55c0213fa26..00000000000 --- a/docs/reference/ddl/extensions.rst +++ /dev/null @@ -1,86 +0,0 @@ -.. _ref_eql_ddl_extensions: - -========== -Extensions -========== - -This section describes the DDL commands pertaining to -:ref:`extensions `. - - -Create extension -================ - -:eql-statement: - -Enable a particular extension for the current schema. - -.. eql:synopsis:: - - create extension ";" - -There's a :ref:`corresponding SDL declaration ` -for enabling an extension, which is the recommended way of doing this. - -Description ------------ - -The command ``create extension`` enables the specified extension for -the current :versionreplace:`database;5.0:branch`. - -Examples --------- - -Enable :ref:`GraphQL ` extension for the current -schema: - -.. code-block:: edgeql - - create extension graphql; - -Enable :ref:`EdgeQL over HTTP ` extension for the -current :versionreplace:`database;5.0:branch`: - -.. code-block:: edgeql - - create extension edgeql_http; - - -drop extension -============== - -:eql-statement: - - -Disable an extension. - -.. eql:synopsis:: - - drop extension ";" - - -Description ------------ - -The command ``drop extension`` disables a currently active extension for the -current :versionreplace:`database;5.0:branch`. - - -Examples --------- - -Disable :ref:`GraphQL ` extension for the current -schema: - -.. code-block:: edgeql - - drop extension graphql; - -Disable :ref:`EdgeQL over HTTP ` extension for the -current :versionreplace:`database;5.0:branch`: - -.. code-block:: edgeql - - drop extension edgeql_http; - - diff --git a/docs/reference/ddl/functions.rst b/docs/reference/ddl/functions.rst deleted file mode 100644 index eef80095c16..00000000000 --- a/docs/reference/ddl/functions.rst +++ /dev/null @@ -1,277 +0,0 @@ -.. _ref_eql_ddl_functions: - -========= -Functions -========= - -This section describes the DDL commands pertaining to -:ref:`functions `. - - -Create function -=============== - -:eql-statement: -:eql-haswith: - - -:ref:`Define ` a new function. - -.. eql:synopsis:: - - [ with [, ...] ] - create function ([ ] [, ... ]) -> - using ( ); - - [ with [, ...] ] - create function ([ ] [, ... ]) -> - using ; - - [ with [, ...] ] - create function ([ ] [, ... ]) -> - "{" [, ...] "}" ; - - # where is: - - [ ] : [ ] [ = ] - - # is: - - [ { variadic | named only } ] - - # is: - - [ { set of | optional } ] - - # and is: - - [ ] - - # and is one of - - set volatility := {'Immutable' | 'Stable' | 'Volatile' | 'Modifying'} ; - create annotation := ; - using ( ) ; - using ; - - -Description ------------ - -The command ``create function`` defines a new function. If *name* is -qualified with a module name, then the function is created in that -module, otherwise it is created in the current module. - -The function name must be distinct from that of any existing function -with the same argument types in the same module. Functions of -different argument types can share a name, in which case the functions -are called *overloaded functions*. - - -Parameters ----------- - -Most sub-commands and options of this command are identical to the -:ref:`SDL function declaration `, with -some additional features listed below: - -:eql:synopsis:`set volatility := {'Immutable' | 'Stable' | 'Volatile' | 'Modifying'}` - Function volatility determines how aggressively the compiler can - optimize its invocations. Other than a slight syntactical - difference this is the same as the corresponding SDL declaration. - -:eql:synopsis:`create annotation := ` - Set the function's :eql:synopsis:`` to - :eql:synopsis:``. - - See :eql:stmt:`create annotation` for details. - - -Examples --------- - -Define a function returning the sum of its arguments: - -.. code-block:: edgeql - - create function mysum(a: int64, b: int64) -> int64 - using ( - select a + b - ); - -The same, but using a variadic argument and an explicit language: - -.. code-block:: edgeql - - create function mysum(variadic argv: int64) -> int64 - using edgeql $$ - select sum(array_unpack(argv)) - $$; - -Define a function using the block syntax: - -.. code-block:: edgeql - - create function mysum(a: int64, b: int64) -> int64 { - using ( - select a + b - ); - create annotation title := "My sum function."; - }; - - -Alter function -============== - -:eql-statement: -:eql-haswith: - -Change the definition of a function. - -.. eql:synopsis:: - - [ with [, ...] ] - alter function ([ ] [, ... ]) "{" - [, ...] - "}" - - # where is: - - [ ] : [ ] [ = ] - - # and is one of - - set volatility := {'Immutable' | 'Stable' | 'Volatile' | 'Modifying'} ; - reset volatility ; - rename to ; - create annotation := ; - alter annotation := ; - drop annotation ; - using ( ) ; - using ; - - -Description ------------ - -The command ``alter function`` changes the definition of a function. -The command allows to change annotations, the volatility level, and -other attributes. - - -Subcommands ------------ - -The following subcommands are allowed in the ``alter function`` block -in addition to the commands common to the ``create function``: - -:eql:synopsis:`reset volatility` - Remove explicitly specified volatility in favor of the volatility - inferred from the function body. - -:eql:synopsis:`rename to ` - Change the name of the function to *newname*. - -:eql:synopsis:`alter annotation ;` - Alter function :eql:synopsis:``. - See :eql:stmt:`alter annotation` for details. - -:eql:synopsis:`drop annotation ;` - Remove function :eql:synopsis:``. - See :eql:stmt:`drop annotation` for details. - -:eql:synopsis:`reset errmessage;` - Remove the error message from this abstract constraint. - The error message specified in the base abstract constraint - will be used instead. - - -Example -------- - -.. code-block:: edgeql - - create function mysum(a: int64, b: int64) -> int64 { - using ( - select a + b - ); - create annotation title := "My sum function."; - }; - - alter function mysum(a: int64, b: int64) { - set volatility := 'Immutable'; - DROP ANNOTATION title; - }; - - alter function mysum(a: int64, b: int64) { - using ( - select (a + b) * 100 - ) - }; - - -Drop function -============= - -:eql-statement: -:eql-haswith: - - -Remove a function. - -.. eql:synopsis:: - - [ with [, ...] ] - drop function ([ ] [, ... ]); - - # where is: - - [ ] : [ ] [ = ] - - -Description ------------ - -The command ``drop function`` removes the definition of an existing function. -The argument types to the function must be specified, since there -can be different functions with the same name. - - -Parameters ----------- - -:eql:synopsis:`` - The name (optionally module-qualified) of an existing function. - -:eql:synopsis:`` - The name of an argument used in the function definition. - -:eql:synopsis:`` - The mode of an argument: ``set of`` or ``optional`` or ``variadic``. - -:eql:synopsis:`` - The data type(s) of the function's arguments - (optionally module-qualified), if any. - - -Example -------- - -Remove the ``mysum`` function: - -.. code-block:: edgeql - - drop function mysum(a: int64, b: int64); - - -.. list-table:: - :class: seealso - - * - **See also** - * - :ref:`Schema > Functions ` - * - :ref:`SDL > Functions ` - * - :ref:`Reference > Function calls ` - * - :ref:`Introspection > Functions ` - * - :ref:`Cheatsheets > Functions ` - * - `Tutorial > Advanced EdgeQL > User-Defined Functions - `_ diff --git a/docs/reference/ddl/future.rst b/docs/reference/ddl/future.rst deleted file mode 100644 index 301f5b1396a..00000000000 --- a/docs/reference/ddl/future.rst +++ /dev/null @@ -1,81 +0,0 @@ -.. _ref_eql_ddl_future: - -=============== -Future Behavior -=============== - -This section describes the DDL commands pertaining to -:ref:`future `. - - -Create future -============= - -:eql-statement: - -Enable a particular future behavior for the current schema. - -.. eql:synopsis:: - - create future ";" - -There's a :ref:`corresponding SDL declaration ` -for enabling a future behavior, which is the recommended way of doing this. - -Description ------------ - -The command ``create future`` enables the specified future behavior for -the current :versionreplace:`database;5.0:branch`. - -Examples --------- - -Enable simpler non-recursive access policy behavior :ref:`non-recursive access -policy ` for the current schema: - -.. code-block:: edgeql - - create future nonrecursive_access_policies; - - -drop future -=========== - -:eql-statement: - - -Stop importing future behavior prior to the EdgeDB version in which it appears. - -.. eql:synopsis:: - - drop future ";" - - -Description ------------ - -The command ``drop future`` disables a currently active future behavior for the -current :versionreplace:`database;5.0:branch`. However, this is only possible -for versions of EdgeDB when the behavior in question is not officially -introduced. Once a particular behavior is introduced as the standard behavior -in an EdgeDB release, it cannot be disabled. Running this command will simply -denote that no special action is needed to enable it in this case. - - -Examples --------- - -Disable simpler non-recursive access policy behavior :ref:`non-recursive -access policy ` for the current -schema. This will make access policy restrictions apply to the expressions -defining other access policies: - -.. code-block:: edgeql - - drop future nonrecursive_access_policies; - - -Once EdgeDB 3.0 is released there is no more need for enabling non-recursive -access policy behavior anymore. So the above command will simply indicate that -the database no longer does anything non-standard. diff --git a/docs/reference/ddl/globals.rst b/docs/reference/ddl/globals.rst deleted file mode 100644 index cf15642cb69..00000000000 --- a/docs/reference/ddl/globals.rst +++ /dev/null @@ -1,236 +0,0 @@ -.. versionadded:: 2.0 - -.. _ref_eql_ddl_globals: - -======= -Globals -======= - -This section describes the DDL commands pertaining to global variables. - - -Create global -============= - -:eql-statement: -:eql-haswith: - -:ref:`Declare ` a new global variable. - -.. eql:synopsis:: - - [ with [, ...] ] - create [{required | optional}] [single] - global -> - [ "{" ; [...] "}" ] ; - - # Computed global variable form: - - [ with [, ...] ] - create [{required | optional}] [{single | multi}] - global := ; - - # where is one of - - set default := - create annotation := - -Description ------------ - -There two different forms of ``global`` declaration, as shown in the syntax -synopsis above. The first form is for defining a ``global`` variable that can -be :ref:`set ` in a session. The second -form is not directly set, but instead it is *computed* based on an expression, -potentially deriving its value from other global variables. - -Parameters ----------- - -Most sub-commands and options of this command are identical to the -:ref:`SDL global variable declaration `. The -following subcommands are allowed in the ``create global`` block: - -:eql:synopsis:`set default := ` - Specifies the default value for the global variable as an EdgeQL - expression. The default value is used by the session if the value was not - explicitly specified or by the :ref:`reset - ` command. - -:eql:synopsis:`create annotation := ` - Set global variable :eql:synopsis:`` to - :eql:synopsis:``. - - See :eql:stmt:`create annotation` for details. - -Examples --------- - -Define a new global property ``current_user_id``: - -.. code-block:: edgeql - - create global current_user_id -> uuid; - -Define a new *computed* global property ``current_user`` based on the -previously defined ``current_user_id``: - -.. code-block:: edgeql - - create global current_user := ( - select User filter .id = global current_user_id - ); - - -Alter global -============ - -:eql-statement: -:eql-haswith: - -Change the definition of a global variable. - -.. eql:synopsis:: - - [ with [, ...] ] - alter global - [ "{" ; [...] "}" ] ; - - # where is one of - - set default := - reset default - rename to - set required - set optional - reset optionalily - set single - set multi - reset cardinality - set type reset to default - using () - create annotation := - alter annotation := - drop annotation - -Description ------------ - -The command :eql:synopsis:`alter global` changes the definition of a global -variable. - -Parameters ----------- - -:eql:synopsis:`` - The name of the global variable to modify. - -The following subcommands are allowed in the ``alter global`` block: - -:eql:synopsis:`reset default` - Remove the default value from this global variable. - -:eql:synopsis:`rename to ` - Change the name of the global variable to :eql:synopsis:``. - -:eql:synopsis:`set required` - Make the global variable *required*. - -:eql:synopsis:`set optional` - Make the global variable no longer *required* (i.e. make it *optional*). - -:eql:synopsis:`reset optionalily` - Reset the optionality of the global variable to the default value - (``optional``). - -:eql:synopsis:`set single` - Change the maximum cardinality of the global variable to *one*. - -:eql:synopsis:`set multi` - Change the maximum cardinality of the global variable set to - *greater than one*. Only valid for computed global variables. - -:eql:synopsis:`reset cardinality` - Reset the maximum cardinality of the global variable to the default value - (``single``), or, if the property is computed, to the value inferred - from its expression. - -:eql:synopsis:`set type reset to default` - Change the type of the global variable to the specified - :eql:synopsis:``. The ``reset to default`` clause is mandatory - and it specifies that the variable will be reset to its default value - after this command. - -:eql:synopsis:`using ()` - Change the expression of a computed global variable. Only valid for - computed variables. - -:eql:synopsis:`alter annotation ;` - Alter global variable annotation :eql:synopsis:``. - See :eql:stmt:`alter annotation` for details. - -:eql:synopsis:`drop annotation ;` - Remove global variable :eql:synopsis:``. - See :eql:stmt:`drop annotation` for details. - -All the subcommands allowed in the ``create global`` block are also -valid subcommands for ``alter global`` block. - -Examples --------- - -Set the ``description`` annotation of global variable ``current_user``: - -.. code-block:: edgeql - - alter global current_user - create annotation description := - 'Current User as specified by the global ID'; - -Make the ``current_user_id`` global variable ``required``: - -.. code-block:: edgeql - - alter global current_user_id { - set required; - # A required global variable MUST have a default value. - set default := '00ea8eaa-02f9-11ed-a676-6bd11cc6c557'; - } - - -Drop global -=========== - -:eql-statement: -:eql-haswith: - -Remove a global variable from the schema. - -.. eql:synopsis:: - - [ with [, ...] ] - drop global ; - -Description ------------ - -The command :eql:synopsis:`drop global` removes the specified global variable -from the schema. - -Example -------- - -Remove the ``current_user`` global variable: - -.. code-block:: edgeql - - drop global current_user; - - -.. list-table:: - :class: seealso - - * - **See also** - * - :ref:`Schema > Globals ` - * - :ref:`SDL > Globals ` - diff --git a/docs/reference/ddl/index.rst b/docs/reference/ddl/index.rst index 36207ac8b06..b16578327c6 100644 --- a/docs/reference/ddl/index.rst +++ b/docs/reference/ddl/index.rst @@ -7,41 +7,26 @@ DDL :maxdepth: 3 :hidden: - modules - objects - scalars - links properties - aliases - indexes - constraints - annotations - globals - access_policies - functions - triggers - mutation_rewrites - extensions - future migrations :edb-alt-title: Data Definition Language EdgeQL includes a set of *data definition language* (DDL) commands that manipulate the database's schema. DDL is the low-level equivalent to -:ref:`EdgeDB schema definition language `. You can execute DDL +:ref:`Gel schema definition language `. You can execute DDL commands against your database, just like any other EdgeQL query. .. code-block:: edgeql-repl - edgedb> create type Person { - ....... create required property name -> str; - ....... }; + gel> create type Person { + .... create required property name -> str; + .... }; OK: CREATE TYPE - edgedb> create type Movie { - ....... create required property title -> str; - ....... create required link director -> Person; - ....... }; + gel> create type Movie { + .... create required property title -> str; + .... create required link director -> Person; + .... }; OK: CREATE TYPE In DDL, the *order* of commands is important. In the example above, you @@ -50,7 +35,7 @@ to ``Person``. Under the hood, all migrations are represented as DDL scripts: a sequence of imperative commands representing the migration. When you :ref:`create a -migration ` with the CLI, EdgeDB produces a DDL script. +migration ` with the CLI, Gel produces a DDL script. Comparison to SDL diff --git a/docs/reference/ddl/indexes.rst b/docs/reference/ddl/indexes.rst deleted file mode 100644 index c33eda1ca54..00000000000 --- a/docs/reference/ddl/indexes.rst +++ /dev/null @@ -1,174 +0,0 @@ -.. _ref_eql_ddl_indexes: - -======= -Indexes -======= - -This section describes the DDL commands pertaining to -:ref:`indexes `. - - -Create index -============ - -:eql-statement: - - -:ref:`Define ` an new index for a given object -type or link. - -.. eql:synopsis:: - - create index on ( ) - [ except ( ) ] - [ "{" ; [...] "}" ] ; - - # where is one of - - create annotation := - - -Description ------------ - -The command ``create index`` constructs a new index for a given object type or -link using *index-expr*. - - -Parameters ----------- - -Most sub-commands and options of this command are identical to the -:ref:`SDL index declaration `. There's -only one subcommand that is allowed in the ``create index`` block: - -:eql:synopsis:`create annotation := ` - Set object type :eql:synopsis:`` to - :eql:synopsis:``. - - See :eql:stmt:`create annotation` for details. - - -Example -------- - -Create an object type ``User`` with an indexed ``name`` property: - -.. code-block:: edgeql - - create type User { - create property name -> str { - set default := ''; - }; - - create index on (.name); - }; - - -Alter index -=========== - -:eql-statement: - - -Alter the definition of an :ref:`index `. - -.. eql:synopsis:: - - alter index on ( ) [ except ( ) ] - [ "{" ; [...] "}" ] ; - - # where is one of - - create annotation := - alter annotation := - drop annotation - - -Description ------------ - -The command ``alter index`` is used to change the :ref:`annotations -` of an index. The *index-expr* is used to -identify the index to be altered. - - -Parameters ----------- - -:sdl:synopsis:`on ( )` - The specific expression for which the index is made. Note also - that ```` itself has to be parenthesized. - -The following subcommands are allowed in the ``alter index`` block: - -:eql:synopsis:`create annotation := ` - Set index :eql:synopsis:`` to - :eql:synopsis:``. - See :eql:stmt:`create annotation` for details. - -:eql:synopsis:`alter annotation ;` - Alter index :eql:synopsis:``. - See :eql:stmt:`alter annotation` for details. - -:eql:synopsis:`drop annotation ;` - Remove constraint :eql:synopsis:``. - See :eql:stmt:`drop annotation` for details. - - -Example -------- - -Add an annotation to the index on the ``name`` property of object type -``User``: - -.. code-block:: edgeql - - alter type User { - alter index on (.name) { - create annotation title := "User name index"; - }; - }; - - -Drop index -========== - -:eql-statement: - -Remove an index from a given schema item. - -.. eql:synopsis:: - - drop index on ( ) [ except ( ) ]; - -Description ------------ - -The command ``drop index`` removes an index from a schema item. - -:sdl:synopsis:`on ( )` - The specific expression for which the index was made. - -This statement can only be used as a subdefinition in another -DDL statement. - - -Example -------- - -Drop the ``name`` index from the ``User`` object type: - -.. code-block:: edgeql - - alter type User { - drop index on (.name); - }; - -.. list-table:: - :class: seealso - - * - **See also** - * - :ref:`Schema > Indexes ` - * - :ref:`SDL > Indexes ` - * - :ref:`Introspection > Indexes ` diff --git a/docs/reference/ddl/links.rst b/docs/reference/ddl/links.rst deleted file mode 100644 index 57d3d52d5a8..00000000000 --- a/docs/reference/ddl/links.rst +++ /dev/null @@ -1,435 +0,0 @@ -.. _ref_eql_ddl_links: - -===== -Links -===== - -This section describes the DDL commands pertaining to -:ref:`links `. - - -Create link -=========== - -:eql-statement: -:eql-haswith: - -:ref:`Define ` a new link. - -.. eql:synopsis:: - - [ with [, ...] ] - {create|alter} type "{" - [ ... ] - create [{required | optional}] [{single | multi}] - link - [ extending [, ...] ] -> - [ "{" ; [...] "}" ] ; - [ ... ] - "}" - - # Computed link form: - - [ with [, ...] ] - {create|alter} type "{" - [ ... ] - create [{required | optional}] [{single | multi}] - link := ; - [ ... ] - "}" - - # Abstract link form: - - [ with [, ...] ] - create abstract link [::] [extending [, ...]] - [ "{" ; [...] "}" ] - - # where is one of - - set default := - set readonly := {true | false} - create annotation := - create property ... - create constraint ... - on target delete - on source delete - reset on target delete - create index on - - -Description ------------ - -The combinations of ``create type ... create link`` and ``alter type -... create link`` define a new concrete link for a given object type. - -There are three forms of ``create link``, as shown in the syntax synopsis -above. The first form is the canonical definition form, the second -form is a syntax shorthand for defining a -:ref:`computed link `, and the third is a -form to define an abstract link item. The abstract form allows creating -the link in the specified :eql:synopsis:``. Concrete link forms -are always created in the same module as the containing object type. - - -.. _ref_eql_ddl_links_syntax: - -Parameters ----------- - -Most sub-commands and options of this command are identical to the -:ref:`SDL link declaration `. The following -subcommands are allowed in the ``create link`` block: - -:eql:synopsis:`set default := ` - Specifies the default value for the link as an EdgeQL expression. - Other than a slight syntactical difference this is the same as the - corresponding SDL declaration. - -:eql:synopsis:`set readonly := {true | false}` - Specifies whether the link is considered *read-only*. Other than a - slight syntactical difference this is the same as the - corresponding SDL declaration. - -:eql:synopsis:`create annotation := ;` - Add an annotation :eql:synopsis:`` - set to :eql:synopsis:`` to the type. - - See :eql:stmt:`create annotation` for details. - -:eql:synopsis:`create property ...` - Define a concrete property item for this link. See - :eql:stmt:`create property` for details. - -:eql:synopsis:`create constraint ...` - Define a concrete constraint for this link. See - :eql:stmt:`create constraint` for details. - -:eql:synopsis:`on target delete ` - Valid values for *action* are: ``restrict``, ``DELETE - SOURCE``, ``allow``, and ``deferred restrict``. The details of - what ``on target delete`` options mean are described in - :ref:`this section `. - -:eql:synopsis:`reset on target delete` - Reset the delete policy to either the inherited value or to the - default ``restrict``. The details of what ``on target delete`` - options mean are described in :ref:`this section `. - -:eql:synopsis:`create index on ` - Define a new :ref:`index ` - using *index-expr* for this link. See - :eql:stmt:`create index` for details. - - -Examples --------- - -Define a new link ``friends`` on the ``User`` object type: - -.. code-block:: edgeql - - alter type User { - create multi link friends -> User - }; - -Define a new :ref:`computed link ` -``special_group`` on the ``User`` object type, which contains all the -friends from the same town: - -.. code-block:: edgeql - - alter type User { - create link special_group := ( - select __source__.friends - filter .town = __source__.town - ) - }; - -Define a new abstract link ``orderable`` and a concrete link -``interests`` that extends it, inheriting its ``weight`` property: - -.. code-block:: edgeql - - create abstract link orderable { - create property weight -> std::int64 - }; - - alter type User { - create multi link interests extending orderable -> Interest - }; - - - -Alter link -========== - -:eql-statement: -:eql-haswith: - - -Change the definition of a :ref:`link `. - -.. eql:synopsis:: - - [ with [, ...] ] - {create|alter} type "{" - [ ... ] - alter link - [ "{" ] ; [...] [ "}" ]; - [ ... ] - "}" - - - [ with [, ...] ] - alter abstract link [::] - [ "{" ] ; [...] [ "}" ]; - - # where is one of - - set default := - reset default - set readonly := {true | false} - reset readonly - rename to - extending ... - set required - set optional - reset optionality - set single - set multi - reset cardinality - set type [using () - create annotation := - alter annotation := - drop annotation - create property ... - alter property ... - drop property ... - create constraint ... - alter constraint ... - drop constraint ... - on target delete - on source delete - create index on - drop index on - -Description ------------ - -The combinations of``create type ... alter link`` and ``alter type ... -alter link`` change the definition of a concrete link for a given -object type. - -The command ``alter abstract link`` changes the definition of an -abstract link item. *name* must be the identity of an existing -abstract link, optionally qualified with a module name. - -Parameters ----------- - -The following subcommands are allowed in the ``alter link`` block: - -:eql:synopsis:`rename to ` - Change the name of the link item to *newname*. All concrete links - inheriting from this links are also renamed. - -:eql:synopsis:`extending ...` - Alter the link parent list. The full syntax of this subcommand is: - - .. eql:synopsis:: - - extending [, ...] - [ first | last | before | after ] - - This subcommand makes the link a child of the specified list - of parent links. The requirements for the parent-child - relationship are the same as when creating a link. - - It is possible to specify the position in the parent list - using the following optional keywords: - - * ``first`` -- insert parent(s) at the beginning of the - parent list, - * ``last`` -- insert parent(s) at the end of the parent list, - * ``before `` -- insert parent(s) before an - existing *parent*, - * ``after `` -- insert parent(s) after an existing - *parent*. - -:eql:synopsis:`set required` - Make the link *required*. - -:eql:synopsis:`set optional` - Make the link no longer *required* (i.e. make it *optional*). - -:eql:synopsis:`reset optionality` - Reset the optionality of the link to the default value (``optional``), - or, if the link is inherited, to the value inherited from links in - supertypes. - -:eql:synopsis:`set single` - Change the link set's maximum cardinality to *one*. Only - valid for concrete links. - -:eql:synopsis:`set multi` - Remove the upper limit on the link set's cardinality. Only valid for - concrete links. - -:eql:synopsis:`reset cardinality` - Reset the link set's maximum cardinality to the default value - (``single``), or to the value inherited from the link's supertypes. - -:eql:synopsis:`set type [using (`. The optional ``using`` clause specifies - a conversion expression that computes the new link value from the old. - The conversion expression must return a singleton set and is evaluated - on each element of ``multi`` links. A ``using`` clause must be provided - if there is no implicit or assignment cast from old to new type. - -:eql:synopsis:`reset type` - Reset the type of the link to be strictly the inherited type. This only - has an effect on links that have been :ref:`overloaded - ` in order to change their inherited - type. It is an error to ``reset type`` on a link that is not inherited. - -:eql:synopsis:`using ()` - Change the expression of a :ref:`computed link - `. Only valid for concrete links. - -:eql:synopsis:`alter annotation ;` - Alter link annotation :eql:synopsis:``. - See :eql:stmt:`alter annotation` for details. - -:eql:synopsis:`drop annotation ;` - Remove link item's annotation :eql:synopsis:``. - See :eql:stmt:`drop annotation` for details. - -:eql:synopsis:`alter property ...` - Alter the definition of a property item for this link. See - :eql:stmt:`alter property` for details. - -:eql:synopsis:`drop property ;` - Remove a property item from this link. See - :eql:stmt:`drop property` for details. - -:eql:synopsis:`alter constraint ...` - Alter the definition of a constraint for this link. See - :eql:stmt:`alter constraint` for details. - -:eql:synopsis:`drop constraint ;` - Remove a constraint from this link. See - :eql:stmt:`drop constraint` for details. - -:eql:synopsis:`drop index on ` - Remove an :ref:`index ` defined on *index-expr* - from this link. See :eql:stmt:`drop index` for details. - -:eql:synopsis:`reset default` - Remove the default value from this link, or reset it to the value - inherited from a supertype, if the link is inherited. - -:eql:synopsis:`reset readonly` - Set link writability to the default value (writable), or, if the link is - inherited, to the value inherited from links in supertypes. - -All the subcommands allowed in the ``create link`` block are also -valid subcommands for ``alter link`` block. - - -Examples --------- - -On the object type ``User``, set the ``title`` annotation of its -``friends`` link to ``"Friends"``: - -.. code-block:: edgeql - - alter type User { - alter link friends create annotation title := "Friends"; - }; - -Rename the abstract link ``orderable`` to ``sorted``: - -.. code-block:: edgeql - - alter abstract link orderable rename to sorted; - -Redefine the :ref:`computed link ` -``special_group`` to be those who have some shared interests: - -.. code-block:: edgeql - - alter type User { - create link special_group := ( - select __source__.friends - # at least one of the friend's interests - # must match the user's - filter .interests IN __source__.interests - ) - }; - - -Drop link -========= - -:eql-statement: -:eql-haswith: - - -Remove the specified link from the schema. - -.. eql:synopsis:: - - [ with [, ...] ] - alter type "{" - [ ... ] - drop link - [ ... ] - "}" - - - [ with [, ...] ] - drop abstract link []:: - - -Description ------------ - -The combination of ``alter type`` and ``drop link`` removes the -specified link from its containing object type. All links that -inherit from this link are also removed. - -The command ``drop abstract link`` removes an existing link item from -the database schema. All subordinate schema items defined on this -link, such as link properties and constraints, are removed as well. - - -Examples --------- - -Remove link ``friends`` from object type ``User``: - -.. code-block:: edgeql - - alter type User drop link friends; - - -Drop abstract link ``orderable``: - -.. code-block:: edgeql - - drop abstract link orderable; - - -.. list-table:: - :class: seealso - - * - **See also** - * - :ref:`Schema > Links ` - * - :ref:`SDL > Links ` - * - :ref:`Introspection > Object types - ` diff --git a/docs/reference/ddl/migrations.rst b/docs/reference/ddl/migrations.rst index 25a778bba31..d2025558cc1 100644 --- a/docs/reference/ddl/migrations.rst +++ b/docs/reference/ddl/migrations.rst @@ -10,7 +10,7 @@ This section describes the DDL commands pertaining to migrations. Like all DDL commands, ``start migration`` and other migration commands are considered low-level. Users are encouraged to use the - built-in :ref:`migration tools ` + built-in :ref:`migration tools ` instead. Start migration @@ -31,7 +31,7 @@ Parameters ---------- :eql:synopsis:`` - Complete schema defined with the declarative :ref:`EdgeDB schema + Complete schema defined with the declarative :ref:`Gel schema definition language`. Description @@ -70,7 +70,7 @@ available: Examples -------- -Create a new migration to a target schema specified by the EdgeDB Schema +Create a new migration to a target schema specified by the Gel Schema syntax: .. code-block:: edgeql @@ -102,17 +102,9 @@ Create a new migration using an explicit EdgeQL script. Parameters ---------- -.. versionchanged:: _default - - :eql:synopsis:`` - Any valid EdgeQL statement, except ``database``, ``role``, ``configure``, - ``migration``, or ``transaction`` statements. - -.. versionchanged:: 5.0 - - :eql:synopsis:`` - Any valid EdgeQL statement, except ``database``, ``branch``, ``role``, - ``configure``, ``migration``, or ``transaction`` statements. +:eql:synopsis:`` + Any valid EdgeQL statement, except ``database``, ``branch``, ``role``, + ``configure``, ``migration``, or ``transaction`` statements. Description @@ -125,7 +117,7 @@ and records the migration into the system migration log. Examples -------- -Create a new migration to a target schema specified by the EdgeDB Schema +Create a new migration to a target schema specified by the Gel Schema syntax: .. code-block:: edgeql @@ -342,8 +334,6 @@ Create and execute the current migration: Reset schema to initial ======================= -.. versionadded:: 3.0 - :eql-statement: Reset the database schema to its initial state. @@ -362,8 +352,6 @@ Reset the database schema to its initial state. Migration Rewrites ================== -.. versionadded:: 3.0 - Migration rewrites allow you to change the migration history as long as your final schema matches the current database schema. diff --git a/docs/reference/ddl/modules.rst b/docs/reference/ddl/modules.rst deleted file mode 100644 index afc578d85f9..00000000000 --- a/docs/reference/ddl/modules.rst +++ /dev/null @@ -1,99 +0,0 @@ -.. _ref_eql_ddl_modules: - -======= -Modules -======= - -This section describes the DDL commands pertaining to -:ref:`modules `. - - -Create module -============= - -:eql-statement: - -Create a new module. - -.. eql:synopsis:: - - create module [ if not exists ]; - -There's a :ref:`corresponding SDL declaration ` -for a module, although in SDL a module declaration is likely to also -include that module's content. - -.. versionadded:: 3.0 - - You may also create a nested module. - - .. eql:synopsis:: - - create module :: [ if not exists ]; - -Description ------------ - -The command ``create module`` defines a new module for the current -:versionreplace:`database;5.0:branch`. The name of the new module must be -distinct from any existing module in the current -:versionreplace:`database;5.0:branch`. Unlike :ref:`SDL module declaration -` the ``create module`` command does not have -sub-commands, as module contents are created separately. - -Parameters ----------- - -:eql:synopsis:`if not exists` - Normally creating a module that already exists is an error, but - with this flag the command will succeed. It is useful for scripts - that add something to a module or if the module is missing the - module is created as well. - -Examples --------- - -Create a new module: - -.. code-block:: edgeql - - create module payments; - -.. versionadded:: 3.0 - - Create a new nested module: - - .. code-block:: edgeql - - create module payments::currencies; - - -Drop module -=========== - -:eql-statement: - - -Remove a module. - -.. eql:synopsis:: - - drop module ; - - -Description ------------ - -The command ``drop module`` removes an existing empty module from the -current :versionreplace:`database;5.0:branch`. If the module contains any -schema items, this command will fail. - - -Examples --------- - -Remove a module: - -.. code-block:: edgeql - - drop module payments; diff --git a/docs/reference/ddl/mutation_rewrites.rst b/docs/reference/ddl/mutation_rewrites.rst deleted file mode 100644 index 38885c924bf..00000000000 --- a/docs/reference/ddl/mutation_rewrites.rst +++ /dev/null @@ -1,147 +0,0 @@ -.. versionadded:: 3.0 - -.. _ref_eql_ddl_mutation_rewrites: - -================= -Mutation Rewrites -================= - -This section describes the DDL commands pertaining to -:ref:`mutation rewrites `. - - -Create rewrite -============== - -:eql-statement: - - -:ref:`Define ` a new mutation rewrite. - -When creating a new property or link: - -.. eql:synopsis:: - - {create | alter} type "{" - create { property | link } -> "{" - create rewrite {insert | update} [, ...] - using - "}" ; - "}" ; - -When altering an existing property or link: - -.. eql:synopsis:: - - {create | alter} type "{" - alter { property | link } "{" - create rewrite {insert | update} [, ...] - using - "}" ; - "}" ; - - -Description ------------ - -The command ``create rewrite`` nested under ``create type`` or ``alter type`` -and then under ``create property/link`` or ``alter property/link`` defines a -new mutation rewrite for the given property or link on the given object. - - -Parameters ----------- - -:eql:synopsis:`` - The name (optionally module-qualified) of the type containing the rewrite. - -:eql:synopsis:`` - The name (optionally module-qualified) of the property or link being - rewritten. - -:eql:synopsis:`insert | update [, ...]` - The query type (or types) that are rewritten. Separate multiple values with - commas to invoke the same rewrite for multiple types of queries. - - -Examples --------- - -Declare two mutation rewrites on new properties: one that sets a ``created`` -property when a new object is inserted and one that sets a ``modified`` -property on each update: - -.. code-block:: edgeql - - alter type User { - create property created -> datetime { - create rewrite insert using (datetime_of_statement()); - }; - create property modified -> datetime { - create rewrite update using (datetime_of_statement()); - }; - }; - - -Drop rewrite -============ - -:eql-statement: - - -Remove a mutation rewrite. - -.. eql:synopsis:: - - alter type "{" - alter property "{" - drop rewrite {insert | update} ; - "}" ; - "}" ; - - -Description ------------ - -The command ``drop rewrite`` inside an ``alter type`` block and further inside -an ``alter property`` block removes the definition of an existing mutation -rewrite on the specified property or link of the specified type. - - -Parameters ----------- - -:eql:synopsis:`` - The name (optionally module-qualified) of the type containing the rewrite. - -:eql:synopsis:`` - The name (optionally module-qualified) of the property or link being - rewritten. - -:eql:synopsis:`insert | update [, ...]` - The query type (or types) that are rewritten. Separate multiple values with - commas to invoke the same rewrite for multiple types of queries. - - -Example -------- - -Remove the ``insert`` rewrite of the ``created`` property on the ``User`` type: - -.. code-block:: edgeql - - alter type User { - alter property created { - drop rewrite insert; - }; - }; - - -.. list-table:: - :class: seealso - - * - **See also** - * - :ref:`Schema > Mutation rewrites ` - * - :ref:`SDL > Mutation rewrites ` - * - :ref:`Introspection > Mutation rewrites - ` diff --git a/docs/reference/ddl/objects.rst b/docs/reference/ddl/objects.rst deleted file mode 100644 index b855fe56762..00000000000 --- a/docs/reference/ddl/objects.rst +++ /dev/null @@ -1,272 +0,0 @@ -.. _ref_eql_ddl_object_types: - -============ -Object Types -============ - -This section describes the DDL commands pertaining to -:ref:`object types `. - - -Create type -=========== - -:eql-statement: -:eql-haswith: - - -:ref:`Define ` a new object type. - -.. eql:synopsis:: - - [ with [, ...] ] - create [abstract] type [ extending [, ...] ] - [ "{" ; [...] "}" ] ; - - # where is one of - - create annotation := - create link ... - create property ... - create constraint ... - create index on - -Description ------------ - -The command ``create type`` defines a new object type for use in the -current :versionreplace:`database;5.0:branch`. - -If *name* is qualified with a module name, then the type is created -in that module, otherwise it is created in the current module. -The type name must be distinct from that of any existing schema item -in the module. - -Parameters ----------- - -Most sub-commands and options of this command are identical to the -:ref:`SDL object type declaration `, -with some additional features listed below: - -:eql:synopsis:`with [, ...]` - Alias declarations. - - The ``with`` clause allows specifying module aliases - that can be referenced by the command. See :ref:`ref_eql_statements_with` - for more information. - -The following subcommands are allowed in the ``create type`` block: - -:eql:synopsis:`create annotation := ` - Set object type :eql:synopsis:`` to - :eql:synopsis:``. - - See :eql:stmt:`create annotation` for details. - -:eql:synopsis:`create link ...` - Define a new link for this object type. See - :eql:stmt:`create link` for details. - -:eql:synopsis:`create property ...` - Define a new property for this object type. See - :eql:stmt:`create property` for details. - -:eql:synopsis:`create constraint ...` - Define a concrete constraint for this object type. See - :eql:stmt:`create constraint` for details. - -:eql:synopsis:`create index on ` - Define a new :ref:`index ` - using *index-expr* for this object type. See - :eql:stmt:`create index` for details. - -Examples --------- - -Create an object type ``User``: - -.. code-block:: edgeql - - create type User { - create property name -> str; - }; - - -.. _ref_eql_ddl_object_types_alter: - -Alter type -========== - -:eql-statement: -:eql-haswith: - - -Change the definition of an -:ref:`object type `. - -.. eql:synopsis:: - - [ with [, ...] ] - alter type - [ "{" ; [...] "}" ] ; - - [ with [, ...] ] - alter type ; - - # where is one of - - rename to - extending [, ...] - create annotation := - alter annotation := - drop annotation - create link ... - alter link ... - drop link ... - create property ... - alter property ... - drop property ... - create constraint ... - alter constraint ... - drop constraint ... - create index on - drop index on - - -Description ------------ - -The command ``alter type`` changes the definition of an object type. -*name* must be a name of an existing object type, optionally qualified -with a module name. - -Parameters ----------- - -The following subcommands are allowed in the ``alter type`` block: - -:eql:synopsis:`with [, ...]` - Alias declarations. - - The ``with`` clause allows specifying module aliases - that can be referenced by the command. See :ref:`ref_eql_statements_with` - for more information. - -:eql:synopsis:`` - The name (optionally module-qualified) of the type being altered. - -:eql:synopsis:`extending [, ...]` - Alter the supertype list. The full syntax of this subcommand is: - - .. eql:synopsis:: - - extending [, ...] - [ first | last | before | after ] - - This subcommand makes the type a subtype of the specified list - of supertypes. The requirements for the parent-child relationship - are the same as when creating an object type. - - It is possible to specify the position in the parent list - using the following optional keywords: - - * ``first`` -- insert parent(s) at the beginning of the - parent list, - * ``last`` -- insert parent(s) at the end of the parent list, - * ``before `` -- insert parent(s) before an - existing *parent*, - * ``after `` -- insert parent(s) after an existing - *parent*. - -:eql:synopsis:`alter annotation ;` - Alter object type annotation :eql:synopsis:``. - See :eql:stmt:`alter annotation` for details. - -:eql:synopsis:`drop annotation ` - Remove object type :eql:synopsis:``. - See :eql:stmt:`drop annotation` for details. - -:eql:synopsis:`alter link ...` - Alter the definition of a link for this object type. See - :eql:stmt:`alter link` for details. - -:eql:synopsis:`drop link ` - Remove a link item from this object type. See - :eql:stmt:`drop link` for details. - -:eql:synopsis:`alter property ...` - Alter the definition of a property item for this object type. - See :eql:stmt:`alter property` for details. - -:eql:synopsis:`drop property ` - Remove a property item from this object type. See - :eql:stmt:`drop property` for details. - -:eql:synopsis:`alter constraint ...` - Alter the definition of a constraint for this object type. See - :eql:stmt:`alter constraint` for details. - -:eql:synopsis:`drop constraint ;` - Remove a constraint from this object type. See - :eql:stmt:`drop constraint` for details. - -:eql:synopsis:`drop index on ` - Remove an :ref:`index ` defined as *index-expr* - from this object type. See :eql:stmt:`drop index` for details. - -All the subcommands allowed in the ``create type`` block are also -valid subcommands for ``alter type`` block. - -Examples --------- - -Alter the ``User`` object type to make ``name`` required: - -.. code-block:: edgeql - - alter type User { - alter property name { - set required; - } - }; - - -Drop type -========= - -:eql-statement: -:eql-haswith: - - -Remove the specified object type from the schema. - -.. eql:synopsis:: - - drop type ; - -Description ------------ - -The command ``drop type`` removes the specified object type from the -schema. schema. All subordinate schema items defined on this type, -such as links and indexes, are removed as well. - -Examples --------- - -Remove the ``User`` object type: - -.. code-block:: edgeql - - drop type User; - -.. list-table:: - :class: seealso - - * - **See also** - * - :ref:`Schema > Object types ` - * - :ref:`SDL > Object types ` - * - :ref:`Introspection > Object types - ` - * - :ref:`Cheatsheets > Object types ` diff --git a/docs/reference/ddl/scalars.rst b/docs/reference/ddl/scalars.rst deleted file mode 100644 index 6c52796eb69..00000000000 --- a/docs/reference/ddl/scalars.rst +++ /dev/null @@ -1,208 +0,0 @@ -.. _ref_eql_ddl_scalars: - -============ -Scalar Types -============ - -This section describes the DDL commands pertaining to -:ref:`scalar types `. - - -Create scalar type -================== - -:eql-statement: -:eql-haswith: - -:ref:`Define ` a new scalar type. - -.. eql:synopsis:: - - [ with [, ...] ] - create [abstract] scalar type [ extending ] - [ "{" ; [...] "}" ] ; - - # where is one of - - create annotation := - create constraint ... - - -Description ------------ - -The command ``create scalar type`` defines a new scalar type for use in the -current :versionreplace:`database;5.0:branch`. - -If *name* is qualified with a module name, then the type is created -in that module, otherwise it is created in the current module. -The type name must be distinct from that of any existing schema item -in the module. - -If the ``abstract`` keyword is specified, the created type will be -*abstract*. - -All non-abstract scalar types must have an underlying core -implementation. For user-defined scalar types this means that -``create scalar type`` must have another non-abstract scalar type -as its *supertype*. - -The most common use of ``create scalar type`` is to define a scalar -subtype with constraints. - -Most sub-commands and options of this command are identical to the -:ref:`SDL scalar type declaration `. The -following subcommands are allowed in the ``create scalar type`` -block: - -:eql:synopsis:`create annotation := ;` - Set scalar type's :eql:synopsis:`` to - :eql:synopsis:``. - - See :eql:stmt:`create annotation` for details. - -:eql:synopsis:`create constraint ...` - Define a new constraint for this scalar type. See - :eql:stmt:`create constraint` for details. - - -Examples --------- - -Create a new non-negative integer type: - -.. code-block:: edgeql - - create scalar type posint64 extending int64 { - create constraint min_value(0); - }; - - -Create a new enumerated type: - -.. code-block:: edgeql - - create scalar type Color - extending enum; - - -Alter scalar type -================= - -:eql-statement: -:eql-haswith: - - -Alter the definition of a :ref:`scalar type `. - -.. eql:synopsis:: - - [ with [, ...] ] - alter scalar type - "{" ; [...] "}" ; - - # where is one of - - rename to - extending ... - create annotation := - alter annotation := - drop annotation - create constraint ... - alter constraint ... - drop constraint ... - - -Description ------------ - -The command ``alter scalar type`` changes the definition of a scalar type. -*name* must be a name of an existing scalar type, optionally qualified -with a module name. - -The following subcommands are allowed in the ``alter scalar type`` block: - -:eql:synopsis:`rename to ;` - Change the name of the scalar type to *newname*. - -:eql:synopsis:`extending ...` - Alter the supertype list. It works the same way as in - :eql:stmt:`alter type`. - -:eql:synopsis:`alter annotation ;` - Alter scalar type :eql:synopsis:``. - See :eql:stmt:`alter annotation` for details. - -:eql:synopsis:`drop annotation ` - Remove scalar type's :eql:synopsis:`` from - :eql:synopsis:``. - See :eql:stmt:`drop annotation` for details. - -:eql:synopsis:`alter constraint ...` - Alter the definition of a constraint for this scalar type. See - :eql:stmt:`alter constraint` for details. - -:eql:synopsis:`drop constraint ` - Remove a constraint from this scalar type. See - :eql:stmt:`drop constraint` for details. - -All the subcommands allowed in the ``create scalar type`` block are also -valid subcommands for ``alter scalar type`` block. - - -Examples --------- - -Define a new constraint on a scalar type: - -.. code-block:: edgeql - - alter scalar type posint64 { - create constraint max_value(100); - }; - -Add one more label to an enumerated type: - -.. code-block:: edgeql - - alter scalar type Color - extending enum; - - -Drop scalar type -================ - -:eql-statement: -:eql-haswith: - - -Remove a scalar type. - -.. eql:synopsis:: - - [ with [, ...] ] - drop scalar type ; - - -Description ------------ - -The command ``drop scalar type`` removes a scalar type. - - -Parameters ----------- - -*name* - The name (optionally qualified with a module name) of an existing - scalar type. - - -Example -------- - -Remove a scalar type: - -.. code-block:: edgeql - - drop scalar type posint64; diff --git a/docs/reference/ddl/triggers.rst b/docs/reference/ddl/triggers.rst deleted file mode 100644 index 72789fbf5ce..00000000000 --- a/docs/reference/ddl/triggers.rst +++ /dev/null @@ -1,146 +0,0 @@ -.. versionadded:: 3.0 - -.. _ref_eql_ddl_triggers: - -======== -Triggers -======== - -This section describes the DDL commands pertaining to -:ref:`triggers `. - - -Create trigger -============== - -:eql-statement: - - -:ref:`Define ` a new trigger. - -.. eql:synopsis:: - :version-lt: 4.0 - - {create | alter} type "{" - create trigger - after - {insert | update | delete} [, ...] - for {each | all} - do - "}" - -.. eql:synopsis:: - - {create | alter} type "{" - create trigger - after - {insert | update | delete} [, ...] - for {each | all} - [ when () ] - do - "}" - - -Description ------------ - -The command ``create trigger`` nested under ``create type`` or ``alter type`` -defines a new trigger for a given object type. - -The trigger name must be distinct from that of any existing trigger -on the same type. - -Parameters ----------- - -The options of this command are identical to the -:ref:`SDL trigger declaration `. - - -Example -------- - -Declare a trigger that inserts a ``Log`` object for each new ``User`` object: - -.. code-block:: edgeql - - alter type User { - create trigger log_insert after insert for each do ( - insert Log { - action := 'insert', - target_name := __new__.name - } - ); - }; - -.. versionadded:: 4.0 - - Declare a trigger that inserts a ``Log`` object conditionally when an update - query makes a change to a ``User`` object: - - .. code-block:: edgeql - - alter type User { - create trigger log_update after update for each - when (__old__ {**} != __new__ {**}) - do ( - insert Log { - action := 'update', - target_name := __new__.name, - change := __old__.name ++ '->' ++ __new__.name - } - ); - } - - -Drop trigger -============ - -:eql-statement: - - -Remove a trigger. - -.. eql:synopsis:: - - alter type "{" - drop trigger ; - "}" - - -Description ------------ - -The command ``drop trigger`` inside an ``alter type`` block removes the -definition of an existing trigger on the specified type. - - -Parameters ----------- - -:eql:synopsis:`` - The name (optionally module-qualified) of the type being triggered on. - -:eql:synopsis:`` - The name of the trigger. - - -Example -------- - -Remove the ``log_insert`` trigger on the ``User`` type: - -.. code-block:: edgeql - - alter type User { - drop trigger log_insert; - }; - - -.. list-table:: - :class: seealso - - * - **See also** - * - :ref:`Schema > Triggers ` - * - :ref:`SDL > Triggers ` - * - :ref:`Introspection > Triggers ` diff --git a/docs/reference/dsn.rst b/docs/reference/dsn.rst index 84c046651e5..0c108975ee6 100644 --- a/docs/reference/dsn.rst +++ b/docs/reference/dsn.rst @@ -6,46 +6,22 @@ DSN specification DSNs (data source names) are a convenient and flexible way to specify connection information with a simple string. It takes the following form: -.. versionchanged:: _default +* :geluri:`USERNAME:PASSWORD@HOSTNAME:PORT/BRANCH` +* e.g.: :geluri:`alice:pa$$w0rd@example.com:1234/my_branch` - .. code-block:: - - edgedb://USERNAME:PASSWORD@HOSTNAME:PORT/DATABASE - - For instance, here is a typical DSN: - ``edgedb://alice:pa$$w0rd@example.com:1234/my_db``. - -.. versionchanged:: 5.0 - - .. code-block:: - - edgedb://USERNAME:PASSWORD@HOSTNAME:PORT/BRANCH - - For instance, here is a typical DSN: - ``edgedb://alice:pa$$w0rd@example.com:1234/my_branch``. - -All components of the DSN are optional; in fact, ``edgedb://`` is a valid DSN. +All components of the DSN are optional; in fact, |geluri| is a valid DSN. Any unspecified values will fall back to their defaults: -.. versionchanged:: _default +The defaults for urername and branch are: |admin| and |main|. - .. code-block:: +The defaults are: - Host: "localhost" - Port: 5656 - User: "edgedb" - Password: null - Database name: "edgedb" +* Host: "localhost" +* Port: 5656 +* User: |admin| +* Password: null +* Branch: |main| -.. versionchanged:: 5.0 - - .. code-block:: - - Host: "localhost" - Port: 5656 - User: "edgedb" - Password: null - Branch name: "main" Query parameters ---------------- @@ -61,63 +37,37 @@ containing the value (``?host_file=./hostname.txt``). For a breakdown of these configuration options, see :ref:`Reference > Connection Parameters `. -.. versionchanged:: _default - - .. list-table:: - - * - **Plain param** - - **File param** - - **Environment param** - * - ``host`` - - ``host_file`` - - ``host_env`` - * - ``port`` - - ``port_file`` - - ``port_env`` - * - ``database`` - - ``database_file`` - - ``database_env`` - * - ``user`` - - ``user_file`` - - ``user_env`` - * - ``password`` - - ``password_file`` - - ``password_env`` - * - ``tls_ca_file`` - - ``tls_ca_file_file`` - - ``tls_ca_file_env`` - * - ``tls_security`` - - ``tls_security_file`` - - ``tls_security_env`` - -.. versionchanged:: 5.0 - - .. list-table:: - - * - **Plain param** - - **File param** - - **Environment param** - * - ``host`` - - ``host_file`` - - ``host_env`` - * - ``port`` - - ``port_file`` - - ``port_env`` - * - ``branch`` - - ``branch_file`` - - ``branch_env`` - * - ``user`` - - ``user_file`` - - ``user_env`` - * - ``password`` - - ``password_file`` - - ``password_env`` - * - ``tls_ca_file`` - - ``tls_ca_file_file`` - - ``tls_ca_file_env`` - * - ``tls_security`` - - ``tls_security_file`` - - ``tls_security_env`` + .. list-table:: + + * - **Plain param** + - **File param** + - **Environment param** + * - ``host`` + - ``host_file`` + - ``host_env`` + * - ``port`` + - ``port_file`` + - ``port_env`` + * - ``branch`` + - ``branch_file`` + - ``branch_env`` + * - ``user`` + - ``user_file`` + - ``user_env`` + * - ``password`` + - ``password_file`` + - ``password_env`` + * - ``tls_ca_file`` + - ``tls_ca_file_file`` + - ``tls_ca_file_env`` + * - ``tls_security`` + - ``tls_security_file`` + - ``tls_security_env`` + +.. note:: + Prior to |Gel| and |EdgeDB| 5.0 *branches* were called *databases*. + If you're using or composing a DSN for an older version of |EdgeDB| + you should change ``branch*`` options to ``database*``. **Plain params** These "plain" parameters can be used to provide values for options that can't @@ -125,11 +75,8 @@ containing the value (``?host_file=./hostname.txt``). detail below). You can't specify the same setting both in the body of the DSN and in a query - parameter. For instance, the DSN below is invalid, as the port is ambiguous. - - .. code-block:: - - edgedb://hostname.com:1234?port=5678 + parameter. For instance, this DSN is invalid, as the port is ambiguous: + :geluri:`hostname.com:1234?port=5678`. **File params** If you prefer to store sensitive credentials in local files, you can use file @@ -138,7 +85,7 @@ containing the value (``?host_file=./hostname.txt``). .. code-block:: - edgedb://hostname.com:1234?user_file=./username.txt + gel://hostname.com:1234?user_file=./username.txt # ./username.txt my_username @@ -154,5 +101,5 @@ containing the value (``?host_file=./hostname.txt``). .. code-block:: MY_PASSWORD=p@$$w0rd - EDGEDB_DSN=edgedb://hostname.com:1234?password_env=MY_PASSWORD + GEL_DSN=gel://hostname.com:1234?password_env=MY_PASSWORD diff --git a/docs/reference/edgeql/analyze.rst b/docs/reference/edgeql/analyze.rst index 8c55864c971..f7f6c2d8fb3 100644 --- a/docs/reference/edgeql/analyze.rst +++ b/docs/reference/edgeql/analyze.rst @@ -1,7 +1,5 @@ .. _ref_eql_statements_analyze: -.. versionadded:: 3.0 - Analyze ======= @@ -22,7 +20,7 @@ Description ``analyze`` returns a table with performance metrics broken down by node. You may prepend the ``analyze`` keyword in either of our REPLs (CLI or :ref:`UI -`) or you may prepend in the UI's query builder for a +`) or you may prepend in the UI's query builder for a helpful visualization of your query's performance. After any ``analyze`` in a REPL, run the ``\expand`` command to see @@ -58,5 +56,5 @@ Example :class: seealso * - **See also** - * - :ref:`CLI > edgedb analyze ` + * - :ref:`CLI > gel analyze ` * - :ref:`EdgeQL > Analyze ` diff --git a/docs/reference/edgeql/cardinality.rst b/docs/reference/edgeql/cardinality.rst index 052ebfd121a..a5c83f5a5ea 100644 --- a/docs/reference/edgeql/cardinality.rst +++ b/docs/reference/edgeql/cardinality.rst @@ -12,12 +12,12 @@ Terminology ----------- The term **cardinality** is used to refer to both the *exact* number of -elements in a given set or a *range* of possible values. Internally, EdgeDB +elements in a given set or a *range* of possible values. Internally, Gel tracks 5 different cardinality ranges: ``Empty`` (zero elements), ``One`` (a singleton set), ``AtMostOne`` (zero or one elements), ``AtLeastOne`` (one or more elements), and ``Many`` (any number of elements). -EdgeDB uses this information to statically check queries for validity. For +|Gel| uses this information to statically check queries for validity. For instance, when assigning to a ``required multi`` link, the value being assigned in question *must* have a cardinality of ``One`` or ``AtLeastOne`` (as empty sets are not permitted). @@ -27,14 +27,14 @@ assigned in question *must* have a cardinality of ``One`` or ``AtLeastOne`` Functions and operators ----------------------- -It's often useful to think of EdgeDB functions/operators as either +It's often useful to think of Gel functions/operators as either *element-wise* or *aggregate*. Element-wise operations are applied to *each item* in a set. Aggregate operations operate on sets *as a whole*. .. note:: This is a simplification, but it's a useful mental model when getting - started with EdgeDB. + started with Gel. .. _ref_reference_cardinality_aggregate: @@ -95,7 +95,7 @@ operation is applied to a cartesian product of all the input sets. {true, true, true, false} By extension, if any of the input sets are empty, the result of applying an -element-wise function is also empty. In effect, when EdgeDB detects an empty +element-wise function is also empty. In effect, when Gel detects an empty set, it "short-circuits" and returns an empty set without applying the operation. diff --git a/docs/reference/edgeql/casts.rst b/docs/reference/edgeql/casts.rst index c51f32e0af9..034819f4114 100644 --- a/docs/reference/edgeql/casts.rst +++ b/docs/reference/edgeql/casts.rst @@ -34,22 +34,21 @@ information on type casting rules. .. lint-off -.. versionadded:: 3.0 - You can cast a UUID into an object: +You can cast a UUID into an object: - .. code-block:: edgeql-repl +.. code-block:: edgeql-repl - db> select '01d9cc22-b776-11ed-8bef-73f84c7e91e7'; - {default::Hero {id: 01d9cc22-b776-11ed-8bef-73f84c7e91e7}} + db> select '01d9cc22-b776-11ed-8bef-73f84c7e91e7'; + {default::Hero {id: 01d9cc22-b776-11ed-8bef-73f84c7e91e7}} - If you try to cast a UUID that no object of the type has as its ``id`` - property, you'll get an error: +If you try to cast a UUID that no object of the type has as its ``id`` +property, you'll get an error: - .. code-block:: edgeql-repl +.. code-block:: edgeql-repl - db> select 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'; - edgedb error: CardinalityViolationError: 'default::Hero' with id 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa' does not exist + db> select 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'; + gel error: CardinalityViolationError: 'default::Hero' with id 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa' does not exist .. lint-on @@ -142,7 +141,7 @@ Casting Table .. note:: - The UUID-to-object cast is only available in EdgeDB 3.0+. + The UUID-to-object cast is only available since |EdgeDB| 3.0+. .. This file is automatically generated by `make casts`: .. csv-table:: diff --git a/docs/reference/edgeql/describe.rst b/docs/reference/edgeql/describe.rst index 438ff82abc2..5d9edc00dc5 100644 --- a/docs/reference/edgeql/describe.rst +++ b/docs/reference/edgeql/describe.rst @@ -115,21 +115,6 @@ Examples Consider the following schema: -.. code-block:: sdl - :version-lt: 3.0 - - abstract type Named { - required property name -> str { - delegated constraint exclusive; - } - } - - type User extending Named { - required property email -> str { - annotation title := 'Contact email'; - } - } - .. code-block:: sdl abstract type Named { diff --git a/docs/reference/edgeql/functions.rst b/docs/reference/edgeql/functions.rst index 1087c4aede8..a32ddbaf0ea 100644 --- a/docs/reference/edgeql/functions.rst +++ b/docs/reference/edgeql/functions.rst @@ -5,7 +5,7 @@ Function calls ============== -EdgeDB provides a number of functions in the :ref:`standard library +|Gel| provides a number of functions in the :ref:`standard library `. It is also possible for users to :ref:`define their own ` functions. @@ -53,6 +53,4 @@ default value: * - :ref:`DDL > Functions ` * - :ref:`Introspection > Functions ` * - :ref:`Cheatsheets > Functions ` - * - `Tutorial > Advanced EdgeQL > User-Defined Functions - `_ diff --git a/docs/reference/edgeql/group.rst b/docs/reference/edgeql/group.rst index f2d28531948..c7722143dca 100644 --- a/docs/reference/edgeql/group.rst +++ b/docs/reference/edgeql/group.rst @@ -1,5 +1,3 @@ -.. versionadded:: 2.0 - .. _ref_eql_statements_group: Group @@ -10,10 +8,6 @@ Group :index: group using by -.. note:: - - The ``group`` statement is only available in EdgeDB 2.0 or later. - ``group``--partition a set into subsets based on one or more keys .. eql:synopsis:: diff --git a/docs/reference/edgeql/index.rst b/docs/reference/edgeql/index.rst index 86ec2943871..28ce6110afd 100644 --- a/docs/reference/edgeql/index.rst +++ b/docs/reference/edgeql/index.rst @@ -69,11 +69,9 @@ Introspection command: * :eql:stmt:`describe`. -.. versionadded:: 3.0 +Performance analysis statement: - Performance analysis statement: - - * :eql:stmt:`analyze`. +* :eql:stmt:`analyze`. .. toctree:: diff --git a/docs/reference/edgeql/insert.rst b/docs/reference/edgeql/insert.rst index 81c16b20eec..bc56006012a 100644 --- a/docs/reference/edgeql/insert.rst +++ b/docs/reference/edgeql/insert.rst @@ -67,9 +67,7 @@ See :ref:`ref_eql_forstatement` for more details. parent type. The specified *property-expr* may be either a reference to a property (or - link) or a tuple of references to properties (or links). Although versions - prior to 2.10 do *not* support ``unless conflict`` on :ref:`multi - properties `, 2.10 adds support for these. + link) or a tuple of references to properties (or links). A caveat, however, is that ``unless conflict`` will not prevent conflicts caused between multiple DML operations in the same diff --git a/docs/reference/edgeql/lexical.rst b/docs/reference/edgeql/lexical.rst index 594d2bc8c5b..6f11a27786f 100644 --- a/docs/reference/edgeql/lexical.rst +++ b/docs/reference/edgeql/lexical.rst @@ -188,10 +188,10 @@ Here's some examples of regular strings using escape sequences ... world'; {'hello world'} - db> select 'https://edgedb.com/\ + db> select 'https://geldata.com/\ ... docs/edgeql/lexical\ ... #constants'; - {'https://edgedb.com/docs/edgeql/lexical#constants'} + {'https://geldata.com/docs/edgeql/lexical#constants'} db> select 'hello \\ world'; {'hello \ world'} diff --git a/docs/reference/edgeql/shapes.rst b/docs/reference/edgeql/shapes.rst index 61596448a7b..607918547c4 100644 --- a/docs/reference/edgeql/shapes.rst +++ b/docs/reference/edgeql/shapes.rst @@ -64,14 +64,6 @@ Consider the task of getting "names of users and all of the friends' names associated with the given user" in a database defined by the following schema: -.. code-block:: sdl - :version-lt: 3.0 - - type User { - required property name -> str; - multi link friends -> User; - } - .. code-block:: sdl type User { @@ -118,7 +110,7 @@ This achieves a couple of things: it's easier to see which friends belong to which user and we no longer need the placeholder ``''`` for those users who don't have friends. -The recommended way to get this information in EdgeDB, however, is to +The recommended way to get this information in Gel, however, is to use *shapes*, because they mimic the structure of the data and the output: .. code-block:: edgeql-repl @@ -218,7 +210,7 @@ these flags out as part of the shape's computed properties: It looks like this refactoring came at the cost of putting extra things into the output. In this case we don't want our intermediate calculations to actually show up in the output, so what can we do? In -EdgeDB the output structure is determined *only* by the expression +|Gel| the output structure is determined *only* by the expression appearing in the top-level :eql:stmt:`select`. This means that we can move our intermediate calculations into the :eql:kw:`with` block: @@ -260,7 +252,7 @@ leaking them into the output. General Shaping Rules ===================== -In EdgeDB typically all shapes appearing in the top-level +In Gel typically all shapes appearing in the top-level :eql:stmt:`select` should be reflected in the output. This also applies to shapes no matter where and how they are nested. Aside from other shapes, this includes nesting in arrays: diff --git a/docs/reference/edgeql/tx_commit.rst b/docs/reference/edgeql/tx_commit.rst index 67cd94654a1..c4dc157eca9 100644 --- a/docs/reference/edgeql/tx_commit.rst +++ b/docs/reference/edgeql/tx_commit.rst @@ -1,5 +1,5 @@ .. - Portions Copyright (c) 2019 MagicStack Inc. and the EdgeDB authors. + Portions Copyright (c) 2019 MagicStack Inc. and the Gel authors. Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group Portions Copyright (c) 1994, The Regents of the University of California diff --git a/docs/reference/edgeql/tx_rollback.rst b/docs/reference/edgeql/tx_rollback.rst index d5fa1e9cc8e..b66c0851e39 100644 --- a/docs/reference/edgeql/tx_rollback.rst +++ b/docs/reference/edgeql/tx_rollback.rst @@ -1,5 +1,5 @@ .. - Portions Copyright (c) 2019 MagicStack Inc. and the EdgeDB authors. + Portions Copyright (c) 2019 MagicStack Inc. and the Gel authors. Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group Portions Copyright (c) 1994, The Regents of the University of California diff --git a/docs/reference/edgeql/tx_sp_declare.rst b/docs/reference/edgeql/tx_sp_declare.rst index a19e1c5432e..fe499192b83 100644 --- a/docs/reference/edgeql/tx_sp_declare.rst +++ b/docs/reference/edgeql/tx_sp_declare.rst @@ -1,5 +1,5 @@ .. - Portions Copyright (c) 2019 MagicStack Inc. and the EdgeDB authors. + Portions Copyright (c) 2019 MagicStack Inc. and the Gel authors. Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group Portions Copyright (c) 1994, The Regents of the University of California diff --git a/docs/reference/edgeql/tx_sp_release.rst b/docs/reference/edgeql/tx_sp_release.rst index 440d8e0ba96..0a56db65008 100644 --- a/docs/reference/edgeql/tx_sp_release.rst +++ b/docs/reference/edgeql/tx_sp_release.rst @@ -1,5 +1,5 @@ .. - Portions Copyright (c) 2019 MagicStack Inc. and the EdgeDB authors. + Portions Copyright (c) 2019 MagicStack Inc. and the Gel authors. Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group Portions Copyright (c) 1994, The Regents of the University of California diff --git a/docs/reference/edgeql/tx_sp_rollback.rst b/docs/reference/edgeql/tx_sp_rollback.rst index 850fc86720f..04f39a6b939 100644 --- a/docs/reference/edgeql/tx_sp_rollback.rst +++ b/docs/reference/edgeql/tx_sp_rollback.rst @@ -1,5 +1,5 @@ .. - Portions Copyright (c) 2019 MagicStack Inc. and the EdgeDB authors. + Portions Copyright (c) 2019 MagicStack Inc. and the Gel authors. Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group Portions Copyright (c) 1994, The Regents of the University of California diff --git a/docs/reference/edgeql/tx_start.rst b/docs/reference/edgeql/tx_start.rst index 9562ee3cc42..1e4dd551c6b 100644 --- a/docs/reference/edgeql/tx_start.rst +++ b/docs/reference/edgeql/tx_start.rst @@ -1,5 +1,5 @@ .. - Portions Copyright (c) 2019 MagicStack Inc. and the EdgeDB authors. + Portions Copyright (c) 2019 MagicStack Inc. and the Gel authors. Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group Portions Copyright (c) 1994, The Regents of the University of California @@ -48,7 +48,7 @@ Description This command starts a new transaction block. -Any EdgeDB command outside of an explicit transaction block starts +Any Gel command outside of an explicit transaction block starts an implicit transaction block; the transaction is then automatically committed if the command was executed successfully, or automatically rollbacked if there was an error. This behavior is often called @@ -61,12 +61,12 @@ Parameters The :eql:synopsis:`` can be one of the following: :eql:synopsis:`isolation serializable` - All statements in the current transaction can only see data - changes that were committed before the first query or data - modification statement was executed within this transaction. + All statements in the current transaction can only see data + changes that were committed before the first query or data + modification statement was executed within this transaction. If a pattern of reads and writes among concurrent serializable - transactions creates a situation that could not have occurred - in any serial (one-at-a-time) execution of those transactions, + transactions creates a situation that could not have occurred + in any serial (one-at-a-time) execution of those transactions, one of them will be rolled back with a serialization_failure error. :eql:synopsis:`read write` diff --git a/docs/reference/edgeql/update.rst b/docs/reference/edgeql/update.rst index 4e976cd512f..7d86451ae11 100644 --- a/docs/reference/edgeql/update.rst +++ b/docs/reference/edgeql/update.rst @@ -95,18 +95,6 @@ assignments using ``:=``: For usage of ``+=`` and ``-=`` consider the following ``Post`` type: -.. code-block:: sdl - :version-lt: 3.0 - - # ... Assume some User type is already defined - type Post { - required property title -> str; - required property body -> str; - # A "tags" property containing a set of strings - multi property tags -> str; - link author -> User; - } - .. code-block:: sdl # ... Assume some User type is already defined diff --git a/docs/reference/edgeql/with.rst b/docs/reference/edgeql/with.rst index 05b491d9b93..02be2afc11f 100644 --- a/docs/reference/edgeql/with.rst +++ b/docs/reference/edgeql/with.rst @@ -141,6 +141,8 @@ An example of incorrect refactoring would be: select (Issue, U); +.. _ref_edgeql_with_detached: + Detached ++++++++ diff --git a/docs/reference/environment.rst b/docs/reference/environment.rst index 7e052ae75e2..ad125dec861 100644 --- a/docs/reference/environment.rst +++ b/docs/reference/environment.rst @@ -3,9 +3,9 @@ Environment Variables ===================== -The behavior of EdgeDB can be configured with environment variables. The +The behavior of Gel can be configured with environment variables. The variables documented on this page are supported when using the -``edgedb-server`` tool and the official :ref:`Docker image +|gel-server| tool and the official :ref:`Docker image `. @@ -29,99 +29,104 @@ Docker image variables These variables are only used by the Docker image. Setting these variables outside that context will have no effect. +.. note:: -EDGEDB_DOCKER_ABORT_CODE -........................ + For |EdgeDB| versions before 6.0 (Gel) the prefix for all environment + variables is ``EDGEDB_`` instead of ``GEL_``. + + +GEL_DOCKER_ABORT_CODE +..................... If the process fails, the arguments are logged to stderr and the script is terminated with this exit code. Default is ``1``. -EDGEDB_DOCKER_APPLY_MIGRATIONS -.............................. +GEL_DOCKER_APPLY_MIGRATIONS +........................... The container will attempt to apply migrations in ``dbschema/migrations`` unless this variable is set to ``never``. Default is ``always``. -EDGEDB_DOCKER_BOOTSTRAP_TIMEOUT_SEC -................................... +GEL_DOCKER_BOOTSTRAP_TIMEOUT_SEC +................................ Sets the number of seconds to wait for instance bootstrapping to complete before timing out. Default is ``300``. -EDGEDB_DOCKER_LOG_LEVEL -....................... +GEL_DOCKER_LOG_LEVEL +.................... Change the logging level for the docker container. Default is ``info``. Other levels are ``trace``, ``debug``, ``warning``, and ``error``. -EDGEDB_DOCKER_SHOW_GENERATED_CERT -................................. +GEL_DOCKER_SHOW_GENERATED_CERT +.............................. Shows the generated TLS certificate in console output. Default is ``always``. May instead be set to ``never``. -EDGEDB_DOCKER_SKIP_MIGRATIONS -............................. +GEL_DOCKER_SKIP_MIGRATIONS +.......................... .. warning:: Deprecated - Use ``EDGEDB_DOCKER_APPLY_MIGRATIONS`` instead. + Use :gelenv:`DOCKER_APPLY_MIGRATIONS` instead. The container will skip applying migrations in ``dbschema/migrations`` if this is set. -EDGEDB_SERVER_BINARY -.................... +GEL_SERVER_BINARY +................. -Sets the EdgeDB server binary to run. Default is ``edgedb-server``. +Sets the Gel server binary to run. Default is |gel-server|. -EDGEDB_SERVER_BOOTSTRAP_COMMAND_FILE -.................................... +GEL_SERVER_BOOTSTRAP_COMMAND_FILE +................................. Run the script when initializing the database. The script is run by the default -user within the default :versionreplace:`database;5.0:branch`. May be used with -or without ``EDGEDB_SERVER_BOOTSTRAP_ONLY``. +user within the default |branch|. May be used with or without +:gelenv:`SERVER_BOOTSTRAP_ONLY`. -EDGEDB_SERVER_BOOTSTRAP_SCRIPT_FILE -................................... +GEL_SERVER_BOOTSTRAP_SCRIPT_FILE +................................ .. warning:: Deprecated in image version 2.8 - Use ``EDGEDB_SERVER_BOOTSTRAP_COMMAND_FILE`` instead. + Use :gelenv:`SERVER_BOOTSTRAP_COMMAND_FILE` instead. Run the script when initializing the database. The script is run by the default -user within the default :versionreplace:`database;5.0:branch`. +user within the default |branch|. -EDGEDB_SERVER_COMPILER_POOL_MODE -................................ +GEL_SERVER_COMPILER_POOL_MODE +............................. Choose a mode for the compiler pool to scale. ``fixed`` means the pool will not -scale and sticks to ``EDGEDB_SERVER_COMPILER_POOL_SIZE``, while ``on_demand`` +scale and sticks to :gelenv:`SERVER_COMPILER_POOL_SIZE`, while ``on_demand`` means the pool will maintain at least 1 worker and automatically scale up (to -``EDGEDB_SERVER_COMPILER_POOL_SIZE`` workers ) and down to the demand. +:gelenv:`SERVER_COMPILER_POOL_SIZE` workers ) and down to the demand. Default is ``fixed`` in production mode and ``on_demand`` in development mode. -EDGEDB_SERVER_COMPILER_POOL_SIZE -................................ +GEL_SERVER_COMPILER_POOL_SIZE +............................. -When ``EDGEDB_SERVER_COMPILER_POOL_MODE`` is ``fixed``, this setting is the -exact size of the compiler pool. When ``EDGEDB_SERVER_COMPILER_POOL_MODE`` is +When :gelenv:`SERVER_COMPILER_POOL_MODE` is ``fixed``, this setting is the +exact size of the compiler pool. When :gelenv:`SERVER_COMPILER_POOL_MODE` is ``on_demand``, this will serve as the maximum size of the compiler pool. -EDGEDB_SERVER_EMIT_SERVER_STATUS -................................ +GEL_SERVER_EMIT_SERVER_STATUS +............................. Instruct the server to emit changes in status to *DEST*, where *DEST* is a URI specifying a file (``file://``), or a file descriptor @@ -129,112 +134,112 @@ specifying a file (``file://``), or a file descriptor assumed. -EDGEDB_SERVER_EXTRA_ARGS -........................ +GEL_SERVER_EXTRA_ARGS +..................... -Additional arguments to pass when starting the EdgeDB server. +Additional arguments to pass when starting the Gel server. -EDGEDB_SERVER_GENERATE_SELF_SIGNED_CERT -....................................... +GEL_SERVER_GENERATE_SELF_SIGNED_CERT +.................................... .. warning:: Deprecated - Use ``EDGEDB_SERVER_TLS_CERT_MODE="generate_self_signed"`` instead. + Use :gelenv:`SERVER_TLS_CERT_MODE="generate_self_signed"` instead. Instructs the server to generate a self-signed certificate when set. -EDGEDB_SERVER_PASSWORD -...................... +GEL_SERVER_PASSWORD +................... The password for the default superuser account (or the user specified in -``EDGEDB_SERVER_USER``) will be set to this value. If no value is provided, a -password will not be set, unless set via ``EDGEDB_SERVER_BOOTSTRAP_COMMAND``. -(If a value for ``EDGEDB_SERVER_BOOTSTRAP_COMMAND`` is provided, this variable +:gelenv:`SERVER_USER`) will be set to this value. If no value is provided, a +password will not be set, unless set via :gelenv:`SERVER_BOOTSTRAP_COMMAND`. +(If a value for :gelenv:`SERVER_BOOTSTRAP_COMMAND` is provided, this variable will be ignored.) The ``*_FILE`` and ``*_ENV`` variants are also supported. -EDGEDB_SERVER_PASSWORD_HASH -........................... +GEL_SERVER_PASSWORD_HASH +........................ -A variant of ``EDGEDB_SERVER_PASSWORD``, where the specified value is a hashed +A variant of :gelenv:`SERVER_PASSWORD`, where the specified value is a hashed password verifier instead of plain text. -If ``EDGEDB_SERVER_BOOTSTRAP_COMMAND`` is set, this variable will be ignored. +If :gelenv:`SERVER_BOOTSTRAP_COMMAND` is set, this variable will be ignored. The ``*_FILE`` and ``*_ENV`` variants are also supported. -EDGEDB_SERVER_SKIP_MIGRATIONS -............................. +GEL_SERVER_SKIP_MIGRATIONS +.......................... .. warning:: Deprecated - Use ``EDGEDB_DOCKER_APPLY_MIGRATIONS="never"`` instead. + Use :gelenv:`DOCKER_APPLY_MIGRATIONS="never"` instead. When set, skips applying migrations in ``dbschema/migrations``. Not set by default. -EDGEDB_SERVER_TENANT_ID -....................... +GEL_SERVER_TENANT_ID +.................... -Specifies the tenant ID of this server when hosting multiple EdgeDB instances +Specifies the tenant ID of this server when hosting multiple Gel instances on one Postgres cluster. Must be an alphanumeric ASCII string, maximum 10 characters long. -EDGEDB_SERVER_UID -................. +GEL_SERVER_UID +.............. Specifies the ID of the user which should run the server binary. Default is ``1``. -EDGEDB_SERVER_USER -.................. +GEL_SERVER_USER +............... -If set to anything other than the default username (``edgedb``), the username +If set to anything other than the default username |admin|, the username specified will be created. The user defined here will be the one assigned the -password set in ``EDGEDB_SERVER_PASSWORD`` or the hash set in -``EDGEDB_SERVER_PASSWORD_HASH``. +password set in :gelenv:`SERVER_PASSWORD` or the hash set in +:gelenv:`SERVER_PASSWORD_HASH`. Server variables ---------------- -These variables will work whether you are running EdgeDB inside Docker or not. +These variables will work whether you are running Gel inside Docker or not. -EDGEDB_DEBUG_HTTP_INJECT_CORS -............................. +GEL_DEBUG_HTTP_INJECT_CORS +.......................... -Set to ``1`` to have EdgeDB send appropriate CORS headers with HTTP responses. +Set to ``1`` to have Gel send appropriate CORS headers with HTTP responses. .. note:: - This is set to ``1`` by default for EdgeDB Cloud instances. + This is set to ``1`` by default for Gel Cloud instances. .. _ref_reference_envvar_admin_ui: -EDGEDB_SERVER_ADMIN_UI -...................... +GEL_SERVER_ADMIN_UI +................... Set to ``enabled`` to enable the web-based admininstrative UI for the instance. -Maps directly to the ``edgedb-server`` flag ``--admin-ui``. +Maps directly to the |gel-server| flag ``--admin-ui``. -EDGEDB_SERVER_ALLOW_INSECURE_BINARY_CLIENTS -........................................... +GEL_SERVER_ALLOW_INSECURE_BINARY_CLIENTS +........................................ .. warning:: Deprecated - Use ``EDGEDB_SERVER_BINARY_ENDPOINT_SECURITY`` instead. + Use :gelenv:`SERVER_BINARY_ENDPOINT_SECURITY` instead. Specifies the security mode of the server's binary endpoint. When set to ``1``, non-TLS connections are allowed. Not set by default. @@ -244,12 +249,12 @@ non-TLS connections are allowed. Not set by default. Disabling TLS is not recommended in production. -EDGEDB_SERVER_ALLOW_INSECURE_HTTP_CLIENTS -......................................... +GEL_SERVER_ALLOW_INSECURE_HTTP_CLIENTS +...................................... .. warning:: Deprecated - Use ``EDGEDB_SERVER_HTTP_ENDPOINT_SECURITY`` instead. + Use :gelenv:`SERVER_HTTP_ENDPOINT_SECURITY` instead. Specifies the security mode of the server's HTTP endpoint. When set to ``1``, non-TLS connections are allowed. Not set by default. @@ -259,31 +264,31 @@ non-TLS connections are allowed. Not set by default. Disabling TLS is not recommended in production. -.. _ref_reference_docker_edgedb_server_backend_dsn: +.. _ref_reference_docker_gel_server_backend_dsn: -EDGEDB_SERVER_BACKEND_DSN -......................... +GEL_SERVER_BACKEND_DSN +...................... Specifies a PostgreSQL connection string in the `URI format`_. If set, the PostgreSQL cluster specified by the URI is used instead of the builtin -PostgreSQL server. Cannot be specified alongside ``EDGEDB_SERVER_DATADIR``. +PostgreSQL server. Cannot be specified alongside :gelenv:`SERVER_DATADIR`. -Maps directly to the ``edgedb-server`` flag ``--backend-dsn``. The ``*_FILE`` +Maps directly to the |gel-server| flag ``--backend-dsn``. The ``*_FILE`` and ``*_ENV`` variants are also supported. .. _URI format: https://www.postgresql.org/docs/13/libpq-connect.html#id-1.7.3.8.3.6 -EDGEDB_SERVER_MAX_BACKEND_CONNECTIONS -..................................... +GEL_SERVER_MAX_BACKEND_CONNECTIONS +.................................. -The maximum NUM of connections this EdgeDB instance could make to the backend -PostgreSQL cluster. If not set, EdgeDB will detect and calculate the NUM: +The maximum NUM of connections this Gel instance could make to the backend +PostgreSQL cluster. If not set, Gel will detect and calculate the NUM: RAM/100MiB for local Postgres, or pg_settings.max_connections for remote Postgres minus the NUM of ``--reserved-pg-connections``. -EDGEDB_SERVER_BINARY_ENDPOINT_SECURITY -...................................... +GEL_SERVER_BINARY_ENDPOINT_SECURITY +................................... Specifies the security mode of the server's binary endpoint. When set to ``optional``, non-TLS connections are allowed. Default is ``tls``. @@ -293,81 +298,65 @@ Specifies the security mode of the server's binary endpoint. When set to Disabling TLS is not recommended in production. -EDGEDB_SERVER_BIND_ADDRESS -.......................... +GEL_SERVER_BIND_ADDRESS +....................... -Specifies the network interface on which EdgeDB will listen. +Specifies the network interface on which Gel will listen. -Maps directly to the ``edgedb-server`` flag ``--bind-address``. The ``*_FILE`` +Maps directly to the |gel-server| flag ``--bind-address``. The ``*_FILE`` and ``*_ENV`` variants are also supported. -EDGEDB_SERVER_BOOTSTRAP_COMMAND -............................... +GEL_SERVER_BOOTSTRAP_COMMAND +............................ Useful to fine-tune initial user creation and other initial setup. -.. versionchanged:: _default - .. note:: - - A :eql:stmt:`create database` statement cannot be combined in a block with - any other statements. Since all statements in - ``EDGEDB_SERVER_BOOTSTRAP_COMMAND`` run in a single block, it cannot be - used to create a database and, for example, create a user for that - database. - - For Docker deployments, you can instead write :ref:`custom scripts to run - before migrations `. - These are placed in ``/edgedb-bootstrap.d/``. By writing your ``create - database`` statements in one ``.edgeql`` file each placed in - ``/edgedb-bootstrap.d/`` and other statements in their own file, you can - create databases and still run other EdgeQL statements to bootstrap your - instance. - -.. versionchanged:: 5.0 - - .. note:: - - A create branch statement (i.e., :eql:stmt:`create empty branch`, - :eql:stmt:`create schema branch`, or :eql:stmt:`create data branch`) - cannot be combined in a block with any other statements. Since all - statements in ``EDGEDB_SERVER_BOOTSTRAP_COMMAND`` run in a single - block, it cannot be used to create a branch and, for example, create a - user on that branch. - - For Docker deployments, you can instead write :ref:`custom scripts to run - before migrations `. - These are placed in ``/edgedb-bootstrap.d/``. By writing your ``create - branch`` statements in one ``.edgeql`` file each placed in - ``/edgedb-bootstrap.d/`` and other statements in their own file, you can - create branches and still run other EdgeQL statements to bootstrap your - instance. +.. note:: -Maps directly to the ``edgedb-server`` flag ``--bootstrap-command``. The + A create branch statement (i.e., :eql:stmt:`create empty branch`, + :eql:stmt:`create schema branch`, or :eql:stmt:`create data branch`) + cannot be combined in a block with any other statements. Since all + statements in :gelenv:`SERVER_BOOTSTRAP_COMMAND` run in a single + block, it cannot be used to create a branch and, for example, create a + user on that branch. + + For Docker deployments, you can instead write :ref:`custom scripts to run + before migrations `. + These are placed in ``/gel-bootstrap.d/``. By writing your ``create + branch`` statements in one ``.edgeql`` file each placed in + ``/gel-bootstrap.d/`` and other statements in their own file, you can + create branches and still run other EdgeQL statements to bootstrap your + instance. + + Note that for |EdgeDB| versions prior to 5.0, paths contain "edgedb" + instead of "gel", so ``/gel-bootstrap.d/`` becomes ``/edgedb-bootstrap.d/``. + +Maps directly to the |gel-server| flag ``--bootstrap-command``. The ``*_FILE`` and ``*_ENV`` variants are also supported. -EDGEDB_SERVER_BOOTSTRAP_ONLY -............................ +GEL_SERVER_BOOTSTRAP_ONLY +......................... When set, bootstrap the database cluster and exit. Not set by default. -.. _ref_reference_docer_edgedb_server_datadir: +.. _ref_reference_docer_gel_server_datadir: -EDGEDB_SERVER_DATADIR -..................... +GEL_SERVER_DATADIR +.................. Specifies a path where the database files are located. Default is -``/var/lib/edgedb/data``. Cannot be specified alongside -``EDGEDB_SERVER_BACKEND_DSN``. +``/var/lib/gel/data``. Cannot be specified alongside +:gelenv:`SERVER_BACKEND_DSN`. -Maps directly to the ``edgedb-server`` flag ``--data-dir``. +Maps directly to the |gel-server| flag ``--data-dir``. -EDGEDB_SERVER_DEFAULT_AUTH_METHOD -................................. +GEL_SERVER_DEFAULT_AUTH_METHOD +.............................. Optionally specifies the authentication method used by the server instance. Supported values are ``SCRAM`` (the default) and ``Trust``. When set to @@ -382,8 +371,8 @@ Use at your own risk and only for development and testing. The ``*_FILE`` and ``*_ENV`` variants are also supported. -EDGEDB_SERVER_HTTP_ENDPOINT_SECURITY -.................................... +GEL_SERVER_HTTP_ENDPOINT_SECURITY +................................. Specifies the security mode of the server's HTTP endpoint. When set to ``optional``, non-TLS connections are allowed. Default is ``tls``. @@ -393,68 +382,68 @@ Specifies the security mode of the server's HTTP endpoint. When set to Disabling TLS is not recommended in production. -EDGEDB_SERVER_INSTANCE_NAME -........................... +GEL_SERVER_INSTANCE_NAME +........................ Specify the server instance name. -EDGEDB_SERVER_JWS_KEY_FILE -.......................... +GEL_SERVER_JWS_KEY_FILE +....................... Specifies a path to a file containing a public key in PEM format used to verify JWT signatures. The file could also contain a private key to sign JWT for local testing. -EDGEDB_SERVER_LOG_LEVEL -....................... +GEL_SERVER_LOG_LEVEL +.................... Set the logging level. Default is ``info``. Other possible values are ``debug``, ``warn``, ``error``, and ``silent``. -EDGEDB_SERVER_PORT -.................. +GEL_SERVER_PORT +............... -Specifies the network port on which EdgeDB will listen. Default is ``5656``. +Specifies the network port on which Gel will listen. Default is ``5656``. -Maps directly to the ``edgedb-server`` flag ``--port``. The ``*_FILE`` and +Maps directly to the |gel-server| flag ``--port``. The ``*_FILE`` and ``*_ENV`` variants are also supported. -EDGEDB_SERVER_POSTGRES_DSN -.......................... +GEL_SERVER_POSTGRES_DSN +....................... .. warning:: Deprecated - Use ``EDGEDB_SERVER_BACKEND_DSN`` instead. + Use :gelenv:`SERVER_BACKEND_DSN` instead. Specifies a PostgreSQL connection string in the `URI format`_. If set, the PostgreSQL cluster specified by the URI is used instead of the builtin -PostgreSQL server. Cannot be specified alongside ``EDGEDB_SERVER_DATADIR``. +PostgreSQL server. Cannot be specified alongside :gelenv:`SERVER_DATADIR`. -Maps directly to the ``edgedb-server`` flag ``--backend-dsn``. The ``*_FILE`` +Maps directly to the |gel-server| flag ``--backend-dsn``. The ``*_FILE`` and ``*_ENV`` variants are also supported. .. _URI format: https://www.postgresql.org/docs/13/libpq-connect.html#id-1.7.3.8.3.6 -EDGEDB_SERVER_RUNSTATE_DIR -.......................... +GEL_SERVER_RUNSTATE_DIR +....................... -Specifies a path where EdgeDB will place its Unix socket and other transient +Specifies a path where Gel will place its Unix socket and other transient files. -Maps directly to the ``edgedb-server`` flag ``--runstate-dir``. +Maps directly to the |gel-server| flag ``--runstate-dir``. -EDGEDB_SERVER_SECURITY -...................... +GEL_SERVER_SECURITY +................... -When set to ``insecure_dev_mode``, sets ``EDGEDB_SERVER_DEFAULT_AUTH_METHOD`` -to ``Trust``, and ``EDGEDB_SERVER_TLS_CERT_MODE`` to ``generate_self_signed`` +When set to ``insecure_dev_mode``, sets :gelenv:`SERVER_DEFAULT_AUTH_METHOD` +to ``Trust``, and :gelenv:`SERVER_TLS_CERT_MODE` to ``generate_self_signed`` (unless an explicit TLS certificate is specified). Finally, if this option is set, the server will accept plaintext HTTP connections. @@ -462,39 +451,39 @@ set, the server will accept plaintext HTTP connections. Disabling TLS is not recommended in production. -Maps directly to the ``edgedb-server`` flag ``--security``. +Maps directly to the |gel-server| flag ``--security``. -EDGEDB_SERVER_TLS_CERT_FILE/EDGEDB_SERVER_TLS_KEY_FILE -...................................................... +GEL_SERVER_TLS_CERT_FILE/GEL_SERVER_TLS_KEY_FILE +................................................... The TLS certificate and private key files, exclusive with -``EDGEDB_SERVER_TLS_CERT_MODE=generate_self_signed``. +:gelenv:`SERVER_TLS_CERT_MODE=generate_self_signed`. -Maps directly to the ``edgedb-server`` flags ``--tls-cert-file`` and +Maps directly to the |gel-server| flags ``--tls-cert-file`` and ``--tls-key-file``. -EDGEDB_SERVER_TLS_CERT_MODE -........................... +GEL_SERVER_TLS_CERT_MODE +........................ Specifies what to do when the TLS certificate and key are either not specified or are missing. - When set to ``require_file``, the TLS certificate and key must be specified - in the ``EDGEDB_SERVER_TLS_CERT`` and ``EDGEDB_SERVER_TLS_KEY`` variables and + in the :gelenv:`SERVER_TLS_CERT` and :gelenv:`SERVER_TLS_KEY` variables and both must exist. - When set to ``generate_self_signed`` a new self-signed certificate and private key will be generated and placed in the path specified by - ``EDGEDB_SERVER_TLS_CERT`` and ``EDGEDB_SERVER_TLS_KEY``, if those are set. + :gelenv:`SERVER_TLS_CERT` and :gelenv:`SERVER_TLS_KEY`, if those are set. Otherwise, the generated certificate and key are stored as ``edbtlscert.pem`` - and ``edbprivkey.pem`` in ``EDGEDB_SERVER_DATADIR``, or, if - ``EDGEDB_SERVER_DATADIR`` is not set, they will be placed in - ``/etc/ssl/edgedb``. + and ``edbprivkey.pem`` in :gelenv:`SERVER_DATADIR`, or, if + :gelenv:`SERVER_DATADIR` is not set, they will be placed in + ``/etc/ssl/gel``. Default is ``generate_self_signed`` when -``EDGEDB_SERVER_SECURITY=insecure_dev_mode``. Otherwise, the default is +:gelenv:`SERVER_SECURITY=insecure_dev_mode`. Otherwise, the default is ``require_file``. -Maps directly to the ``edgedb-server`` flag ``--tls-cert-mode``. The ``*_FILE`` +Maps directly to the |gel-server| flag ``--tls-cert-mode``. The ``*_FILE`` and ``*_ENV`` variants are also supported. diff --git a/docs/reference/edgedb_toml.rst b/docs/reference/gel_toml.rst similarity index 58% rename from docs/reference/edgedb_toml.rst rename to docs/reference/gel_toml.rst index 36fa602f91e..bda4e47562c 100644 --- a/docs/reference/edgedb_toml.rst +++ b/docs/reference/gel_toml.rst @@ -1,13 +1,13 @@ -.. _ref_reference_edgedb_toml: +.. _ref_reference_gel_toml: -=========== -edgedb.toml -=========== +======== +gel.toml +======== -The ``edgedb.toml`` file is created in the project root after running -:ref:`ref_cli_edgedb_project_init`. If this file is present in a directory, it +The |gel.toml| file is created in the project root after running +:ref:`ref_cli_gel_project_init`. If this file is present in a directory, it signals to the CLI and client bindings that the directory is an instance-linked -EdgeDB project. It supports two configuration settings across two tables: +|Gel| project. It supports two configuration settings across two tables: .. note:: @@ -16,25 +16,30 @@ EdgeDB project. It supports two configuration settings across two tables: out `the TOML documentation `_. -``[edgedb]`` table -================== +[instance] table +================ -- ``server-version``- The server version of the EdgeDB project. +- ``server-version``- The server version of the Gel project. .. note:: The version specification is assumed to be **a minimum version**, but the CLI will *not* upgrade to subsequent major versions. This means if the - version specified is ``3.1`` and versions 3.2 and 3.3 are available, 3.3 - will be installed, even if version 4.0 is also available. + version specified is ``6.1`` and versions 6.2 and 6.3 are available, 6.3 + will be installed, even if version 7.0 is also available. - To specify an exact version, prepend with ``=`` like this: ``=3.1``. We + To specify an exact version, prepend with ``=`` like this: ``=6.1``. We support `all of the same version specifications as Cargo`_, Rust's package manager. + .. note:: + + ``edgedb.toml`` files for versions of |Gel| prior to 6.0 use + ``[edgedb]`` table, not ``[instance]``. + -``[project]`` table -=================== +[project] table +=============== - ``schema-dir``- The directory where schema files will be stored. Defaults to ``dbschema``. @@ -45,8 +50,8 @@ Example .. code-block:: toml - [edgedb] - server-version = "3.1" + [gel] + server-version = "6.0" [project] schema-dir = "db/schema" diff --git a/docs/reference/http.rst b/docs/reference/http.rst index 35062efb156..d8545b212d1 100644 --- a/docs/reference/http.rst +++ b/docs/reference/http.rst @@ -3,56 +3,36 @@ HTTP API ======== -Using HTTP, you may check the health of your EdgeDB instance, check metrics on +Using HTTP, you may check the health of your Gel instance, check metrics on your instance, and make queries. -.. versionchanged:: _default +Your instance's URL takes the form of ``http://:/``. - Your instance's URL takes the form of ``http://:/``. For - queries, you will append ``db//edgeql``. +For queries, you will append ``db//edgeql`` for |EdgeDB| < 5, +or ``branch//edgeql`` for Gel and |EdgeDB| >= 5. -.. versionchanged:: 5.0 +Here's how to determine your *local* Gel instance's HTTP server URL: - Your instance's URL takes the form of ``http://:/``. For - queries, you will append ``branch//edgeql``. +- The ````, in most cases, will be |main|. -.. note:: - - Here's how to determine your local EdgeDB instance's HTTP server URL: - -.. versionchanged:: _default - - - The ``hostname`` will be ``localhost`` - - Find the ``port`` by running ``edgedb instance list``. This will print a - table of all EdgeDB instances on your machine, including their associated - port number. - - In most cases, ``database-name`` will be ``edgedb``. An EdgeDB *instance* - can contain multiple databases. On initialization, a default database - called ``edgedb`` is created; all queries are executed against this - database unless otherwise specified. +- The ``hostname`` will be ``localhost`` -.. versionchanged:: 5.0 +- Find the ``port`` by running :gelcmd:`instance list`. This will print a + table of all Gel instances on your machine, including their associated + port number. - - The ``hostname`` will be ``localhost`` - - Find the ``port`` by running ``edgedb instance list``. This will print a - table of all EdgeDB instances on your machine, including their associated - port number. - - The default branch in your EdgeDB database is ``main``. Use this for - ```` unless you want to query a different branch. - - To determine the URL of a remote instance you have linked with the CLI, you - can get both the hostname and port of the instance from the "Port" column - of the ``edgedb instance list`` table (formatted as ``:``). - The same guidance on local :versionreplace:`database;5.0:branch` names - applies to remote instances. +To determine the URL of a remote instance you have linked with the CLI, you +can get both the hostname and port of the instance from the "Port" column +of the :gelcmd:`instance list` table (formatted as ``:``). +The same guidance on local |branch| names applies to remote instances. .. _ref_reference_health_checks: Health Checks ------------- -EdgeDB exposes endpoints to check for aliveness and readiness of your database +|Gel| exposes endpoints to check for aliveness and readiness of your database instance. Aliveness @@ -93,7 +73,7 @@ Retrieve instance metrics. http://:/metrics -All EdgeDB instances expose a Prometheus-compatible endpoint available via GET +All Gel instances expose a Prometheus-compatible endpoint available via GET request. The following metrics are made available. System @@ -222,8 +202,8 @@ schema. Add this to your schema, outside any ``module``: using extension edgeql_http; Then create a new migration and apply it using -:ref:`ref_cli_edgedb_migration_create` and -:ref:`ref_cli_edgedb_migrate`, respectively. +:ref:`ref_cli_gel_migration_create` and +:ref:`ref_cli_gel_migrate`, respectively. Your instance is now able to receive EdgeQL queries over HTTP. @@ -235,19 +215,11 @@ Your instance is now able to receive EdgeQL queries over HTTP. Making a query request ^^^^^^^^^^^^^^^^^^^^^^ -Make a query to your EdgeDB database using this URL: - -.. versionchanged:: _default - - .. code-block:: - - http://:/db//edgeql +Make a query to your Gel database using this URL: -.. versionchanged:: 5.0 - - .. code-block:: +.. code-block:: - http://:/branch//edgeql + http://:/branch//edgeql You may make queries via either the POST or GET HTTP method. Query requests can take the following fields: @@ -263,7 +235,7 @@ submit a JSON payload with ``query`` and ``variables`` as top-level keys in that payload as in this example: Here's an example query you might want to run to insert a new person in your -database, as executed from the EdgeDB REPL: +database, as executed from the Gel REPL: .. code-block:: edgeql-repl @@ -274,23 +246,12 @@ database, as executed from the EdgeDB REPL: The query inserts a ``Person`` object. The object's ``name`` value is parameterized in the query as ``$name``. -.. versionchanged:: _default - - This GET request would run the same query (assuming the instance is local - and the database is named ``edgedb``): - - .. code-block:: +This GET request would run the same query (assuming the instance is local +and you want to query the |main| branch): - GET http://localhost:/db/edgedb/edgeql?query=insert%20Person%20%7B%20name%20%3A%3D%20%3Cstr%3E$name%20%7D%3B&variables=%7B%22name%22%3A%20%22Pat%22%7D - -.. versionchanged:: 5.0 - - This GET request would run the same query (assuming the instance is local - and you want to query the ``main`` branch): - - .. code-block:: +.. code-block:: - GET http://localhost:/branch/main/edgeql?query=insert%20Person%20%7B%20name%20%3A%3D%20%3Cstr%3E$name%20%7D%3B&variables=%7B%22name%22%3A%20%22Pat%22%7D + GET http://localhost:/branch/main/edgeql?query=insert%20Person%20%7B%20name%20%3A%3D%20%3Cstr%3E$name%20%7D%3B&variables=%7B%22name%22%3A%20%22Pat%22%7D As you can see with even this simple query, URL encoding can quickly become onerous with queries over GET. diff --git a/docs/reference/index.rst b/docs/reference/index.rst index 527747c13db..555a75f5979 100644 --- a/docs/reference/index.rst +++ b/docs/reference/index.rst @@ -18,7 +18,7 @@ Reference connection environment projects - edgedb_toml + gel_toml dsn dump_format backend_ha @@ -31,4 +31,4 @@ Reference This section contains comprehensive reference documentation on the internals of -EdgeDB, the binary protocol, the formal syntax of EdgeQL, and more. +|Gel|, the binary protocol, the formal syntax of EdgeQL, and more. diff --git a/docs/reference/projects.rst b/docs/reference/projects.rst index f1e79ceee7c..ee1a11441a5 100644 --- a/docs/reference/projects.rst +++ b/docs/reference/projects.rst @@ -4,42 +4,42 @@ Create a project ================ -Projects are the most convenient way to develop applications with EdgeDB. This +Projects are the most convenient way to develop applications with Gel. This is the recommended approach. To get started, navigate to the root directory of your codebase in a shell and -run ``edgedb project init``. You'll see something like this: +run :gelcmd:`project init`. You'll see something like this: .. code-block:: bash - $ edgedb project init - No `edgedb.toml` found in this repo or above. + $ gel project init + No `gel.toml` found in this repo or above. Do you want to initialize a new project? [Y/n] > Y - Checking EdgeDB versions... - Specify the version of EdgeDB to use with this project [1-rc3]: + Checking Gel versions... + Specify the version of Gel to use with this project [1-rc3]: > # left blank for default - Specify the name of EdgeDB instance to use with this project: + Specify the name of Gel instance to use with this project: > my_instance - Initializing EdgeDB instance... + Initializing Gel instance... Bootstrap complete. Server is up and running now. Project initialialized. Let's unpack that. -1. First, it asks you to specify an EdgeDB version, defaulting to the most +1. First, it asks you to specify an Gel version, defaulting to the most recent version you have installed. You can also specify a version you *don't* have installed, in which case it will be installed. -2. Then it asks you how you'd like to run EdgeDB: locally, in a Docker image, +2. Then it asks you how you'd like to run Gel: locally, in a Docker image, or in the cloud (coming soon!). 3. Then it asks for an instance name. If no instance currently exists with this name, it will be created (using the method you specified in #2). 4. Then it **links** the current directory to that instance. A "link" is - represented as some metadata stored in EdgeDB's :ref:`config directory - `β€”feel free to peek inside to see how it's stored. -5. Then it creates an :ref:`ref_reference_edgedb_toml` file, which marks this - directory as an EdgeDB project. -6. Finally, it creates a ``dbschema`` directory and a ``dbschema/default.esdl`` + represented as some metadata stored in Gel's :ref:`config directory + `β€”feel free to peek inside to see how it's stored. +5. Then it creates an :ref:`ref_reference_gel_toml` file, which marks this + directory as an Gel project. +6. Finally, it creates a ``dbschema`` directory and a :dotgel:`dbschema/default` schema file (if they don't already exist). @@ -51,11 +51,11 @@ How does this help me? Once you've initialized a project, your project directory is *linked* to a particular instance. That means, you can run CLI commands without connection -flags. For instance, ``edgedb -I my_instance migrate`` becomes simply ``edgedb -migrate``. The CLI detects the existence of the ``edgedb.toml`` file, reads the -current directory, and checks if it's associated with an existing project. If -it is, it looks up the credentials of the linked instance (they're stored in a -:ref:`standardized location `), uses that information to +flags. For instance, :gelcmd:`-I my_instance migrate` becomes simply +:gelcmd:`migrate`. The CLI detects the existence of the |gel.toml| file, reads +the current directory, and checks if it's associated with an existing project. +If it is, it looks up the credentials of the linked instance (they're stored in +a :ref:`standardized location `), uses that information to connect to the instance, and applies the command. Similarly, all :ref:`client libraries ` will use the same @@ -64,17 +64,17 @@ required. .. code-block:: typescript-diff - import edgedb from "edgedb"; + import gel from "gel"; - - const pool = edgedb.createPool("my_instance"); - + const pool = edgedb.createPool(); + - const pool = gel.createPool("my_instance"); + + const pool = gel.createPool(); What do you mean *link*? ^^^^^^^^^^^^^^^^^^^^^^^^ The "link" is just metaphor that makes projects easier to think about; in -practice, it's just a bit of metadata we store in the EdgeDB :ref:`config -directory `. When the CLI or client libraries try to +practice, it's just a bit of metadata we store in the Gel :ref:`config +directory `. When the CLI or client libraries try to connect to an instance, they read the currect directory and cross-reference it against the list of initialized projects. If there's a match, it reads the credentials of the project's associated instance and auto-connects. @@ -83,23 +83,23 @@ How does this work in production? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ It doesn't. Projects are intended as a convenient development tool that make it -easier to develop EdgeDB-backed applications locally. In production, you should +easier to develop Gel-backed applications locally. In production, you should provide instance credentials to your client library of choice using environment variables. See :ref:`Connection parameters ` page for more information. -What's the ``edgedb.toml`` file? +What's the |gel.toml| file? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The most important role of ``edgedb.toml`` is to mark a directory as an +The most important role of |gel.toml| is to mark a directory as an instance-linked project, but it can also specify the server version and the schema directory for a project. The server version value in the generated -``edgedb.toml`` is determined by the EdgeDB version you selected when you ran -:ref:`ref_cli_edgedb_project_init`. +|gel.toml| is determined by the Gel version you selected when you ran +:ref:`ref_cli_gel_project_init`. -Read :ref:`our reference documentation on edgedb.toml -` to learn more. +Read :ref:`our reference documentation on gel.toml ` +to learn more. .. note:: @@ -108,34 +108,34 @@ Read :ref:`our reference documentation on edgedb.toml out `the TOML documentation `_. -How do I use ``edgedb project`` for existing codebases? +How do I use :gelcmd:`project` for existing codebases? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -If you already have an project on your computer that uses EdgeDB, follow these -steps to convert it into an EdgeDB project: +If you already have an project on your computer that uses Gel, follow these +steps to convert it into an Gel project: 1. Navigate into the project directory (the one containing you ``dbschema`` directory). -2. Run ``edgedb project init``. +2. Run :gelcmd:`project init`. 3. When asked for an instance name, enter the name of the existing local instance you use for development. -This will create ``edgedb.toml`` and link your project directory to the +This will create |gel.toml| and link your project directory to the instance. And you're done! Try running some commands without connection flags. Feels good, right? How does this make projects more portable? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Let's say you just cloned a full-stack application that uses EdgeDB. The -project directory already contains an ``edgedb.toml`` file. What do you do? +Let's say you just cloned a full-stack application that uses Gel. The +project directory already contains an |gel.toml| file. What do you do? -Just run ``edgedb project init`` inside the directory! This is the beauty of -``edgedb project``. You don't need to worry about creating an instance with a +Just run :gelcmd:`project init` inside the directory! This is the beauty of +:gelcmd:`project`. You don't need to worry about creating an instance with a particular name, running on a particular port, creating users and passwords, specifying environment variables, or any of the other things that make setting -up local databases hard. Running ``edgedb project init`` will install the -necessary version of EdgeDB (if you don't already have it installed), create an +up local databases hard. Running :gelcmd:`project init` will install the +necessary version of Gel (if you don't already have it installed), create an instance, apply all unapplied migrations. Then you can start up the application and it should work out of the box. @@ -144,63 +144,63 @@ How do I unlink a project? ^^^^^^^^^^^^^^^^^^^^^^^^^^ If you want to remove the link between your project and its linked instance, -run ``edgedb project unlink`` anywhere inside the project. This doesn't affect -the instance, it continues running as before. After unlinking, can run ``edgedb -project init`` inside project again to create or select a new instance. +run :gelcmd:`project unlink` anywhere inside the project. This doesn't affect +the instance, it continues running as before. After unlinking, can run +:gelcmd:`project init` inside project again to create or select a new instance. .. code-block:: bash - $ edgedb project init - No `edgedb.toml` found in `~/path/to/my_project` or above. + $ gel project init + No `gel.toml` found in `~/path/to/my_project` or above. Do you want to initialize a new project? [Y/n] > Y - Specify the name of EdgeDB instance to use with this project + Specify the name of Gel instance to use with this project [default: my_project]: > my_project - Checking EdgeDB versions... - Specify the version of EdgeDB to use with this project [default: 2.x]: - > 2.x + Checking Gel versions... + Specify the version of Gel to use with this project [default: x.x]: + > x.x -How do I use ``edgedb project`` with a non-local instance? +How do I use :gelcmd:`project` with a non-local instance? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Sometimes you may want to work on an EdgeDB instance that is just not in your +Sometimes you may want to work on an Gel instance that is just not in your local development environment, like you may have a second workstation, or you want to test against a staging database shared by the team. -This is totally a valid case and EdgeDB fully supports it! +This is totally a valid case and Gel fully supports it! -Before running ``edgedb project init``, you just need to create a local link to -the remote EdgeDB instance first: +Before running :gelcmd:`project init`, you just need to create a local link to +the remote Gel instance first: -.. TODO: Will need to change this once https://github.com/edgedb/edgedb-cli/issues/1269 is resolved +.. TODO: Will need to change this once https://github.com/geldata/gel-cli/issues/1269 is resolved .. lint-off .. code-block:: bash - $ edgedb instance link + $ gel instance link Specify the host of the server [default: localhost]: > 192.168.4.2 Specify the port of the server [default: 5656]: > 10818 - Specify the database user [default: edgedb]: - > edgedb - Specify the database name [default: edgedb]: - > edgedb + Specify the database user [default: admin]: + > admin + Specify the branch name [default: main]: + > main Unknown server certificate: SHA1:c38a7a90429b033dfaf7a81e08112a9d58d97286. Trust? [y/N] > y - Password for 'edgedb': + Password for 'admin': Specify a new instance name for the remote server [default: 192_168_4_2_10818]: > staging_db Successfully linked to remote instance. To connect run: - edgedb -I staging_db + gel -I staging_db .. lint-on -Then you could run the normal ``edgedb project init`` and use ``staging_db`` as +Then you could run the normal :gelcmd:`project init` and use ``staging_db`` as the instance name. .. note:: diff --git a/docs/reference/protocol/dataformats.rst b/docs/reference/protocol/dataformats.rst index 84669be6089..1f8763f9b15 100644 --- a/docs/reference/protocol/dataformats.rst +++ b/docs/reference/protocol/dataformats.rst @@ -4,7 +4,7 @@ Data wire formats ================= -This section describes the data wire format of standard EdgeDB types. +This section describes the data wire format of standard Gel types. .. _ref_protocol_fmt_array: @@ -406,7 +406,7 @@ std::datetime :eql:type:`std::datetime` values are represented as a 64-bit integer, most sigificant byte first. The value is the number of *microseconds* between the encoded datetime and January 1st 2000, 00:00 UTC. A Unix -timestamp can be converted into an EdgeDB ``datetime`` value using this +timestamp can be converted into an Gel ``datetime`` value using this formula: .. code-block:: c diff --git a/docs/reference/protocol/errors.rst b/docs/reference/protocol/errors.rst index bbff21a29d5..612c11f9af6 100644 --- a/docs/reference/protocol/errors.rst +++ b/docs/reference/protocol/errors.rst @@ -7,14 +7,14 @@ Errors Errors inheritance ================== -Each error in EdgeDB consists of a code, a name, and optionally tags. Errors -in EdgeDB can inherit from other errors. This is denoted by matching code +Each error in Gel consists of a code, a name, and optionally tags. Errors +in Gel can inherit from other errors. This is denoted by matching code prefixes. For example, ``TransactionConflictError`` (``0x_05_03_01_00``) is the parent error for ``TransactionSerializationError`` (``0x_05_03_01_01``) and ``TransactionDeadlockError`` (``0x_05_03_01_02``). The matching prefix here is ``0x_05_03_01``. -When the EdgeDB client expects a more general error and EdgeDB returns a more +When the Gel client expects a more general error and Gel returns a more specific error that inherits from the general error, the check in the client must take this into account. This can be expressed by the ``binary and`` operation or ``&`` opeator in most programming languages: diff --git a/docs/reference/protocol/index.rst b/docs/reference/protocol/index.rst index d1975ca8ae7..c7c86a32c9b 100644 --- a/docs/reference/protocol/index.rst +++ b/docs/reference/protocol/index.rst @@ -4,7 +4,7 @@ Binary protocol =============== -EdgeDB uses a message-based binary protocol for communication between +|Gel| uses a message-based binary protocol for communication between clients and servers. The protocol is supported over TCP/IP. @@ -20,11 +20,11 @@ clients and servers. The protocol is supported over TCP/IP. .. _ref_protocol_connecting: -Connecting to EdgeDB -==================== +Connecting to Gel +================= -The EdgeDB binary protocol has two modes of operation: sockets and HTTP -tunnelling. When connecting to EdgeDB, the client can specify an accepted +The Gel binary protocol has two modes of operation: sockets and HTTP +tunnelling. When connecting to Gel, the client can specify an accepted `ALPN Protocol`_ to use. If the client does not specify an ALPN protocol, HTTP tunnelling is assumed. @@ -45,13 +45,12 @@ HTTP tunnelling differs in a few ways: * Authentication is handled at ``/auth/token``. -.. versionchanged:: _default +* Query execution is handled at ``/branch/{BRANCH}``. - * Query execution is handled at ``/db/{DATABASE}``. - -.. versionchanged:: 5.0 - - * Query execution is handled at ``/branch/{BRANCH}``. + .. note:: + Prior to |Gel| and |EdgeDB| 5.0 *branches* were called *databases*. + If you're making a request against an older version of |EdgeDB| + you should change ``/branch/`` options to ``/db/``. * Transactions are not supported. @@ -74,19 +73,12 @@ The auth payload's format is described by the auth method, usually ``SCRAM-SHA-256``. If the auth method differs from the requested method, the client should abort the authentication attempt. -.. versionchanged:: _default - - Once the :ref:`authentication ` phase is complete, the - final response's body will contain an authorization token used to authenticate - the HTTP connection. The client then sends any following message to - ``/db/{DATABASE}`` with the following headers: -.. versionchanged:: 5.0 - - Once the :ref:`authentication ` phase is complete, the - final response's body will contain an authorization token used to authenticate - the HTTP connection. The client then sends any following message to - ``/branch/{BRANCH}`` with the following headers: +Once the :ref:`authentication ` phase is complete, the +final response's body will contain an authorization token used to authenticate +the HTTP connection. The client then sends any following message to +``/branch/{BRANCH}`` (or ``/db/{DATABASE}`` if you're using a version of +|EdgeDB| < 5) with the following headers: * ``X-EdgeDB-User``: The username specified in the :ref:`connection parameters `. @@ -102,7 +94,7 @@ multiple message can be included in the response body, and should be parsed in order. .. _ALPN Protocol: - https://github.com/edgedb/rfcs/blob/master/text/ + https://github.com/geldata/rfcs/blob/master/text/ 1008-tls-and-alpn.rst#alpn-and-protocol-changes .. _ref_protocol_conventions: @@ -169,7 +161,7 @@ The following data types are used in the descriptions: Message Format ============== -All messages in the EdgeDB wire protocol have the following format: +All messages in the Gel wire protocol have the following format: .. code-block:: c @@ -211,7 +203,7 @@ message and continue as before. Message Flow ============ -There are two main phases in the lifetime of an EdgeDB connection: the +There are two main phases in the lifetime of an Gel connection: the connection phase, and the command phase. The connection phase is responsible for negotiating the protocol and connection parameters, including authentication. The command phase is the regular operation phase where the @@ -239,19 +231,12 @@ the connection if protocol version is unsupported. Server *MUST* send subset of the extensions received in :ref:`ref_protocol_msg_client_handshake` (i.e. it never adds extra ones). -While it's not required by the protocol specification itself, EdgeDB server +While it's not required by the protocol specification itself, Gel server currently requires setting the following params in :ref:`ref_protocol_msg_client_handshake`: -.. versionchanged:: _default - - * ``user`` -- username for authentication - * ``database`` -- database to connect to - -.. versionchanged:: 5.0 - - * ``user`` -- username for authentication - * ``branch`` -- branch to connect to +* ``user`` -- username for authentication +* ``branch`` -- branch to connect to .. _ref_authentication: @@ -354,19 +339,10 @@ are always atomic, they will be executed in an implicit transaction block if no explicit transaction is currently active. Therefore, EdgeQL scripts have limitations on the kinds of EdgeQL commands they can contain: -.. versionchanged:: _default - - * Transaction control commands are not allowed, like ``start transaction``, - ``commit``, ``declare savepoint``, or ``rollback to savepoint``. - * Non-transactional commands, like ``create database`` or - ``configure instance`` are not allowed. - -.. versionchanged:: 5.0 - - * Transaction control commands are not allowed, like ``start transaction``, - ``commit``, ``declare savepoint``, or ``rollback to savepoint``. - * Non-transactional commands, like ``create branch`` or - ``configure instance`` are not allowed. +* Transaction control commands are not allowed, like ``start transaction``, + ``commit``, ``declare savepoint``, or ``rollback to savepoint``. +* Non-transactional commands, like ``create branch``, + ``configure instance``, or ``create database`` are not allowed. In the command phase, the server can be in one of the three main states: @@ -406,7 +382,7 @@ to finish implicit transaction. Restore Flow ------------ -Restore procedure fills up the :versionreplace:`database;5.0:branch` the +Restore procedure fills up the |branch| the client is connected to with the schema and data from the dump file. Flow is the following: diff --git a/docs/reference/protocol/messages.rst b/docs/reference/protocol/messages.rst index 5a94a776b89..f6dac4ffdbd 100644 --- a/docs/reference/protocol/messages.rst +++ b/docs/reference/protocol/messages.rst @@ -292,8 +292,7 @@ Restore Sent by: client. -Initiate restore to the current :versionreplace:`database;5.0:branch`. -See :ref:`ref_protocol_restore_flow`. +Initiate restore to the current |branch|. See :ref:`ref_protocol_restore_flow`. Format: @@ -609,7 +608,7 @@ by the server. .. note:: At the moment, the only SASL authentication method supported - by EdgeDB is ``SCRAM-SHA-256`` + by Gel is ``SCRAM-SHA-256`` (`RFC 7677 `_). The client must select an appropriate authentication method from the list @@ -682,4 +681,4 @@ Format: .. eql:struct:: edb.protocol.Terminate .. _RFC1004: - https://github.com/edgedb/rfcs/blob/master/text/1004-transactions-api.rst + https://github.com/geldata/rfcs/blob/master/text/1004-transactions-api.rst diff --git a/docs/reference/protocol/typedesc.rst b/docs/reference/protocol/typedesc.rst index 5e85962b11a..1c9152e6d7d 100644 --- a/docs/reference/protocol/typedesc.rst +++ b/docs/reference/protocol/typedesc.rst @@ -15,31 +15,20 @@ The type descriptor is essentially a list of type information *blocks*: * *blocks* can reference other *blocks*. While parsing the *blocks*, a database driver can assemble an -*encoder* or a *decoder* of the EdgeDB binary data. +*encoder* or a *decoder* of the Gel binary data. An *encoder* is used to encode objects, native to the driver's runtime, -to binary data that EdgeDB can decode and work with. +to binary data that Gel can decode and work with. -A *decoder* is used to decode data from EdgeDB native format to +A *decoder* is used to decode data from Gel native format to data types native to the driver. -.. versionchanged:: _default - - There is one special type with *type id* of zero: - ``00000000-0000-0000-0000-000000000000``. The describe result of this type - contains zero *blocks*. It's used when a statement returns no meaningful - results, e.g. the ``CREATE DATABASE example`` statement. It is also used - to represent the input descriptor when a query does not receive any - arguments, or the state descriptor for an empty/default state. - -.. versionchanged:: 5.0 - - There is one special type with *type id* of zero: - ``00000000-0000-0000-0000-000000000000``. The describe result of this type - contains zero *blocks*. It's used when a statement returns no meaningful - results, e.g. the ``CREATE BRANCH example`` statement. It is also used to - represent the input descriptor when a query does not receive any arguments, - or the state descriptor for an empty/default state. +There is one special type with *type id* of zero: +``00000000-0000-0000-0000-000000000000``. The describe result of this type +contains zero *blocks*. It's used when a statement returns no meaningful +results, e.g. the ``CREATE BRANCH example`` statement. It is also used to +represent the input descriptor when a query does not receive any arguments, +or the state descriptor for an empty/default state. .. versionadded:: 6.0 @@ -106,7 +95,7 @@ Scalar Type Descriptor }; The descriptor IDs for fundamental scalar types are constant. -The following table lists all EdgeDB fundamental type descriptor IDs: +The following table lists all Gel fundamental type descriptor IDs: .. list-table:: :header-rows: 1 diff --git a/docs/reference/sdl/access_policies.rst b/docs/reference/sdl/access_policies.rst deleted file mode 100644 index c3a19d73c7f..00000000000 --- a/docs/reference/sdl/access_policies.rst +++ /dev/null @@ -1,214 +0,0 @@ -.. versionadded:: 2.0 - -.. _ref_eql_sdl_access_policies: - -=============== -Access Policies -=============== - -This section describes the SDL declarations pertaining to access policies. - -Examples --------- - -Declare a schema where users can only see their own profiles: - -.. code-block:: sdl - :version-lt: 3.0 - - # Declare some global variables to store "current user" - # information. - global current_user_id -> uuid; - global current_user := ( - select User filter .id = global current_user_id - ); - - type User { - required property name -> str; - } - - type Profile { - link owner -> User; - - # Only allow reading to the owner, but also - # ensure that a user cannot set the "owner" link - # to anything but themselves. - access policy owner_only - allow all using (.owner = global current_user) - { errmessage := 'Profile may only be accessed by the owner'; } - } - -.. code-block:: sdl - - # Declare some global variables to store "current user" - # information. - global current_user_id: uuid; - global current_user := ( - select User filter .id = global current_user_id - ); - - type User { - required name: str; - } - - type Profile { - owner: User; - - # Only allow reading to the owner, but also - # ensure that a user cannot set the "owner" link - # to anything but themselves. - access policy owner_only - allow all using (.owner = global current_user); - } - -.. _ref_eql_sdl_access_policies_syntax: - -Syntax ------- - -Define a new access policy corresponding to the :ref:`more explicit DDL -commands `. - -.. sdl:synopsis:: - :version-lt: 3.0 - - # Access policy used inside a type declaration: - access policy - [ when () ] - { allow | deny } [, ... ] - [ using () ] - [ "{" - [ errmessage := value ; ] - [ ] - "}" ] ; - - # where is one of - all - select - insert - delete - update [{ read | write }] - -.. sdl:synopsis:: - - # Access policy used inside a type declaration: - access policy - [ when () ] - { allow | deny } [, ... ] - [ using () ] - [ "{" - [ errmessage := value ; ] - [ ] - "}" ] ; - - # where is one of - all - select - insert - delete - update [{ read | write }] - -Description ------------ - -Access policies are used to implement object-level security and as such they -are defined on object types. In practice the access policies often work -together with :ref:`global variables `. - -Access policies are an opt-in feature, so once at least one access policy is -defined for a given type, all access not explicitly allowed by that policy -becomes forbidden. - -Any sub-type :ref:`extending ` a base type also -inherits all the access policies of the base type. - -The access policy declaration options are as follows: - -:eql:synopsis:`` - The name of the access policy. - -:eql:synopsis:`when ()` - Specifies which objects this policy applies to. The - :eql:synopsis:`` has to be a :eql:type:`bool` expression. - - When omitted, it is assumed that this policy applies to all objects of a - given type. - -:eql:synopsis:`allow` - Indicates that qualifying objects should allow access under this policy. - -:eql:synopsis:`deny` - Indicates that qualifying objects should *not* allow access under this - policy. This flavor supersedes any :eql:synopsis:`allow` policy and can - be used to selectively deny access to a subset of objects that otherwise - explicitly allows accessing them. - -:eql:synopsis:`all` - Apply the policy to all actions. It is exactly equivalent to listing - :eql:synopsis:`select`, :eql:synopsis:`insert`, :eql:synopsis:`delete`, - :eql:synopsis:`update` actions explicitly. - -:eql:synopsis:`select` - Apply the policy to all selection queries. Note that any object that - cannot be selected, cannot be modified either. This makes - :eql:synopsis:`select` the most basic "visibility" policy. - -:eql:synopsis:`insert` - Apply the policy to all inserted objects. If a newly inserted object would - violate this policy, an error is produced instead. - -:eql:synopsis:`delete` - Apply the policy to all objects about to be deleted. If an object does not - allow access under this kind of policy, it is not going to be considered - by any :eql:stmt:`delete` command. - - Note that any object that cannot be selected, cannot be modified either. - -:eql:synopsis:`update read` - Apply the policy to all objects selected for an update. If an object does - not allow access under this kind of policy, it is not visible cannot be - updated. - - Note that any object that cannot be selected, cannot be modified either. - -:eql:synopsis:`update write` - Apply the policy to all objects at the end of an update. If an updated - object violates this policy, an error is produced instead. - - Note that any object that cannot be selected, cannot be modified either. - -:eql:synopsis:`update` - This is just a shorthand for :eql:synopsis:`update read` and - :eql:synopsis:`update write`. - - Note that any object that cannot be selected, cannot be modified either. - -:eql:synopsis:`using ` - Specifies what the policy is with respect to a given eligible (based on - :eql:synopsis:`when` clause) object. The :eql:synopsis:`` has to be - a :eql:type:`bool` expression. The specific meaning of this value also - depends on whether this policy flavor is :eql:synopsis:`allow` or - :eql:synopsis:`deny`. - - The expression must be :ref:`Stable `. - - When omitted, it is assumed that this policy applies to all eligible - objects of a given type. - -.. versionadded:: 3.0 - - :eql:synopsis:`set errmessage := ` - Set a custom error message of :eql:synopsis:`` that is displayed - when this access policy prevents a write action. - -:sdl:synopsis:`` - Set access policy :ref:`annotation ` - to a given *value*. - - -.. list-table:: - :class: seealso - - * - **See also** - * - :ref:`Schema > Access policies ` - * - :ref:`DDL > Access policies ` diff --git a/docs/reference/sdl/aliases.rst b/docs/reference/sdl/aliases.rst deleted file mode 100644 index e0520f98d9c..00000000000 --- a/docs/reference/sdl/aliases.rst +++ /dev/null @@ -1,66 +0,0 @@ -.. _ref_eql_sdl_aliases: - -================== -Expression Aliases -================== - -This section describes the SDL declarations pertaining to -:ref:`expression aliases `. - -Example -------- - -Declare a "UserAlias" that provides additional information for a "User" -via a :ref:`computed link ` "friend_of": - -.. code-block:: sdl - - alias UserAlias := User { - # declare a computed link - friend_of := User.`. - -.. sdl:synopsis:: - - alias := ; - - alias "{" - using ; - [ ] - "}" ; - - -Description ------------ - -This declaration defines a new alias with the following options: - -:eql:synopsis:`` - The name (optionally module-qualified) of an alias to be created. - -:eql:synopsis:`` - The aliased expression. Must be a :ref:`Stable ` - EdgeQL expression. - -The valid SDL sub-declarations are listed below: - -:sdl:synopsis:`` - Set alias :ref:`annotation ` - to a given *value*. - - -.. list-table:: - :class: seealso - - * - **See also** - * - :ref:`Schema > Aliases ` - * - :ref:`DDL > Aliases ` - * - :ref:`Cheatsheets > Aliases ` diff --git a/docs/reference/sdl/annotations.rst b/docs/reference/sdl/annotations.rst deleted file mode 100644 index 495c7c4c8a8..00000000000 --- a/docs/reference/sdl/annotations.rst +++ /dev/null @@ -1,103 +0,0 @@ -.. _ref_eql_sdl_annotations: - -=========== -Annotations -=========== - -This section describes the SDL declarations pertaining to -:ref:`annotations `. - - -Examples --------- - -Declare a new annotation: - -.. code-block:: sdl - - abstract annotation admin_note; - -Specify the value of an annotation for a type: - -.. code-block:: sdl - :version-lt: 3.0 - - type Status { - annotation admin_note := 'system-critical'; - required property name -> str { - constraint exclusive - } - } - -.. code-block:: sdl - - type Status { - annotation admin_note := 'system-critical'; - required name: str { - constraint exclusive - } - } - -.. _ref_eql_sdl_annotations_syntax: - -Syntax ------- - -Define a new annotation corresponding to the :ref:`more explicit DDL -commands `. - -.. sdl:synopsis:: - - # Abstract annotation form: - abstract [ inheritable ] annotation - [ "{" ; [...] "}" ] ; - - # Concrete annotation (same as ) form: - annotation := ; - - -Description ------------ - -There are two forms of annotation declarations: abstract and concrete. -The *abstract annotation* form is used for declaring new kinds of -annotation in a module. The *concrete annotation* declarations are -used as sub-declarations for all other declarations in order to -actually annotate them. - -The annotation declaration options are as follows: - -:eql:synopsis:`abstract` - If specified, the annotation will be *abstract*. - -:eql:synopsis:`inheritable` - If specified, the annotation will be *inheritable*. The - annotations are non-inheritable by default. That is, if a schema - item has an annotation defined on it, the descendants of that - schema item will not automatically inherit the annotation. Normal - inheritance behavior can be turned on by declaring the annotation - with the ``inheritable`` qualifier. This is only valid for *abstract - annotation*. - -:eql:synopsis:`` - The name (optionally module-qualified) of the annotation. - -:eql:synopsis:`` - Any string value that the specified annotation is intended to have - for the given context. - -The only valid SDL sub-declarations are *concrete annotations*: - -:sdl:synopsis:`` - Annotations can also have annotations. Set the *annotation* of the - enclosing annotation to a specific value. - -.. list-table:: - :class: seealso - - * - **See also** - * - :ref:`Schema > Annotations ` - * - :ref:`DDL > Annotations ` - * - :ref:`Cheatsheets > Annotations ` - * - :ref:`Introspection > Object types - ` diff --git a/docs/reference/sdl/constraints.rst b/docs/reference/sdl/constraints.rst deleted file mode 100644 index 7b9d3c706e6..00000000000 --- a/docs/reference/sdl/constraints.rst +++ /dev/null @@ -1,177 +0,0 @@ -.. _ref_eql_sdl_constraints: - -=========== -Constraints -=========== - -This section describes the SDL declarations pertaining to -:ref:`constraints `. - - -Examples --------- - -Declare an *abstract* constraint: - -.. code-block:: sdl - - abstract constraint min_value(min: anytype) { - errmessage := - 'Minimum allowed value for {__subject__} is {min}.'; - - using (__subject__ >= min); - } - -Declare a *concrete* constraint on an integer type: - -.. code-block:: sdl - - scalar type posint64 extending int64 { - constraint min_value(0); - } - -Declare a *concrete* constraint on an object type: - -.. code-block:: sdl - :version-lt: 3.0 - - type Vector { - required property x -> float64; - required property y -> float64; - constraint expression on ( - __subject__.x^2 + __subject__.y^2 < 25 - ); - } - -.. code-block:: sdl - - type Vector { - required x: float64; - required y: float64; - constraint expression on ( - __subject__.x^2 + __subject__.y^2 < 25 - ); - } - -.. _ref_eql_sdl_constraints_syntax: - -Syntax ------- - -Define a constraint corresponding to the :ref:`more explicit DDL -commands `. - -.. sdl:synopsis:: - - [{abstract | delegated}] constraint [ ( [] [, ...] ) ] - [ on ( ) ] - [ except ( ) ] - [ extending [, ...] ] - "{" - [ using ; ] - [ errmessage := ; ] - [ ] - [ ... ] - "}" ; - - # where is: - - [ : ] { | } - - -Description ------------ - -This declaration defines a new constraint with the following options: - -:eql:synopsis:`abstract` - If specified, the constraint will be *abstract*. - -:eql:synopsis:`delegated` - If specified, the constraint is defined as *delegated*, which - means that it will not be enforced on the type it's declared on, - and the enforcement will be delegated to the subtypes of this - type. This is particularly useful for :eql:constraint:`exclusive` - constraints in abstract types. This is only valid for *concrete - constraints*. - -:eql:synopsis:`` - The name (optionally module-qualified) of the new constraint. - -:eql:synopsis:`` - An optional list of constraint arguments. - - For an *abstract constraint* :eql:synopsis:`` optionally - specifies the argument name and :eql:synopsis:`` - specifies the argument type. - - For a *concrete constraint* :eql:synopsis:`` optionally - specifies the argument name and :eql:synopsis:`` - specifies the argument value. The argument value specification must - match the parameter declaration of the abstract constraint. - -:eql:synopsis:`on ( )` - An optional expression defining the *subject* of the constraint. - If not specified, the subject is the value of the schema item on - which the concrete constraint is defined. - - The expression must refer to the original subject of the constraint as - ``__subject__``. The expression must be - :ref:`Immutable `, but may refer to - ``__subject__`` and its properties and links. - - Note also that ```` itself has to - be parenthesized. - -:eql:synopsis:`except ( )` - An optional expression defining a condition to create exceptions - to the constraint. If ```` evaluates to ``true``, - the constraint is ignored for the current subject. If it evaluates - to ``false`` or ``{}``, the constraint applies normally. - - ``except`` may only be declared on object constraints, and is - otherwise follows the same rules as ``on``, above. - -:eql:synopsis:`extending [, ...]` - If specified, declares the *parent* constraints for this abstract - constraint. - -The valid SDL sub-declarations are listed below: - -:eql:synopsis:`using ` - A boolean expression that returns ``true`` for valid data and - ``false`` for invalid data. The expression may refer to the - subject of the constraint as ``__subject__``. This declaration is - only valid for *abstract constraints*. - -:eql:synopsis:`errmessage := ` - An optional string literal defining the error message template - that is raised when the constraint is violated. The template is a - formatted string that may refer to constraint context variables in - curly braces. The template may refer to the following: - - - ``$argname`` -- the value of the specified constraint argument - - ``__subject__`` -- the value of the ``title`` annotation of the - scalar type, property or link on which the constraint is - defined. - - If the content of curly braces does not match any variables, - the curly braces are emitted as-is. They can also be escaped by - using double curly braces. - -:sdl:synopsis:`` - Set constraint :ref:`annotation ` - to a given *value*. - - -.. list-table:: - :class: seealso - - * - **See also** - * - :ref:`Schema > Constraints ` - * - :ref:`DDL > Constraints ` - * - :ref:`Introspection > Constraints - ` - * - :ref:`Standard Library > Constraints ` - * - `Tutorial > Advanced EdgeQL > Constraints - `_ diff --git a/docs/reference/sdl/extensions.rst b/docs/reference/sdl/extensions.rst deleted file mode 100644 index d73ded8d7c9..00000000000 --- a/docs/reference/sdl/extensions.rst +++ /dev/null @@ -1,44 +0,0 @@ -.. _ref_eql_sdl_extensions: - -========== -Extensions -========== - -This section describes the SDL commands pertaining to -:ref:`extensions `. - - -Syntax ------- - -Declare that the current schema enables a particular extension. - -.. sdl:synopsis:: - - using extension ";" - - -Description ------------ - -Extension declaration must be outside any :ref:`module block -` since extensions affect the entire database and -not a specific module. - - -Examples --------- - -Enable :ref:`GraphQL ` extension for the current -schema: - -.. code-block:: sdl - - using extension graphql; - -Enable :ref:`EdgeQL over HTTP ` extension for the -current database: - -.. code-block:: sdl - - using extension edgeql_http; diff --git a/docs/reference/sdl/functions.rst b/docs/reference/sdl/functions.rst deleted file mode 100644 index 916e858bd27..00000000000 --- a/docs/reference/sdl/functions.rst +++ /dev/null @@ -1,190 +0,0 @@ -.. _ref_eql_sdl_functions: - -========= -Functions -========= - -This section describes the SDL declarations pertaining to -:ref:`functions `. - - -Example -------- - -Declare a custom function that concatenates the length of a string to -the end of the that string: - -.. code-block:: sdl - - function foo(s: str) -> str - using ( - select s ++ len(a) - ); - -.. _ref_eql_sdl_functions_syntax: - -Syntax ------- - -Define a new function corresponding to the :ref:`more explicit DDL -commands `. - -.. sdl:synopsis:: - - function ([ ] [, ... ]) -> - using ( ); - - function ([ ] [, ... ]) -> - using ; - - function ([ ] [, ... ]) -> - "{" - [ ] - [ volatility := {'Immutable' | 'Stable' | 'Volatile' | 'Modifying'} ] - [ using ( ) ; ] - [ using ; ] - [ ... ] - "}" ; - - # where is: - - [ ] : [ ] [ = ] - - # is: - - [ { variadic | named only } ] - - # is: - - [ { set of | optional } ] - - # and is: - - [ ] - - -Description ------------ - - - -This declaration defines a new constraint with the following options: - -:eql:synopsis:`` - The name (optionally module-qualified) of the function to create. - -:eql:synopsis:`` - The kind of an argument: ``variadic`` or ``named only``. - - If not specified, the argument is called *positional*. - - The ``variadic`` modifier indicates that the function takes an - arbitrary number of arguments of the specified type. The passed - arguments will be passed as as array of the argument type. - Positional arguments cannot follow a ``variadic`` argument. - ``variadic`` parameters cannot have a default value. - - The ``named only`` modifier indicates that the argument can only - be passed using that specific name. Positional arguments cannot - follow a ``named only`` argument. - -:eql:synopsis:`` - The name of an argument. If ``named only`` modifier is used this - argument *must* be passed using this name only. - -.. _ref_sdl_function_typequal: - -:eql:synopsis:`` - The type qualifier: ``set of`` or ``optional``. - - The ``set of`` qualifier indicates that the function is taking the - argument as a *whole set*, as opposed to being called on the input - product element-by-element. - - User defined functions can not use ``set of`` arguments. - - The ``optional`` qualifier indicates that the function will be called - if the argument is an empty set. The default behavior is to return - an empty set if the argument is not marked as ``optional``. - -:eql:synopsis:`` - The data type of the function's arguments - (optionally module-qualified). - -:eql:synopsis:`` - An expression to be used as default value if the parameter is not - specified. The expression has to be of a type compatible with the - type of the argument. - -.. _ref_sdl_function_rettype: - -:eql:synopsis:`` - The return data type (optionally module-qualified). - - The ``set of`` modifier indicates that the function will return - a non-singleton set. - - The ``optional`` qualifier indicates that the function may return - an empty set. - -The valid SDL sub-declarations are listed below: - -:eql:synopsis:`volatility := {'Immutable' | 'Stable' | 'Volatile' | 'Modifying'}` - Function volatility determines how aggressively the compiler can - optimize its invocations. - - If not explicitly specified the function volatility is - :ref:`inferred ` from the function body. - - * An ``Immutable`` function cannot modify the database and is - guaranteed to return the same results given the same arguments - *in all statements*. - - * A ``Stable`` function cannot modify the database and is - guaranteed to return the same results given the same - arguments *within a single statement*. - - * A ``Volatile`` function cannot modify the database and can return - different results on successive calls with the same arguments. - - * A ``Modifying`` function can modify the database and can return - different results on successive calls with the same arguments. - -:eql:synopsis:`using ( )` - Specified the body of the function. :eql:synopsis:`` is an - arbitrary EdgeQL expression. - -:eql:synopsis:`using ` - A verbose version of the :eql:synopsis:`using` clause that allows - to specify the language of the function body. - - * :eql:synopsis:`` is the name of the language that - the function is implemented in. Currently can only be ``edgeql``. - - * :eql:synopsis:`` is a string constant defining - the function. It is often helpful to use - :ref:`dollar quoting ` - to write the function definition string. - -:sdl:synopsis:`` - Set function :ref:`annotation ` - to a given *value*. - -The function name must be distinct from that of any existing function -with the same argument types in the same module. Functions of -different argument types can share a name, in which case the functions -are called *overloaded functions*. - - -.. list-table:: - :class: seealso - - * - **See also** - * - :ref:`Schema > Functions ` - * - :ref:`DDL > Functions ` - * - :ref:`Reference > Function calls ` - * - :ref:`Introspection > Functions ` - * - :ref:`Cheatsheets > Functions ` - * - `Tutorial > Advanced EdgeQL > User-Defined Functions - `_ - diff --git a/docs/reference/sdl/future.rst b/docs/reference/sdl/future.rst deleted file mode 100644 index ad0673d2fbf..00000000000 --- a/docs/reference/sdl/future.rst +++ /dev/null @@ -1,37 +0,0 @@ -.. _ref_eql_sdl_future: - -=============== -Future Behavior -=============== - -This section describes the SDL commands pertaining to -:ref:`future `. - - -Syntax ------- - -Declare that the current schema enables a particular future behavior. - -.. sdl:synopsis:: - - using future ";" - - -Description ------------ - -Future behavior declaration must be outside any :ref:`module block -` since this behavior affects the entire database and not -a specific module. - - -Examples --------- - -Enable simpler non-recursive access policy behavior :ref:`non-recursive access -policy ` for the current schema: - -.. code-block:: sdl - - using extension nonrecursive_access_policies; diff --git a/docs/reference/sdl/globals.rst b/docs/reference/sdl/globals.rst deleted file mode 100644 index 1587c6e4ac7..00000000000 --- a/docs/reference/sdl/globals.rst +++ /dev/null @@ -1,151 +0,0 @@ -.. versionadded:: 2.0 - -.. _ref_eql_sdl_globals: - -======= -Globals -======= - -This section describes the SDL commands pertaining to global variables. - -Examples --------- - -Declare a new global variable: - -.. code-block:: sdl - - global current_user_id -> uuid; - global current_user := ( - select User filter .id = global current_user_id - ); - -Set the global variable to a specific value using :ref:`session-level commands -`: - -.. code-block:: edgeql - - set global current_user_id := - '00ea8eaa-02f9-11ed-a676-6bd11cc6c557'; - -Use the computed global variable that is based on the value that was just set: - -.. code-block:: edgeql - - select global current_user { name }; - -:ref:`Reset ` the global variable to -its default value: - -.. code-block:: edgeql - - reset global user_id; - - -.. _ref_eql_sdl_globals_syntax: - -Syntax ------- - -Define a new global variable corresponding to the :ref:`more explicit DDL -commands `. - -.. sdl:synopsis:: - - - # Global variable declaration: - [{required | optional}] [single] - global -> - [ "{" - [ default := ; ] - [ ] - ... - "}" ] - - # Computed global variable declaration: - [{required | optional}] [{single | multi}] - global := ; - - -Description ------------ - -There two different forms of ``global`` declaration, as shown in the syntax -synopsis above. The first form is for defining a ``global`` variable that can -be :ref:`set ` in a session. The second -form is not directly set, but instead it is *computed* based on an expression, -potentially deriving its value from other global variables. - -The following options are available: - -:eql:synopsis:`required` - If specified, the global variable is considered *required*. It is an - error for this variable to have an empty value. If a global variable is - declared *required*, it must also declare a *default* value. - -:eql:synopsis:`optional` - This is the default qualifier assumed when no qualifier is specified, but - it can also be specified explicitly. The global variable is considered - *optional*, i.e. it is possible for the variable to have an empty value. - -:eql:synopsis:`multi` - Specifies that the global variable may have a set of values. Only - *computed* global variables can have this qualifier. - -:eql:synopsis:`single` - Specifies that the global variable must have at most a *single* value. It - is assumed that a global variable is ``single`` if nether ``multi`` nor - ``single`` qualifier is specified. All non-computed global variables must - be *single*. - -:eql:synopsis:`` - Specifies the name of the global variable. The name has to be either - fully-qualified with the module name it belongs to or it will be assumed - to belong to the module in which it appears. - -:eql:synopsis:`` - The type must be a valid :ref:`type expression ` - denoting a non-abstract scalar or a container type. - -:eql:synopsis:` := ` - Defines a *computed* global variable. - - The provided expression must be a :ref:`Stable ` - EdgeQL expression. It can refer to other global variables. - - The type of a *computed* global variable is not limited to - scalar and container types, but also includes object types. So it is - possible to use that to define a global object variable based on an - another global scalar variable. - - For example: - - .. code-block:: sdl - - # Global scalar variable that can be set in a session: - global current_user_id -> uuid; - # Global computed object based on that: - global current_user := ( - select User filter .id = global current_user_id - ); - - -The valid SDL sub-declarations are listed below: - -:eql:synopsis:`default := ` - Specifies the default value for the global variable as an EdgeQL - expression. The default value is used by the session if the value was not - explicitly specified or by the client or was reset with the :ref:`reset - ` command. - -:sdl:synopsis:`` - Set global variable :ref:`annotation ` - to a given *value*. - - -.. list-table:: - :class: seealso - - * - **See also** - * - :ref:`Schema > Globals ` - * - :ref:`DDL > Globals ` diff --git a/docs/reference/sdl/index.rst b/docs/reference/sdl/index.rst index cca47ba4927..266329183d2 100644 --- a/docs/reference/sdl/index.rst +++ b/docs/reference/sdl/index.rst @@ -6,24 +6,15 @@ SDL :edb-alt-title: Schema Definition Language -This section describes the high-level language used to define EdgeDB -schema. It is called the EdgeDB *schema definition language* or +This section describes the high-level language used to define Gel +schema. It is called the Gel *schema definition language* or *SDL*. There's a correspondence between this declarative high-level language and the imperative low-level :ref:`DDL `. -.. versionchanged:: _default - - SDL is a declarative language optimized for human readability and - expressing the state of the EdgeDB schema without getting into the details - of how to arrive at that state. Each *SDL* block represents the complete - schema state for a given :ref:`database `. - -.. versionchanged:: 5.0 - - SDL is a declarative language optimized for human readability and - expressing the state of the EdgeDB schema without getting into the details - of how to arrive at that state. Each *SDL* block represents the complete - schema state for a given :ref:`branch `. +SDL is a declarative language optimized for human readability and +expressing the state of the Gel schema without getting into the details +of how to arrive at that state. Each *SDL* block represents the complete +schema state for a given :ref:`branch `. Syntactically, an SDL declaration mirrors the ``create`` DDL for the corresponding entity, but with all of the ``create`` and ``set`` @@ -31,62 +22,12 @@ keywords omitted. The typical SDL structure is to use :ref:`module blocks ` with the rest of the declarations being nested in their respective modules. -.. versionadded:: 3.0 - - EdgeDB 3.0 introduces a new SDL syntax which diverges slightly from DDL. - The old SDL syntax is still fully supported, but the new syntax allows for - cleaner and less verbose expression of your schemas. - - * Pointers no longer require an arrow (``->``). You may instead use a colon - after the name of the link or property. - * The ``link`` and ``property`` keywords are now optional for non-computed - pointers when the target type is explicitly specified. - - That means that this type definition: - - .. code-block:: sdl - - type User { - required property email -> str; - } - - could be replaced with this equivalent one in EdgeDB 3+: - - .. code-block:: sdl - - type User { - required email: str; - } - - When reading our documentation, the version selection dropdown will update - the syntax of most SDL examples to the preferred syntax for the version - selected. This is only true for versioned sections of the documentation. - - Since SDL is declarative in nature, the specific order of declarations of module blocks or individual items does not matter. -The built-in :ref:`migration tools` expect +The built-in :ref:`migration tools` expect the schema to be given in SDL format. For example: -.. code-block:: sdl - :version-lt: 3.0 - - # "default" module block - module default { - type Movie { - required property title -> str; - # the year of release - property year -> int64; - required link director -> Person; - required multi link actors -> Person; - } - type Person { - required property first_name -> str; - required property last_name -> str; - } - } - .. code-block:: sdl # "default" module block @@ -110,22 +51,6 @@ declarations must use :ref:`fully-qualified names to their respective modules. For example, the following is equivalent to the previous migration: -.. code-block:: sdl - :version-lt: 3.0 - - # no module block - type default::Movie { - required property title -> str; - # the year of release - property year -> int64; - required link director -> default::Person; - required multi link actors -> default::Person; - } - type default::Person { - required property first_name -> str; - required property last_name -> str; - } - .. code-block:: sdl # no module block @@ -145,19 +70,4 @@ to the previous migration: :maxdepth: 3 :hidden: - modules - objects - scalars - links properties - aliases - indexes - constraints - annotations - globals - access_policies - functions - triggers - mutation_rewrites - extensions - future diff --git a/docs/reference/sdl/indexes.rst b/docs/reference/sdl/indexes.rst deleted file mode 100644 index 00a267ad242..00000000000 --- a/docs/reference/sdl/indexes.rst +++ /dev/null @@ -1,91 +0,0 @@ -.. _ref_eql_sdl_indexes: - -======= -Indexes -======= - -This section describes the SDL declarations pertaining to -:ref:`indexes `. - - -Example -------- - -Declare an index for a "User" based on the "name" property: - -.. code-block:: sdl - :version-lt: 3.0 - - type User { - required property name -> str; - property address -> str; - - multi link friends -> User; - - # define an index for User based on name - index on (.name) { - annotation title := 'User name index'; - } - } - -.. code-block:: sdl - - type User { - required name: str; - address: str; - - multi friends: User; - - # define an index for User based on name - index on (.name) { - annotation title := 'User name index'; - } - } - -.. _ref_eql_sdl_indexes_syntax: - -Syntax ------- - -Define a new index corresponding to the :ref:`more explicit DDL -commands `. - -.. sdl:synopsis:: - - index on ( ) - [ except ( ) ] - [ "{" "}" ] ; - - -Description ------------ - -This declaration defines a new index with the following options: - -:sdl:synopsis:`on ( )` - The specific expression for which the index is made. - - The expression must be :ref:`Immutable ` but may - refer to the indexed object's properties and links. - - Note also that ```` itself has to be parenthesized. - -:eql:synopsis:`except ( )` - An optional expression defining a condition to create exceptions - to the index. If ```` evaluates to ``true``, - the object is omitted from the index. If it evaluates - to ``false`` or ``{}``, it appears in the index. - -The valid SDL sub-declarations are listed below: - -:sdl:synopsis:`` - Set index :ref:`annotation ` - to a given *value*. - -.. list-table:: - :class: seealso - - * - **See also** - * - :ref:`Schema > Indexes ` - * - :ref:`DDL > Indexes ` - * - :ref:`Introspection > Indexes ` diff --git a/docs/reference/sdl/links.rst b/docs/reference/sdl/links.rst deleted file mode 100644 index f90a05ff702..00000000000 --- a/docs/reference/sdl/links.rst +++ /dev/null @@ -1,332 +0,0 @@ -.. _ref_eql_sdl_links: - -===== -Links -===== - -This section describes the SDL declarations pertaining to -:ref:`links `. - - -Examples --------- - -Declare an *abstract* link "friends_base" with a helpful title: - -.. code-block:: sdl - - abstract link friends_base { - # declare a specific title for the link - annotation title := 'Close contacts'; - } - -Declare a *concrete* link "friends" within a "User" type: - -.. code-block:: sdl - :version-lt: 3.0 - - type User { - required property name -> str; - property address -> str; - # define a concrete link "friends" - multi link friends extending friends_base -> User; - - index on (__subject__.name); - } - -.. code-block:: sdl - - type User { - required name: str; - address: str; - # define a concrete link "friends" - multi friends: User { - extending friends_base; - }; - - index on (__subject__.name); - } - -.. _ref_eql_sdl_links_overloading: - -Overloading -~~~~~~~~~~~ - -Any time that the SDL declaration refers to an inherited link that is -being overloaded (by adding more constraints or changing the target -type, for example), the ``overloaded`` keyword must be used. This is -to prevent unintentional overloading due to name clashes: - -.. code-block:: sdl - :version-lt: 3.0 - - abstract type Friendly { - # this type can have "friends" - multi link friends -> Friendly; - } - - type User extending Friendly { - # overload the link target to be User, specifically - overloaded multi link friends -> User; - # ... other links and properties - } - -.. code-block:: sdl - - abstract type Friendly { - # this type can have "friends" - multi friends: Friendly; - } - - type User extending Friendly { - # overload the link target to be User, specifically - overloaded multi friends: User; - # ... other links and properties - } - -.. _ref_eql_sdl_links_syntax: - -Syntax ------- - -Define a new link corresponding to the :ref:`more explicit DDL -commands `. - -.. sdl:synopsis:: - :version-lt: 3.0 - - # Concrete link form used inside type declaration: - [ overloaded ] [{required | optional}] [{single | multi}] - link - [ extending [, ...] ] -> - [ "{" - [ default := ; ] - [ readonly := {true | false} ; ] - [ on target delete ; ] - [ on source delete ; ] - [ ] - [ ] - [ ] - ... - "}" ] - - - # Computed link form used inside type declaration: - [{required | optional}] [{single | multi}] - link := ; - - # Computed link form used inside type declaration (extended): - [ overloaded ] [{required | optional}] [{single | multi}] - link - [ extending [, ...] ] [-> ] - [ "{" - using () ; - [ ] - [ ] - ... - "}" ] - - # Abstract link form: - abstract link [extending [, ...]] - [ "{" - [ readonly := {true | false} ; ] - [ ] - [ ] - [ ] - [ ] - ... - "}" ] - -.. sdl:synopsis:: - :version-lt: 4.0 - - # Concrete link form used inside type declaration: - [ overloaded ] [{required | optional}] [{single | multi}] - link - [ extending [, ...] ] -> - [ "{" - [ default := ; ] - [ readonly := {true | false} ; ] - [ on target delete ; ] - [ on source delete ; ] - [ ] - [ ] - [ ] - ... - "}" ] - - - # Computed link form used inside type declaration: - [{required | optional}] [{single | multi}] - link := ; - - # Computed link form used inside type declaration (extended): - [ overloaded ] [{required | optional}] [{single | multi}] - link - [ extending [, ...] ] [-> ] - [ "{" - using () ; - [ ] - [ ] - ... - "}" ] - - # Abstract link form: - abstract link [extending [, ...]] - [ "{" - [ readonly := {true | false} ; ] - [ ] - [ ] - [ ] - [ ] - ... - "}" ] - -.. sdl:synopsis:: - - # Concrete link form used inside type declaration: - [ overloaded ] [{required | optional}] [{single | multi}] - [ link ] : - [ "{" - [ extending [, ...] ; ] - [ default := ; ] - [ readonly := {true | false} ; ] - [ on target delete ; ] - [ on source delete ; ] - [ ] - [ ] - [ ] - ... - "}" ] - - - # Computed link form used inside type declaration: - [{required | optional}] [{single | multi}] - [ link ] := ; - - # Computed link form used inside type declaration (extended): - [ overloaded ] [{required | optional}] [{single | multi}] - link [: ] - [ "{" - using () ; - [ extending [, ...] ; ] - [ ] - [ ] - ... - "}" ] - - # Abstract link form: - abstract link - [ "{" - [extending [, ...] ; ] - [ readonly := {true | false} ; ] - [ ] - [ ] - [ ] - [ ] - ... - "}" ] - - -Description ------------ - -There are several forms of link declaration, as shown in the syntax synopsis -above. The first form is the canonical definition form, the second form is used -for defining a :ref:`computed link `, and the last form -is used to define an abstract link. The abstract form allows declaring the link -directly inside a :ref:`module `. Concrete link forms are -always used as sub-declarations of an :ref:`object type -`. - -The following options are available: - -:eql:synopsis:`overloaded` - If specified, indicates that the link is inherited and that some - feature of it may be altered in the current object type. It is an - error to declare a link as *overloaded* if it is not inherited. - -:eql:synopsis:`required` - If specified, the link is considered *required* for the parent - object type. It is an error for an object to have a required - link resolve to an empty value. Child links **always** inherit - the *required* attribute, i.e it is not possible to make a - required link non-required by extending it. - -:eql:synopsis:`optional` - This is the default qualifier assumed when no qualifier is - specified, but it can also be specified explicitly. The link is - considered *optional* for the parent object type, i.e. it is - possible for the link to resolve to an empty value. - -:eql:synopsis:`multi` - Specifies that there may be more than one instance of this link - in an object, in other words, ``Object.link`` may resolve to a set - of a size greater than one. - -:eql:synopsis:`single` - Specifies that there may be at most *one* instance of this link - in an object, in other words, ``Object.link`` may resolve to a set - of a size not greater than one. ``single`` is assumed if nether - ``multi`` nor ``single`` qualifier is specified. - -:eql:synopsis:`extending [, ...]` - Optional clause specifying the *parents* of the new link item. - - Use of ``extending`` creates a persistent schema relationship - between the new link and its parents. Schema modifications - to the parent(s) propagate to the child. - - If the same *property* name exists in more than one parent, or - is explicitly defined in the new link and at least one parent, - then the data types of the property targets must be *compatible*. - If there is no conflict, the link properties are merged to form a - single property in the new link item. - - .. versionadded:: 3.0 - - As of EdgeDB 3.0, the ``extending`` clause is now a sub-declaration of - the link and included inside the curly braces rather than an option as - in earlier versions. - -:eql:synopsis:`` - The type must be a valid :ref:`type expression ` - denoting an object type. - -The valid SDL sub-declarations are listed below: - -:eql:synopsis:`default := ` - Specifies the default value for the link as an EdgeQL expression. - The default value is used in an ``insert`` statement if an explicit - value for this link is not specified. - - The expression must be :ref:`Stable `. - -:eql:synopsis:`readonly := {true | false}` - If ``true``, the link is considered *read-only*. Modifications - of this link are prohibited once an object is created. All of the - derived links **must** preserve the original *read-only* value. - -:sdl:synopsis:`` - Set link :ref:`annotation ` - to a given *value*. - -:sdl:synopsis:`` - Define a concrete :ref:`property ` on the link. - -:sdl:synopsis:`` - Define a concrete :ref:`constraint ` on the link. - -:sdl:synopsis:`` - Define an :ref:`index ` for this abstract - link. Note that this index can only refer to link properties. - - -.. list-table:: - :class: seealso - - * - **See also** - * - :ref:`Schema > Links ` - * - :ref:`DDL > Links ` - * - :ref:`Introspection > Object types - ` diff --git a/docs/reference/sdl/modules.rst b/docs/reference/sdl/modules.rst deleted file mode 100644 index bb8068dffe1..00000000000 --- a/docs/reference/sdl/modules.rst +++ /dev/null @@ -1,165 +0,0 @@ -.. _ref_eql_sdl_modules: - -======= -Modules -======= - -This section describes the SDL commands pertaining to -:ref:`modules `. - - -Example -------- - -Declare an empty module: - -.. code-block:: sdl - - module my_module {} - - -Declare a module with some content: - -.. code-block:: sdl - :version-lt: 3.0 - - module my_module { - type User { - required property name -> str; - } - } - -.. code-block:: sdl - - module my_module { - type User { - required name: str; - } - } - -Syntax ------- - -Define a module corresponding to the :ref:`more explicit DDL -commands `. - -.. sdl:synopsis:: - - module "{" - [ ] - ... - "}" - -.. versionadded:: 3.0 - - Define a nested module. - - .. sdl:synopsis:: - - module "{" - [ ] - module "{" - [ ] - "}" - ... - "}" - - -Description ------------ - -The module block declaration defines a new module similar to the -:eql:stmt:`create module` command, but it also allows putting the -module content as nested declarations: - -:sdl:synopsis:`` - Define various schema items that belong to this module. - -Unlike :eql:stmt:`create module` command, a module block with the -same name can appear multiple times in an SDL document. In that case -all blocks with the same name are merged into a single module under -that name. For example: - -.. code-block:: sdl - :version-lt: 3.0 - - module my_module { - abstract type Named { - required property name -> str; - } - } - - module my_module { - type User extending Named; - } - -.. code-block:: sdl - - module my_module { - abstract type Named { - required name: str; - } - } - - module my_module { - type User extending Named; - } - -The above is equivalent to: - -.. code-block:: sdl - :version-lt: 3.0 - - module my_module { - abstract type Named { - required property name -> str; - } - - type User extending Named; - } - -.. code-block:: sdl - - module my_module { - abstract type Named { - required name: str; - } - - type User extending Named; - } - -Typically, in the documentation examples of SDL the *module block* is -omitted and instead its contents are described without assuming which -specific module they belong to. - -It's also possible to declare modules implicitly. In this style SDL -declaration uses :ref:`fully-qualified -name` for the item that is being -declared. The *module* part of the *fully-qualified* name implies -that a module by that name will be automatically created in the -schema. The following declaration is equivalent to the previous -examples, but it declares module ``my_module`` implicitly: - -.. code-block:: sdl - :version-lt: 3.0 - - abstract type my_module::Named { - required property name -> str; - } - - type my_module::User extending my_module::Named; - -.. code-block:: sdl - - abstract type my_module::Named { - required name: str; - } - - type my_module::User extending my_module::Named; - -.. versionadded:: 3.0 - - A module block can be nested inside another module block to create a nested - module. If you want reference an entity in a nested module by its - fully-qualified name, you will need to reference all of the containing - modules' names: ``::::`` diff --git a/docs/reference/sdl/mutation_rewrites.rst b/docs/reference/sdl/mutation_rewrites.rst deleted file mode 100644 index 359526335ed..00000000000 --- a/docs/reference/sdl/mutation_rewrites.rst +++ /dev/null @@ -1,66 +0,0 @@ -.. versionadded:: 3.0 - -.. _ref_eql_sdl_mutation_rewrites: - -================= -Mutation rewrites -================= - -This section describes the SDL declarations pertaining to -:ref:`mutation rewrites `. - - -Example -------- - -Declare two mutation rewrites: one that sets a ``created`` property when a new -object is inserted and one that sets a ``modified`` property on each update: - -.. code-block:: sdl - - type User { - created: datetime { - rewrite insert using (datetime_of_statement()); - } - modified: datetime { - rewrite update using (datetime_of_statement()); - } - }; - -.. _ref_eql_sdl_mutation_rewrites_syntax: - -Syntax ------- - -Define a new mutation rewrite corresponding to the :ref:`more explicit DDL -commands `. - -.. sdl:synopsis:: - - rewrite {insert | update} [, ...] - using - -Mutation rewrites must be defined inside a property or link block. - - -Description ------------ - -This declaration defines a new trigger with the following options: - -:eql:synopsis:`insert | update [, ...]` - The query type (or types) the rewrite runs on. Separate multiple values - with commas to invoke the same rewrite for multiple types of queries. - -:eql:synopsis:`` - The expression to be evaluated to produce the new value of the property. - - -.. list-table:: - :class: seealso - - * - **See also** - * - :ref:`Schema > Mutation rewrites ` - * - :ref:`DDL > Mutation rewrites ` - * - :ref:`Introspection > Mutation rewrites - ` diff --git a/docs/reference/sdl/objects.rst b/docs/reference/sdl/objects.rst deleted file mode 100644 index cc9b12cf519..00000000000 --- a/docs/reference/sdl/objects.rst +++ /dev/null @@ -1,165 +0,0 @@ -.. _ref_eql_sdl_object_types: - -============ -Object Types -============ - -This section describes the SDL declarations pertaining to -:ref:`object types `. - - -Example -------- - -Consider a ``User`` type with a few properties: - -.. code-block:: sdl - :version-lt: 3.0 - - type User { - # define some properties and a link - required property name -> str; - property address -> str; - - multi link friends -> User; - - # define an index for User based on name - index on (__subject__.name); - } - -.. code-block:: sdl - - type User { - # define some properties and a link - required name: str; - address: str; - - multi friends: User; - - # define an index for User based on name - index on (__subject__.name); - } - -.. _ref_eql_sdl_object_types_inheritance: - -An alternative way to define the same ``User`` type could be by using -abstract types. These abstract types can then be re-used in other type -definitions as well: - -.. code-block:: sdl - :version-lt: 3.0 - - abstract type Named { - required property name -> str; - } - - abstract type HasAddress { - property address -> str; - } - - type User extending Named, HasAddress { - # define some user-specific properties and a link - multi link friends -> User; - - # define an index for User based on name - index on (__subject__.name); - } - -.. code-block:: sdl - - abstract type Named { - required name: str; - } - - abstract type HasAddress { - address: str; - } - - type User extending Named, HasAddress { - # define some user-specific properties and a link - multi friends: User; - - # define an index for User based on name - index on (__subject__.name); - } - -Introducing abstract types opens up the possibility of -:ref:`polymorphic queries `. - - -.. _ref_eql_sdl_object_types_syntax: - -Syntax ------- - -Define a new object type corresponding to the :ref:`more explicit DDL -commands `. - -.. sdl:synopsis:: - - [abstract] type [extending [, ...] ] - [ "{" - [ ] - [ ] - [ ] - [ ] - [ ] - ... - "}" ] - -Description ------------ - -This declaration defines a new object type with the following options: - -:eql:synopsis:`abstract` - If specified, the created type will be *abstract*. - -:eql:synopsis:`` - The name (optionally module-qualified) of the new type. - -:eql:synopsis:`extending [, ...]` - Optional clause specifying the *supertypes* of the new type. - - Use of ``extending`` creates a persistent type relationship - between the new subtype and its supertype(s). Schema modifications - to the supertype(s) propagate to the subtype. - - References to supertypes in queries will also include objects of - the subtype. - - If the same *link* name exists in more than one supertype, or - is explicitly defined in the subtype and at least one supertype, - then the data types of the link targets must be *compatible*. - If there is no conflict, the links are merged to form a single - link in the new type. - -These sub-declarations are allowed in the ``Type`` block: - -:sdl:synopsis:`` - Set object type :ref:`annotation ` - to a given *value*. - -:sdl:synopsis:`` - Define a concrete :ref:`property ` for this object type. - -:sdl:synopsis:`` - Define a concrete :ref:`link ` for this object type. - -:sdl:synopsis:`` - Define a concrete :ref:`constraint ` for this - object type. - -:sdl:synopsis:`` - Define an :ref:`index ` for this object type. - - -.. list-table:: - :class: seealso - - * - **See also** - * - :ref:`Schema > Object types ` - * - :ref:`DDL > Object types ` - * - :ref:`Introspection > Object types - ` - * - :ref:`Cheatsheets > Object types ` diff --git a/docs/reference/sdl/properties.rst b/docs/reference/sdl/properties.rst index 42817e68da4..a835fb0a964 100644 --- a/docs/reference/sdl/properties.rst +++ b/docs/reference/sdl/properties.rst @@ -22,19 +22,6 @@ Declare an *abstract* property "address_base" with a helpful title: Declare *concrete* properties "name" and "address" within a "User" type: -.. code-block:: sdl - :version-lt: 3.0 - - type User { - # define concrete properties - required property name -> str; - property address extending address_base -> str; - - multi link friends -> User; - - index on (__subject__.name); - } - .. code-block:: sdl type User { @@ -54,19 +41,6 @@ is being overloaded (by adding more constraints, for example), the ``overloaded`` keyword must be used. This is to prevent unintentional overloading due to name clashes: -.. code-block:: sdl - :version-lt: 3.0 - - abstract type Named { - property name -> str; - } - - type User extending Named { - # define concrete properties - overloaded required property name -> str; - # ... other links and properties - } - .. code-block:: sdl abstract type Named { @@ -87,82 +61,6 @@ Syntax Define a new property corresponding to the :ref:`more explicit DDL commands `. -.. sdl:synopsis:: - :version-lt: 3.0 - - # Concrete property form used inside type declaration: - [ overloaded ] [{required | optional}] [{single | multi}] - property - [ extending [, ...] ] -> - [ "{" - [ default := ; ] - [ readonly := {true | false} ; ] - [ ] - [ ] - ... - "}" ] - - # Computed property form used inside type declaration: - [{required | optional}] [{single | multi}] - property := ; - - # Computed property form used inside type declaration (extended): - [ overloaded ] [{required | optional}] [{single | multi}] - property - [ extending [, ...] ] [-> ] - [ "{" - using () ; - [ ] - [ ] - ... - "}" ] - - # Abstract property form: - abstract property [::] [extending [, ...]] - [ "{" - [ readonly := {true | false} ; ] - [ ] - ... - "}" ] - -.. sdl:synopsis:: - :version-lt: 4.0 - - # Concrete property form used inside type declaration: - [ overloaded ] [{required | optional}] [{single | multi}] - property - [ extending [, ...] ] -> - [ "{" - [ default := ; ] - [ readonly := {true | false} ; ] - [ ] - [ ] - ... - "}" ] - - # Computed property form used inside type declaration: - [{required | optional}] [{single | multi}] - property := ; - - # Computed property form used inside type declaration (extended): - [ overloaded ] [{required | optional}] [{single | multi}] - property - [ extending [, ...] ] [-> ] - [ "{" - using () ; - [ ] - [ ] - ... - "}" ] - - # Abstract property form: - abstract property [::] [extending [, ...]] - [ "{" - [ readonly := {true | false} ; ] - [ ] - ... - "}" ] - .. sdl:synopsis:: # Concrete property form used inside type declaration: @@ -253,12 +151,6 @@ The following options are available: between the new property and its parents. Schema modifications to the parent(s) propagate to the child. - .. versionadded:: 3.0 - - As of EdgeDB 3.0, the ``extended`` clause is now a sub-declaration of - the property and included inside the curly braces rather than an option - as in earlier versions. - :eql:synopsis:`` The type must be a valid :ref:`type expression ` denoting a non-abstract scalar or a container type. diff --git a/docs/reference/sdl/scalars.rst b/docs/reference/sdl/scalars.rst deleted file mode 100644 index de31b6f1187..00000000000 --- a/docs/reference/sdl/scalars.rst +++ /dev/null @@ -1,70 +0,0 @@ -.. _ref_eql_sdl_scalars: - -============ -Scalar Types -============ - -This section describes the SDL declarations pertaining to -:ref:`scalar types `. - - -Example -------- - -Declare a new non-negative integer type: - -.. code-block:: sdl - - scalar type posint64 extending int64 { - constraint min_value(0); - } - -.. _ref_eql_sdl_scalars_syntax: - -Syntax ------- - -Define a new scalar type corresponding to the :ref:`more explicit DDL -commands `. - -.. sdl:synopsis:: - - [abstract] scalar type [extending [, ...] ] - [ "{" - [ ] - [ ] - ... - "}" ] - - -Description ------------ - -This declaration defines a new object type with the following options: - -:eql:synopsis:`abstract` - If specified, the created scalar type will be *abstract*. - -:eql:synopsis:`` - The name (optionally module-qualified) of the new scalar type. - -:eql:synopsis:`extending ` - Optional clause specifying the *supertype* of the new type. - - If :eql:synopsis:`` is an - :eql:type:`enumerated type ` declaration then - an enumerated scalar type is defined. - - Use of ``extending`` creates a persistent type relationship - between the new subtype and its supertype(s). Schema modifications - to the supertype(s) propagate to the subtype. - -The valid SDL sub-declarations are listed below: - -:sdl:synopsis:`` - Set scalar type :ref:`annotation ` - to a given *value*. - -:sdl:synopsis:`` - Define a concrete :ref:`constraint ` for - this scalar type. diff --git a/docs/reference/sdl/triggers.rst b/docs/reference/sdl/triggers.rst deleted file mode 100644 index 1ba55945722..00000000000 --- a/docs/reference/sdl/triggers.rst +++ /dev/null @@ -1,127 +0,0 @@ -.. versionadded:: 3.0 - -.. _ref_eql_sdl_triggers: - -======== -Triggers -======== - -This section describes the SDL declarations pertaining to -:ref:`triggers `. - - -Example -------- - -Declare a trigger that inserts a ``Log`` object for each new ``User`` object: - -.. code-block:: sdl - - type User { - required name: str; - - trigger log_insert after insert for each do ( - insert Log { - action := 'insert', - target_name := __new__.name - } - ); - } - -.. versionadded:: 4.0 - -Declare a trigger that inserts a ``Log`` object conditionally when an update -query makes a change to a ``User`` object: - -.. code-block:: sdl - - type User { - required name: str; - - trigger log_update after update for each - when (__old__ {**} != __new__ {**}) - do ( - insert Log { - action := 'update', - target_name := __new__.name, - change := __old__.name ++ '->' ++ __new__.name - } - ); - } - -.. _ref_eql_sdl_triggers_syntax: - -Syntax ------- - -Define a new trigger corresponding to the :ref:`more explicit DDL -commands `. - -.. sdl:synopsis:: - :version-lt: 4.0 - - type "{" - trigger - after - {insert | update | delete} [, ...] - for {each | all} - do - "}" - -.. sdl:synopsis:: - - type "{" - trigger - after - {insert | update | delete} [, ...] - for {each | all} - [ when () ] - do - "}" - - -Description ------------ - -This declaration defines a new trigger with the following options: - -:eql:synopsis:`` - The name (optionally module-qualified) of the type to be triggered on. - -:eql:synopsis:`` - The name of the trigger. - -:eql:synopsis:`insert | update | delete [, ...]` - The query type (or types) to trigger on. Separate multiple values with - commas to invoke the same trigger for multiple types of queries. - -:eql:synopsis:`each` - The expression will be evaluated once per modified object. ``__new__`` and - ``__old__`` in this context within the expression will refer to a single - object. - -:eql:synopsis:`all` - The expression will be evaluted once for the entire query, even if multiple - objects were modified. ``__new__`` and ``__old__`` in this context within - the expression refer to sets of the modified objects. - -.. versionadded:: 4.0 - - :eql:synopsis:`when ()` - Optionally provide a condition for the trigger. If the condition is - met, the trigger will run. If not, the trigger is skipped. - -:eql:synopsis:`` - The expression to be evaluated when the trigger is invoked. - -The trigger name must be distinct from that of any existing trigger -on the same type. - - -.. list-table:: - :class: seealso - - * - **See also** - * - :ref:`Schema > Triggers ` - * - :ref:`DDL > Triggers ` - * - :ref:`Introspection > Triggers ` diff --git a/docs/reference/sql_adapter.rst b/docs/reference/sql_adapter.rst index 2cecdf8fa02..74c2a1bc68f 100644 --- a/docs/reference/sql_adapter.rst +++ b/docs/reference/sql_adapter.rst @@ -1,65 +1,46 @@ -.. versionadded:: 3.0 - .. _ref_sql_adapter: =========== SQL adapter =========== -.. edb:youtube-embed:: 0KdY2MPb2oc - Connecting ========== -EdgeDB server supports PostgreSQL connection interface. It implements PostgreSQL +|Gel| server supports PostgreSQL connection interface. It implements PostgreSQL wire protocol as well as SQL query language. -As of EdgeDB 6.0, it also supports a subset of Data Modification Language, +As of |Gel| 6.0, it also supports a subset of Data Modification Language, namely INSERT, DELETE and UPDATE statements. It does not, however, support PostgreSQL Data Definition Language (e.g. ``CREATE TABLE``). This means that it is not possible to use SQL -connections to EdgeDB to modify its schema. Instead, the schema should be -managed using ESDL (EdgeDB Schema Definition Language) and migration commands. - -Any Postgres-compatible client can connect to an EdgeDB database by using the -same port that is used for the EdgeDB protocol and the -:versionreplace:`database;5.0:branch` name, username, and password already used -for the database. - -.. versionchanged:: _default - - Here's how you might connect to a local instance on port 10701 (determined - by running ``edgedb instance list``) with a database ``edgedb`` using the - ``psql`` CLI: +connections to Gel to modify its schema. Instead, the schema should be +managed in |.gel| files using Gel Schema Definition Language and migration +commands. - .. code-block:: bash - - $ psql -h localhost -p 10701 -U edgedb -d edgedb - - You'll then be prompted for a password. If you don't have it, you can run - ``edgedb instance credentials --insecure-dsn`` and grab it out of the DSN - the command returns. (It's the string between the second colon and the "at" - symbol: ``edgedb://edgedb:PASSWORD_IS_HERE@:/``) +Any Postgres-compatible client can connect to an Gel database by using the +same port that is used for the Gel protocol and the |branch| name, username, +and password already used for the database. .. versionchanged:: 5.0 Here's how you might connect to a local instance on port 10701 (determined - by running ``edgedb instance list``) on a branch ``main`` using the + by running :gelcmd:`instance list`) on a branch |main| using the ``psql`` CLI: .. code-block:: bash - $ psql -h localhost -p 10701 -U edgedb -d main + $ psql -h localhost -p 10701 -U admin -d main You'll then be prompted for a password. If you don't have it, you can run - ``edgedb instance credentials --insecure-dsn`` and grab it out of the DSN + :gelcmd:`instance credentials --insecure-dsn` and grab it out of the DSN the command returns. (It's the string between the second colon and the "at" - symbol: ``edgedb://edgedb:PASSWORD_IS_HERE@:/``) + symbol: :geluri:`admin:PASSWORD_IS_HERE@:/`) .. note:: - The insecure DSN returned by the CLI for EdgeDB Cloud instances will not + The insecure DSN returned by the CLI for Gel Cloud instances will not contain the password. You will need to either :ref:`create a new role and set the password `, using those values to connect to your SQL client, or change the password of the existing role, using that @@ -67,14 +48,14 @@ for the database. .. code-block:: edgeql-repl - db> alter role edgedb { + db> alter role admin { ... set password := 'my-password' ... }; OK: ALTER ROLE .. warning:: - Connecting to an EdgeDB Cloud instance via a Postgres client requires SNI + Connecting to an Gel Cloud instance via a Postgres client requires SNI support which was introduced in libpq v14. If a Postgres client uses your system's libpq (``psql`` does), you can connect as long as your libpq version is 14+. To check your version, run ``psql --version`` or @@ -101,35 +82,27 @@ name as your user name when you connect via your SQL client. set password := 'your-password' }; -.. versionchanged:: _default - - .. code-block:: bash - - $ psql -h localhost -p 10701 -U sql -d edgedb - -.. versionchanged:: 5.0 - - .. code-block:: bash +.. code-block:: bash - $ psql -h localhost -p 10701 -U sql -d main + $ psql -h localhost -p 10701 -U sql -d main In this example, when prompted for the password, you would enter ``your-password``. .. warning:: - EdgeDB server requires TLS by default, and this is also true for our SQL + Gel server requires TLS by default, and this is also true for our SQL support. Make sure to require SSL encryption in your SQL tool or client - when using EdgeDB's SQL support. Alternatively, you can disable the TLS - requirement by setting the ``EDGEDB_SERVER_BINARY_ENDPOINT_SECURITY`` + when using Gel's SQL support. Alternatively, you can disable the TLS + requirement by setting the :gelenv:`SERVER_BINARY_ENDPOINT_SECURITY` environment variable to ``optional``. Querying ======== -Object types in your EdgeDB schema are exposed as regular SQL tables containing -all the data you store in your EdgeDB database. +Object types in your Gel schema are exposed as regular SQL tables containing +all the data you store in your Gel database. If you have a database with the following schema: @@ -253,16 +226,16 @@ Tested SQL tools - `dbt `_ [2]_ -.. [1] At the moment, EdgeDB does not support "Log replication" (i.e., using +.. [1] At the moment, Gel does not support "Log replication" (i.e., using the `Postgres replication mechanism`_). Supported replication methods include `XMIN Replication`_, incremental updates using "a user-defined monotonically increasing id," and full table updates. .. [2] dbt models are built and stored in the database as either tables or - views. Because the EdgeDB SQL adapter does not allow writing or even + views. Because the Gel SQL adapter does not allow writing or even creating schemas, view, or tables, any attempt to materialize dbt models will result in errors. If you want to build the models, we suggest first transferring your data to a true Postgres instance via pg_dump or Airbyte. - Tests and previews can still be run directy against the EdgeDB instance. + Tests and previews can still be run directy against the Gel instance. .. _Postgres replication mechanism: https://www.postgresql.org/docs/current/runtime-config-replication.html @@ -270,12 +243,12 @@ Tested SQL tools https://www.postgresql.org/docs/15/ddl-system-columns.html -ESDL to PostgreSQL -================== +Gel to PostgreSQL +================= -As mentioned, the SQL schema of the database is managed trough EdgeDB Schema -Definition Language (ESDL). Here is a breakdown of how each of the ESDL -construct is mapped to PostgreSQL schema: +As mentioned, the SQL schema of the database is managed trough Gel Schema +Definition Language. Here is a breakdown of how each of its +constructs is mapped to PostgreSQL schema: - Objects types are mapped into tables. Each table has columns ``id UUID`` and ``__type__ UUID`` and one column for @@ -318,33 +291,26 @@ construct is mapped to PostgreSQL schema: DML commands ============ -.. versionchanged:: _default - - Data Modification Language commands (``INSERT``, ``UPDATE``, ``DELETE``, ..) - are not supported in EdgeDB <6.0. - -.. versionchanged:: 6.0 - .. versionadded:: 6.0 - When using ``INSERT``, ``DELETE`` or ``UPDATE`` on any table, mutation - rewrites and triggers are applied. These commands do not have a - straight-forward translation to EdgeQL DML commands, but instead use the - following mapping: +When using ``INSERT``, ``DELETE`` or ``UPDATE`` on any table, mutation +rewrites and triggers are applied. These commands do not have a +straight-forward translation to EdgeQL DML commands, but instead use the +following mapping: - - ``INSERT INTO "Foo"`` object table maps to ``insert Foo``, +- ``INSERT INTO "Foo"`` object table maps to ``insert Foo``, - - ``INSERT INTO "Foo.keywords"`` link/property table maps to an - ``update Foo { keywords += ... }``, +- ``INSERT INTO "Foo.keywords"`` link/property table maps to an + ``update Foo { keywords += ... }``, - - ``DELETE FROM "Foo"`` object table maps to ``delete Foo``, +- ``DELETE FROM "Foo"`` object table maps to ``delete Foo``, - - ``DELETE FROM "Foo.keywords"`` link property/table maps to - ``update Foo { keywords -= ... }``, +- ``DELETE FROM "Foo.keywords"`` link property/table maps to + ``update Foo { keywords -= ... }``, - - ``UPDATE "Foo"`` object table maps to ``update Foo set { ... }``, +- ``UPDATE "Foo"`` object table maps to ``update Foo set { ... }``, - - ``UPDATE "Foo.keywords"`` is not supported. +- ``UPDATE "Foo.keywords"`` is not supported. Connection settings @@ -363,7 +329,7 @@ SQL adapter supports most of PostgreSQL connection settings .. versionadded:: 6.0 - In addition, there are the following EdgeDB-specific settings: + In addition, there are the following Gel-specific settings: - settings prefixed with ``"global "`` set the values of globals. @@ -421,25 +387,19 @@ perform worse compared to other tables in the database. As a result, tools like Locking ======= -.. versionchanged:: _default - - SQL adapter does not support ``LOCK`` in EdgeDB <6.0. - -.. versionchanged:: 6.0 - .. versionadded:: 6.0 - SQL adapter supports LOCK command with the following limitations: +SQL adapter supports LOCK command with the following limitations: - - it cannot be used on tables that represent object types with access - properties or links of such objects, - - it cannot be used on tables that represent object types that have child - types extending them. +- it cannot be used on tables that represent object types with access + properties or links of such objects, +- it cannot be used on tables that represent object types that have child + types extending them. Query cache =========== -An SQL query is issued to EdgeDB, it is compiled to an internal SQL query, which +An SQL query is issued to Gel, it is compiled to an internal SQL query, which is then issued to the backing PostgreSQL instance. The compiled query is then cached, so each following issue of the same query will not perform any compilation, but just pass through the cached query. @@ -450,7 +410,7 @@ compilation, but just pass through the cached query. extracts constant values and replaces them by internal query parameters. This allows sharing of compilation cache between queries that differ in only constant values. This process is totally opaque and is fully handled by - EdgeDB. For example: + Gel. For example: .. code-block:: sql @@ -462,7 +422,7 @@ compilation, but just pass through the cached query. SELECT $1, $2; - This way, when a similar query is issued to EdgeDB: + This way, when a similar query is issued to Gel: .. code-block:: sql @@ -503,16 +463,16 @@ Following functions are not supported: - most of system administration functions. -Example: gradual transition from ORMs to EdgeDB -=============================================== +Example: gradual transition from ORMs to Gel +============================================ When a project is using Object-Relational Mappings (e.g. SQLAlchemy, Django, -Hibernate ORM, TypeORM) and is considering the migration to EdgeDB, it might +Hibernate ORM, TypeORM) and is considering the migration to Gel, it might want to execute the transition gradually, as opposed to a total rewrite of the project. In this case, the project can start the transition by migrating the ORM models -to EdgeDB Schema Definition Language. +to Gel Schema Definition Language. For example, such Hibernate ORM model in Java: @@ -532,7 +492,7 @@ For example, such Hibernate ORM model in Java: // ... getters and setters ... } -... would be translated to the following EdgeDB SDL: +... would be translated to the following Gel SDL: .. code-block:: sdl @@ -542,8 +502,8 @@ For example, such Hibernate ORM model in Java: required releaseYear: int32; } -A new EdgeDB instance can now be created and migrated to the translated schema. -At this stage, EdgeDB will allow SQL connections to write into the ``"Movie"`` +A new Gel instance can now be created and migrated to the translated schema. +At this stage, Gel will allow SQL connections to write into the ``"Movie"`` table, just as it would have been created with the following DDL command: .. code-block:: sql @@ -555,11 +515,11 @@ table, just as it would have been created with the following DDL command: releaseYear INTEGER NOT NULL ); -When translating the old ORM model to EdgeDB SDL, one should aim to make the -SQL schema of EdgeDB match the SQL schema that the ORM expects. +When translating the old ORM model to Gel SDL, one should aim to make the +SQL schema of Gel match the SQL schema that the ORM expects. When this match is accomplished, any query that used to work with the old, plain -PostgreSQL, should now also work with the EdgeDB. For example, we can execute +PostgreSQL, should now also work with the Gel. For example, we can execute the following query: .. code-block:: sql @@ -569,7 +529,7 @@ the following query: RETURNING id, title, releaseYear; To complete the migration, the data can be exported from our old database into -an ``.sql`` file, which can be import it into EdgeDB: +an ``.sql`` file, which can be import it into Gel: .. code-block:: bash @@ -577,18 +537,18 @@ an ``.sql`` file, which can be import it into EdgeDB: --data-only --inserts --no-owner --no-privileges \ > dump.sql - $ psql {your EdgeDB connection params} --file dump.sql + $ psql {your Gel connection params} --file dump.sql -Now, the ORM can be pointed to EdgeDB instead of the old PostgreSQL database, +Now, the ORM can be pointed to Gel instead of the old PostgreSQL database, which has been fully replaced. Arguably, the development of new features with the ORM is now more complex for the duration of the transition, since the developer has to modify two model -definitions: the ORM and the EdgeDB schema. +definitions: the ORM and the Gel schema. -But it allows any new models to use EdgeDB schema, EdgeQL and code generators +But it allows any new models to use Gel schema, EdgeQL and code generators for the client language of choice. The ORM-based code can now also be gradually rewritten to use EdgeQL, one model at the time. For a detailed migration example, see repository -`edgedb/hibernate-example `_. +`geldata/hibernate-example `_. diff --git a/docs/stdlib/array.rst b/docs/stdlib/array.rst index acf313ac607..90f7f05d914 100644 --- a/docs/stdlib/array.rst +++ b/docs/stdlib/array.rst @@ -78,7 +78,7 @@ Empty arrays ^^^^^^^^^^^^ You can also create an empty array, but it must be done by providing the type -information using type casting. EdgeDB cannot infer the type of an empty array +information using type casting. Gel cannot infer the type of an empty array created otherwise. For example: .. code-block:: edgeql-repl @@ -105,7 +105,7 @@ Reference Array indexing starts at zero. - An array can contain any type except another array. In EdgeDB, arrays are + An array can contain any type except another array. In Gel, arrays are always one-dimensional. An array type is created implicitly when an :ref:`array @@ -128,14 +128,6 @@ Reference Array types may also appear in schema declarations: - .. code-block:: sdl - :version-lt: 3.0 - - type Person { - property str_array -> array; - property json_array -> array; - } - .. code-block:: sdl type Person { @@ -153,6 +145,8 @@ Reference .. eql:operator:: arrayidx: array [ int64 ] -> anytype + :index: [int], index access + Accesses the array element at a given index. Example: @@ -185,6 +179,8 @@ Reference .. eql:operator:: arrayslice: array [ int64 : int64 ] -> anytype + :index: [int:int] + Produces a sub-array from an existing array. Omitting the lower bound of an array slice will default to a lower bound @@ -228,6 +224,8 @@ Reference .. eql:operator:: arrayplus: array ++ array -> array + :index: ++, concatenate, join, add + Concatenates two arrays of the same type into one. .. code-block:: edgeql-repl diff --git a/docs/stdlib/bool.rst b/docs/stdlib/bool.rst index 5a106661600..7ac3fb48f74 100644 --- a/docs/stdlib/bool.rst +++ b/docs/stdlib/bool.rst @@ -134,6 +134,8 @@ Booleans .. eql:operator:: or: bool or bool -> bool + :index: or + Evaluates ``true`` if either boolean is ``true``. .. code-block:: edgeql-repl @@ -166,6 +168,8 @@ Booleans .. eql:operator:: and: bool and bool -> bool + :index: and + Evaluates ``true`` if both booleans are ``true``. .. code-block:: edgeql-repl @@ -198,6 +202,8 @@ Booleans .. eql:operator:: not: not bool -> bool + :index: not + Logically negates a given boolean value. .. code-block:: edgeql-repl @@ -321,8 +327,6 @@ operator. named only message: optional str = {} \ ) -> bool - .. versionadded:: 3.0 - Checks that the input bool is ``true``. If the input bool is ``false``, ``assert`` raises a @@ -334,10 +338,10 @@ operator. {true} db> select assert(false); - edgedb error: QueryAssertionError: assertion failed + gel error: QueryAssertionError: assertion failed db> select assert(false, message := 'value is not true'); - edgedb error: QueryAssertionError: value is not true + gel error: QueryAssertionError: value is not true ``assert`` can be used in triggers to create more powerful constraints. In this schema, the ``Person`` type has both ``friends`` and ``enemies`` @@ -384,7 +388,7 @@ operator. ... select detached Person filter .name = 'Dracula' ... ) ... }; - edgedb error: EdgeDBError: Invalid frenemies + gel error: GelError: Invalid frenemies In the following examples, the ``size`` properties of the ``File`` objects are ``1024``, ``1024``, and ``131,072``. @@ -397,7 +401,7 @@ operator. db> for obj in (select File) ... union (assert(obj.size <= 64*1024, message := 'file too big')); - edgedb error: QueryAssertionError: file too big + gel error: QueryAssertionError: file too big You may call ``assert`` in the ``order by`` clause of your ``select`` statement. This will ensure it is called only on objects that pass your @@ -415,7 +419,7 @@ operator. db> select File { name, size } ... order by assert(.size <= 64*1024, message := "file too big"); - edgedb error: QueryAssertionError: file too big + gel error: QueryAssertionError: file too big db> select File { name, size } ... filter .size <= 64*1024 diff --git a/docs/stdlib/bytes.rst b/docs/stdlib/bytes.rst index 18dc389c956..17f065ab9e8 100644 --- a/docs/stdlib/bytes.rst +++ b/docs/stdlib/bytes.rst @@ -99,10 +99,10 @@ Bytes .. code-block:: edgeql-repl - db> select b'Hello EdgeDB!'; + db> select b'Hello Gel!'; {"\"SGVsbG8gRWRnZURCIQ==\""} db> select to_json("\"SGVsbG8gRWRnZURCIQ==\""); - {b'Hello EdgeDB!'} + {b'Hello Gel!'} ---------- @@ -139,6 +139,8 @@ Bytes .. eql:operator:: bytesidx: bytes [ int64 ] -> bytes + :index: [int] + Accesses a byte at a given index. Examples: @@ -156,6 +158,8 @@ Bytes .. eql:operator:: bytesslice: bytes [ int64 : int64 ] -> bytes + :index: [int:int] + Produces a bytes sub-sequence from an existing bytes value. Examples: @@ -171,7 +175,9 @@ Bytes --------- -.. eql:operator:: bytesplus: bytes ++ bytes -> bytes +.. eql:operator:: bytesplus: bytes ++ bytes -> + + :index: ++, bytes, concatenate, join, add Concatenates two bytes values into one. @@ -280,4 +286,4 @@ Bytes db> select enc::base64_decode('aGVsbG8='); {b'hello'} db> select enc::base64_decode('aGVsbG8'); - edgedb error: InvalidValueError: invalid base64 end sequence + gel error: InvalidValueError: invalid base64 end sequence diff --git a/docs/stdlib/cfg.rst b/docs/stdlib/cfg.rst index a0fc12e5133..2cf4eadd91b 100644 --- a/docs/stdlib/cfg.rst +++ b/docs/stdlib/cfg.rst @@ -5,7 +5,7 @@ Config ====== The ``cfg`` module contains a set of types and scalars used for configuring -EdgeDB. +|Gel|. .. list-table:: @@ -16,17 +16,17 @@ EdgeDB. * - :eql:type:`cfg::AbstractConfig` - The abstract base type for all configuration objects. The properties of this type define the set of configuruation settings supported by - EdgeDB. + Gel. * - :eql:type:`cfg::Config` - The main configuration object. The properties of this object reflect the overall configuration setting from instance level all the way to session level. * - :eql:type:`cfg::DatabaseConfig` - The database configuration object. It reflects all the applicable - configuration at the EdgeDB database level. + configuration at the Gel database level. * - :eql:type:`cfg::BranchConfig` - The database branch configuration object. It reflects all the applicable - configuration at the EdgeDB branch level. + configuration at the Gel branch level. * - :eql:type:`cfg::InstanceConfig` - The instance configuration object. * - :eql:type:`cfg::ExtensionConfig` @@ -36,7 +36,7 @@ EdgeDB. * - :eql:type:`cfg::Auth` - An object type representing an authentication profile. * - :eql:type:`cfg::ConnectionTransport` - - An enum type representing the different protocols that EdgeDB speaks. + - An enum type representing the different protocols that Gel speaks. * - :eql:type:`cfg::AuthMethod` - An abstract object type representing a method of authentication * - :eql:type:`cfg::Trust` @@ -64,6 +64,8 @@ Configuration Parameters Connection settings ------------------- +.. index:: listen_addresses, listen_port + :eql:synopsis:`listen_addresses -> multi str` Specifies the TCP/IP address(es) on which the server is to listen for connections from client applications. If the list is empty, the server @@ -76,6 +78,8 @@ Connection settings Resource usage -------------- +.. index:: effective_io_concurrency, query_work_mem, shared_buffers + :eql:synopsis:`effective_io_concurrency -> int64` Sets the number of concurrent disk I/O operations that can be executed simultaneously. Corresponds to the PostgreSQL @@ -95,6 +99,8 @@ Resource usage Query planning -------------- +.. index:: default_statistics_target, effective_cache_size + :eql:synopsis:`default_statistics_target -> int64` Sets the default data statistics target for the planner. Corresponds to the PostgreSQL configuration parameter of the same @@ -112,6 +118,8 @@ Query cache .. versionadded:: 5.0 +.. index:: auto_rebuild_query_cache, query_cache_mode, cfg::QueryCacheMode + :eql:synopsis:`auto_rebuild_query_cache -> bool` Determines whether to recompile the existing query cache to SQL any time DDL is executed. @@ -120,7 +128,7 @@ Query cache Allows the developer to set where the query cache is stored. Possible values: * ``cfg::QueryCacheMode.InMemory``- All query cache is lost on server restart. - This mirrors pre-5.0 EdgeDB's behavior. + This mirrors pre-5.0 |EdgeDB| behavior. * ``cfg::QueryCacheMode.RegInline``- The in-memory query cache is also stored in the database as-is so it can be restored on restart. * ``cfg::QueryCacheMode.Default``- Allow the server to select the best caching @@ -135,6 +143,9 @@ Query cache Query behavior -------------- +.. index:: allow_bare_ddl, cfg::AllowBareDDL, apply_access_policies, + apply_access_policies_pg, force_database_error + :eql:synopsis:`allow_bare_ddl -> cfg::AllowBareDDL` Allows for running bare DDL outside a migration. Possible values are ``cfg::AllowBareDDL.AlwaysAllow`` and ``cfg::AllowBareDDL.NeverAllow``. @@ -154,8 +165,8 @@ Query behavior .. note:: This setting can also be conveniently accessed via the "Config" dropdown - menu at the top of the EdgeDB UI (accessible by running the CLI command - ``edgedb ui`` from within a project). The setting will apply only to your + menu at the top of the Gel UI (accessible by running the CLI command + :gelcmd:`ui` from within a project). The setting will apply only to your UI session, so you won't have to remember to re-enable it when you're done. @@ -171,7 +182,7 @@ Query behavior This parameter takes a ``str`` instead of a ``bool`` to allow more verbose messages when all queries are forced to fail. The database will attempt to deserialize this ``str`` into a JSON object that must include - a ``type`` (which must be an EdgeDB + a ``type`` (which must be an Gel :ref:`error type ` name), and may also include ``message``, ``hint``, and ``details`` which can be set ad-hoc by the user. @@ -192,6 +203,9 @@ Query behavior Client connections ------------------ +.. index:: allow_user_specified_id, session_idle_timeout, + session_idle_transaction_timeout, query_execution_timeout + :eql:synopsis:`allow_user_specified_id -> bool` Makes it possible to set the ``.id`` property when inserting new objects. @@ -271,7 +285,7 @@ Client connections An abstract type representing the configuration of an instance or database. The properties of this object type represent the set of configuration - options supported by EdgeDB (listed above). + options supported by Gel (listed above). ---------- @@ -282,7 +296,7 @@ Client connections The main configuration object type. This type will have only one object instance. The ``cfg::Config`` object - represents the sum total of the current EdgeDB configuration. It reflects + represents the sum total of the current Gel configuration. It reflects the result of applying instance, branch, and session level configuration. Examining this object is the recommended way of determining the current configuration. @@ -303,35 +317,15 @@ Client connections ---------- -.. eql:type:: cfg::DatabaseConfig - - The :versionreplace:`database;5.0:branch`-level configuration object type. - - This type will have only one object instance. The ``cfg::DatabaseConfig`` - object represents the state of :versionreplace:`database;5.0:branch` and - instance-level EdgeDB configuration. - - For overall configuration state please refer to the :eql:type:`cfg::Config` - instead. - - .. versionadded:: 5.0 - - As of EdgeDB 5.0, this config object represents database *branch* - and instance-level configuration. - - ----------- - - .. eql:type:: cfg::BranchConfig .. versionadded:: 5.0 - The :versionreplace:`database;5.0:branch`-level configuration object type. + The branch-level configuration object type. This type will have only one object instance. The ``cfg::BranchConfig`` - object represents the state of :versionreplace:`database;5.0:branch` and - instance-level EdgeDB configuration. + object represents the state of the branch and instance-level Gel + configuration. For overall configuration state please refer to the :eql:type:`cfg::Config` instead. @@ -345,7 +339,7 @@ Client connections The instance-level configuration object type. This type will have only one object instance. The ``cfg::InstanceConfig`` - object represents the state of only instance-level EdgeDB configuration. + object represents the state of only instance-level Gel configuration. For overall configuraiton state please refer to the :eql:type:`cfg::Config` instead. @@ -426,7 +420,7 @@ Client connections .. eql:type:: cfg::ConnectionTransport - An enum listing the various protocols that EdgeDB can speak. + An enum listing the various protocols that Gel can speak. Possible values are: @@ -436,12 +430,12 @@ Client connections * - **Value** - **Description** * - ``cfg::ConnectionTransport.TCP`` - - EdgeDB binary protocol + - Gel binary protocol * - ``cfg::ConnectionTransport.TCP_PG`` - Postgres protocol for the :ref:`SQL query mode ` * - ``cfg::ConnectionTransport.HTTP`` - - EdgeDB binary protocol + - Gel binary protocol :ref:`tunneled over HTTP ` * - ``cfg::ConnectionTransport.SIMPLE_HTTP`` - :ref:`EdgeQL over HTTP ` diff --git a/docs/stdlib/constraints.rst b/docs/stdlib/constraints.rst index ceb4a0766d1..2e34442d682 100644 --- a/docs/stdlib/constraints.rst +++ b/docs/stdlib/constraints.rst @@ -23,17 +23,6 @@ Constraints Example of using an ``expression`` constraint based on two object properties to restrict maximum magnitude for a vector: - .. code-block:: sdl - :version-lt: 3.0 - - type Vector { - required property x -> float64; - required property y -> float64; - constraint expression on ( - __subject__.x^2 + __subject__.y^2 < 25 - ); - } - .. code-block:: sdl type Vector { @@ -166,30 +155,12 @@ Constraints Scalar type definitions cannot include this constraint. This constraint has an additional effect of creating an - implicit :ref:`index ` on a property. - This means that there's no need to add explicit indexes + implicit :ref:`index ` on a property. + This means that there's no need to add explicit indexes for properties with this constraint. Example: - .. code-block:: sdl - :version-lt: 3.0 - - type User { - # Make sure user names are unique. - required property name -> str { - constraint exclusive; - } - # Already indexed, don't need to do this: - # index on (.name) - - # Make sure none of the "owned" items belong - # to any other user. - multi link owns -> Item { - constraint exclusive; - } - } - .. code-block:: sdl type User { @@ -212,17 +183,6 @@ Constraints ``exclusive`` constraint for the combination, rather than on each property: - .. code-block:: sdl - :version-lt: 3.0 - - type UniqueCoordinates { - required property x -> int64; - required property y -> int64; - - # Each combination of x and y must be unique. - constraint exclusive on ( (.x, .y) ); - } - .. code-block:: sdl type UniqueCoordinates { @@ -252,5 +212,3 @@ Constraints * - :ref:`DDL > Constraints ` * - :ref:`Introspection > Constraints ` - * - `Tutorial > Advanced EdgeQL > Constraints - `_ diff --git a/docs/stdlib/datetime.rst b/docs/stdlib/datetime.rst index 7ed6d12a436..69bf71e5c7e 100644 --- a/docs/stdlib/datetime.rst +++ b/docs/stdlib/datetime.rst @@ -101,7 +101,7 @@ Dates and Times .. _ref_std_datetime_intro: -EdgeDB offers two ways of representing date/time values: +|Gel| offers two ways of representing date/time values: * a timezone-aware :eql:type:`std::datetime` type; @@ -119,7 +119,7 @@ There are also two different ways of measuring duration: All related operators, functions, and type casts are designed to maintain a strict separation between timezone-aware and "local" date/time values. -EdgeDB stores and outputs timezone-aware values in UTC format. +|Gel| stores and outputs timezone-aware values in UTC format. .. note:: @@ -310,7 +310,7 @@ functionality. db> select '48 hours 45 minutes'; {'48:45:00'} db> select '11 months'; - edgedb error: InvalidValueError: invalid input syntax for type + gel error: InvalidValueError: invalid input syntax for type std::duration: '11 months' Hint: Units bigger than hours cannot be used for std::duration. @@ -496,8 +496,6 @@ functionality. .. eql:type:: cal::date_duration - .. versionadded:: 2.0 - A type for representing a span of time in days. This type is similar to :eql:type:`cal::relative_duration`, except it only @@ -538,7 +536,7 @@ functionality. In most cases, ``date_duration`` is fully compatible with :eql:type:`cal::relative_duration` and shares the same general behavior - and caveats. EdgeDB will apply type coercion in the event it expects a + and caveats. Gel will apply type coercion in the event it expects a :eql:type:`cal::relative_duration` and finds a ``cal::date_duration`` instead. @@ -573,6 +571,8 @@ functionality. -> cal::local_datetime cal::local_date + duration -> cal::local_datetime + :index: +, duration, datetime, add + Adds a duration and any other datetime value. This operator is commutative. @@ -621,6 +621,8 @@ functionality. cal::relative_duration - duration\ -> cal::relative_duration + :index: -, duration, datetime, subtract + Subtracts two compatible datetime or duration values. .. code-block:: edgeql-repl @@ -649,10 +651,10 @@ functionality. Subtraction doesn't make sense for some type combinations. You couldn't subtract a point in time from a duration, so neither can - EdgeDB (although the inverse β€” subtracting a duration from a point in + Gel (although the inverse β€” subtracting a duration from a point in time β€” is perfectly fine). You also couldn't subtract a timezone-aware datetime from a local one or vice versa. If you attempt any of these, - EdgeDB will raise an exception as shown in these examples. + Gel will raise an exception as shown in these examples. When subtracting a date/time object from a time interval, an exception will be raised: @@ -876,8 +878,6 @@ functionality. std::duration_get(dt: cal::date_duration, \ el: str) -> float64 - .. versionadded:: 2.0 - Returns the element of a duration given a unit name. You may pass any of these unit names as ``el``: @@ -1416,8 +1416,6 @@ functionality. :index: justify_hours - .. versionadded:: 2.0 - Convert 24-hour chunks into days. This function converts all 24-hour chunks into day units. The resulting @@ -1448,8 +1446,6 @@ functionality. :index: justify_days - .. versionadded:: 2.0 - Convert 30-day chunks into months. This function converts all 30-day chunks into month units. The resulting diff --git a/docs/stdlib/deprecated.rst b/docs/stdlib/deprecated.rst index a26722da047..46cde1f5082 100644 --- a/docs/stdlib/deprecated.rst +++ b/docs/stdlib/deprecated.rst @@ -135,3 +135,14 @@ Deprecated {'data'} db> select str_rtrim('data.:.:.', '.:'); {'data'} + +---------- + +.. eql:type:: cfg::DatabaseConfig + + The branch-level configuration object type. + + As of |EdgeDB| 5.0, this config object represents database *branch* + and instance-level configuration. + + **Use the identical** :eql:type:`cfg::BranchConfig` instead. diff --git a/docs/stdlib/fts.rst b/docs/stdlib/fts.rst index 2412370494d..ab9eca95c5a 100644 --- a/docs/stdlib/fts.rst +++ b/docs/stdlib/fts.rst @@ -7,7 +7,7 @@ Full-text Search ================ The ``fts`` built-in module contains various tools that enable full-text -search functionality in EdgeDB. +search functionality in Gel. .. note:: @@ -121,7 +121,7 @@ Consider the following: .. code-block:: edgeql-repl - edgedb> select Item{name, description}; + gel> select Item{name, description}; { default::Item {name: 'Canned corn', description: {}}, default::Item { @@ -134,11 +134,11 @@ Consider the following: }, } - edgedb> with res := ( - ....... select fts::search(Item, 'corn treat', language := 'eng') - ....... ) - ....... select res.object {name, description, score := res.score} - ....... order by res.score desc; + gel> with res := ( + .... select fts::search(Item, 'corn treat', language := 'eng') + .... ) + .... select res.object {name, description, score := res.score} + .... order by res.score desc; { default::Item { name: 'Candy corn', @@ -166,15 +166,15 @@ to change this trend: .. code-block:: edgeql-repl - edgedb> with res := ( - ....... select fts::search( - ....... Item, 'corn treat', - ....... language := 'eng', - ....... weights := [0.2, 1], - ....... ) - ....... ) - ....... select res.object {name, description, score := res.score} - ....... order by res.score desc; + gel> with res := ( + .... select fts::search( + .... Item, 'corn treat', + .... language := 'eng', + .... weights := [0.2, 1], + .... ) + .... ) + .... select res.object {name, description, score := res.score} + .... order by res.score desc; { default::Item { name: 'Sweet', @@ -199,16 +199,16 @@ the score to make this work properly: .. code-block:: edgeql-repl - edgedb> with res := ( - ....... select fts::search( - ....... Item, 'corn treat', - ....... language := 'eng', - ....... weights := [0, 1], - ....... ) - ....... ) - ....... select res.object {name, description, score := res.score} - ....... filter res.score > 0 - ....... order by res.score desc; + gel> with res := ( + .... select fts::search( + .... Item, 'corn treat', + .... language := 'eng', + .... weights := [0, 1], + .... ) + .... ) + .... select res.object {name, description, score := res.score} + .... filter res.score > 0 + .... order by res.score desc; { default::Item { name: 'Sweet', @@ -229,14 +229,14 @@ increased importance and should appear in all matches: .. code-block:: edgeql-repl - edgedb> with res := ( - ....... select fts::search( - ....... Item, '"corn sugar"', - ....... language := 'eng', - ....... ) - ....... ) - ....... select res.object {name, description, score := res.score} - ....... order by res.score desc; + gel> with res := ( + .... select fts::search( + .... Item, '"corn sugar"', + .... language := 'eng', + .... ) + .... ) + .... select res.object {name, description, score := res.score} + .... order by res.score desc; { default::Item { name: 'Sweet', @@ -254,14 +254,14 @@ required or optional: .. code-block:: edgeql-repl - edgedb> with res := ( - ....... select fts::search( - ....... Item, 'sweet AND treat', - ....... language := 'eng', - ....... ) - ....... ) - ....... select res.object {name, description, score := res.score} - ....... order by res.score desc; + gel> with res := ( + .... select fts::search( + .... Item, 'sweet AND treat', + .... language := 'eng', + .... ) + .... ) + .... select res.object {name, description, score := res.score} + .... order by res.score desc; { default::Item { name: 'Sweet', @@ -275,14 +275,14 @@ the matching object *must not* contain: .. code-block:: edgeql-repl - edgedb> with res := ( - ....... select fts::search( - ....... Item, '!treat', - ....... language := 'eng', - ....... ) - ....... ) - ....... select res.object {name, description, score := res.score} - ....... order by res.score desc; + gel> with res := ( + .... select fts::search( + .... Item, '!treat', + .... language := 'eng', + .... ) + .... ) + .... select res.object {name, description, score := res.score} + .... order by res.score desc; { default::Item { name: 'Canned corn', @@ -291,11 +291,6 @@ the matching object *must not* contain: }, } -.. note:: - - EdgeDB 4.0 only supports Postgres full-text search backend. Support for - other backends is still in development. - ---------- @@ -429,4 +424,4 @@ the matching object *must not* contain: overridden when making a call to :eql:func:`fts::search`. -.. _iso639: https://iso639-3.sil.org/code_tables/639/data \ No newline at end of file +.. _iso639: https://iso639-3.sil.org/code_tables/639/data diff --git a/docs/stdlib/generic.rst b/docs/stdlib/generic.rst index dadaea2012e..f3a9fa7802e 100644 --- a/docs/stdlib/generic.rst +++ b/docs/stdlib/generic.rst @@ -53,6 +53,8 @@ Generic .. eql:operator:: eq: anytype = anytype -> bool + :index: =, equal, comparison, compare + Compares two values for equality. .. code-block:: edgeql-repl @@ -89,6 +91,8 @@ Generic .. eql:operator:: neq: anytype != anytype -> bool + :index: !=, not equal, comparison, compare + Compares two values for inequality. .. code-block:: edgeql-repl @@ -127,6 +131,8 @@ Generic .. eql:operator:: coaleq: optional anytype ?= optional anytype -> bool + :index: ?=, coalesce equal, comparison, compare, empty set + Compares two (potentially empty) values for equality. This works the same as a regular :eql:op:`=` operator, but also allows @@ -147,6 +153,8 @@ Generic .. eql:operator:: coalneq: optional anytype ?!= optional anytype -> bool + :index: ?!=, coalesce not equal, comparison, compare + Compares two (potentially empty) values for inequality. This works the same as a regular :eql:op:`=` operator, but also allows @@ -167,6 +175,8 @@ Generic .. eql:operator:: lt: anytype < anytype -> bool + :index: <, less than, comparison, compare + Less than operator. The operator returns ``true`` if the value of the left expression is less @@ -208,6 +218,8 @@ Generic .. eql:operator:: gt: anytype > anytype -> bool + :index: >, greater than, comparison, compare + Greater than operator. The operator returns ``true`` if the value of the left expression is @@ -249,6 +261,8 @@ Generic .. eql:operator:: lteq: anytype <= anytype -> bool + :index: <=, less than or equal, comparison, compare + Less or equal operator. The operator returns ``true`` if the value of the left expression is less @@ -292,6 +306,8 @@ Generic .. eql:operator:: gteq: anytype >= anytype -> bool + :index: >=, greater than or equal, comparison, compare + Greater or equal operator. The operator returns ``true`` if the value of the left expression is diff --git a/docs/stdlib/index.rst b/docs/stdlib/index.rst index 58cb4509714..ecede42cdec 100644 --- a/docs/stdlib/index.rst +++ b/docs/stdlib/index.rst @@ -40,7 +40,7 @@ Standard Library pgvector deprecated -EdgeDB comes with a rigorously defined type system consisting of **scalar +|Gel| comes with a rigorously defined type system consisting of **scalar types**, **collection types** (like arrays and tuples), and **object types**. There is also a library of built-in functions and operators for working with each datatype. diff --git a/docs/stdlib/json.rst b/docs/stdlib/json.rst index 578d1125e92..e0651075a96 100644 --- a/docs/stdlib/json.rst +++ b/docs/stdlib/json.rst @@ -58,7 +58,7 @@ JSON Constructing JSON Values ------------------------ -JSON in EdgeDB is a :ref:`scalar type `. This type +JSON in Gel is a :ref:`scalar type `. This type doesn't have its own literal, and instead can be obtained by either casting a value to the :eql:type:`json` type, or by using the :eql:func:`to_json` function: @@ -70,7 +70,7 @@ function: db> select 'hello world'; {Json("\"hello world\"")} -Any value in EdgeDB can be cast to a :eql:type:`json` type as well: +Any value in Gel can be cast to a :eql:type:`json` type as well: .. code-block:: edgeql-repl @@ -79,18 +79,16 @@ Any value in EdgeDB can be cast to a :eql:type:`json` type as well: db> select cal::to_local_date(datetime_current(), 'UTC'); {Json("\"2022-11-21\"")} -.. versionadded:: 3.0 +The :eql:func:`json_object_pack` function provides one more way to +construct JSON. It constructs a JSON object from an array of key/value +tuples: - The :eql:func:`json_object_pack` function provides one more way to - construct JSON. It constructs a JSON object from an array of key/value - tuples: - - .. code-block:: edgeql-repl +.. code-block:: edgeql-repl - db> select json_object_pack({("hello", "world")}); - {Json("{\"hello\": \"world\"}")} + db> select json_object_pack({("hello", "world")}); + {Json("{\"hello\": \"world\"}")} -Additionally, any :eql:type:`Object` in EdgeDB can be cast as a +Additionally, any :eql:type:`Object` in Gel can be cast as a :eql:type:`json` type. This produces the same JSON value as the JSON-serialized result of that said object. Furthermore, this result will be the same as the output of a :eql:stmt:`select expression