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
awaitwith 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