Metadata-Version: 2.4
Name: laydata
Version: 0.1.1
Summary: LayData Python client SDK
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Typing :: Typed
Classifier: Operating System :: OS Independent
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: httpx[http2]>=0.25.0
Requires-Dist: python-dotenv>=1.0.0
Requires-Dist: typing-extensions>=4.0.0

LayData Python Client SDK

🚀 An async Python SDK for interacting with LayData — an API-first database platform similar to Airtable, but built for developer speed and flexibility.

⸻

📦 Installation

pip install laydata


⸻

⚡ Quickstart

A minimal example showing the full high-level flow: connect, navigate the structure, work with records, and close the session.

import asyncio
from laydata import Data

async def main():
    # 1. Connect to LayData
    data = Data(endpoint="http://127.0.0.1:8077")

    # 2. Navigate the structure (use PascalCase!)
    MyCompany = await data.space("MyCompany")
    SalesCRM = await MyCompany.base("SalesCRM")
    Customers = await SalesCRM.table("Customers")

    # 3. Work with records
    NewCustomer = await Customers.add({
        "CustomerName": "Alice",
        "Email": "alice@example.com",
        "IsActive": True
    })

    AllCustomers = await Customers.records(take=10)
    await Customers.delete_record(NewCustomer["id"])

    # 4. Close the connection
    await data.close()

asyncio.run(main())

💡 Tip: Always use PascalCase for Space, Base, Table, and field names. It keeps your data model clean, predictable, and less error-prone.

⸻

🧠 Core Concepts

LayData organizes your data in a simple hierarchy:

Space → Base → Table → Record

Entity	Example	Description
Space	MyCompany	Top-level workspace (e.g. a company or project)
Base	SalesCRM	A database within a Space
Table	Customers	A table containing records
Record	Customer	A single row inside a table

📌 All operations are async and follow the same pattern:
space → base → table → record

⸻

🪄 Common Workflows

✏️ Create and Update Records

# Create a new record
Customer = await Customers.add({
    "CustomerName": "Alice",
    "Email": "alice@example.com"
})

# Find a record and edit it
PlumberJob = await Jobs.get_by("JobName", "Plumber")
await PlumberJob.edit({"JobName": "Plumba"})

# Get a specific field value
salary = PlumberJob.field("Salary")
print(salary)


⸻

🔍 Query and Filter Data

# Simple filtering
HighValueCustomers = await Customers.where("Value", ">=", 10000).all()

# Get the top record
TopCustomer = await Customers.desc("Value").first()

# Find by field
SpecificCustomer = await Customers.get_by("Email", "alice@example.com")


⸻

🔗 Chained Queries

TopElectronics = await (
    Products
    .contains("Category", "Electronics")
    .gte("Price", 200)
    .is_not_empty("Description")
    .desc("Price")
    .take(10)
    .all()
)


⸻

⚙️ Configuration

Create a .env file:

LAYDATA_BASE_URL=http://127.0.0.1:8077
LAYDATA_ALLOW_ATTACHMENTS=1  # for local development only

Load it automatically:

from dotenv import load_dotenv
load_dotenv()

data = Data()  # uses LAYDATA_BASE_URL from .env


⸻

🧰 Requirements
	•	Python >= 3.10
	•	httpx – async HTTP client
	•	python-dotenv (optional)

⸻

🧪 Advanced Usage

💡 These features are powerful but not essential for getting started.

📁 Special Field Types

from laydata import SingleSelect, MultiSelect, Date, Attachment
from datetime import datetime

Employee = await Employees.add({
    "Department": SingleSelect("Engineering"),
    "Skills": MultiSelect(["Python", "React"]),
    "HireDate": Date(datetime(2023, 1, 15)),
    "ProfilePhoto": Attachment("https://example.com/photo.jpg")
})


⸻

🛠 Table Metadata Management

Tasks = await ProjectBase.table("Tasks", icon="📋", description="Task tracking")
await Tasks.update_icon("✅")
await Tasks.update_description("Updated description")

AllTables = await ProjectBase.tables()


⸻

📦 Batch Operations & Error Handling

BatchData = [{"Name": f"Item {i}", "Price": 10 + i} for i in range(10)]

for item in BatchData:
    try:
        await Items.add(item)
    except Exception as e:
        print(f"Failed: {e}")


⸻

💡 Best Practices

✅ Always use PascalCase for Space, Base, Table, and field names.
✅ Treat records as objects — record.edit() and record.field() are the preferred ways to work with them.
✅ Start with simple queries (where().all(), get_by()) and build up to more complex filters as needed.
✅ Keep risky or infrequent operations (bulk deletes, update_icon) in dedicated functions or scripts.

⸻

📚 Next Steps
	•	📘 Explore Advanced Usage
	•	🛠 Use LayData as a backend for admin panels, CRMs, or internal tools
	•	🌐 Watch for new releases on GitHub

⸻
