Quickstart Guide

This guide will walk you through the basics of using Tapestry to interact with SurrealDB.

Basic Setup

First, make sure you have SurrealDB running and Tapestry installed. Then, let’s create a simple application.

Connecting to SurrealDB

Start by establishing a connection to your SurrealDB instance:

from surrealdb import Surreal

async def get_db():
    db = Surreal("ws://localhost:8000/rpc")
    await db.connect()
    await db.signin({"user": "root", "pass": "root"})
    await db.use("myapp", "myapp")
    return db

Defining Models

Tapestry uses Python classes to define your database schema. Let’s create a simple blog application:

Node Models

Nodes represent entities in your database:

from tapestry import Node
from datetime import datetime
from typing import Optional

class Author(Node):
    """Represents a blog author."""
    username: str
    email: str
    full_name: str
    bio: Optional[str] = None
    joined_date: datetime

class Post(Node):
    """Represents a blog post."""
    title: str
    content: str
    published: bool = False
    created_at: datetime
    updated_at: datetime

Edge Models

Edges represent relationships between nodes:

from tapestry import Edge

class Wrote(Edge):
    """Links an author to their posts."""
    in_: Post
    out_: Author
    published_at: datetime

Creating Records

Create instances of your models and save them to the database:

import asyncio
from datetime import datetime

async def create_data():
    db = await get_db()

    # Create an author
    alice = Author(
        username="alice",
        email="alice@example.com",
        full_name="Alice Smith",
        bio="Tech writer and developer",
        joined_date=datetime.now()
    )
    await alice.create(db)
    print(f"Created author: {alice.id}")

    # Create a post
    post = Post(
        title="Getting Started with Tapestry",
        content="Tapestry makes working with SurrealDB a breeze...",
        published=True,
        created_at=datetime.now(),
        updated_at=datetime.now()
    )
    await post.create(db)
    print(f"Created post: {post.id}")

    # Create relationship
    wrote = Wrote(
        in_=post,
        out_=alice,
        published_at=datetime.now()
    )
    await wrote.relate(db)
    print(f"Created relationship: {wrote.id}")

# Run it
asyncio.run(create_data())

Querying Records

Fetch records from the database:

Select All

async def get_all_authors():
    db = await get_db()

    # Get all authors
    authors = await Author.select(db)
    for author in authors:
        print(f"{author.username}: {author.email}")

Select by ID

from tapestry.utils import RecordID

async def get_author_by_id():
    db = await get_db()

    # Get specific author
    author_id = RecordID("author:alice")
    alice = await Author.select(db, author_id)
    print(alice.full_name)

Filter Records

async def get_published_posts():
    db = await get_db()

    # Query with conditions
    query = "SELECT * FROM post WHERE published = true"
    posts = await db.query(query)

    # Deserialize to Post objects
    from tapestry import Base
    posts = [Base.deserialize_record(p) for p in posts[0]['result']]
    return posts

Updating Records

Update existing records:

async def update_post():
    db = await get_db()

    # Get the post
    post_id = RecordID("post:123")
    post = await Post.select(db, post_id)

    # Update fields
    post.title = "Updated Title"
    post.updated_at = datetime.now()

    # Save changes
    await post.update(db)
    print("Post updated!")

Deleting Records

Delete records from the database:

async def delete_post():
    db = await get_db()

    # Get the post
    post_id = RecordID("post:123")
    post = await Post.select(db, post_id)

    # Delete it
    await post.delete(db)
    print("Post deleted!")

Schema Generation

Tapestry can automatically generate SurrealQL schema from your models:

from tapestry import Base

# Generate schema for all registered models
schema = Base.generate_schema()
print(schema)

# Apply schema to database
async def setup_schema():
    db = await get_db()
    schema = Base.generate_schema()
    await db.query(schema)
    print("Schema created!")

asyncio.run(setup_schema())

Complete Example

Here’s a complete example putting it all together:

import asyncio
from datetime import datetime
from typing import Optional
from surrealdb import Surreal
from tapestry import Node, Edge, Base
from tapestry.utils import RecordID

# Define models
class Author(Node):
    username: str
    email: str
    full_name: str
    bio: Optional[str] = None
    joined_date: datetime

class Post(Node):
    title: str
    content: str
    published: bool = False
    created_at: datetime
    updated_at: datetime

class Wrote(Edge):
    in_: Post
    out_: Author
    published_at: datetime

async def main():
    # Connect to database
    db = Surreal("ws://localhost:8000/rpc")
    await db.connect()
    await db.signin({"user": "root", "pass": "root"})
    await db.use("blog", "blog")

    # Setup schema
    schema = Base.generate_schema()
    await db.query(schema)
    print("✓ Schema created")

    # Create author
    alice = Author(
        username="alice",
        email="alice@example.com",
        full_name="Alice Smith",
        bio="Tech enthusiast",
        joined_date=datetime.now()
    )
    await alice.create(db)
    print(f"✓ Created author: {alice.username}")

    # Create post
    post = Post(
        title="My First Post",
        content="Hello, SurrealDB!",
        published=True,
        created_at=datetime.now(),
        updated_at=datetime.now()
    )
    await post.create(db)
    print(f"✓ Created post: {post.title}")

    # Create relationship
    wrote = Wrote(
        in_=post,
        out_=alice,
        published_at=datetime.now()
    )
    await wrote.relate(db)
    print(f"✓ Linked author to post")

    # Query all authors
    authors = await Author.select(db)
    print(f"✓ Found {len(authors)} author(s)")

    # Cleanup
    await db.close()

if __name__ == "__main__":
    asyncio.run(main())

Next Steps

Now that you know the basics, you can:

  • Explore the API Reference for detailed documentation

  • Learn about advanced querying and graph traversals

  • Check out type hints and validation features

  • Understand how to optimize your schema

Tips & Best Practices

Use Type Hints

Always use type hints for better IDE support and validation:

class User(Node):
    name: str  # Required
    age: int
    bio: Optional[str] = None  # Optional with default
Initialize Datetime Fields

Use datetime.now() for timestamp fields:

from datetime import datetime

user = User(
    name="Alice",
    age=30,
    created_at=datetime.now()
)
Handle Async Properly

Always use await with database operations:

# Correct
user = await User.select(db, user_id)

# Wrong - will not work
user = User.select(db, user_id)
Close Connections

Use context managers or remember to close connections:

async with Surreal("ws://localhost:8000/rpc") as db:
    await db.signin({"user": "root", "pass": "root"})
    # Your code here
    # Connection automatically closed
Generate Schema First

Always set up your schema before inserting data:

schema = Base.generate_schema()
await db.query(schema)
# Now you can create records