diff --git a/docs/intro/quickstart/connecting/fastapi.rst b/docs/intro/quickstart/connecting/fastapi.rst index c02707f024d..af928ef09b9 100644 --- a/docs/intro/quickstart/connecting/fastapi.rst +++ b/docs/intro/quickstart/connecting/fastapi.rst @@ -10,9 +10,7 @@ Connecting to the database .. note:: - Notice that the ``create_client`` function isn't being passed any connection details. How does Gel know how to connect to the database you set up earlier? When we ran ``gel project init`` earlier, the CLI created credentials for the local database and stored them in a well-known location. When you initialize your client with ``create_client()``, Gel will check the places it knows about for 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 when you're ready to deploy, and the client knows what to do! + Notice that the ``create_async_client`` 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 ``create_async_client`` function knows what to do! .. edb:split-point:: @@ -20,11 +18,14 @@ Connecting to the database :caption: ./test.py import gel + import asyncio - client = gel.create_async_client() + async def main(): + client = gel.create_async_client() + result = await client.query_single("select 'Hello from Gel!';") + print(result) - result = client.query_single("select 'Hello from Gel!';") - print(result) + asyncio.run(main()) .. code-block:: sh @@ -41,31 +42,33 @@ Connecting to the database :caption: ./test.py import gel - - client = gel.create_async_client() - - - result = client.query_single("select 'Hello from Gel!';") - - print(result) - + client.query(""" - + insert Deck { name := "I am one" } - + """) + import asyncio + + async def main(): + client = gel.create_async_client() + - result = await client.query_single("select 'Hello from Gel!';") + - print(result) + + await client.query(""" + + insert Deck { name := "I am one" } + + """) + - + client.query(""" - + insert Deck { name := "I am two" } - + """) + + await client.query(""" + + insert Deck { name := "I am two" } + + """) + - + decks = client.query(""" - + select Deck { - + id, - + name - + } - + """) + + decks = await client.query(""" + + select Deck { + + id, + + name + + } + + """) + - + for deck in decks: - + print(f"ID: {deck.id}, Name: {deck.name}") + + for deck in decks: + + print(f"ID: {deck.id}, Name: {deck.name}") + - + client.query("delete Deck") + + await client.query("delete Deck") + asyncio.run(main()) .. code-block:: sh diff --git a/docs/intro/quickstart/connecting/index.rst b/docs/intro/quickstart/connecting/index.rst index 57300c04ea8..ac820e5025f 100644 --- a/docs/intro/quickstart/connecting/index.rst +++ b/docs/intro/quickstart/connecting/index.rst @@ -1,8 +1,8 @@ .. edb:env-switcher:: -========== -Connecting -========== +========================== +Connecting to the database +========================== .. toctree:: :maxdepth: 3 diff --git a/docs/intro/quickstart/inheritance/fastapi.rst b/docs/intro/quickstart/inheritance/fastapi.rst index 591ddaef41b..c386577c28d 100644 --- a/docs/intro/quickstart/inheritance/fastapi.rst +++ b/docs/intro/quickstart/inheritance/fastapi.rst @@ -85,6 +85,6 @@ Adding shared properties order by .order ) } - + order by .updated_at DESC + + order by .updated_at desc """) return decks diff --git a/docs/intro/quickstart/inheritance/index.rst b/docs/intro/quickstart/inheritance/index.rst index 7be2509f578..8ad77d34c8e 100644 --- a/docs/intro/quickstart/inheritance/index.rst +++ b/docs/intro/quickstart/inheritance/index.rst @@ -1,8 +1,8 @@ .. edb:env-switcher:: -=========== -Inheritance -=========== +======================== +Adding shared properties +======================== .. toctree:: :maxdepth: 3 diff --git a/docs/intro/quickstart/modeling/fastapi.rst b/docs/intro/quickstart/modeling/fastapi.rst index edd6c4cef44..c1c407ed897 100644 --- a/docs/intro/quickstart/modeling/fastapi.rst +++ b/docs/intro/quickstart/modeling/fastapi.rst @@ -6,16 +6,15 @@ Modeling the data .. edb:split-section:: - The flashcards application has a simple data model, but it's interesting enough to get a taste of many of the features of the Gel schema language. You have a ``Card`` class that extends the ``CardBase`` class describing a single flashcard, which for now contains two required string properties: ``front`` and ``back``. Each ``Card`` belongs to a ``Deck``, and there is an explicit ordering to the cards in a given deck. + 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, you can see this structure in the JSON. + Looking at the mock data in the example JSON file ``./deck-edgeql.json``, you can see this structure in the JSON. There is a ``Card`` class that describes a single flashcard, which contains two required string properties: ``front`` and ``back``. Each ``Deck`` object has zero or more ``Card`` objects in a list. - .. code-block:: typescript + .. code-block:: python from pydantic import BaseModel class CardBase(BaseModel): - order: int front: str back: str @@ -62,30 +61,34 @@ Modeling the data 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: + To make |Gel| do that, you need to do two quick steps: - * **Create a migration**: a file with a list of low-level instructions. + 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:: + .. 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. + 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. - * **Apply the migration**: basically, tell Gel "I want you to use these instructions and get my types ready for action." + 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. .. code-block:: sh - $ gel migration create - Created ./dbschema/migrations/00001-m125ajr.edgeql, id: m125ajrbqp7ov36s7aniefxc376ofxdlketzspy4yddd3hrh4lxmla - $ gel migrate - Applying m125ajrbqp7ov36s7aniefxc376ofxdlketzspy4yddd3hrh4lxmla (00001-m125ajr.edgeql) - ... parsed - ... applied + $ uvx gel migration create + Created ./dbschema/migrations/00001-m125ajr.edgeql, id: m125ajrbqp7ov36s7aniefxc376ofxdlketzspy4yddd3hrh4lxmla + $ uvx gel migrate + Applying m125ajrbqp7ov36s7aniefxc376ofxdlketzspy4yddd3hrh4lxmla (00001-m125ajr.edgeql) + ... parsed + ... applied .. 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 - $ gel ui + $ uvx gel ui + + .. image:: images/schema-ui.png diff --git a/docs/intro/quickstart/modeling/index.rst b/docs/intro/quickstart/modeling/index.rst index 4d9a9f626db..64e5ac4a46e 100644 --- a/docs/intro/quickstart/modeling/index.rst +++ b/docs/intro/quickstart/modeling/index.rst @@ -1,8 +1,8 @@ .. edb:env-switcher:: -======== -Modeling -======== +================= +Modeling the data +================= .. toctree:: :maxdepth: 3 diff --git a/docs/intro/quickstart/modeling/nextjs.rst b/docs/intro/quickstart/modeling/nextjs.rst index ce54e63690d..903d9ffba3d 100644 --- a/docs/intro/quickstart/modeling/nextjs.rst +++ b/docs/intro/quickstart/modeling/nextjs.rst @@ -8,7 +8,7 @@ Modeling the data 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. + Looking at the mock data in the 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 zero or more ``Card`` objects in an array. .. code-block:: typescript diff --git a/docs/intro/quickstart/overview/fastapi.rst b/docs/intro/quickstart/overview/fastapi.rst index 219d098a0eb..d12d835ee71 100644 --- a/docs/intro/quickstart/overview/fastapi.rst +++ b/docs/intro/quickstart/overview/fastapi.rst @@ -5,57 +5,54 @@ Quickstart ========== Welcome to the quickstart tutorial! In this tutorial, you will update a FastAPI -backend for a Flashcards application to use Gel as your data layer. The +backend for a Flashcards 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 -FastAPI backend 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 +Don't worry if you're new to |Gel| - you will be up and running with a working +FastAPI backend 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 -- Building an app backed by Gel +* Creating and updating a database schema +* Running migrations to evolve your data +* Writing EdgeQL queries +* Building an app backed by |Gel| -******************************** - Features of the flashcards app -******************************** -- Create, edit, and delete decks -- Add/remove cards with front/back content -- Clean, type-safe schema with Gel +Features of the flashcards app +------------------------------ -************** - Requirements -************** +* Create, edit, and delete decks +* Add/remove cards with front/back content +* Clean, type-safe schema with |Gel| + +Requirements +------------ Before you start, you need: -- Basic familiarity with Python and FastAPI -- Python 3.8+ on a Unix-like OS (Linux, macOS, or WSL) -- A code editor you love +* Basic familiarity with Python and FastAPI +* Python 3.8+ on a Unix-like OS (Linux, macOS, or WSL) +* A code editor you love -********************** - Why Gel for FastAPI? -********************** +Why |Gel| for FastAPI? +---------------------- -- **Type Safety**: Catch data errors before runtime -- **Rich Modeling**: Use object types and links to model relations -- **Modern Tooling**: Python-friendly schemas and migrations -- **Performance**: Efficient queries for complex data -- **Developer Experience**: An intuitive query language (EdgeQL) +* **Type Safety**: Catch data errors before runtime +* **Rich Modeling**: Use object types and links to model relations +* **Modern Tooling**: Python-friendly schemas and migrations +* **Performance**: Efficient queries for complex data +* **Developer Experience**: An intuitive query language (EdgeQL) -************ - Need Help? -************ +Need Help? +---------- If you run into issues while following this tutorial: -- Check the `Gel documentation `_ +- Check the `|Gel| documentation `_ - Visit our `community Discord `_ - File an issue on `GitHub `_ diff --git a/docs/intro/quickstart/overview/index.rst b/docs/intro/quickstart/overview/index.rst index 4da839aa34f..ce33c92eef9 100644 --- a/docs/intro/quickstart/overview/index.rst +++ b/docs/intro/quickstart/overview/index.rst @@ -1,8 +1,8 @@ .. edb:env-switcher:: -======== -Overview -======== +========== +Quickstart +========== .. toctree:: :maxdepth: 3 diff --git a/docs/intro/quickstart/setup/fastapi.rst b/docs/intro/quickstart/setup/fastapi.rst index ef99d920887..72de1479320 100644 --- a/docs/intro/quickstart/setup/fastapi.rst +++ b/docs/intro/quickstart/setup/fastapi.rst @@ -1,12 +1,12 @@ .. _ref_quickstart_fastapi_setup: -############################# - Setting up your environment -############################# +=========================== +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 installed and the project being initialized. You are now ready to start building the application. + Use git to clone the `FastAPI starter template `_ into a new directory called ``flashcards``. This will create a fully configured FastAPI 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 @@ -17,23 +17,7 @@ $ python -m venv venv $ source venv/bin/activate # or venv\Scripts\activate on Windows $ pip install -r requirements.txt - -.. edb:split-section:: - - Next, you need to install the Gel CLI. The Gel CLI is a tool that helps you manage your Gel project. You will use it to run migrations, generate code, and interact with the database. - - .. code-block:: sh - - $ curl --proto '=https' --tlsv1.2 -sSf https://sh.edgedb.com | sh - -.. edb:split-section:: - - Once you've installed the Gel CLI, you can initialize the project by running the following command from the project root. This will create a new Gel project instance in the current directory. - - - .. code-block:: sh - - $ gel project init + $ uvx gel project init .. edb:split-section:: @@ -41,7 +25,7 @@ .. code-block:: sh - $ gel + $ uvx gel .. edb:split-section:: @@ -73,12 +57,26 @@ .. 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 we have. Here are the new files that integrate Gel: + Fun! You will create a proper data model for the application in the next step, but for now, take a look around the project we have. Here are the files that integrate |Gel|: - - ``gel.toml``: The configuration file for the Gel project instance. + - ``gel.toml``: The configuration file for the |Gel| project instance. Notice that we have a ``hooks.migration.apply.after`` hook that will run ``uvx gel-py`` after migrations are applied. This will run the code generator that you will use later to get fully type-safe queries you can run from your FastAPI backend. 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. - .. code-block:: sh + .. tabs:: + + .. code-tab:: toml + :caption: gel.toml + + [instance] + server-version = 6.0 + + [hooks] + schema.update.after = "uvx gel-py" + + .. code-tab:: sdl + :caption: dbschema/default.gel + + module default { - $ tree + } diff --git a/docs/intro/quickstart/setup/index.rst b/docs/intro/quickstart/setup/index.rst index babe44065d7..0135167bee7 100644 --- a/docs/intro/quickstart/setup/index.rst +++ b/docs/intro/quickstart/setup/index.rst @@ -1,8 +1,8 @@ .. edb:env-switcher:: -===== -Setup -===== +=========================== +Setting up your environment +=========================== .. toctree:: :maxdepth: 3 diff --git a/docs/intro/quickstart/setup/nextjs.rst b/docs/intro/quickstart/setup/nextjs.rst index 371fb5bd57d..578d4433996 100644 --- a/docs/intro/quickstart/setup/nextjs.rst +++ b/docs/intro/quickstart/setup/nextjs.rst @@ -58,10 +58,10 @@ Setting up your environment 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! + - ``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. + - ``lib/gel.ts``: A utility module that exports the |Gel| client, which you'll use to interact with the database. .. tabs:: diff --git a/docs/intro/quickstart/working/fastapi.rst b/docs/intro/quickstart/working/fastapi.rst index c42370f30d6..ad120a6f46a 100644 --- a/docs/intro/quickstart/working/fastapi.rst +++ b/docs/intro/quickstart/working/fastapi.rst @@ -11,7 +11,7 @@ Bulk importing of data .. edb:split-section:: - First, you need to update the imports and Pydantic models to use UUID instead of string for ID fields, since this is what |Gel| returns. You also need to initialize the |Gel| client and import the asyncio module to work with async functions. + First, update the imports and Pydantic models to use UUID instead of string for ID fields, since this is what |Gel| returns. You also need to initialize the |Gel| client and import the asyncio module to work with async functions. .. code-block:: python-diff :caption: main.py @@ -138,7 +138,7 @@ Bulk importing of data + description := $description, + cards := ( + select Card - + filter .id IN array_unpack(>$card_ids) + + filter contains(>$card_ids, .id) + ) + } + ) { ** } @@ -149,77 +149,57 @@ Bulk importing of data .. edb:split-section:: - The above works but isn't atomic - if creating a card fails, you could end up with partial data. Let's wrap it in a transaction: + The above works but isn't atomic - if any single query fails, you could end up with partial data. Let's wrap it in a transaction: .. code-block:: python-diff :caption: main.py @app.post("/decks/import", response_model=Deck) async def import_deck(deck: DeckCreate): - - card_ids = [] - - for i, card in enumerate(deck.cards): - - created_card = await client.query_single(""" - - insert Card { - - front := $front, - - back := $back, - - order := $order - - } - - """, front=card.front, back=card.back, order=i) - - card_ids.append(created_card.id) - - - - new_deck = await client.query_single(""" - - select( - - insert Deck { - - name := $name, - - description := $description, - - cards := ( - - select Card - - filter .id IN array_unpack(>$card_ids) - - ) - - } - - ) { ** } - - """, name=deck.name, description=deck.description, - - card_ids=card_ids) + async for tx in client.transaction(): + async with tx: - + card_ids = [] - + for i, card in enumerate(deck.cards): + card_ids = [] + for i, card in enumerate(deck.cards): + - created_card = await client.query_single( + created_card = await tx.query_single( - + """ - + insert Card { - + front := $front, - + back := $back, - + order := $order - + } - + """, - + front=card.front, - + back=card.back, - + order=i, - + ) - + card_ids.append(created_card.id) - + - + new_deck = await client.query_single(""" - + select( - + insert Deck { - + name := $name, - + description := $description, - + cards := ( - + select Card - + filter .id IN array_unpack(>$card_ids) - + ) - + } - + ) { ** } - + """, - + name=deck.name, - + description=deck.description, - + card_ids=card_ids, - + ) + """ + insert Card { + front := $front, + back := $back, + order := $order + } + """, + front=card.front, + back=card.back, + order=i, + ) + card_ids.append(created_card.id) + + - new_deck = await client.query_single(""" + + new_deck = await tx.query_single(""" + select( + insert Deck { + name := $name, + description := $description, + cards := ( + select Card + filter .id IN array_unpack(>$card_ids) + ) + } + ) { ** } + """, + name=deck.name, + description=deck.description, + card_ids=card_ids, + ) return new_deck .. edb:split-section:: - We can make this even more efficient by doing everything in a single query: + One of the most powerful features of EdgeQL is the ability to compose complex queries in a way that is both readable and efficient. Use this super-power to create a single query that inserts the deck and cards, along with their links, in one efficient query. + + This new query uses a ``for`` expression to iterate over the set of cards, and sets the ``Deck.cards`` link to the result of inserting each card. This is logically equivalent to the previous approach, but is more efficient since it inserts the deck and cards in a single query. .. code-block:: python-diff :caption: main.py @@ -270,13 +250,11 @@ Bulk importing of data + description := $description, + cards := ( + for card in array_unpack(cards) - + union ( - + insert Card { - + front := card.0, - + back := card.1, - + order := card.2 - + } - + ) + + insert Card { + + front := card.0, + + back := card.1, + + order := card.2 + + } + ) + } + ) { ** } @@ -322,22 +300,17 @@ Updating data + return await get_deck(deck_id) + + updated_deck = await client.query(f""" - + UPDATE Deck - + FILTER .id = $id - + SET {{ {', '.join(sets)} }} + + with updated := ( + + update Deck + + filter .id = $id + + set {{ {', '.join(sets)} }} + + ) + + select updated { ** } + """, **params) + + if not updated_deck: + raise HTTPException(status_code=404, detail="Deck not found") + - + query = """ - + select( - + update Deck - + filter .id = $id - + set { %s } - + ) { ** } - + """ % ", ".join(sets) - + + return updated_deck @@ -346,7 +319,9 @@ Adding linked data .. edb:split-section:: - Now, update the card operations to use |Gel| to add cards to a deck: + Now, update the add card operation to use |Gel|. This operation will 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:: python-diff :caption: main.py @@ -362,36 +337,29 @@ Adding linked data - deck.cards.append(new_card) - write_decks(decks) - return new_card - + # Get max order and increment - + deck = await client.query_single(""" - + select max(.cards.order) - + from Deck - + filter .id = $id - + """, id=deck_id) - + - + new_order = (deck.max_order or -1) + 1 - + - + new_card = await client.query_single(""" - + insert Card { - + front := $front, - + back := $back, - + order := $order, - + } - + """, front=card.front, back=card.back, - + order=new_order, deck_id=deck_id) - + - + new_deck = await client.query_single( + + new_card = await client.query_single( + """ - + select( - + update Deck - + filter .id = $id - + set { - + cards += (select Card { id, front, back } filter .id = $card_id) - + } - + ) { ** } + + with + + deck := (select Deck filter .id = $id), + + order := (max(deck.cards.order) + 1), + + new_card := ( + + insert Card { + + front := $front, + + back := $back, + + order := order, + + } + + ), + + updated := ( + + update deck + + set { + + cards += new_card + + } + + ), + + select new_card { ** } + """, + id=deck_id, - + card_id=new_card.id, + + front=card.front, + + back=card.back, + ) + + if not new_card: @@ -419,17 +387,14 @@ Deleting linked data - - deck.cards = [card for card in deck.cards if card.id != card_id] - write_decks(decks) - - return {"message": "Card deleted"} - + deleted = await client.query(""" - + delete Card - + filter - + .id = $card_id + + deleted = await client.query_single(""" + + delete Card filter .id = $card_id + """, card_id=card_id) + + if not deleted: + raise HTTPException(status_code=404, detail="Card not found") + - + return "Card deleted" + return {"message": "Card deleted"} Querying data ============= @@ -455,7 +420,7 @@ Querying data + front, + back + } - + order BY .order + + order by .order + ) + } + """) @@ -479,10 +444,10 @@ Querying data + front, + back + } - + order BY .order + + order by .order + ) + } - + FILTER .id = $id + + filter .id = $id + """, id=deck_id) + + if not deck: @@ -505,4 +470,4 @@ Querying data The API documentation will be available at http://localhost:8000/docs. You can use this interface to test your endpoints and import the sample flashcard deck. - .. image:: https://github.com/user-attachments/assets/707ba9e3-4c58-40a4-b5e9-7bb95d9d9d6e + .. image:: images/flashcards-api.png diff --git a/docs/intro/quickstart/working/images/flashcards-api.png b/docs/intro/quickstart/working/images/flashcards-api.png new file mode 100644 index 00000000000..40cffeb5ea6 Binary files /dev/null and b/docs/intro/quickstart/working/images/flashcards-api.png differ diff --git a/docs/intro/quickstart/working/index.rst b/docs/intro/quickstart/working/index.rst index bcb3c003254..bf8e51a8031 100644 --- a/docs/intro/quickstart/working/index.rst +++ b/docs/intro/quickstart/working/index.rst @@ -1,8 +1,8 @@ .. edb:env-switcher:: -======= -Working -======= +===================== +Working with the data +===================== .. toctree:: :maxdepth: 3