diff --git a/.github/ISSUE_TEMPLATE/UPDATE.md b/.github/ISSUE_TEMPLATE/UPDATE.md new file mode 100644 index 0000000..c131553 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/UPDATE.md @@ -0,0 +1,31 @@ +--- +name: Documentation Update +about: Suggest updates, additions, or improvements to the documentation +title: '[Docs Update] ' +labels: 'documentation' +assignees: '' +--- + +## Documentation Area +*Indicate the area of the documentation that needs updating (e.g., API reference, user guide, tutorials, etc.).* + +### Current Documentation Link +*Provide a link to the current documentation that needs updating (if applicable).* + +[Link to the current documentation] + +## Description of Changes +*Describe the changes you would like to see in the documentation.* + +## Rationale +*Explain why these changes are necessary or how they improve the documentation.* + +## Examples and Code Snippets +*Include any examples or code snippets that should be added to the documentation.* + +### Example 1 + +### Example 2 + +## Additional Context and Relevant Repos +*Provide any additional context or information that will help in making the necessary updates.* diff --git a/.github/workflows/aisearch.yaml b/.github/workflows/aisearch.yaml new file mode 100644 index 0000000..c5e8eac --- /dev/null +++ b/.github/workflows/aisearch.yaml @@ -0,0 +1,24 @@ +name: Process docs for SQLite AI Search + +on: + push: + branches: + - main + - stage + workflow_dispatch: + +jobs: + docsearch: + runs-on: ubuntu-latest + environment: ${{ github.ref_name }} + + steps: + - uses: actions/checkout@v4 + + - uses: sqliteai/sqlite-aisearch-action@v1 + with: + connection_string: ${{ secrets.PROJECT_STRING }} + base_url: ${{ vars.BASE_URL }} + database_name: documentation_ai.sqlite + source_files: ./ + only_extensions: "md,mdx" diff --git a/.github/workflows/search.yml b/.github/workflows/search.yml index 96b127e..2c48cf0 100644 --- a/.github/workflows/search.yml +++ b/.github/workflows/search.yml @@ -13,12 +13,12 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: sqlitecloud/docsearch-action@v3 + - uses: sqlitecloud/docsearch-action@v6 with: project-string: ${{ secrets.PROJECT_STRING }} base-url: ${{ vars.BASE_URL }} database: documentation.sqlite - strip-astro-header: true + use-front-matter: true strip-md-titles: true strip-jsx: true strip-html: true diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e43b0f9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store diff --git a/README.md b/README.md index 941e356..126db91 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,10 @@ title: SQLite Cloud Documentation description: Documentation files for docs.sqlitecloud.io category: getting-started -status: publish +status: draft --- # SQLite Cloud Documentation The content folder contains all the documentation files that the docs.sqlitecloud.io website imports. -These pages are open source and can be edited by anyone. +These pages are open source and can be edited by anyone. Just submit a pull request. diff --git a/sqlite-cloud/_nav.ts b/sqlite-cloud/_nav.ts index 8fc25c0..6d4eb79 100644 --- a/sqlite-cloud/_nav.ts +++ b/sqlite-cloud/_nav.ts @@ -2,165 +2,1018 @@ import type { SidebarNavStruct } from "@docs-website/types/sidebar-navigation"; const sidebarNav: SidebarNavStruct = [ { title: "", type: "primary" }, - { title: "Getting Started", type: "secondary", icon: "docs-star" }, - { title: "Introduction", href: "/docs/sqlite-cloud", type: "inner", level: 0 }, // should be index page for /docs and highlight "introduction" in nav - { title: "Fundamentals", type: "inner", level: 0 }, - { title: "Connecting", filePath: "sqlite-cloud/connect-cluster", type: "inner", level: 1 }, - { title: "Creating a database", filePath: "sqlite-cloud/create-database", type: "inner", level: 1 }, - { title: "Writing data", filePath: "sqlite-cloud/write-data", type: "inner", level: 1 }, + // ### AI ### + { title: "SQLite AI", type: "secondary", icon: "docs-star" }, + { title: "Overview", filePath: "ai-overview", type: "inner", level: 0 }, + + { title: "SQLite-AI", type: "inner", level: 0 }, + { title: "Overview", filePath: "sqlite-ai", type: "inner", level: 1 }, + { + title: "Getting Started", + filePath: "sqlite-ai-getting-started", + type: "inner", + level: 1, + }, + { + title: "Examples", + filePath: "sqlite-ai-examples", + type: "inner", + level: 1, + }, + { + title: "API Reference", + filePath: "sqlite-ai-api-reference", + type: "inner", + level: 1, + }, + { + title: "Embedding Notes", + filePath: "sqlite-ai-embedding-notes", + type: "inner", + level: 1, + }, + + { title: "SQLite-Memory", type: "inner", level: 0 }, + { title: "Overview", filePath: "sqlite-memory", type: "inner", level: 1 }, + { + title: "Getting Started", + filePath: "sqlite-memory-getting-started", + type: "inner", + level: 1, + }, + { + title: "Examples", + filePath: "sqlite-memory-examples", + type: "inner", + level: 1, + }, + { + title: "API Reference", + filePath: "sqlite-memory-api-reference", + type: "inner", + level: 1, + }, + { title: "CLI", filePath: "sqlite-memory-cli", type: "inner", level: 1 }, + + { title: "SQLite-Vector", type: "inner", level: 0 }, + { title: "Overview", filePath: "sqlite-vector", type: "inner", level: 1 }, + { + title: "Getting Started", + filePath: "sqlite-vector-getting-started", + type: "inner", + level: 1, + }, + { + title: "Examples", + filePath: "sqlite-vector-examples", + type: "inner", + level: 1, + }, + { + title: "API Reference", + filePath: "sqlite-vector-api-reference", + type: "inner", + level: 1, + }, + { + title: "Quantization", + filePath: "sqlite-vector-quantization", + type: "inner", + level: 1, + }, + + { title: "SQLite-Sync", type: "inner", level: 0 }, + { + title: "Introduction", + filePath: "sqlite-sync-introduction", + type: "inner", + level: 1, + }, + { + title: "Getting Started", + filePath: "sqlite-sync-getting-started", + type: "inner", + level: 1, + }, + { + title: "Installation", + filePath: "sqlite-sync-installation", + type: "inner", + level: 1, + }, + { title: "Platform Quick Starts", type: "inner", level: 1 }, + { + title: "Android", + filePath: "sqlite-sync-quick-start-android", + type: "inner", + level: 2, + }, + { + title: "iOS", + filePath: "sqlite-sync-quick-start-ios", + type: "inner", + level: 2, + }, + { + title: "macOS", + filePath: "sqlite-sync-quick-start-macos", + type: "inner", + level: 2, + }, + { + title: "Linux", + filePath: "sqlite-sync-quick-start-linux", + type: "inner", + level: 2, + }, + { + title: "Windows", + filePath: "sqlite-sync-quick-start-windows", + type: "inner", + level: 2, + }, + { + title: "Expo / React Native", + filePath: "sqlite-sync-quick-start-expo", + type: "inner", + level: 2, + }, + { + title: "WASM", + filePath: "sqlite-sync-quick-start-wasm", + type: "inner", + level: 2, + }, + { title: "PostgreSQL Backends", type: "inner", level: 1 }, + { + title: "Self-Hosted PostgreSQL", + filePath: "sqlite-sync-postgresql-quick-start", + type: "inner", + level: 2, + }, + { + title: "Self-Hosted Supabase", + filePath: "sqlite-sync-supabase-self-hosted-quick-start", + type: "inner", + level: 2, + }, + { + title: "JWT Claims Reference", + filePath: "sqlite-sync-jwt-claims", + type: "inner", + level: 2, + }, + { + title: "RLS Reference", + filePath: "sqlite-sync-rls-reference", + type: "inner", + level: 2, + }, + { + title: "Management API", + filePath: "sqlite-sync-cloudsync-management-api", + type: "inner", + level: 1, + }, + { + title: "Best Practices", + filePath: "sqlite-sync-best-practices", + type: "inner", + level: 1, + }, + { + title: "Row-Level Security", + filePath: "sqlite-sync-row-level-security", + type: "inner", + level: 1, + }, + { + title: "Block-Level LWW", + filePath: "sqlite-sync-block-lww", + type: "inner", + level: 1, + }, + { title: "Client API Reference", type: "inner", level: 1 }, + { + title: "Overview", + filePath: "sqlite-sync-api-reference", + type: "inner", + level: 2, + }, + { + title: "cloudsync_init", + filePath: "sqlite-sync-api-cloudsync-init", + type: "inner", + level: 2, + }, + { + title: "cloudsync_enable", + filePath: "sqlite-sync-api-cloudsync-enable", + type: "inner", + level: 2, + }, + { + title: "cloudsync_disable", + filePath: "sqlite-sync-api-cloudsync-disable", + type: "inner", + level: 2, + }, + { + title: "cloudsync_is_enabled", + filePath: "sqlite-sync-api-cloudsync-is-enabled", + type: "inner", + level: 2, + }, + { + title: "cloudsync_set_filter", + filePath: "sqlite-sync-api-cloudsync-set-filter", + type: "inner", + level: 2, + }, + { + title: "cloudsync_clear_filter", + filePath: "sqlite-sync-api-cloudsync-clear-filter", + type: "inner", + level: 2, + }, + { + title: "cloudsync_cleanup", + filePath: "sqlite-sync-api-cloudsync-cleanup", + type: "inner", + level: 2, + }, + { + title: "cloudsync_terminate", + filePath: "sqlite-sync-api-cloudsync-terminate", + type: "inner", + level: 2, + }, + { + title: "cloudsync_set_column", + filePath: "sqlite-sync-api-cloudsync-set-column", + type: "inner", + level: 2, + }, + { + title: "cloudsync_text_materialize", + filePath: "sqlite-sync-api-cloudsync-text-materialize", + type: "inner", + level: 2, + }, + { + title: "cloudsync_version", + filePath: "sqlite-sync-api-cloudsync-version", + type: "inner", + level: 2, + }, + { + title: "cloudsync_siteid", + filePath: "sqlite-sync-api-cloudsync-siteid", + type: "inner", + level: 2, + }, + { + title: "cloudsync_db_version", + filePath: "sqlite-sync-api-cloudsync-db-version", + type: "inner", + level: 2, + }, + { + title: "cloudsync_uuid", + filePath: "sqlite-sync-api-cloudsync-uuid", + type: "inner", + level: 2, + }, + { + title: "cloudsync_begin_alter", + filePath: "sqlite-sync-api-cloudsync-begin-alter", + type: "inner", + level: 2, + }, + { + title: "cloudsync_commit_alter", + filePath: "sqlite-sync-api-cloudsync-commit-alter", + type: "inner", + level: 2, + }, + { + title: "cloudsync_network_init", + filePath: "sqlite-sync-api-cloudsync-network-init", + type: "inner", + level: 2, + }, + { + title: "cloudsync_network_cleanup", + filePath: "sqlite-sync-api-cloudsync-network-cleanup", + type: "inner", + level: 2, + }, + { + title: "cloudsync_network_set_token", + filePath: "sqlite-sync-api-cloudsync-network-set-token", + type: "inner", + level: 2, + }, + { + title: "cloudsync_network_set_apikey", + filePath: "sqlite-sync-api-cloudsync-network-set-apikey", + type: "inner", + level: 2, + }, + { + title: "cloudsync_network_send_changes", + filePath: "sqlite-sync-api-cloudsync-network-send-changes", + type: "inner", + level: 2, + }, + { + title: "cloudsync_network_receive_changes", + filePath: "sqlite-sync-api-cloudsync-network-receive-changes", + type: "inner", + level: 2, + }, + { + title: "cloudsync_network_check_changes", + filePath: "sqlite-sync-api-cloudsync-network-check-changes", + type: "inner", + level: 2, + }, + { + title: "cloudsync_network_sync", + filePath: "sqlite-sync-api-cloudsync-network-sync", + type: "inner", + level: 2, + }, + { + title: "cloudsync_network_reset_sync_version", + filePath: "sqlite-sync-api-cloudsync-network-reset-sync-version", + type: "inner", + level: 2, + }, + { + title: "cloudsync_network_has_unsent_changes", + filePath: "sqlite-sync-api-cloudsync-network-has-unsent-changes", + type: "inner", + level: 2, + }, + { + title: "cloudsync_network_logout", + filePath: "sqlite-sync-api-cloudsync-network-logout", + type: "inner", + level: 2, + }, + + { title: "SQLite-Columnar", type: "inner", level: 0 }, + { title: "Overview", filePath: "sqlite-columnar", type: "inner", level: 1 }, + { + title: "Getting Started", + filePath: "sqlite-columnar-getting-started", + type: "inner", + level: 1, + }, + { + title: "API Reference", + filePath: "sqlite-columnar-api-reference", + type: "inner", + level: 1, + }, + { + title: "Benchmarks", + filePath: "sqlite-columnar-benchmarks", + type: "inner", + level: 1, + }, + + { title: "SQLite-JS", type: "inner", level: 0 }, + { title: "Overview", filePath: "sqlite-js", type: "inner", level: 1 }, + { + title: "Getting Started", + filePath: "sqlite-js-getting-started", + type: "inner", + level: 1, + }, + { + title: "API Reference", + filePath: "sqlite-js-api-reference", + type: "inner", + level: 1, + }, + { + title: "Examples", + filePath: "sqlite-js-examples", + type: "inner", + level: 1, + }, + + { title: "Tools & Workflows", type: "inner", level: 0 }, + { title: "MCP Server", filePath: "mcp-server", type: "inner", level: 1 }, + { + title: "AI-Powered Docs Search", + filePath: "aisearch-documents", + type: "inner", + level: 1, + }, + + // ### CLOUD ### + { title: "SQLite Cloud", type: "secondary", icon: "docs-star" }, + { title: "Overview", filePath: "overview", type: "inner", level: 0 }, + { title: "Scaling", filePath: "architecture", type: "inner", level: 0 }, + { title: "Getting Started", type: "inner", level: 0 }, + { title: "Connecting", filePath: "connect-cluster", type: "inner", level: 1 }, + { + title: "Creating a database", + filePath: "create-database", + type: "inner", + level: 1, + }, + { title: "Writing data", filePath: "write-data", type: "inner", level: 1 }, { title: "Quick Start Guides", type: "inner", level: 0 }, - { title: "React", filePath: "sqlite-cloud/quick-start-react", type: "inner", level: 1 }, - { title: "React Native", filePath: "sqlite-cloud/quick-start-react-native", type: "inner", level: 1 }, + { title: "CDN", filePath: "quick-start-cdn", type: "inner", level: 1 }, + { title: "Node.js", filePath: "quick-start-node", type: "inner", level: 1 }, + { title: "React", filePath: "quick-start-react", type: "inner", level: 1 }, + { + title: "React Native", + filePath: "quick-start-react-native", + type: "inner", + level: 1, + }, + { + title: "Apollo / GraphQL", + filePath: "quick-start-apollo-graphql", + type: "inner", + level: 1, + }, + { title: "Next.js", filePath: "quick-start-next", type: "inner", level: 1 }, + { title: "Django", filePath: "quick-start-django", type: "inner", level: 1 }, + { title: "Flask", filePath: "quick-start-flask", type: "inner", level: 1 }, + { + title: "SQLAlchemy", + filePath: "quick-start-sqlalchemy-orm", + type: "inner", + level: 1, + }, + { + title: "Streamlit", + filePath: "quick-start-streamlit", + type: "inner", + level: 1, + }, + { + title: "PHP / Laravel", + filePath: "quick-start-php-laravel", + type: "inner", + level: 1, + }, + { title: "Gin", filePath: "quick-start-gin", type: "inner", level: 1 }, + { title: "Knex.js", filePath: "quick-start-knex", type: "inner", level: 1 }, - { title: "Platform", type: "secondary", icon: "docs-plat" }, - { title: "Edge Functions", filePath: "edge-functions", type: "inner", level: 0 }, + // ### DASHBOARD ### + { title: "Dashboard", type: "secondary", icon: "docs-plat" }, + { + title: "Edge Functions", + filePath: "edge-functions", + type: "inner", + level: 0, + }, { title: "Webhooks", filePath: "webhooks", type: "inner", level: 0 }, - { title: "Pub/Sub", filePath: "pub-sub", type: "inner", level: 0 }, - { title: "Scaling", type: "inner", filePath: "scaling", level: 0 }, - { title: "Security and Access Control", filePath: "security", type: "inner", level: 0 }, + //{ title: "Vector", filePath: "vector", type: "inner", level: 0 }, + { title: "Users", filePath: "users", type: "inner", level: 0 }, + { title: "Roles & Privileges", filePath: "roles", type: "inner", level: 0 }, + { title: "API Keys", filePath: "apikey", type: "inner", level: 0 }, + { title: "Row-Level Security", filePath: "rls", type: "inner", level: 0 }, + { title: "CloudSync", filePath: "cloudsync", type: "inner", level: 0 }, + { + title: "Access Tokens", + filePath: "access-tokens", + type: "inner", + level: 0, + }, { title: "Backups", filePath: "backups", type: "inner", level: 0 }, { title: "Query Analyzer", filePath: "analyzer", type: "inner", level: 0 }, + { title: "Logs", filePath: "logs", type: "inner", level: 0 }, { title: "Extensions", filePath: "extensions", type: "inner", level: 0 }, - // { title: "Storage", type: "inner", level: 0 }, - // { title: "Partitioning", type: "inner", level: 0 }, - { title: "Settings", filePath: "settings", type: "inner", level: 0 }, + { title: "Weblite (REST API)", filePath: "weblite", type: "inner", level: 0 }, - { title: "SDKs", type: "secondary", icon: "docs-sdk" }, + // ### CLOUD SDK ### + { title: "Cloud SDKs", type: "secondary", icon: "docs-sdk" }, { title: "C/C++", type: "inner", level: 0 }, - { title: "Introduction", type: "inner", filePath: "sqlite-cloud/sdks/c/getting-started", level: 1, }, - { title: 'Basic APIs', type: "inner", level: 1 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudConnect', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudConnectWithString', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudExec', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudExecArray', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudUUID', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudDisconnect', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudConfig', type: "inner", level: 2 }, - - { title: 'Result APIs', type: "inner", level: 1 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudResultIsOK', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudResultIsError', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudResultType', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudResultLen', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudResultInt32', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudResultInt64', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudResultFloat', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudResultDouble', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudResultFree', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudResultDump', type: "inner", level: 2 }, + { + title: "Introduction", + type: "inner", + filePath: "sdk-c-introduction", + level: 1, + }, + { title: "Basic APIs", type: "inner", level: 1 }, + { filePath: "sqlite-cloud/sdks/c/SQCloudConnect", type: "inner", level: 2 }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudConnectWithString", + type: "inner", + level: 2, + }, + { filePath: "sqlite-cloud/sdks/c/SQCloudExec", type: "inner", level: 2 }, + { filePath: "sqlite-cloud/sdks/c/SQCloudExecArray", type: "inner", level: 2 }, + { filePath: "sqlite-cloud/sdks/c/SQCloudUUID", type: "inner", level: 2 }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudDisconnect", + type: "inner", + level: 2, + }, + { filePath: "sqlite-cloud/sdks/c/SQCloudConfig", type: "inner", level: 2 }, - { title: "Rowset APIs", type: "inner", level: 1 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudRowsetValueType', type: "inner", level: 3 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudRowsetColumnName', type: "inner", level: 3 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudRowsetValue', type: "inner", level: 3 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudRowsetInt32Value', type: "inner", level: 3 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudRowsetInt64Value', type: "inner", level: 3 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudRowsetFloatValue', type: "inner", level: 3 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudRowsetDoubleValue', type: "inner", level: 3 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudRowsetDump', type: "inner", level: 3 }, + { title: "Result APIs", type: "inner", level: 1 }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudResultIsOK", + type: "inner", + level: 2, + }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudResultIsError", + type: "inner", + level: 2, + }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudResultType", + type: "inner", + level: 2, + }, + { filePath: "sqlite-cloud/sdks/c/SQCloudResultLen", type: "inner", level: 2 }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudResultInt32", + type: "inner", + level: 2, + }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudResultInt64", + type: "inner", + level: 2, + }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudResultFloat", + type: "inner", + level: 2, + }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudResultDouble", + type: "inner", + level: 2, + }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudResultFree", + type: "inner", + level: 2, + }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudResultDump", + type: "inner", + level: 2, + }, + { title: "Rowset APIs", type: "inner", level: 1 }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudRowsetValueType", + type: "inner", + level: 2, + }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudRowsetColumnName", + type: "inner", + level: 2, + }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudRowsetValue", + type: "inner", + level: 2, + }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudRowsetInt32Value", + type: "inner", + level: 2, + }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudRowsetInt64Value", + type: "inner", + level: 2, + }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudRowsetFloatValue", + type: "inner", + level: 2, + }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudRowsetDoubleValue", + type: "inner", + level: 2, + }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudRowsetDump", + type: "inner", + level: 2, + }, { title: "Array APIs", type: "inner", level: 1 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudArrayValueType', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudArrayCount', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudArrayValue', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudArrayInt32Value', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudArrayInt64Value', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudArrayFloatValue', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudArrayDoubleValue', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudArrayDump', type: "inner", level: 2 }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudArrayValueType", + type: "inner", + level: 2, + }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudArrayCount", + type: "inner", + level: 2, + }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudArrayValue", + type: "inner", + level: 2, + }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudArrayInt32Value", + type: "inner", + level: 2, + }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudArrayInt64Value", + type: "inner", + level: 2, + }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudArrayFloatValue", + type: "inner", + level: 2, + }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudArrayDoubleValue", + type: "inner", + level: 2, + }, + { filePath: "sqlite-cloud/sdks/c/SQCloudArrayDump", type: "inner", level: 2 }, { title: "Error APIs", type: "inner", level: 1 }, - { title: 'SQCloudIsError', filePath: 'sqlite-cloud/sdks/c/SQCloudError', type: "inner", level: 2 }, - { title: 'SQCloudIsSQLiteError', filePath: 'sqlite-cloud/sdks/c/SQCloudError', type: "inner", level: 2 }, - { title: 'SQCloudErrorCode', filePath: 'sqlite-cloud/sdks/c/SQCloudError', type: "inner", level: 2 }, - { title: 'SQCloudExtendedErrorCode', filePath: 'sqlite-cloud/sdks/c/SQCloudError', type: "inner", level: 2 }, - { title: 'SQCloudErrorOffset', filePath: 'sqlite-cloud/sdks/c/SQCloudError', type: "inner", level: 2 }, - { title: 'SQCloudErrorMsg', filePath: 'sqlite-cloud/sdks/c/SQCloudError', type: "inner", level: 2 }, + { + title: "SQCloudIsError", + filePath: "sqlite-cloud/sdks/c/SQCloudError", + type: "inner", + level: 2, + }, + { + title: "SQCloudIsSQLiteError", + ref: "/docs/sqlite-cloud/sdks/c/sqclouderror", + type: "inner", + level: 2, + }, + { + title: "SQCloudErrorCode", + ref: "/docs/sqlite-cloud/sdks/c/sqclouderror", + type: "inner", + level: 2, + }, + { + title: "SQCloudExtendedErrorCode", + ref: "/docs/sqlite-cloud/sdks/c/sqclouderror", + type: "inner", + level: 2, + }, + { + title: "SQCloudErrorOffset", + ref: "/docs/sqlite-cloud/sdks/c/sqclouderror", + type: "inner", + level: 2, + }, + { + title: "SQCloudErrorMsg", + ref: "/docs/sqlite-cloud/sdks/c/sqclouderror", + type: "inner", + level: 2, + }, { title: "VM APIs", type: "inner", level: 1 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudVMCompile', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudVMStep', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudVMResult', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudVMClose', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudVMErrorMsg', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudVMErrorCode', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudVMIsReadOnly', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudVMIsExplain', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudVMIsFinalized', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudVMBindParameterCount', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudVMBindParameterIndex', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudVMBindParameterName', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudVMColumnCount', type: "inner", level: 2 }, - { title: 'SQCloudVMBindDouble', filePath: 'sqlite-cloud/sdks/c/SQCloudVMBind', type: "inner", level: 2 }, - { title: 'SQCloudVMBindInt', filePath: 'sqlite-cloud/sdks/c/SQCloudVMBind', type: "inner", level: 2 }, - { title: 'SQCloudVMBindInt64', filePath: 'sqlite-cloud/sdks/c/SQCloudVMBind', type: "inner", level: 2 }, - { title: 'SQCloudVMBindNull', filePath: 'sqlite-cloud/sdks/c/SQCloudVMBind', type: "inner", level: 2 }, - { title: 'SQCloudVMBindText', filePath: 'sqlite-cloud/sdks/c/SQCloudVMBind', type: "inner", level: 2 }, - { title: 'SQCloudVMBindBlob', filePath: 'sqlite-cloud/sdks/c/SQCloudVMBind', type: "inner", level: 2 }, - { title: 'SQCloudVMBindZeroBlob', filePath: 'sqlite-cloud/sdks/c/SQCloudVMBind', type: "inner", level: 2 }, - { title: 'SQCloudVMColumnBlob', filePath: 'sqlite-cloud/sdks/c/SQCloudVMColumn', type: "inner", level: 2 }, - { title: 'SQCloudVMColumnText', filePath: 'sqlite-cloud/sdks/c/SQCloudVMColumn', type: "inner", level: 2 }, - { title: 'SQCloudVMColumnDouble', filePath: 'sqlite-cloud/sdks/c/SQCloudVMColumn', type: "inner", level: 2 }, - { title: 'SQCloudVMColumnInt32', filePath: 'sqlite-cloud/sdks/c/SQCloudVMColumn', type: "inner", level: 2 }, - { title: 'SQCloudVMColumnInt64', filePath: 'sqlite-cloud/sdks/c/SQCloudVMColumn', type: "inner", level: 2 }, - { title: 'SQCloudVMColumnLen', filePath: 'sqlite-cloud/sdks/c/SQCloudVMColumn', type: "inner", level: 2 }, - { title: 'SQCloudVMColumnType', filePath: 'sqlite-cloud/sdks/c/SQCloudVMColumn', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudVMLastRowID', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudVMChanges', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudVMTotalChanges', type: "inner", level: 2 }, + { filePath: "sqlite-cloud/sdks/c/SQCloudVMCompile", type: "inner", level: 2 }, + { filePath: "sqlite-cloud/sdks/c/SQCloudVMStep", type: "inner", level: 2 }, + { filePath: "sqlite-cloud/sdks/c/SQCloudVMResult", type: "inner", level: 2 }, + { filePath: "sqlite-cloud/sdks/c/SQCloudVMClose", type: "inner", level: 2 }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudVMErrorMsg", + type: "inner", + level: 2, + }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudVMErrorCode", + type: "inner", + level: 2, + }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudVMIsReadOnly", + type: "inner", + level: 2, + }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudVMIsExplain", + type: "inner", + level: 2, + }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudVMIsFinalized", + type: "inner", + level: 2, + }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudVMBindParameterCount", + type: "inner", + level: 2, + }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudVMBindParameterIndex", + type: "inner", + level: 2, + }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudVMBindParameterName", + type: "inner", + level: 2, + }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudVMColumnCount", + type: "inner", + level: 2, + }, + { + title: "SQCloudVMBindDouble", + filePath: "sqlite-cloud/sdks/c/SQCloudVMBind", + type: "inner", + level: 2, + }, + { + title: "SQCloudVMBindInt", + ref: "/docs/sqlite-cloud/sdks/c/sqcloudvmbind", + type: "inner", + level: 2, + }, + { + title: "SQCloudVMBindInt64", + ref: "/docs/sqlite-cloud/sdks/c/sqcloudvmbind", + type: "inner", + level: 2, + }, + { + title: "SQCloudVMBindNull", + ref: "/docs/sqlite-cloud/sdks/c/sqcloudvmbind", + type: "inner", + level: 2, + }, + { + title: "SQCloudVMBindText", + ref: "/docs/sqlite-cloud/sdks/c/sqcloudvmbind", + type: "inner", + level: 2, + }, + { + title: "SQCloudVMBindBlob", + ref: "/docs/sqlite-cloud/sdks/c/sqcloudvmbind", + type: "inner", + level: 2, + }, + { + title: "SQCloudVMBindZeroBlob", + ref: "/docs/sqlite-cloud/sdks/c/sqcloudvmbind", + type: "inner", + level: 2, + }, + { + title: "SQCloudVMColumnBlob", + filePath: "sqlite-cloud/sdks/c/SQCloudVMColumn", + type: "inner", + level: 2, + }, + { + title: "SQCloudVMColumnText", + ref: "/docs/sqlite-cloud/sdks/c/sqcloudvmcolumn", + type: "inner", + level: 2, + }, + { + title: "SQCloudVMColumnDouble", + ref: "/docs/sqlite-cloud/sdks/c/sqcloudvmcolumn", + type: "inner", + level: 2, + }, + { + title: "SQCloudVMColumnInt32", + ref: "/docs/sqlite-cloud/sdks/c/sqcloudvmcolumn", + type: "inner", + level: 2, + }, + { + title: "SQCloudVMColumnInt64", + ref: "/docs/sqlite-cloud/sdks/c/sqcloudvmcolumn", + type: "inner", + level: 2, + }, + { + title: "SQCloudVMColumnLen", + ref: "/docs/sqlite-cloud/sdks/c/sqcloudvmcolumn", + type: "inner", + level: 2, + }, + { + title: "SQCloudVMColumnType", + ref: "/docs/sqlite-cloud/sdks/c/sqcloudvmcolumn", + type: "inner", + level: 2, + }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudVMLastRowID", + type: "inner", + level: 2, + }, + { filePath: "sqlite-cloud/sdks/c/SQCloudVMChanges", type: "inner", level: 2 }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudVMTotalChanges", + type: "inner", + level: 2, + }, { title: "Blob APIs", type: "inner", level: 1 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudBlobOpen', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudBlobReOpen', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudBlobClose', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudBlobBytes', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudBlobRead', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudBlobWrite', type: "inner", level: 2 }, - { title: "Pub/Sub APIs", type: "inner", level: 1 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudSetPubSubCallback', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudSetPubSubOnly', type: "inner", level: 2 }, + { filePath: "sqlite-cloud/sdks/c/SQCloudBlobOpen", type: "inner", level: 2 }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudBlobReOpen", + type: "inner", + level: 2, + }, + { filePath: "sqlite-cloud/sdks/c/SQCloudBlobClose", type: "inner", level: 2 }, + { filePath: "sqlite-cloud/sdks/c/SQCloudBlobBytes", type: "inner", level: 2 }, + { filePath: "sqlite-cloud/sdks/c/SQCloudBlobRead", type: "inner", level: 2 }, + { filePath: "sqlite-cloud/sdks/c/SQCloudBlobWrite", type: "inner", level: 2 }, { title: "Upload/Download APIs", type: "inner", level: 1 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudUploadDatabase', type: "inner", level: 2 }, - { filePath: 'sqlite-cloud/sdks/c/SQCloudDownloadDatabase', type: "inner", level: 2 }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudUploadDatabase", + type: "inner", + level: 2, + }, + { + filePath: "sqlite-cloud/sdks/c/SQCloudDownloadDatabase", + type: "inner", + level: 2, + }, { title: "JavaScript", type: "inner", level: 0 }, - { title: 'Introduction', type: "inner", filePath: "sqlite-cloud/sdks/js/getting-started", level: 1 }, - { title: 'React Quick Start', type: "inner", filePath: "sqlite-cloud/quick-start-react", level: 1 }, + { + title: "Introduction", + type: "inner", + filePath: "sdk-js-introduction", + level: 1, + }, + { title: "Quick Starts", type: "inner", level: 1 }, + { title: "React", ref: "/docs/quick-start-react", type: "inner", level: 2 }, + { title: "Node.js", ref: "/docs/quick-start-node", type: "inner", level: 2 }, + { title: "Next.js", ref: "/docs/quick-start-next", type: "inner", level: 2 }, + { title: "Tutorials", type: "inner", level: 1 }, + { + title: "Using SQLite Extensions - Geopoly", + filePath: "tutorial-geopoly", + type: "inner", + level: 2, + }, + { title: "Classes", type: "inner", level: 1 }, + { + title: "Database", + filePath: "sqlite-cloud/sdks/js/classes/Database", + type: "inner", + level: 2, + }, + { + title: "SQLiteCloudConnection", + filePath: "sqlite-cloud/sdks/js/classes/SQLiteCloudConnection", + type: "inner", + level: 2, + }, + { + title: "SQLiteCloudError", + filePath: "sqlite-cloud/sdks/js/classes/SQLiteCloudError", + type: "inner", + level: 2, + }, + { + title: "SQLiteCloudRow", + filePath: "sqlite-cloud/sdks/js/classes/SQLiteCloudRow", + type: "inner", + level: 2, + }, + { + title: "SQLiteCloudRowset", + filePath: "sqlite-cloud/sdks/js/classes/SQLiteCloudRowset", + type: "inner", + level: 2, + }, + { + title: "SQLiteCloudStatement", + filePath: "sqlite-cloud/sdks/js/classes/Statement", + type: "inner", + level: 2, + }, + + { title: "Interfaces", type: "inner", level: 1 }, + { + title: "SQLCloudRowsetMetadata", + filePath: "sqlite-cloud/sdks/js/interfaces/SQLCloudRowsetMetadata", + type: "inner", + level: 2, + }, + { + title: "SQLiteCloudConfig", + filePath: "sqlite-cloud/sdks/js/interfaces/SQLiteCloudConfig", + type: "inner", + level: 2, + }, + { title: "Modules", filePath: "sdk-js-modules", type: "inner", level: 1 }, { title: "Python", type: "inner", level: 0 }, - { title: 'Introduction', type: "inner", filePath: "sdk-python-introduction", level: 1 }, + { + title: "Introduction", + type: "inner", + filePath: "sdk-python-introduction", + level: 1, + }, + { title: "Django", ref: "/docs/quick-start-django", type: "inner", level: 1 }, + { title: "Flask", ref: "/docs/quick-start-flask", type: "inner", level: 1 }, + { + title: "SQLAlchemy", + ref: "/docs/quick-start-sqlalchemy-orm", + type: "inner", + level: 1, + }, - { title: "Go", type: "inner", level: 0 }, - { title: 'Introduction', type: "inner", filePath: "sqlite-cloud/sdks/go/getting-started", level: 1 }, + { title: "Go", type: "inner", level: 0 }, + { + title: "Introduction", + type: "inner", + filePath: "sdk-go-introduction", + level: 1, + }, { title: "PHP", type: "inner", level: 0 }, - { title: 'Introduction', type: "inner", filePath: "sqlite-cloud/sdks/php/getting-started", level: 1 }, - { title: "Methods", filePath: "sqlite-cloud/sdks/php/methods", type: "inner", level: 1 }, + { + title: "Introduction", + type: "inner", + filePath: "sdk-php-introduction", + level: 1, + }, + { title: "Methods", filePath: "sdk-php-methods", type: "inner", level: 1 }, + + { title: "Swift", type: "inner", level: 0 }, + { + title: "Introduction", + type: "inner", + filePath: "sdk-swift-introduction", + level: 1, + }, + // ### REFERENCE ### { title: "Reference", type: "secondary", icon: "docs-ref" }, { title: "Server-side Commands", type: "inner", level: 0 }, - { title: "Introduction", filePath: "server-side-commands", type: "inner", level: 1 }, + { + title: "Introduction", + filePath: "server-side-commands", + type: "inner", + level: 1, + }, { title: "API Keys", filePath: "api-key-commands", type: "inner", level: 1 }, - { title: "Authentication", filePath: "auth-commands", type: "inner", level: 1 }, + { + title: "Authentication", + filePath: "auth-commands", + type: "inner", + level: 1, + }, { title: "Backups", filePath: "backup-commands", type: "inner", level: 1 }, { title: "Cluster", filePath: "cluster-commands", type: "inner", level: 1 }, { title: "Database", filePath: "database-commands", type: "inner", level: 1 }, - { title: "General Info", filePath: "general-commands", type: "inner", level: 1 }, + { + title: "General Info", + filePath: "general-commands", + type: "inner", + level: 1, + }, { title: "IP", filePath: "ip-commands", type: "inner", level: 1 }, { title: "Logs", filePath: "log-commands", type: "inner", level: 1 }, { title: "Plugins", filePath: "plugin-commands", type: "inner", level: 1 }, - { title: "Privileges", filePath: "privilege-commands", type: "inner", level: 1 }, - { title: "Pub/Sub", filePath: "pub-sub-commands", type: "inner", level: 1 }, - { title: "Query Analyzer", filePath: "query-analyzer-commands", type: "inner", level: 1 }, + { + title: "Privileges", + filePath: "privilege-commands", + type: "inner", + level: 1, + }, + { + title: "Query Analyzer", + filePath: "query-analyzer-commands", + type: "inner", + level: 1, + }, { title: "Roles", filePath: "role-commands", type: "inner", level: 1 }, { title: "Settings", filePath: "settings-commands", type: "inner", level: 1 }, { title: "User", filePath: "user-commands", type: "inner", level: 1 }, - { title: "CLI", type: "inner", level: 0 }, + { title: "CLI", type: "inner", level: 0 }, { title: "Introduction", filePath: "cli-commands", type: "inner", level: 1 }, - { title: "SQLite", type: "inner", level: 0, href: "/docs/sqlite/" } - + { title: "SQLite", type: "inner", level: 0, href: "/docs/sqlite" }, ]; -export default sidebarNav +export default sidebarNav; diff --git a/sqlite-cloud/_wip-index-with-card.mdx b/sqlite-cloud/_wip-index-with-card.mdx new file mode 100644 index 0000000..36642ea --- /dev/null +++ b/sqlite-cloud/_wip-index-with-card.mdx @@ -0,0 +1,35 @@ +--- +title: Getting Started +description: Index page for getting started section +category: getting-started +status: publish +icon: docs-star +slug: getting-started +--- +import IndexPage from "@docs-website-components/Docs/IndexPage.astro" + +export const introduction = "SQLite Cloud is a distributed relational database system built on top of the SQLite database engine. It has been specifically designed from the ground up to ensure the strong consistency of your data across all nodes in a cluster while simultaneously managing the technical aspects of scaling, security, and data distribution." + +export const sections = [ + { + icon: "curvedArrow", + title: "Introduction", + description: "SQLite Cloud introduction and getting started guide.", + href: "/docs/introduction", + }, + { + icon: "twoColsGrid", + title: "Fundamentals", + description: "Learn how to connect to a cluster and start using SQLite Cloud.", + href: "/docs/connect-cluster", + }, + { + icon: "puzzle", + title: "Quick start guide", + description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", + href: "/docs/quick-start-cdn", + } +] + + + \ No newline at end of file diff --git a/sqlite-cloud/platform/scaling.mdx b/sqlite-cloud/architecture.mdx similarity index 71% rename from sqlite-cloud/platform/scaling.mdx rename to sqlite-cloud/architecture.mdx index 122a8a3..42eba8c 100644 --- a/sqlite-cloud/platform/scaling.mdx +++ b/sqlite-cloud/architecture.mdx @@ -1,11 +1,20 @@ --- -title: Scaling -description: How to scale your SQLite Cloud cluster. -category: platform +title: Architecture +description: SQLite Cloud Architecture +category: getting-started status: publish -slug: scaling +slug: architecture --- + +## Architecture +SQLite Cloud uses the Raft consensus algorithm to distribute your data changes across a cluster of computing systems, ensuring that each node in the cluster agrees upon the same series of state transitions. Raft implements consensus with a leader approach. + +SQLite Cloud is written in ANSI C and GO, and it works on most POSIX systems (Linux, *BSD, Mac OS X) and Windows. + +SQLite Cloud supports all the SQLite features without any limitations, including ACID compliance and non-deterministic SQL statements. + +## Scaling your cluster SQLite Cloud leverages a customized Raft algorithm to maintain a robust and highly available database cluster. Here’s an essential guide on the node types within SQLite Cloud and strategic tips for scaling your cluster effectively. ## Overview of Node types diff --git a/sqlite-cloud/connect-cluster.mdx b/sqlite-cloud/connect-cluster.mdx index ac44370..ef7b444 100644 --- a/sqlite-cloud/connect-cluster.mdx +++ b/sqlite-cloud/connect-cluster.mdx @@ -3,14 +3,16 @@ title: Connecting to a Cluster description: Learn how to connect to a cluster in SQLite Cloud. category: getting-started status: publish +slug: connect-cluster --- SQLite databases in SQLite Cloud are distributed across a cluster of nodes. Each cluster comes with a multi-region load balancer that routes traffic to the nearest appropriate node. -For this reason, we strongly recommend connecting to your cluster via your project connection string. To retrive your project connection string, navigate to the **Nodes** page and click on any node. -{/* ![Project connection string modal](@docs-website-assets/connect-cluster-1.png) */} +Click "Connect" in the bottom left-hand corner of your dashboard to get your connection string to use with a SQLite Cloud client library. + + +--- -Copy the connection string and use it with a client library to connect to your cluster. ## Connecting with JavaScript Here's an example of how you can connect to your cluster using the `@sqlitecloud/drivers` JavaScript client library: @@ -35,6 +37,8 @@ fetchAlbums().then((albums) => console.log(albums)); // [{ Title: 'For Those About To Rock We Salute You', ... }, ...] ``` +--- + ## Connecting with Python Install the Python client library: @@ -61,6 +65,8 @@ conn.close() # (1, 'For Those About To Rock We Salute You', 1) ``` +--- + ## Next Steps -- [Importing databases](#) -- [Writing data](#) +- [Creating a database](/docs/create-database) +- [Writing data](/docs/write-data) diff --git a/sqlite-cloud/create-database.mdx b/sqlite-cloud/create-database.mdx index fbf69c6..e2d83b0 100644 --- a/sqlite-cloud/create-database.mdx +++ b/sqlite-cloud/create-database.mdx @@ -3,44 +3,71 @@ title: Creating a Database description: Learn how to import a database into SQLite Cloud. category: getting-started status: publish +slug: create-database --- -Create a new database in SQLite Cloud by importing an existing SQLite database, or using the SQLite Cloud UI, API, or client libraries. +import VideoPlayer from '@commons-components/Video/VideoPlayer.astro'; +import uploadDb from '@docs-website-assets/introduction/video/dashboard_upload_db.mp4'; +import createDb from '@docs-website-assets/introduction/video/dashboard_create_db.mp4'; -## Importing an existing SQLite database -SQLite Cloud allows you to import existing SQLite databases into the platform. +You can import an existing SQLite databases, or create new databases using the SQLite Cloud UI, API, or client libraries. -Note that you can download, modify, and re-upload the database file at any time. You can also upload encrypted SQLite databases if you used the official SEE SQLite encryption extension. +--- + +## Uploading an existing SQLite Database +### Via HTTP API +You can upload an existing SQLite database to your cluster using the SQLite Cloud UI or the Weblite API. + +To upload a local SQLite database via weblite, make a POST request to the `/v2/weblite/.sqlite` endpoint. + +```bash +curl -X 'POST' \ + 'https://.sqlite.cloud/v2/weblite/.sqlite' \ + -H 'accept: application/json' \ + -H 'Authorization: Bearer sqlitecloud://.sqlite.cloud:8860?apikey=' \ + -d '' +``` + +To upload a local SQLite database via the SQLite Cloud UI, navigate to the Database tab in the left-hand navigation. Click the "Upload Database" button and select your local SQLite database. +### Via Dashboard UI To import a database from the UI, navigate to the Databases tab and click the "Upload Database" button. -![Dashbord Upload Database](@docs-website-assets/introduction/dashboard_upload_db.png) Select the database file you want to upload, and click "Upload Database". The database will be available in your cluster within a few minutes. + + +--- + ## Creating a new database ### From the Dashboard To create a new database from the SQLite Cloud UI, navigate to the Databases tab and click the "Create Database" button. -![Dashboard Create Database](@docs-website-assets/introduction/dashboard_create_database.png) The default encoding is set to UTF-8, and the default page size is 4096KB. + + ### From the API -To create a new database or upload an existing database via [Weblite](#), our REST API, you can make a request with the following parameters: +To create a new database or upload an existing database via [Weblite](/docs/weblite), our REST API, you can make a request with the following parameters: ```bash curl -X 'POST' \ - 'https://.sqlite.cloud:8090/v2/weblite/.sqlite' \ + 'https://.sqlite.cloud/v2/weblite/.sqlite' \ -H 'accept: application/json' \ -H 'Authorization: Bearer sqlitecloud://.sqlite.cloud:8860?apikey=' \ -d '' ``` ### From client libraries -To create a new database from a client library, use the CREATE DATABASE command. +To create a new database from a client library, connect to your cluster using a connection string without a specified database. + +Then, use the CREATE DATABASE command to create a new database. + +To start using the database within the connection, you can use the `USE DATABASE` command. ```javascript import { Database } from '@sqlitecloud/drivers'; - +// note that no database name is specified in the connection string path const db = new Database('sqlitecloud://.sqlite.cloud:?apikey=') const createDatabase = async () => await db.sql`CREATE DATABASE ;`; @@ -48,5 +75,16 @@ const createDatabase = async () => await db.sql`CREATE DATABASE ; createDatabase().then((res) => console.log(res)); // "OK" + +db.exec('USE DATABASE ;') + +// now you can use the database +const fetchAlbums = async () => await db.exec`SELECT * FROM albums;`; + +fetchAlbums().then((albums) => console.log(albums)); + +// [{ Title: 'For Those About To Rock We Salute You', ... }, ...] ``` +## Next Steps +- [Writing data](/docs/write-data) diff --git a/sqlite-cloud/index.mdx b/sqlite-cloud/index.mdx deleted file mode 100644 index 733e36c..0000000 --- a/sqlite-cloud/index.mdx +++ /dev/null @@ -1,34 +0,0 @@ ---- -title: Introduction to SQLite Cloud -description: SQLite Cloud is a distributed relational database system built on top of the SQLite database engine. -category: getting-started -status: publish ---- - -## Overview -**SQLite Cloud** is a distributed relational database system built on top of the SQLite database engine. - -It has been designed from the ground up to ensure the strong consistency of your data across all nodes in a cluster while simultaneously managing the technical aspects of scaling, security, and data distribution. This ensures that you can focus on your core tasks while relying on **SQLite Cloud** to handle the complexities of managing your databases. - -**SQLite Cloud** is written in ANSI C and GO, and it works on most POSIX systems like Linux, *BSD, and Mac OS X (Windows is supported too). You can use **SQLite Cloud** from the [most popular programming](../docs/sdk/) languages or its REST API. - ---- - -## Architecture - -**SQLite Cloud** uses the [Raft](https://raft.github.io) consensus algorithm to distribute your data changes across a cluster of computing systems, ensuring that each node in the cluster agrees upon the same series of state transitions. Raft implements consensus with a leader approach. - -**SQLite Cloud** supports all the SQLite features without any limitations. It is fully ACID compliant, supports non-deterministic SQL statements, and guarantees to be strongly consistent across all the cluster nodes. This ensures that data read from any node in the system returns the most up-to-date version of the data that has been committed. - -In a distributed database system, where data is distributed across multiple nodes, ensuring strong consistency can be challenging due to the potential for network delays, node failures, and concurrent transactions. Maintaining strong consistency is crucial for ensuring that the system behaves as expected and that applications built on top of the system can rely on the accuracy and integrity of the data. - -## Features -SQLite Cloud also provides a suite of tools for building realtime, local-first applications. -* **Local Sync**: Query your local SQLite database and syncronize with the cloud and across devices in real-time (**In development**). -* **Offline-first**: Resolve conflicts between devices and the cloud with CRDTs (**In developmpent**). -* **[Webhooks](/webhooks)**: Send changes to your database to external endpoints, or use to trigger edge functions via HTTP, Websockets, or on database events like INSERT, UPDATE, and DELETE. -* **[Edge Functions](/edge_functions)**: Run serverless functions on the same node that stores your data for low-latency operations. Trigger with webhooks or on database operations. -* **[Pub/Sub](/pub_sub)**: Subscribe to changes in your database to replicate data, power notifications, and build multiplayer experiences. -* **[Weblite](/weblite)**: Autogenerated REST APIs to interact with your database and edge functions. -* **[Query Analyzer](/query_analyzer)**: Receive optimization recommendations for your queries to improve performance. -* **Multi-region Load Balancer**: Connect to SQLite Cloud from anywhere in the world and SQLite Cloud automatically routes traffic to the nearest node for optimal performance. diff --git a/sqlite-cloud/multi-code-example.mdx b/sqlite-cloud/multi-code-example.mdx index e98af34..3fde715 100644 --- a/sqlite-cloud/multi-code-example.mdx +++ b/sqlite-cloud/multi-code-example.mdx @@ -1,7 +1,7 @@ --- title: Multi Code Component Examples description: Multi Code Component Examples -slug: components/multicode +slug: multicode category: getting-started status: draft --- @@ -10,8 +10,8 @@ import MultiCode from '@commons-components/Code/MultiCode.astro'; In this examples, we will show how to use the `MultiCode` component: -- [Here](https://github.com/sqlitecloud/website/blob/docs-stage/commons/components/Code/MultiCode.astro) the definition of the `MultiCode` component. -- [Here](https://github.com/sqlitecloud/website/blob/docs-stage/commons/components/Code/Code.astro) the definition of the `Code` component that is used inside the `MultiCode` component. +- Here the definition of the `MultiCode` component. +- Here the definition of the `Code` component that is used inside the `MultiCode` component. In these two files there are the TypeScript definitions usefull to know all the avaible properties. @@ -25,7 +25,7 @@ export const WebliteSourceCode = ` + + + + +

+ SQLite Cloud Example: Checking Chinook Customers +

+ +
+ + + + +
+ + +

Results:

+
    + + + + +``` + + - This HTML form sends a query to the `chinook.sqlite` database. You can load the form by simply dragging and dropping the file into your browser. + - To use SQLite Cloud's JS drivers, the example includes an additional script in the `` tag: ``. Update `{version}` with the most recent repo release. + +5. **Query data** + - There are 2 ways to query data. + 1. In your SQLite Cloud account dashboard, click on a Node, copy the Connection String, and paste it into the form's `Database Connection String` input. The expected string format is: `sqlitecloud://{host}.sqlite.cloud:8860?apikey={apikey}`. + + - Since this Connection String format does NOT contain the database to query, you MUST include the database name in your query. The expected query format is: `USE DATABASE {database}; select * from {table}`. + - IMPORTANT: The example SQL we provide (`USE DATABASE chinook.sqlite; select * from customers limit 3`) queries the `customers` table in the `chinook` database. The results are specifically parsed to be more readable. To display raw data from any table, uncomment the `index.html` code starting after `// list raw data` and comment out the later `for` loop. + + 2. An alternative Connection String format is: `sqlitecloud://{username}:{password}@{host}.sqlite.cloud:8860/{database}`. + + - Since this Connection String format DOES contain the database to query, you can exclude the database name from your query: `select * from {table}`. + - To get your admin username, go to your SQLite Cloud account dashboard. In the left nav, open Security and select Users. Your admin username has already been created. Replace `{username}` the connection string. + - To set your admin user's password, click the row's down chevron and select Edit. Enter a new Password and click Save. Replace `{password}` in the connection string. + - To get the host, see under your Project name `{host}.sqlite.cloud`. + - To get the database name, in the left nav, open Databases and select Tables. All of your databases are listed in the Select Database dropdown. + + - Send your query! Returned results will be listed, from most to least recent, below the form inputs. + +And that's it! You've successfully submitted a simple form to read data from a SQLite Cloud database. \ No newline at end of file diff --git a/sqlite-cloud/quickstart/quick-start-django.mdx b/sqlite-cloud/quickstart/quick-start-django.mdx new file mode 100644 index 0000000..8d467b6 --- /dev/null +++ b/sqlite-cloud/quickstart/quick-start-django.mdx @@ -0,0 +1,155 @@ +--- +title: Django Quick Start Guide +description: Get started with SQLite Cloud using Django. +category: getting-started +status: publish +slug: quick-start-django +--- + +In this quickstart, we will show you how to get started with SQLite Cloud and Django by building a simple application that connects to and reads from a SQLite Cloud database. + +1. **Set up a SQLite Cloud account** + - If you haven't already, sign up for a SQLite Cloud account and create a new project. + - In this guide, we will use the sample datasets that come pre-loaded with SQLite Cloud. + +2. **Create a Django app** + - If you haven't already done so, install Python and Django. + - The following command creates an outer directory (the container for your project) AND an inner directory (the Python package for your project). Both directories will be named `sqlitecloud_quickstart`. + +```bash +django-admin startproject sqlitecloud_quickstart +``` + - The following command creates your app as a separate package within the project container directory. + +```bash +cd sqlitecloud_quickstart +python manage.py startapp albums +``` + +3. **Install the SQLite Cloud Python SDK** + - Run this command from your current directory (i.e. the outer `sqlitecloud_quickstart`). + +```bash +pip install sqlitecloud +``` + +4. **App setup** + - Create a new file `albums/services.py` and copy in the following code. + - In your SQLite Cloud account dashboard, click on a Node, copy the Connection String, and replace `` below. + +```python +import sqlitecloud + +def get_albums(): + conn = sqlitecloud.connect('') + + db_name = "chinook.sqlite" + db_query = "SELECT albums.AlbumId as id, albums.Title as title, artists.name as artist FROM albums INNER JOIN artists WHERE artists.ArtistId = albums.ArtistId LIMIT 20" + + conn.execute(f"USE DATABASE {db_name}") + + cursor = conn.execute(db_query) + + conn.close() + + result = cursor.fetchall() + + return result +``` + + - Copy the following code into `albums/views.py`. This view function invokes the `get_albums()` function defined in `services.py` to connect to the database and return album and artist information. + - The view function converts each returned row from a list to an object to more easily access the information in our HTML template (will discuss further later). + +```python +from django.http import HttpResponse +from django.template import loader +from .services import get_albums + +def index(request): + albumsList = get_albums() + + albumObjsList = [{'album': row[1], 'artist': row[2]} for row in albumsList] + + template = loader.get_template("albums/index.html") + context = { + "albumObjsList": albumObjsList, + } + return HttpResponse(template.render(context, request)) +``` + + - Create a new file `albums/urls.py` and copy in the following code. This URL configuration (URLconf) maps the above view to a URL so we can access the view in the browser. + +```python +from django.urls import path +from . import views + +urlpatterns = [ + path("", views.index, name="index") +] +``` + + - Adjust the code in `sqlitecloud_quickstart/urls.py` to be as follows. We must configure this global URLconf in the inner `sqlitecloud_quickstart` to include the URLconf we defined above in our app. + +```python +from django.contrib import admin +from django.urls import include, path + +# global URLconfs +urlpatterns = [ + path("albums/", include("albums.urls")), + path('admin/', admin.site.urls), +] +``` + + - Now we'll create a Django template the view can use to render HTML. Under `albums`, create a new file at `templates/albums/index.html` and copy in the following code. + - Bear in mind, there are now 2 (outer and inner) `albums` directories. + - The `index` view function above is already set up to load and render the template `albums/index.html`. (NOTE: `albums` here is the inner `albums` dir.) + +```html +
    +

    Albums

    +
      + {% for row in albumObjsList %} +
    • {{ row.album }} by {{ row.artist }}
    • + {% endfor %} +
    +
    +``` + - Lastly, in `sqlitecloud_quickstart/settings.py`, configure `DIRS` in `TEMPLATES` as follows. + - `'APP_DIRS': True` tells Django's templating engine to look for template source files inside project apps. + - `DIRS` provides the filepath to the correct app's `templates` dir. + +```python +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': ['albums/templates'], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] +``` + +5. **Run the Django dev server** + +```bash +python manage.py runserver +``` + + - Visit `http://127.0.0.1:8000/albums/` to see your app data. + +6. **FOLLOW-UP:** +This Quickstart goes a bit deeper into the framework than the other Quickstarts since Django requires more boilerplate to get up-and-running with a simple app. + +If you're new to Django and want to learn more, we referenced the following Django Tutorial pages extensively when writing this Quickstart: + - Part 1 + - Part 3 + +And that's it! You've successfully built a Django app that reads data from a SQLite Cloud database. \ No newline at end of file diff --git a/sqlite-cloud/quickstart/quick-start-flask.mdx b/sqlite-cloud/quickstart/quick-start-flask.mdx new file mode 100644 index 0000000..dfe33ec --- /dev/null +++ b/sqlite-cloud/quickstart/quick-start-flask.mdx @@ -0,0 +1,80 @@ +--- +title: Flask Quick Start Guide +description: Get started with SQLite Cloud using Flask. +category: getting-started +status: publish +slug: quick-start-flask +--- + +In this quickstart, we will show you how to get started with SQLite Cloud and Flask by building a simple application that connects to and reads from a SQLite Cloud database. + +--- + +1. **Set up a SQLite Cloud account** + - If you haven't already, sign up for a SQLite Cloud account and create a new project. + - In this guide, we will use the sample datasets that come pre-loaded with SQLite Cloud. + +2. **Create a Flask app** + - You should have the latest Python version (3) installed locally. + +```bash +mkdir sqlc-quickstart +cd sqlc-quickstart + +python3 -m venv .venv +. .venv/bin/activate + +pip install flask +``` + +3. **Install the SQLite Cloud SDK** + +```bash +pip install sqlitecloud +``` + +4. **Query data** + - Copy the following code into a new `app.py` file. + - In your SQLite Cloud account dashboard, click on a Node, copy the Connection String, and replace `` below. + +```py +from flask import Flask +import sqlitecloud + +app = Flask(__name__) + +@app.route('/') +def get_albums(): + conn = sqlitecloud.connect('') + + db_name = 'chinook.sqlite' + db_query = "SELECT albums.AlbumId as id, albums.Title as title, artists.name as artist FROM albums INNER JOIN artists WHERE artists.ArtistId = albums.ArtistId LIMIT 20" + + conn.execute(f"USE DATABASE {db_name}") + + cursor = conn.execute(db_query) + + conn.close() + + result = '

    Albums

    ' + + for row in cursor: + album = f"{row[1]} by {row[2]}" + result += f"
  • {album}
  • " + + return result + '
    ' +``` + +5. **Run your app** + - If you're using port 5000 or on MacOS, also pass the `--port` option to provdie an open port. + - Pass the --debug option to enable hot reloading and interactive debugging on your dev server. + +```bash +flask run --port 3000 --debug +``` + +6. **View your app** + - Open your browser and navigate to `http://127.0.0.1:3000/` to see your app data. + - If you're unfamiliar with Flask, the code above calls the `get_albums` function when you load the root URL. The function returns a string with HTML for the browser to render. + +And that's it! You've successfully built a Flask app that reads data from a SQLite Cloud database. diff --git a/sqlite-cloud/quickstart/quick-start-gin.mdx b/sqlite-cloud/quickstart/quick-start-gin.mdx new file mode 100644 index 0000000..655f381 --- /dev/null +++ b/sqlite-cloud/quickstart/quick-start-gin.mdx @@ -0,0 +1,141 @@ +--- +title: Gin Quick Start Guide +description: Get started with SQLite Cloud using Gin. +category: getting-started +status: publish +slug: quick-start-gin +--- + +In this quickstart, we will show you how to get started with SQLite Cloud and Go by building a simple Gin application that connects to and reads from a SQLite Cloud database. + +--- + +1. **Set up a SQLite Cloud account** + - If you haven't already, sign up for a SQLite Cloud account and create a new database. + - In this guide, we will use the sample datasets that come pre-loaded with SQLite Cloud. + +2. **Create a Gin app** + - You should have Go installed locally. + - Set up your Go workspace. +```bash +mkdir sqlc-quickstart +cd sqlc-quickstart + +go mod init example.com/sqlc-quickstart +``` + - Create a file called `app.go`. + - Add the following code to your `app.go` file. +```go +package main + +import "fmt" +``` + - Import the Gin package in your Go source code. +```go +import "github.com/gin-gonic/gin" +``` + - Run the `go mod tidy` command to synchronize your module's dependencies. +```bash +$ go mod tidy +go: finding module for package github.com/gin-gonic/gin +go: found github.com/gin-gonic/gin in github.com/gin-gonic/gin v1.10.0 +go: downloading github.com/google/go-cmp v0.5.5 +``` + +3. **Install the SQLite Cloud package** +- Import the package in your Go source code. +```go +import sqlitecloud "github.com/sqlitecloud/sqlitecloud-go" +``` +- Download the package, and run the `go mod tidy` command to synchronize your module’s dependencies. +```bash +$ go mod tidy +go: downloading github.com/sqlitecloud/sqlitecloud-go v1.0.0 +``` + +4. **Connect with a valid SQLite Cloud connection string** +```go +sqlitecloud://{username}:{password}@{host}.sqlite.cloud:8860/{database} +``` +- To get your admin username, go to your SQLite Cloud account dashboard. In the left nav, open Security and select Users. Your admin username has already been created. Replace `{username}` in the connection string. +- To set your admin user’s password, click the row’s down chevron and select Edit. Enter a new Password and click Save. Replace `{password}` in the connection string. +- To get the host, see under your Project name `{host}.sqlite.cloud`. +- To get the database name, in the left nav, open Databases and select Tables. All of your databases are listed in the Select Database dropdown. + + +5. **Query data** + - Copy the following code into the `app.go` file. + - Replace ``. + +```go +type Artist struct { + ArtistID int64 `json:"artist id"` + Name string `json:"name"` +} + +func readArtists(resultSet *sqlitecloud.Result) ([]Artist, error) { + var artists []Artist + + for r := uint64(0); r < resultSet.GetNumberOfRows(); r++ { + id, err := resultSet.GetInt64Value(r, 0) + if err != nil { + return nil, err + } + + name, err := resultSet.GetStringValue(r, 1) + if err != nil { + return nil, err + } + + artists = append(artists, Artist{ + ArtistID: id, + Name: name, + }) + } + + return artists, nil +} + +func main() { + r := gin.Default() + + r.GET("/artists", func(c *gin.Context) { + const connectionString = "" + + db, err := sqlitecloud.Connect(connectionString) + if err != nil { + fmt.Println("Connect error: ", err) + panic("Connect error") + } + + dbResult, err := db.Select("SELECT * FROM artists LIMIT 10;") + if err != nil { + fmt.Println("Select error: ", err) + panic("Select error") + } + + artists, err := readArtists(dbResult) + if err != nil { + fmt.Println("Read artists error: ", err) + panic("Read artists error") + } + + c.JSON(200, artists) + + }) + + r.Run() // listen and serve on 0.0.0.0:8080 +} + +``` + +6. **Run your app** + +```bash +$ go run app.go +``` + +7. **View your app** + - Open your browser and navigate to `localhost:8080/artists`. + +And that's it! You've successfully built a Gin app that reads data from a SQLite Cloud database. \ No newline at end of file diff --git a/sqlite-cloud/quickstart/quick-start-knex.mdx b/sqlite-cloud/quickstart/quick-start-knex.mdx new file mode 100644 index 0000000..ef52c05 --- /dev/null +++ b/sqlite-cloud/quickstart/quick-start-knex.mdx @@ -0,0 +1,154 @@ +--- +title: Knex.js Integration +description: Integrate SQLite Cloud with Knex.js, a popular SQL query builder. +category: getting-started +status: publish +slug: quick-start-knex +--- + +In this tutorial, we'll show you how to connect your TypeScript application to a SQLite Cloud database using the popular SQL builder, Knex.js. + +--- + +**Prerequisites** + +- Node.js and npm installed on your system +- A SQLite Cloud account (you can sign up for a free account here) + +1. **How to connect** + +- Create a Knex.js instance that uses the SQLite Cloud JavaScript driver to connect to your database. + +```typescript +import 'dotenv/config' +import { knex } from 'knex' + +const Client_SQLite3 = require('knex/lib/dialects/sqlite3') + +// client will have sqlite3 dialect, but will use sqlitecloud-js driver +class Client_Libsql extends Client_SQLite3 { + _driver() { + return require('@sqlitecloud/drivers') + } +} + +// Create a Knex.js instance with the custom SQLite3 client +const db = knex({ + client: Client_Libsql as any, + connection: { + filename: process.env.DATABASE_URL as string + } +}) +``` + +2. **Basic Usage** + +In this example, we will use the sample datasets that come pre-loaded with SQLite Cloud. + +- Initialize a new Node project: + +```bash +npm init -y +``` + +- Install the required dependencies: + +```bash +npm install @sqlitecloud/drivers knex dotenv --save +``` + +- Install the necessary development dependencies: + +```bash +npm install @types/node nodemon ts-node typescript --save-dev +``` + +- Create a `.env` file in the root of your project and add your SQLite Cloud connection string: + +```bash +DATABASE_URL="sqlitecloud://{USER}:{PASSWORD}@{HOST}.sqlite.cloud:8860" +``` + +Replace `{USER}`, `{PASSWORD}`, and `{HOST}` with your actual SQLite Cloud credentials and server hostname. + +- Create a `tsconfig.json` file to configure your TypeScript compiler: + +```bash +tsc --init +``` + +- Create a new file called `example.ts` and add the following code: + +```typescript +import 'dotenv/config' +import { knex } from 'knex' + +const Client_SQLite3 = require('knex/lib/dialects/sqlite3') + +class Client_Libsql extends Client_SQLite3 { + _driver() { + return require('@sqlitecloud/drivers') + } +} + +console.assert(process.env.DATABASE_URL, 'Define DATABASE_URL environment variable') + +const db = knex({ + client: Client_Libsql as any, + connection: { + filename: process.env.DATABASE_URL as string + } +}) + +db.raw('USE DATABASE chinook.sqlite; SELECT * FROM customers') + .then(result => { + console.log(`Connected to database via knex and received ${result.length} rows`) + console.log(JSON.stringify(result, null, 2)) + db.destroy() + }) + .catch(err => { + console.error(err) + db.destroy() + }) +``` + +- Update your `package.json` file to include a script for running the example: + +```bash +{ + "scripts": { + "dev": "nodemon --exec ts-node example.ts" + } +} +``` + +- Start the development server: + +```bash +npm run dev +``` + +This will run the `example.ts` file using `ts-node` and will automatically restart the server when you make changes to your code. + +- Observe the output in the console, which should display the customer data fetched from the SQLite Cloud database. +```bash + [ + { + "CustomerId": 1, + "FirstName": "Luís", + "LastName": "Gonçalves", + "Company": "Embraer - Empresa Brasileira de Aeronáutica S.A.", + "Address": "Av. Brigadeiro Faria Lima, 2170", + "City": "São José dos Campos", + "State": "SP", + "Country": "Brazil", + "PostalCode": "12227-000", + "Phone": "+55 (12) 3923-5555", + "Fax": "+55 (12) 3923-5566", + "Email": "luisg@embraer.com.br", + "SupportRepId": 3 + }, + ] +``` + +And that's it! You've successfully connected your TypeScript application to a SQLite Cloud database using Knex.js. diff --git a/sqlite-cloud/quickstart/quick-start-laravel.mdx b/sqlite-cloud/quickstart/quick-start-laravel.mdx new file mode 100644 index 0000000..f2ee817 --- /dev/null +++ b/sqlite-cloud/quickstart/quick-start-laravel.mdx @@ -0,0 +1,147 @@ +--- +title: PHP / Laravel Quick Start Guide +description: Get started with SQLite Cloud using PHP and Laravel. +category: getting-started +status: publish +slug: quick-start-php-laravel +--- + +In this quickstart, we will show you how to get started with SQLite Cloud and PHP by building a simple Laravel application that connects to and reads from a SQLite Cloud database. + +--- + +1. **Set up a SQLite Cloud account** + - If you haven't already, sign up for a SQLite Cloud account and create a new project. + - In this guide, we will use the sample datasets that come pre-loaded with SQLite Cloud. + +2. **Create a Laravel app** + - If you haven't already done so, install PHP, Laravel, and Composer. + - If you use macOS, you can install all 3 in 1 click by downloading Laravel Herd, a PHP dev environment. + - Create a new Laravel project. + +```bash +composer create-project laravel/laravel sqlc-quickstart +``` + + - In the project directory, start Laravel's local dev server. + +```bash +cd sqlc-quickstart +php artisan serve +``` + + - Visit `http://127.0.0.1:8000` to see your Laravel app. + +3. **Configure a Blade frontend** + - Open another terminal. Again in your project dir, install Laravel Breeze. + - By default, Breeze uses simple Blade templates for your app's view layer. Blade is a templating engine included with Laravel. HTML is rendered server-side so you can include dynamic content from your database. + +```bash +composer require laravel/breeze --dev +php artisan breeze:install blade +``` + + - Start a Vite dev server that will hot reload updates to your app. (No need to load the provided localhost link, just keep the Vite server running.) + +```bash +npm run dev +``` + + - Refresh your app in the browser. Click the "Register" link at the top right. Register an account and log in. Save your credentials. + +4. **App setup** + + - Open another terminal. Again in your project dir, run `php artisan make:model -rc Album` to create an Eloquent Model (which we'll ignore) and a HTTP resource controller: `app/Http/Controllers/AlbumController.php`. We'll add functionality to this file to process app requests and return responses later. + - Replace the code in `routes/web.php` with the following snippet to add a route named `albums.index`. + - Run `php artisan route:list` to view all your app routes. + - `albums.index` will route GET requests to the `albums` endpoint to `AlbumController`'s `index` method (will set up later). + +```php +only(['index']); +``` + + - Create a new file `resources/views/albums/index.blade.php` and copy in the following code to create your Blade view template. + +```php +

    Albums

    +
      +@foreach ($albums as $album) +
    • {{ $album['albumTitle'] }} by {{ $album['artistName'] }}
    • +@endforeach +
    +``` + +5. **Install the SQLite Cloud SDK** + +```bash +composer require sqlitecloud/sqlitecloud +``` + +6. **Query data** + + - Replace the code in `app/Http/Controllers/AlbumController.php` with the following snippet. + - In your SQLite Cloud account dashboard, click on `Show connection strings`, copy the Connection String, and replace `` below. + - The `index` method will: + - connect to and query the database, + - create an array of arrays `albums` containing each returned album's title and artist, + - use the global `view` helper to pass `albums` to your view template stored at `resources/views/albums/index.blade.php` (and already set up to list the data), and + - return the completed Blade view to the browser. + +```php +connectWithString(''); + + $db_name = 'chinook.sqlite'; + $db_query = 'SELECT albums.AlbumId as id, albums.Title as title, artists.name as artist FROM albums INNER JOIN artists WHERE artists.ArtistId = albums.ArtistId LIMIT 20'; + + $sqlite->execute("USE DATABASE {$db_name}"); + + $rowset = $sqlite->execute($db_query); + + $sqlite->disconnect(); + + $albums = []; + + for($i = 0; $i < $rowset->nrows; $i++) { + $albums[] = [ + 'albumTitle' => $rowset->value($i, 1), + 'artistName' => $rowset->value($i, 2), + ]; + } + + return view('albums.index', [ + 'albums' => $albums + ]); + } +} +``` + +7. **View your app** + - Visit `http://127.0.0.1:8000/albums` to see your app data. + +8. **FOLLOW-UP:** +This Quickstart goes a bit deeper into the framework than the other Quickstarts since Laravel requires more boilerplate to get up-and-running with a simple app. + +If you're new to Laravel and want to learn more, we referenced the following Laravel Tutorial pages extensively when writing this Quickstart: + - Installation + - Controllers, Routing, Blade + +And that's it! You've successfully built a PHP / Laravel app that reads data from a SQLite Cloud database. \ No newline at end of file diff --git a/sqlite-cloud/quickstart/quick-start-next.mdx b/sqlite-cloud/quickstart/quick-start-next.mdx new file mode 100644 index 0000000..4636cf2 --- /dev/null +++ b/sqlite-cloud/quickstart/quick-start-next.mdx @@ -0,0 +1,436 @@ +--- +title: Next.js Quick Start Guide +description: Get started with SQLite Cloud using Next.js. +category: getting-started +status: publish +slug: quick-start-next +--- + +This quick start guide will walk you through setting up a Next.js application that connects to and queries a SQLite Cloud database. + +--- + +1. **Set up a SQLite Cloud account** + - If you haven't already, sign up for a SQLite Cloud account and create a new project. + - For this guide, we will use the sample datasets that come pre-loaded with SQLite Cloud. + +2. **Create a Next.js app** + - Use ```create-next-app``` to set up a new Next.js project. The following command creates a minimal app with TypeScript and the latest App Router, keeping the focus on querying data. +```bash +npx create-next-app@latest sqlc-quickstart --ts --no-tailwind --eslint --app --src-dir --import-alias "@/*" --use-npm +``` + +3. **Install the SQLite Cloud SDK** +```bash +cd sqlc-quickstart && npm install @sqlitecloud/drivers +``` + +4. **Configure the Database Connection** + - Create a `.env.local` file in the root of your Next.js project and add your SQLite Cloud connection string: +```bash +SQLITECLOUD_URL=sqlitecloud://abcd1234.global1.qwerty.sqlite.cloud:8860/chinook.sqlite?apikey=your-api-key +NEXT_PUBLIC_SQLITECLOUD_URL=sqlitecloud://abcd1234.global1.qwerty.sqlite.cloud:8860/chinook.sqlite?apikey=your-api-key +``` + - The database driver establishes a TLS connection in Node.js and a WebSocket connection in the browser. + + +5. **Set Up the Folder Structure** +```bash +mkdir -p src/app/api/albums +mkdir -p src/app/components +mkdir -p src/constants + +touch src/app/api/albums/route.ts +touch src/app/components/GetAlbumsClient.tsx +touch src/app/components/GetAlbumsServer.tsx +touch src/app/components/UpdateAlbumsClient.tsx +touch src/constants/queries.ts +touch src/types.ts +``` + +6. **Define Data Types** +```ts +// +// src/type.ts (Server Component) +// + +export interface Album { + id: number; + title: string; + artist: string; +} + +``` + +7. **Define Queries** +```ts +// +// src/constants/queries.ts +// + +export const GET_ALBUMS = ` + USE DATABASE chinook.sqlite; + SELECT albums.AlbumId AS id, albums.Title AS title, artists.Name AS artist + FROM albums + INNER JOIN artists ON albums.ArtistId = artists.ArtistId + LIMIT 20; +`; + +export const GET_LAST_TEN_ALBUMS = ` + USE DATABASE chinook.sqlite; + SELECT albums.AlbumId AS id, albums.Title AS title, artists.Name AS artist + FROM albums + INNER JOIN artists ON albums.ArtistId = artists.ArtistId + ORDER BY albums.AlbumId DESC + LIMIT 10; +`; + +export const INSERT_ALBUM = ` + USE DATABASE chinook.sqlite; + INSERT INTO albums (Title, ArtistId) VALUES (?, ?); +`; +``` + +8. **Fetch Data via a Route Handler** + +You can create a route handler for handling `GET` and `POST` requests. + +```ts +// +// src/app/api/albums/route.ts (Route Handler) +// + +import { NextResponse } from "next/server"; +import { Database } from "@sqlitecloud/drivers"; +import { GET_LAST_TEN_ALBUMS, INSERT_ALBUM } from "@/constants/queries"; + +export async function GET() { + let db; + + try { + db = new Database(process.env.SQLITECLOUD_URL!); + const result = await db.sql(GET_LAST_TEN_ALBUMS); + + return NextResponse.json(result); + } catch (error) { + let message = "An unknown error occurred"; + + if (error instanceof Error) { + message = error.message; + } + + return NextResponse.json({ error: message }, { status: 500 }); + } finally { + db?.close(); + } +} + +export async function POST(req: Request) { + const { title, artistId } = await req.json(); + let db; + + try { + db = new Database(process.env.SQLITECLOUD_URL!); + await db.sql(INSERT_ALBUM, ...[title, artistId]); + + return NextResponse.json({ success: true }); + } catch (error) { + let message = "An unknown error occurred"; + + if (error instanceof Error) { + message = error.message; + } + + return NextResponse.json({ error: message }, { status: 500 }); + } finally { + db?.close(); + } +} +``` + +9. **Fetch Data in a Server Component** + +To fetch data directly from the server and render it in a Server Component: + +```tsx +// +// src/app/components/GetAlbumsServer.tsx (Server Component) +// + +import { GET_ALBUMS } from "@/constants/queries"; +import { Album } from "@/types"; +import { Database } from "@sqlitecloud/drivers"; +import { unstable_noStore as noStore } from "next/cache"; + +export default async function GetAlbumsServer() { + noStore(); // Prevents Next.js from caching the database request + let db; + + try { + db = new Database(process.env.SQLITECLOUD_URL!); + const result = await db.sql(GET_ALBUMS); + + return ( +
    +

    + Albums (Server Component) +

    +
      + {result.map((album: Album) => ( +
    • + {album.title} -{" "} + {album.artist} +
    • + ))} +
    +
    + ); + } catch (error) { + let message = "An unknown error occurred"; + + if (error instanceof Error) { + message = error.message; + } + return

    Error loading albums: {message}

    ; + } finally { + db?.close(); + } +} +``` + +10. **Fetch Data in a Client Component** +Since the SQLite Cloud driver can run in the browser, you can use it directly in a Client Component without needing an API route. + +```tsx +// +// src/app/components/GetAlbumsClient.tsx (Client Component) +// + +"use client"; + +import { useEffect, useState } from "react"; +import { Database } from "@sqlitecloud/drivers"; +import { Album } from "@/types"; +import { GET_ALBUMS } from "@/constants/queries"; + +export default function GetAlbumsClient() { + const [albums, setAlbums] = useState([]); + const [error, setError] = useState(null); + + useEffect(() => { + async function fetchAlbums() { + let db; + try { + console.log(process.env.NEXT_PUBLIC_SQLITECLOUD_URL); + db = new Database(process.env.NEXT_PUBLIC_SQLITECLOUD_URL!); + const result = await db.sql(GET_ALBUMS); + setAlbums(result); + } catch (error) { + let message = "An unknown error occurred"; + + if (error instanceof Error) { + message = error.message; + } + setError(message); + } finally { + db?.close(); + } + } + + fetchAlbums(); + }, []); + + if (error) return

    Error: {error}

    ; + + return ( +
    +

    Albums (Client Component)

    + {error ? ( +

    Error: {error}

    + ) : ( +
      + {albums.map((album) => ( +
    • + {album.title} -{" "} + {album.artist} +
    • + ))} +
    + )} +
    + ); +} +``` + +11. **Update Data in a Client Component** +You can also update data directly from a Client Component: + +```tsx +// +// src/app/components/UpdateAlbumsClient.tsx (Client Component) +// + +"use client"; + +import { useState, useEffect } from "react"; + +export default function UpdateAlbumsClient() { + const [albums, setAlbums] = useState< + { id: number; title: string; artist: string }[] + >([]); + const [loading, setLoading] = useState(false); + + // Function to fetch albums from the API route + async function fetchAlbums() { + try { + const res = await fetch("/api/albums"); + if (!res.ok) throw new Error("Failed to fetch albums"); + const data = await res.json(); + setAlbums(data); + } catch (error) { + console.error("Error fetching albums:", error); + } + } + + // Function to add a new album and then reload the albums list + async function addAlbum() { + setLoading(true); + + try { + // Generate a random album name + const randomAlbumTitle = `Album ${Math.random() + .toString(36) + .substring(7)}`; + + // Generate a random artist ID between 1 and 100 + const randomArtistId = Math.floor(Math.random() * 100) + 1; + + const res = await fetch("/api/albums", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + title: randomAlbumTitle, + artistId: randomArtistId, + }), + }); + + if (!res.ok) throw new Error("Failed to add album"); + + await fetchAlbums(); // Refresh album list after adding + } catch (error) { + console.error("Error adding album:", error); + } finally { + setLoading(false); + } + } + + // Fetch albums when component mounts + useEffect(() => { + fetchAlbums(); + }, []); + + return ( +
    + + +

    Latest Albums

    + {albums.length === 0 ? ( +

    No albums found.

    + ) : ( +
      + {albums.map((album) => ( +
    • + {album.title} -{" "} + {album.artist} +
    • + ))} +
    + )} +
    + ); +} + +``` + +12. **Create a Page to Display Components** + +Replace the content of `page.tsx` with: + +```tsx +// +// src/app/page.tsx (Unified Page) +// + +import GetAlbumsClient from "./components/GetAlbumsClient"; +import GetAlbumsServer from "./components/GetAlbumsServer"; +import UpdateAlbumsClient from "./components/UpdateAlbumsClient"; + +export default function page() { + return ( +
    +
    +

    Albums Overview

    + +
    + +
    + +
    + +
    + +
    + +
    +
    +
    + ); +} +``` + +Replace the content of `layout.tsx` with: + +```tsx +// +// src/app/layout.tsx +// + +export default function RootLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( + + + {/* ✅ Add Tailwind CDN */} + + + {children} + + ); +} + +``` + +13. **Run Your App** +```bash +npm run dev +``` + +14. **View Your App** + - Open your browser and navigate to the provided localhost link to see your app in action. + + +--- + +Congratulations! You’ve successfully built a Next.js app that interacts with a SQLite Cloud database. \ No newline at end of file diff --git a/sqlite-cloud/quickstart/quick-start-node.mdx b/sqlite-cloud/quickstart/quick-start-node.mdx new file mode 100644 index 0000000..419a0af --- /dev/null +++ b/sqlite-cloud/quickstart/quick-start-node.mdx @@ -0,0 +1,68 @@ +--- +title: Node.js Quick Start Guide +description: Get started with SQLite Cloud using Node.js and Express. +category: getting-started +status: publish +slug: quick-start-node +--- + +In this quickstart, we will show you how to get started with SQLite Cloud and Node.js by building a simple web server that connects to and reads from a SQLite Cloud database, then serves that data to the client. + +--- + +1. **Set up a SQLite Cloud account** + - If you haven't already, sign up for a SQLite Cloud account and create a new project. + - In this guide, we will use the sample datasets that come pre-loaded with SQLite Cloud. +2. **Create a Node.js app** + - Navigate to your target directory and run the following command to initialize your Node.js app and install the necessary depedencies: +```bash +npm init +``` + - After creating your project, install the SQLite Cloud SDK: +```bash +npm install express @sqlitecloud/drivers --save +``` + - Create a file named `index.js` in the root directory of your project. + +3. **Query data** + - Grab a connection string by clicking on a node in your dashboard. + - Paste the following into your `index.js` file: + +```javascript +const express = require("express"); +const { Database } = require("@sqlitecloud/drivers"); + +const connectionString = process.env.SQLITECLOUD_CONNECTION_STRING +const app = express(); + +app.get("/albums", async (req, res) => { + let db = null; + try { + db = new Database(connectionString) + const result = await db.sql(` + USE DATABASE chinook.sqlite; + SELECT albums.AlbumId as id, albums.Title as title, artists.name as artist + FROM albums + INNER JOIN artists + WHERE artists.ArtistId = albums.ArtistId + LIMIT 20;`); + res.json(result); + } catch (error) { + res.status(500).json({ error: error.message }); + } finally { + db?.close(); + } +}); + +app.listen(3000, () => { + console.log("Server running on port 3000"); +}); +``` +5. **Run your app** +```bash +node index.js +``` +6. **View your web server response** + - Open your browser and navigate to `http://localhost:3000/albums` to see your app in action. + +And that's it! You've successfully built a Node.js app that reads and serves data from a SQLite Cloud database. diff --git a/sqlite-cloud/quickstart/quick-start-prisma.mdx b/sqlite-cloud/quickstart/quick-start-prisma.mdx new file mode 100644 index 0000000..f0fb1c5 --- /dev/null +++ b/sqlite-cloud/quickstart/quick-start-prisma.mdx @@ -0,0 +1,87 @@ +--- +title: Prisma Quick Start Guide +description: Get started with SQLite Cloud using Prisma ORM. +category: getting-started +status: draft +slug: quick-start-prisma +--- + +In this quickstart, we will show you how to get started with SQLite Cloud and Prisma by building a simple application that connects to and reads from a SQLite Cloud database. + +--- + +1. **Set up a SQLite Cloud account** + - If you haven't already, sign up for a SQLite Cloud account and create a new project. + - In this guide, we will use the sample datasets that come pre-loaded with SQLite Cloud. +2. **Create a Next.js app** + - Create a Next app using ```create-next-app```. The following command creates a very simple app (JS, no Tailwind, uses the latest App Router) to keep the focus on querying the data. +```bash +npx create-next-app@latest sqlc-quickstart --js --no-tailwind --eslint --app --src-dir --import-alias "@/*" --use-npm +``` +3. **Install the SQLite Cloud SDK** +```bash +cd sqlc-quickstart && npm install @sqlitecloud/drivers +``` +4. **Query data** + - Replace the code in ```layout.js``` and ```page.js``` with the following snippets. + - Click a node in your account dashboard and copy the connection string. Replace `````` in ```page.js``` with your connection string. + +In ```src/app/layout.js```: +```jsx +export const metadata = { + title: 'Create Next App', + description: 'Generated by create next app', +}; + +export default function RootLayout({ children }) { + return ( + + {children} + + ); +} +``` + +In ```src/app/page.js```: +```jsx +import { Database } from '@sqlitecloud/drivers'; + +async function getAlbums() { + const db = new Database(''); + + const result = await db.sql`USE DATABASE chinook.sqlite; + SELECT albums.AlbumId as id, albums.Title as title, artists.name as artist + FROM albums + INNER JOIN artists + WHERE artists.ArtistId = albums.ArtistId + LIMIT 20;`; + + return result; +} + +export default async function Home() { + const res = await getAlbums(); + + return ( +
    +

    Albums

    +
      + {res.map(({ id, title, artist }) => ( +
    • + {title} by {artist} +
    • + ))} +
    +
    + ); +} +``` + +5. **Run your app** +```bash +npm run dev +``` +6. **View your app** + - Open your browser and navigate to the localhost link provided by the previous command to see your app data. + +And that's it! You've successfully built a Next app that reads data from a SQLite Cloud database. \ No newline at end of file diff --git a/sqlite-cloud/quickstart/quick-start-react-native.mdx b/sqlite-cloud/quickstart/quick-start-react-native.mdx new file mode 100644 index 0000000..8ba114f --- /dev/null +++ b/sqlite-cloud/quickstart/quick-start-react-native.mdx @@ -0,0 +1,115 @@ +--- +title: React Native Quick Start Guide +description: Get started with SQLite Cloud using React Native. +category: getting-started +status: publish +slug: quick-start-react-native +--- + +In this quickstart, we will show you how to get started with SQLite Cloud and React Native by building a simple application that connects to and reads from a SQLite Cloud database. + +--- + +1. **Set up a SQLite Cloud account** + - If you haven't already, sign up for a SQLite Cloud account and create a new project. + - In this guide, we will use the sample datasets that come pre-loaded with SQLite Cloud. + +2. **Create a React Native project** + - If you haven't already, sign up for an Expo account. + - Create a new remote EAS project with the name `sqlc-quickstart`. + - Link your remote project to a new local project. Replace `{id}` below with the project ID provided by Expo. + +```bash +npm install --global eas-cli +npx create-expo-app sqlc-quickstart +cd sqlc-quickstart +eas init --id {id} +``` + +3. **Install the SQLite Cloud JS SDK and peer dependencies** + +```bash +npm install @sqlitecloud/drivers react-native-tcp-socket react-native-fast-base64 +``` + +4. **Query data** + - Replace the code in `app/(tabs)/index.tsx` with the following snippet. + - In your SQLite Cloud account dashboard, click on a Node, copy the Connection String, and replace `` below. + +```jsx +import { Database } from '@sqlitecloud/drivers'; +import { useState, useEffect } from 'react'; +import { View, Text, FlatList, StyleSheet } from 'react-native'; + +export default function App() { + const [albums, setAlbums] = useState([]); + + useEffect(() => { + async function getAlbums() { + let db = null; + try { + db = new Database(''); + + const result = + await db.sql(`USE DATABASE chinook.sqlite; + SELECT albums.AlbumId as id, albums.Title as title, artists.name as artist + FROM albums + INNER JOIN artists + WHERE artists.ArtistId = albums.ArtistId LIMIT 20;`); + + setAlbums(result); + } catch (error) { + // manage error state + console.error(`getAlbums - ${error}`, error) + } finally { + db?.close(); + } + } + + getAlbums(); + }, []); + + return ( + + Albums + item.id} + renderItem={({ item }) => ( + + • {item.title} by {item.artist} + + )} + /> + + ); +} + +const styles = StyleSheet.create({ + container: { + padding: 15, + }, + title: { + fontSize: 34, + fontWeight: 600, + }, + listItem: { + paddingVertical: 3, + }, +}); +``` + - On `App` component mount, `useEffect` defines and calls a function that connects to and queries your database, updates the component's state with the most up-to-date `albums` data, and renders the data in a list. + +5. **Run your app** + +Expo run iOS +```bash +npx expo prebuild && npx expo run:ios +``` + +Expo run Android +```bash +npx expo prebuild && npx expo run:android +``` + +And that's it! You've successfully built a React Native app that reads data from a SQLite Cloud database. \ No newline at end of file diff --git a/sqlite-cloud/quick-start-react.mdx b/sqlite-cloud/quickstart/quick-start-react.mdx similarity index 64% rename from sqlite-cloud/quick-start-react.mdx rename to sqlite-cloud/quickstart/quick-start-react.mdx index ce6ef72..696b4b6 100644 --- a/sqlite-cloud/quick-start-react.mdx +++ b/sqlite-cloud/quickstart/quick-start-react.mdx @@ -3,6 +3,7 @@ title: React Quick Start Guide description: Get started with SQLite Cloud using React. category: getting-started status: publish +slug: quick-start-react --- In this quickstart, we will show you how to get started with SQLite Cloud and React by building a simple application that connects to and reads from a SQLite Cloud database. @@ -10,7 +11,7 @@ In this quickstart, we will show you how to get started with SQLite Cloud and Re --- 1. **Set up a SQLite Cloud account** - - If you haven't already, [sign up for a SQLite Cloud account](https://sqlitecloud.io/register) and create a new database. + - If you haven't already, sign up for a SQLite Cloud account and create a new project. - In this guide, we will use the sample datasets that come pre-loaded with SQLite Cloud. 2. **Create a React app** - Create a React app using a Vite template @@ -28,20 +29,27 @@ cd sqlc-quickstart && npm install @sqlitecloud/drivers import { useEffect, useState } from "react"; import { Database } from '@sqlitecloud/drivers'; -const db = new Database(''); - function App() { const [data, setData] = useState([]); const getAlbums = async () => { - const result = await db.sql` - USE DATABASE chinook.sqlite; - SELECT albums.AlbumId as id, albums.Title as title, artists.name as artist - FROM albums - INNER JOIN artists - WHERE artists.ArtistId = albums.ArtistId - LIMIT 20;`; - setData(result); + let db = null; + try { + db = new Database('') + const result = await db.sql(` + USE DATABASE chinook.sqlite; + SELECT albums.AlbumId as id, albums.Title as title, artists.name as artist + FROM albums + INNER JOIN artists + WHERE artists.ArtistId = albums.ArtistId + LIMIT 20;`); + setData(result); + } catch (err) { + // manage error state + console.error(`getAlbums - ${error}`, error); + } finally { + db?.close(); + } }; useEffect(() => { @@ -67,7 +75,7 @@ export default App npm run dev ``` 6. **View your app** - - Open your browser and navigate to `http://localhost:3000` to see your app in action. + - Open your browser and navigate to the localhost link provided by the previous command to see your app data. And that's it! You've successfully built a React app that reads data from a SQLite Cloud database. diff --git a/sqlite-cloud/quickstart/quick-start-sqlalchemy-orm.mdx b/sqlite-cloud/quickstart/quick-start-sqlalchemy-orm.mdx new file mode 100644 index 0000000..9a723c7 --- /dev/null +++ b/sqlite-cloud/quickstart/quick-start-sqlalchemy-orm.mdx @@ -0,0 +1,167 @@ +--- +title: SQLAlchemy ORM Quick Start Guide +description: Get started with SQLite Cloud using SQLAlchemy ORM in FastAPI. +category: getting-started +status: publish +slug: quick-start-sqlalchemy-orm +--- + +In this Quick Start, we will show you how to get started with SQLite Cloud by building a FastAPI backend that connects to and reads from a SQLite Cloud database using SQLAlchemy. + +NOTE that FastAPI framework: + - does NOT require you to use a relational database or any database at all. + - CAN work with any ORM library (including SQLAlchemy) or database (including SQLite, which comes pre-installed in Python and is a database supported by SQLAlchemy). + - code is MINIMAL in the example below. Most of the code is standard SQLAlchemy and framework-agnostic. + +--- + +1. **Set up a SQLite Cloud account** + - If you haven't already, sign up for a SQLite Cloud account and create a new project. + - In this guide, we will use the sample datasets that come pre-loaded with SQLite Cloud. + +2. **Create a new Python project** + - You should have the latest Python version (3) installed locally. + +```bash +mkdir sqlalchemy-quickstart +cd sqlalchemy-quickstart + +# open the project in VSCode / another editor +code . + +python3 -m venv .venv +. .venv/bin/activate +``` + +3. **Install dependencies** + - Run this command from your current directory: + +```bash +pip install "fastapi[standard]" sqlalchemy sqlalchemy-sqlitecloud +``` + + - Do NOT remove the quotes around the FastAPI package. + - `sqlalchemy-sqlitecloud` includes `sqlitecloud`, so no need to install the latter separately. + +4. **App setup** + - From your current directory, create a sub-directory `fastapi_sqlc_app` with an empty `__init__.py` file to indicate the new sub-directory is a package. + - NOTE: We will create all remaining project files in this sub-directory. + +```bash +mkdir fastapi_sqlc_app +cd fastapi_sqlc_app +touch __init__.py +``` + + - Create a new file `database.py` and copy in the following code. + - In your SQLite Cloud account dashboard, click on `Show connection strings`, copy the Connection String, and replace `` below. Modify your string to include the name of the DB we'll query: `sqlitecloud://{hostname}:8860/chinook.sqlite?apikey={apikey}`. + +```py +from sqlalchemy import create_engine +from sqlalchemy.orm import sessionmaker +from sqlalchemy.ext.declarative import declarative_base + +engine = create_engine('') + +SessionLocal = sessionmaker(bind=engine) + +Base = declarative_base() +``` + + - Create a new file `models.py` and copy in the following code defining 2 SQLAlchemy ORM "models", or classes, to interact with the DB. + - `__tablename__` is the name of a model's corresponding DB table. + - The `Album` class' `id` attribute maps to the `AlbumId` column in the `albums` table. All other class attribute names match their corresponding table column names. + +```py +from .database import Base + +from sqlalchemy import Column, ForeignKey, Integer, String + +class Artist(Base): + __tablename__ = "artists" + + ArtistId = Column(Integer, primary_key=True) + Name = Column(String) + +class Album(Base): + __tablename__ = "albums" + + id = Column("AlbumId", Integer, primary_key=True) + Title = Column(String) + ArtistId = Column(Integer, ForeignKey('artists.ArtistId')) +``` + + - Create a new file `schemas.py` and copy in the following code defining a Pydantic model, or "schema", to validate the shape of the response data. + +```py +from pydantic import BaseModel + +class AlbumResponse(BaseModel): + id: int + Title: str + ArtistName: str +``` + + - Create a new file `read.py` and copy in the following code creating a reusable utility function to read album data. + +```py +from . import models + +from sqlalchemy.orm import Session + +def get_albums(db: Session, skip: int = 0, num: int = 20): + return db.query(models.Album.id, models.Album.Title, models.Artist.Name.label('ArtistName')).join(models.Artist).offset(skip).limit(num).all() +``` + + - Create a new file `main.py` and copy in the following code. + - The `get_db` function handles creating and closing a new `SessionLocal` instance, or DB connection/ session, for every request. + - A GET request to the `/albums/` endpoint calls the `read_albums` function, which returns a list of SQLAlchemy `Album` models. The `response_model` ensures only data declared in the Pydantic schema is returned to the client. + - The `AlbumResponse` Pydantic model in `schemas.py` has `ArtistName`, as opposed to `ArtistId` defined in the `Album` SQLAlchemy model in `models.py`. + - `read_albums` calls the `get_albums` function in `read.py`. `get_albums` queries the `Album` ORM model/ `albums` DB table for the first 20 albums, and joins the `Artist` ORM model/ `artists` DB table to retrieve the `Artist.Name` (re-labeled `ArtistName`) expected by the `AlbumResponse` Pydantic model. + +```py +from .database import SessionLocal +from . import read, schemas + +from fastapi import FastAPI, Depends +from sqlalchemy.orm import Session + +app = FastAPI() + +def get_db(): + db = SessionLocal() + try: + yield db + finally: + db.close() + +@app.get("/albums/", response_model=list[schemas.AlbumResponse]) +def read_albums(skip: int = 0, num: int = 20, db: Session = Depends(get_db)): + albums = read.get_albums(db, skip=skip, num=num) + return albums +``` + +5. **Run your FastAPI app** + - From your `sqlalchemy-quickstart` directory, run the following command: + +```bash +uvicorn fastapi_sqlc_app.main:app --reload +``` + + - Visit `http://127.0.0.1:8000/albums/` to see your app data. + +6. **Troubleshooting** + + - If you encounter the following error, restart your IDE and re-run your app. + +```bash +AttributeError: module 'sqlitecloud.dbapi2' has no attribute 'sqlite_version_info'` +``` + +7. **References** + + - FastAPI introductory example + - FastAPI SQL Databases tutorial + - Latest SQLAlchemy docs + +And that's it! You've successfully built a FastAPI app that uses SQLAlchemy ORM to read data from a SQLite Cloud database. diff --git a/sqlite-cloud/quickstart/quick-start-streamlit.mdx b/sqlite-cloud/quickstart/quick-start-streamlit.mdx new file mode 100644 index 0000000..634c735 --- /dev/null +++ b/sqlite-cloud/quickstart/quick-start-streamlit.mdx @@ -0,0 +1,66 @@ +--- +title: Streamlit Quick Start Guide +description: Get started with SQLite Cloud using Streamlit. +category: getting-started +status: publish +slug: quick-start-streamlit +--- + +In this quickstart, we will show you how to get started with SQLite Cloud and Streamlit by building a simple application that connects to and reads from a SQLite Cloud database. + +--- + +1. **Set up a SQLite Cloud account** + - If you haven't already, sign up for a SQLite Cloud account and create a new project. + - In this guide, we will use the sample datasets that come pre-loaded with SQLite Cloud. + +2. **Create a Streamlit app** + - You should have the latest Python version (3) installed locally. + +```bash +mkdir sqlc-quickstart +cd sqlc-quickstart + +python3 -m venv .venv +. .venv/bin/activate + +pip install streamlit +``` + +3. **Install the SQLite Cloud SDK** + +```bash +pip install sqlitecloud +``` + +4. **Query data** + - Copy the following code into a new `app.py` file. + - In your SQLite Cloud account dashboard, click your Project name, copy the Connection String, and replace `` below. + +```py +import streamlit as st +import sqlitecloud +import pandas as pd + +st.header('Invoices') + +conn = sqlitecloud.connect('') + +db_name = "chinook.sqlite" +conn.execute(f"USE DATABASE {db_name}") + +invoices = pd.read_sql("SELECT * FROM invoices LIMIT 20", conn) + +st.dataframe(invoices, hide_index=True) +``` + +5. **Run your app** + +```bash +streamlit run app.py +``` + +6. **View your app** + - Open your browser and navigate to the localhost link provided by the previous command to see your app data. + +And that's it! You've successfully built a Streamlit app that reads data from a SQLite Cloud database. \ No newline at end of file diff --git a/sqlite-cloud/reference/_wip-index-with-card.mdx b/sqlite-cloud/reference/_wip-index-with-card.mdx new file mode 100644 index 0000000..f6669b2 --- /dev/null +++ b/sqlite-cloud/reference/_wip-index-with-card.mdx @@ -0,0 +1,35 @@ +--- +title: Reference +description: Index page for reference section +category: reference +status: publish +icon: docs-ref +slug: reference +--- +import IndexPage from "@docs-website-components/Docs/IndexPage.astro" + +export const introduction = "SQLite Cloud is a distributed relational database system built on top of the SQLite database engine. It has been specifically designed from the ground up to ensure the strong consistency of your data across all nodes in a cluster while simultaneously managing the technical aspects of scaling, security, and data distribution." + +export const sections = [ + { + icon: "curvedArrow", + title: "Server-side Commands", + description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", + href: "/docs/server-side-commands", + }, + { + icon: "twoColsGrid", + title: "CLI", + description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", + href: "/docs/cli-commands", + }, + { + icon: "sqlite-stacked", + title: "SQLite", + description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", + href: "/docs/sqlite", + }, +] + + + \ No newline at end of file diff --git a/sqlite-cloud/reference/api-key-commands.mdx b/sqlite-cloud/reference/api-key-commands.mdx index 8e4baa7..1d37cbb 100644 --- a/sqlite-cloud/reference/api-key-commands.mdx +++ b/sqlite-cloud/reference/api-key-commands.mdx @@ -8,7 +8,7 @@ slug: api-key-commands ## CREATE APIKEY USER The CREATE APIKEY USER command creates a new APIKEY associated to a specific username and with a mnemonic name. The RESTRICTION option is currently unused and an expiration date can be set using the EXPIRATION parameter. -It returns a [String](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) with the new APIKEY. +It returns a String with the new APIKEY. ### Syntax ```bash @@ -22,7 +22,7 @@ USERADMIN ## LIST APIKEYS The LIST APIKEYS command retrieves all the APIKEYS created on the server. The USER parameter can be used to filter the result further. -It returns a [Rowset](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) with the following columns: +It returns a Rowset with the following columns: * **username**: user name * **key**: API KEY * **name**: mnemonic name @@ -41,7 +41,7 @@ USERADMIN ## LIST MY APIKEYS The LIST MY APIKEYS command returns a list of all the APIKEYs associated with the username used in the current connection. -It returns a [Rowset](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) with the following columns: +It returns a Rowset with the following columns: * **username**: user name * **key**: API KEY * **name**: mnemonic name @@ -60,7 +60,7 @@ USERADMIN ## SET APIKEY The SET KEY command sets or updates a **keyname** to a specific **keyvalue**. Once set, the server immediately uses the updated value (and automatically distributes it on the cluster). -It returns OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +It returns OK string or error value (see SCSP protocol). ### Syntax @@ -75,7 +75,7 @@ SETTINGS ## REMOVE APIKEY The REMOVE APIKEY command permanently removes an APIKEY from the server. -It returns OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +It returns OK string or error value (see SCSP protocol). ### Syntax diff --git a/sqlite-cloud/reference/auth-commands.mdx b/sqlite-cloud/reference/auth-commands.mdx index 3c1feff..e65f23b 100644 --- a/sqlite-cloud/reference/auth-commands.mdx +++ b/sqlite-cloud/reference/auth-commands.mdx @@ -9,7 +9,6 @@ slug: auth-commands ## AUTH USER The AUTH command authenticates the current connection, without authentication the connection cannot send any other command to the server. -Once authenticated, any PubSub connection in place will be closed. ### Syntax AUTH USER **username** PASSWORD **password** @@ -22,4 +21,4 @@ NONE ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). diff --git a/sqlite-cloud/reference/backup-commands.mdx b/sqlite-cloud/reference/backup-commands.mdx index 66d8666..9c3138e 100644 --- a/sqlite-cloud/reference/backup-commands.mdx +++ b/sqlite-cloud/reference/backup-commands.mdx @@ -7,7 +7,7 @@ slug: backup-commands --- ## APPLY BACKUP SETTINGS -Several backup-related settings can be applied using the SET DATABASE KEY command. +Several backup-related settings can be applied using the SET DATABASE KEY command. The following keys affect the backup settings: * **backup**: set to 1 to activate a backup, 0 to disable. @@ -28,7 +28,7 @@ BACKUP ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ## LIST BACKUP SETTINGS @@ -49,7 +49,7 @@ BACKUP ### Return -A [Rowset](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) with the following columns: +A Rowset with the following columns: * **name**: database name * **enabled**: 1 enabled, 0 disabled * **backup_retention**: retention period @@ -91,7 +91,7 @@ BACKUP ### Return -A [Rowset](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) with the following columns: +A Rowset with the following columns: * **type**: can be snapshot or wal * **replica**: always S3 in this version * **generation**: backup generation ID @@ -145,7 +145,7 @@ BACKUP ### Return -A [Rowset](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) with a single **name** column that returns all the databases with backup enabled. +A Rowset with a single **name** column that returns all the databases with backup enabled. ### Example @@ -172,7 +172,7 @@ RESTORE BACKUP DATABASE **database_name** [GENERATION **generation**] [INDEX **i ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Privileges diff --git a/sqlite-cloud/reference/cli-commands.mdx b/sqlite-cloud/reference/cli-commands.mdx index cd92e44..197ba0a 100644 --- a/sqlite-cloud/reference/cli-commands.mdx +++ b/sqlite-cloud/reference/cli-commands.mdx @@ -10,9 +10,9 @@ The **SQLite Cloud Command Line Interface** is a user-friendly interface that ru It's worth noting that there are two versions of the CLI available: one written in C and one written in GO. Both versions offer the same functionality, and the source code is provided for both. The C version was the first to be developed and was extensively used during the development of SQLite Cloud. It's based on the C SDK. The GO version, on the other hand, was created later, after the GO SDK was released. In the future, we plan to combine both projects into a unified CLI. -* Binaries can be downloaded from [GitHub](https://github.com/sqlitecloud/sdk/releases). -* C source code can be downloaded from the [C SDK repo](https://github.com/sqlitecloud/sdk/tree/master/C). -* GO source code can be downlaoded from the [GO SDK repo](https://github.com/sqlitecloud/sdk/tree/master/GO). +* Binaries can be downloaded from GitHub. +* C source code can be downloaded from the C SDK repo. +* GO source code can be downlaoded from the GO SDK repo. The C cli (sqlitecloud-cli) is available for Linux (x86) and macOS (Intel and ARM). diff --git a/sqlite-cloud/reference/cluster-commands.mdx b/sqlite-cloud/reference/cluster-commands.mdx index f7f9bb0..00c3680 100644 --- a/sqlite-cloud/reference/cluster-commands.mdx +++ b/sqlite-cloud/reference/cluster-commands.mdx @@ -20,8 +20,8 @@ CLUSTERADMIN, CLUSTERMONITOR ### Return -A [String](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) containing the IP address and port of the leader. -If the ID parameter is specified then the [Integer](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) nodeID of the leader node is returned. +A String containing the IP address and port of the leader. +If the ID parameter is specified then the Integer nodeID of the leader node is returned. ### Example @@ -49,7 +49,7 @@ CLUSTERADMIN, CLUSTERMONITOR ### Return -A [Rowset](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) with the following columns: +A Rowset with the following columns: * **id**: node ID * **node**: public node DNS name and port * **cluster**: DNS name and port used for Raft intra-node communication @@ -88,7 +88,7 @@ CLUSTERADMIN ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example diff --git a/sqlite-cloud/reference/database-commands.mdx b/sqlite-cloud/reference/database-commands.mdx index 0ac9aae..6f74b0e 100644 --- a/sqlite-cloud/reference/database-commands.mdx +++ b/sqlite-cloud/reference/database-commands.mdx @@ -26,7 +26,7 @@ CREATE_DATABASE ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example @@ -55,7 +55,7 @@ CREATE_DATABASE ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example @@ -80,7 +80,7 @@ DBADMIN ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example @@ -105,7 +105,7 @@ CREATE_DATABASE ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example @@ -130,8 +130,8 @@ HOSTADMIN ### Return -An [Integer](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) if **key** is ID or SIZE. -A [String](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) if **key** is NAME. +An Integer if **key** is ID or SIZE. +A String if **key** is NAME. ### Example @@ -166,7 +166,7 @@ PRAGMA ### Return -A [Rowset](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) with the following columns: +A Rowset with the following columns: * **key**: database key * **value**:database value @@ -198,7 +198,7 @@ NONE ### Return -A [Rowset](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) with only the column **name** if the DETAILED flag is omitted, otherwise several other columns: +A Rowset with only the column **name** if the DETAILED flag is omitted, otherwise several other columns: * **name**: database name * **size**: database size (in bytes) * **connections**: number of clients connected to the database @@ -249,7 +249,7 @@ HOSTADMIN ### Return -A [Rowset](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) with the following columns: +A Rowset with the following columns: * **id**: client ID * **address**: client IP address * **username**: username of the connected client @@ -287,7 +287,7 @@ DROP_DATABASE ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example @@ -307,12 +307,12 @@ USE DATABASE **database_name** ### Privileges ``` -PRIVILEGE_DBADMIN or PRIVILEGE_PUBSUB, which means that the USE DATABASE command succeeds if any of the following Privileges is set: PRIVILEGE_READ, PRIVILEGE_INSERT, RIVILEGE_UPDATE, PRIVILEGE_DELETE, PRIVILEGE_PRAGMA, PRIVILEGE_CREATE_TABLE, PRIVILEGE_CREATE_INDEX, PRIVILEGE_CREATE_VIEW, PRIVILEGE_CREATE_TRIGGER, PRIVILEGE_DROP_TABLE, PRIVILEGE_DROP_INDEX, PRIVILEGE_DROP_VIEW, PRIVILEGE_DROP_TRIGGER, PRIVILEGE_ALTER_TABLE, PRIVILEGE_ANALYZE, PRIVILEGE_ATTACH, PRIVILEGE_DETACH PRIVILEGE_SUB, PRIVILEGE_PUB +PRIVILEGE_DBADMIN, which means that the USE DATABASE command succeeds if any of the following privileges is set: PRIVILEGE_READ, PRIVILEGE_INSERT, PRIVILEGE_UPDATE, PRIVILEGE_DELETE, PRIVILEGE_PRAGMA, PRIVILEGE_CREATE_TABLE, PRIVILEGE_CREATE_INDEX, PRIVILEGE_CREATE_VIEW, PRIVILEGE_CREATE_TRIGGER, PRIVILEGE_DROP_TABLE, PRIVILEGE_DROP_INDEX, PRIVILEGE_DROP_VIEW, PRIVILEGE_DROP_TRIGGER, PRIVILEGE_ALTER_TABLE, PRIVILEGE_ANALYZE, PRIVILEGE_ATTACH, PRIVILEGE_DETACH ``` ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example @@ -337,7 +337,7 @@ READWRITE ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example diff --git a/sqlite-cloud/reference/general-commands.mdx b/sqlite-cloud/reference/general-commands.mdx index 9cb7cec..19b4d68 100644 --- a/sqlite-cloud/reference/general-commands.mdx +++ b/sqlite-cloud/reference/general-commands.mdx @@ -22,7 +22,7 @@ USERADMIN ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example @@ -54,7 +54,7 @@ CLUSTERADMIN, CLUSTERMONITOR ### Return -A single value (usually a [String](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md)) that depends on the input **key**. +A single value (usually a String) that depends on the input **key**. ### Example @@ -79,7 +79,7 @@ READWRITE ### Return -A [String](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) set to the CREATE TABLE sql statement. +A String set to the CREATE TABLE sql statement. ### Example @@ -104,7 +104,7 @@ NONE ### Return -A [Rowset](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) with the following columns: +A Rowset with the following columns: * **command**: command syntax * **count**: how many times the command was executed * **avgtime**: average command execution time @@ -160,7 +160,7 @@ USERADMIN, HOSTADMIN ### Return -A [Rowset](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) with the following columns: +A Rowset with the following columns: * **id**: unique connection (client) ID * **address**: source connection IP address * **username**: username used to authenticate the connection @@ -196,7 +196,7 @@ READWRITE ### Return -A [Rowset](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) with the following columns: +A Rowset with the following columns: * **name**: index name * **tbl_name**: table name @@ -236,7 +236,7 @@ CLUSTERADMIN, CLUSTERMONITOR ### Return -A [Rowset](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) with the following columns: +A Rowset with the following columns: * **key**: server key * **value**: server value @@ -307,7 +307,7 @@ READWRITE, DBADMIN ### Return -A [Rowset](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) with one **key** column that returns all the reserved SQLite keywords. +A Rowset with one **key** column that returns all the reserved SQLite keywords. ### Example @@ -482,7 +482,7 @@ READWRITE ### Return -A [Rowset](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) with several columns that depends on the filters used in the command. The output is similar to the one obtains by calling the [sqlite3_table_column_metadata](https://www.sqlite.org/c3ref/table_column_metadata.html) API. +A Rowset with several columns that depends on the filters used in the command. The output is similar to the one obtains by calling the sqlite3_table_column_metadata API. ### Example @@ -575,11 +575,11 @@ A [Rowset](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) with seve ## LIST TABLES -The LIST TABLES command retrieves the information about the tables available inside the current database. Note that the output of this command can change depending on the privileges associated with the currently connected username. If the PUBSUB parameter is used, then the output will contain the column chname only (to have the same format as the rowset returned by the LIST CHANNELS command). +The LIST TABLES command retrieves the information about the tables available inside the current database. Note that the output of this command can change depending on the privileges associated with the currently connected username. ### Syntax -LIST TABLES [PUBSUB] +LIST TABLES ### Privileges @@ -589,7 +589,7 @@ READWRITE ### Return -A [Rowset](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) with the following columns: +A Rowset with the following columns: * **schema**: database schema name * **name**: table name * **type**: always 'table' in this version @@ -597,8 +597,6 @@ A [Rowset](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) with the * **wr**: without rowid flag * **name**: strict flag -If the PUBSUB option is used then a single **chname** column is returned (to produce the same output as the LIST CHANNELS command). - ### Example ```bash @@ -636,7 +634,7 @@ CLUSTERADMIN ### Return -A [Rowset](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) with the following columns: +A Rowset with the following columns: * **datetime**: the data time of the stat * **key**: stat name * **value**: stat value @@ -710,7 +708,7 @@ NONE ### Return -It returns the "PONG" [String](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md). +It returns the "PONG" String. ### Example @@ -735,7 +733,7 @@ NONE ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example diff --git a/sqlite-cloud/reference/ip-commands.mdx b/sqlite-cloud/reference/ip-commands.mdx index ceb40a7..14baf4c 100644 --- a/sqlite-cloud/reference/ip-commands.mdx +++ b/sqlite-cloud/reference/ip-commands.mdx @@ -21,7 +21,7 @@ USERADMIN ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example @@ -46,10 +46,10 @@ USERADMIN ### Return -A [Rowset](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) with the following columns: +A Rowset with the following columns: * **address**: IP address(es) allowed * **name**: user name or role name -* **type**: user or role [String](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) +* **type**: user or role String ### Example @@ -79,7 +79,7 @@ USERADMIN ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example diff --git a/sqlite-cloud/reference/log-commands.mdx b/sqlite-cloud/reference/log-commands.mdx index 8e4eafc..e12e027 100644 --- a/sqlite-cloud/reference/log-commands.mdx +++ b/sqlite-cloud/reference/log-commands.mdx @@ -45,9 +45,9 @@ HOSTADMIN ### Return -A [Rowset](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) with the following columns: `datetime`, `log_type`, `log_level, `description`, `username`, `database`, `ip_address`, `connection_id`. +A Rowset with the following columns: `datetime`, `log_type`, `log_level, `description`, `username`, `database`, `ip_address`, `connection_id`. -A [Rowset](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) with the following columns: +A Rowset with the following columns: * **datetime**: log entry date and time * **log_type**: log type (a number from 1 to 8, see description) * **log_level**: log level (a number from 0 to 5, see description) diff --git a/sqlite-cloud/reference/plugin-commands.mdx b/sqlite-cloud/reference/plugin-commands.mdx index 69d5476..f657ef0 100644 --- a/sqlite-cloud/reference/plugin-commands.mdx +++ b/sqlite-cloud/reference/plugin-commands.mdx @@ -22,7 +22,7 @@ PLUGIN ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example @@ -47,7 +47,7 @@ PLUGIN ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example @@ -72,7 +72,7 @@ PLUGIN ### Return -A [Rowset](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) with the following columns: +A Rowset with the following columns: * **name**: plugin name * **type**: plugin type (SQLite or SQLiteCloud) * **enabled**: 1 enabled, 0 disabled @@ -120,7 +120,7 @@ PLUGIN ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example diff --git a/sqlite-cloud/reference/privilege-commands.mdx b/sqlite-cloud/reference/privilege-commands.mdx index 688e91f..4416b46 100644 --- a/sqlite-cloud/reference/privilege-commands.mdx +++ b/sqlite-cloud/reference/privilege-commands.mdx @@ -21,7 +21,7 @@ USERADMIN ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example @@ -46,7 +46,7 @@ USERADMIN ### Return -A [Rowset](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) with one privilege **name** column. +A Rowset with one privilege **name** column. ### Example @@ -75,9 +75,6 @@ A [Rowset](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) with one ATTACH | DETACH | DBADMIN | - SUB | - PUB | - PUBSUB | BACKUP | RESTORE | DOWNLOAD | @@ -90,7 +87,6 @@ A [Rowset](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) with one DROP_DATABASE | HOSTADMIN | ADMIN | - PUBSUBCREATE | -----------------| ``` @@ -110,7 +106,7 @@ USERADMIN ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example @@ -135,7 +131,7 @@ USERADMIN ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example diff --git a/sqlite-cloud/reference/pub-sub-commands.mdx b/sqlite-cloud/reference/pub-sub-commands.mdx index 6cc61aa..071bd79 100644 --- a/sqlite-cloud/reference/pub-sub-commands.mdx +++ b/sqlite-cloud/reference/pub-sub-commands.mdx @@ -2,7 +2,7 @@ title: Pub/Sub Commands description: Use these commands to manage the SQLite Cloud Pub/Sub feature. category: reference -status: publish +status: draft slug: pub-sub-commands --- ## CREATE CHANNEL @@ -22,7 +22,7 @@ PUBSUBCREATE ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example @@ -48,7 +48,7 @@ PUBSUB ### Return -A [Rowset](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) with a single **chname** column that returns all channels created for Pub/Sub. +A Rowset with a single **chname** column that returns all channels created for Pub/Sub. ### Example @@ -88,7 +88,7 @@ SUB ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example @@ -112,7 +112,7 @@ PUB ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example @@ -137,7 +137,7 @@ PUBSUBCREATE ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example @@ -165,7 +165,7 @@ NONE ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example diff --git a/sqlite-cloud/reference/query-analyzer-commands.mdx b/sqlite-cloud/reference/query-analyzer-commands.mdx index e708e98..4de10d6 100644 --- a/sqlite-cloud/reference/query-analyzer-commands.mdx +++ b/sqlite-cloud/reference/query-analyzer-commands.mdx @@ -21,7 +21,7 @@ DBADMIN ### Return -A [Rowset](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) with an analysis about the query id. +A Rowset with an analysis about the query id. ### Example @@ -51,7 +51,7 @@ DBADMIN ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example @@ -79,7 +79,7 @@ DBADMIN ### Return -A [Rowset](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) with the following columns: +A Rowset with the following columns: * **statement**: reference to original statement (when multiple suggestions are returned) * **type**: 1 means SQL, 2 means INDEX, 3 means PLAN and 4 means CANDIDATE * **report**: sql or suggestion computed by the SQLite engine @@ -116,7 +116,7 @@ DBADMIN ### Return -A [Rowset](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) with columns that depend on the command flags. +A Rowset with columns that depend on the command flags. ### Example diff --git a/sqlite-cloud/reference/role-commands.mdx b/sqlite-cloud/reference/role-commands.mdx index 4906acc..e30446c 100644 --- a/sqlite-cloud/reference/role-commands.mdx +++ b/sqlite-cloud/reference/role-commands.mdx @@ -23,7 +23,7 @@ USERADMIN ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example @@ -48,7 +48,7 @@ USERADMIN ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example @@ -73,7 +73,7 @@ USERADMIN ### Return -A [Rowset](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) with the following columns: +A Rowset with the following columns: * **rolename**: the name of the role * **builtin**: 1 if it is a built-in role, 0 otherwise * **privileges**: a comma separated list of privileges associated to the role @@ -98,14 +98,6 @@ A [Rowset](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) with the CLUSTERADMIN | 1 | CLUSTERADMIN | NULL | NULL | CLUSTERMONITOR | 1 | CLUSTERMONITOR | NULL | NULL | HOSTADMIN | 1 | BACKUP,RESTORE,... | NULL | NULL | - SUB | 1 | SUB | NULL | NULL | - SUBANYCHANNEL | 1 | SUB | * | * | - PUB | 1 | PUB | NULL | NULL | - PUBANYCHANNEL | 1 | PUB | * | * | - PUBSUB | 1 | SUB,PUB,PUBSUB | NULL | NULL | - PUBSUBANYCHANNEL | 1 | SUB,PUB,PUBSUB | * | * | - PUBSUBADMIN | 1 | SUB,PUB,PUBSUB,PUBSUBCREATE | NULL | NULL | - PUBSUBADMINANYCHANNEL | 1 | SUB,PUB,PUBSUB,PUBSUBCREATE | * | * | -----------------------|---------|-----------------------------|--------------|-----------| ``` @@ -125,7 +117,7 @@ USERADMIN ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example @@ -150,7 +142,7 @@ USERADMIN ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example @@ -175,7 +167,7 @@ USERADMIN ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example diff --git a/sqlite-cloud/reference/settings-commands.mdx b/sqlite-cloud/reference/settings-commands.mdx index c7999ec..9ab989e 100644 --- a/sqlite-cloud/reference/settings-commands.mdx +++ b/sqlite-cloud/reference/settings-commands.mdx @@ -21,7 +21,7 @@ NONE ### Return -A single value (usually a [String](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md)) that depends on the input **keyname**. +A single value (usually a String) that depends on the input **keyname**. ### Example @@ -49,7 +49,7 @@ PRAGMA ### Return -A [String](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) with the requested value. +A String with the requested value. ### Example @@ -74,7 +74,7 @@ SETTINGS ### Return -A single value (usually a [String](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md)) that depends on the input **keyname**. +A single value (usually a String) that depends on the input **keyname**. ### Example @@ -102,7 +102,7 @@ NONE ### Return -A [Rowset](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) with the following columns: +A Rowset with the following columns: * **key**: client key * **value**: client value @@ -146,7 +146,7 @@ SETTINGS ### Return -A [Rowset](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) with the following columns: +A Rowset with the following columns: * **key**: settings key * **value**: settings value * **default_value**: default value @@ -202,7 +202,7 @@ NONE ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example @@ -227,7 +227,7 @@ PRAGMA ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example @@ -252,7 +252,7 @@ SETTINGS ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example @@ -277,7 +277,7 @@ NONE ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example @@ -306,7 +306,7 @@ PRAGMA ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example @@ -331,7 +331,7 @@ SETTINGS ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example diff --git a/sqlite-cloud/reference/user-commands.mdx b/sqlite-cloud/reference/user-commands.mdx index 00ffeb8..4d97509 100644 --- a/sqlite-cloud/reference/user-commands.mdx +++ b/sqlite-cloud/reference/user-commands.mdx @@ -21,7 +21,7 @@ USERADMIN ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example @@ -47,7 +47,7 @@ USERADMIN ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example @@ -72,7 +72,7 @@ USERADMIN ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example @@ -97,7 +97,7 @@ NONE ### Return -A [String](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) set to the current username. +A String set to the current username. ### Example @@ -122,7 +122,7 @@ USERADMIN ### Return -A [Rowset](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) with the following columns: +A Rowset with the following columns: * **username**: user name * **enabled**: 1 enabled, 0 disabled * **roles**: list of roles @@ -165,7 +165,7 @@ USERADMIN ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example @@ -190,7 +190,7 @@ USERADMIN ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example @@ -215,7 +215,7 @@ NONE ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example @@ -240,7 +240,7 @@ USERADMIN ### Return -OK string or error value (see [SCSP](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md) protocol). +OK string or error value (see SCSP protocol). ### Example diff --git a/sqlite-cloud/sdks/_wip-index-with-card.mdx b/sqlite-cloud/sdks/_wip-index-with-card.mdx new file mode 100644 index 0000000..0556522 --- /dev/null +++ b/sqlite-cloud/sdks/_wip-index-with-card.mdx @@ -0,0 +1,53 @@ +--- +title: SDKs +description: Index page for sdks section +category: sdks +status: publish +icon: docs-sdks +slug: sdks +--- +import IndexPage from "@docs-website-components/Docs/IndexPage.astro" + +export const introduction = "SQLite Cloud is a distributed relational database system built on top of the SQLite database engine. It has been specifically designed from the ground up to ensure the strong consistency of your data across all nodes in a cluster while simultaneously managing the technical aspects of scaling, security, and data distribution." + +export const sections = [ + { + icon: "docsSdkC", + title: "C/C++", + description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", + href: "/docs/sdk-c-introduction", + }, + { + icon: "docsSdkJs", + title: "JavaScript", + description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", + href: "/docs/sdk-js-introduction", + }, + { + icon: "docsSdkPython", + title: "Python", + description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", + href: "/docs/sdk-python-introduction", + }, + { + icon: "docsSdkGo", + title: "Go", + description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", + href: "/docs/sdk-go-introduction", + }, + { + icon: "docsSdkPhp", + title: "PHP", + description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", + href: "/docs/sdk-php-introduction", + }, + { + icon: "docsSdkSwift", + title: "Swift", + description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", + href: "/docs/sdk-swift-introduction", + }, +] + + + \ No newline at end of file diff --git a/sqlite-cloud/sdks/c/SQCloudArrayCount.mdx b/sqlite-cloud/sdks/c/SQCloudArrayCount.mdx index 4e27ac2..37dfdf3 100644 --- a/sqlite-cloud/sdks/c/SQCloudArrayCount.mdx +++ b/sqlite-cloud/sdks/c/SQCloudArrayCount.mdx @@ -10,7 +10,7 @@ uint32_t SQCloudArrayCount (SQCloudResult *result); ``` ### Description -If the result of the function [SQCloudResultType](/docs/sdk/c/sqcloudresulttype) is RESULT_ARRAY then use this function to retrieve the number of items in the SQCloudResult array. +If the result of the function [SQCloudResultType](/docs/sqlite-cloud/sdks/c/sqcloudresulttype) is RESULT_ARRAY then use this function to retrieve the number of items in the SQCloudResult array. ### Parameters * **result**: A valid SQCloudResult pointer returned by an SQCloud function. diff --git a/sqlite-cloud/sdks/c/SQCloudArrayDoubleValue.mdx b/sqlite-cloud/sdks/c/SQCloudArrayDoubleValue.mdx index 8b4db0b..91300cd 100644 --- a/sqlite-cloud/sdks/c/SQCloudArrayDoubleValue.mdx +++ b/sqlite-cloud/sdks/c/SQCloudArrayDoubleValue.mdx @@ -10,11 +10,11 @@ double SQCloudArrayDoubleValue (SQCloudResult *result, uint32_t index); ``` ### Description -If the result of the function [SQCloudResultType](/docs/sdk/c/sqcloudresulttype) is RESULT_ARRAY then use this function to retrieve a double value. +If the result of the function [SQCloudResultType](/docs/sqlite-cloud/sdks/c/sqcloudresulttype) is RESULT_ARRAY then use this function to retrieve a double value. ### Parameters * **result**: A valid SQCloudResult pointer returned by an SQCloud function. -* **index**: An array index (from 0 to [SQCloudArrayCount](/docs/sdk/c/sqcloudarraycount)-1) +* **index**: An array index (from 0 to [SQCloudArrayCount](/docs/sqlite-cloud/sdks/c/sqcloudarraycount)-1) ### Return value An `double` value. diff --git a/sqlite-cloud/sdks/c/SQCloudArrayFloatValue.mdx b/sqlite-cloud/sdks/c/SQCloudArrayFloatValue.mdx index 9ddc0f8..0b0314a 100644 --- a/sqlite-cloud/sdks/c/SQCloudArrayFloatValue.mdx +++ b/sqlite-cloud/sdks/c/SQCloudArrayFloatValue.mdx @@ -10,11 +10,11 @@ float SQCloudArrayFloatValue (SQCloudResult *result, uint32_t index); ``` ### Description -If the result of the function [SQCloudResultType](/docs/sdk/c/sqcloudresulttype) is RESULT_ARRAY then use this function to retrieve a float value. +If the result of the function [SQCloudResultType](/docs/sqlite-cloud/sdks/c/sqcloudresulttype) is RESULT_ARRAY then use this function to retrieve a float value. ### Parameters * **result**: A valid SQCloudResult pointer returned by an SQCloud function. -* **index**: An array index (from 0 to [SQCloudArrayCount](/docs/sdk/c/sqcloudarraycount)-1) +* **index**: An array index (from 0 to [SQCloudArrayCount](/docs/sqlite-cloud/sdks/c/sqcloudarraycount)-1) ### Return value A `float` value. diff --git a/sqlite-cloud/sdks/c/SQCloudArrayInt32Value.mdx b/sqlite-cloud/sdks/c/SQCloudArrayInt32Value.mdx index 39fb064..30beeb9 100644 --- a/sqlite-cloud/sdks/c/SQCloudArrayInt32Value.mdx +++ b/sqlite-cloud/sdks/c/SQCloudArrayInt32Value.mdx @@ -10,11 +10,11 @@ int32_t SQCloudArrayInt32Value (SQCloudResult *result, uint32_t index); ``` ### Description -If the result of the function [SQCloudResultType](/docs/sdk/c/sqcloudresulttype) is RESULT_ARRAY then use this function to retrieve an Int32 value. +If the result of the function [SQCloudResultType](/docs/sqlite-cloud/sdks/c/sqcloudresulttype) is RESULT_ARRAY then use this function to retrieve an Int32 value. ### Parameters * **result**: A valid SQCloudResult pointer returned by an SQCloud function. -* **index**: An array index (from 0 to [SQCloudArrayCount](/docs/sdk/c/sqcloudarraycount)-1) +* **index**: An array index (from 0 to [SQCloudArrayCount](/docs/sqlite-cloud/sdks/c/sqcloudarraycount)-1) ### Return value An `int32_t` value. diff --git a/sqlite-cloud/sdks/c/SQCloudArrayInt64Value.mdx b/sqlite-cloud/sdks/c/SQCloudArrayInt64Value.mdx index fee7569..e8f3c79 100644 --- a/sqlite-cloud/sdks/c/SQCloudArrayInt64Value.mdx +++ b/sqlite-cloud/sdks/c/SQCloudArrayInt64Value.mdx @@ -10,11 +10,11 @@ int64_t SQCloudArrayInt64Value (SQCloudResult *result, uint32_t index); ``` ### Description -If the result of the function [SQCloudResultType](/docs/sdk/c/sqcloudresulttype) is RESULT_ARRAY then use this function to retrieve an Int64 value. +If the result of the function [SQCloudResultType](/docs/sqlite-cloud/sdks/c/sqcloudresulttype) is RESULT_ARRAY then use this function to retrieve an Int64 value. ### Parameters * **result**: A valid SQCloudResult pointer returned by an SQCloud function. -* **index**: An array index (from 0 to [SQCloudArrayCount](/docs/sdk/c/sqcloudarraycount)-1) +* **index**: An array index (from 0 to [SQCloudArrayCount](/docs/sqlite-cloud/sdks/c/sqcloudarraycount)-1) ### Return value An `int64_t` value. diff --git a/sqlite-cloud/sdks/c/SQCloudArrayValue.mdx b/sqlite-cloud/sdks/c/SQCloudArrayValue.mdx index e7d3de6..875b525 100644 --- a/sqlite-cloud/sdks/c/SQCloudArrayValue.mdx +++ b/sqlite-cloud/sdks/c/SQCloudArrayValue.mdx @@ -10,11 +10,11 @@ char *SQCloudArrayValue (SQCloudResult *result, uint32_t index, uint32_t *len); ``` ### Description -If the result of the function [SQCloudResultType](/docs/sdk/c/sqcloudresulttype) is RESULT_ARRAY then use this function to retrieve a pointer and a length for an array value. +If the result of the function [SQCloudResultType](/docs/sqlite-cloud/sdks/c/sqcloudresulttype) is RESULT_ARRAY then use this function to retrieve a pointer and a length for an array value. ### Parameters * **result**: A valid SQCloudResult pointer returned by an SQCloud function -* **index**: An array index (from 0 to [SQCloudArrayCount](/docs/sdk/c/sqcloudarraycount)-1) +* **index**: An array index (from 0 to [SQCloudArrayCount](/docs/sqlite-cloud/sdks/c/sqcloudarraycount)-1) * **len**: On output the length of the returned buffer ### Return value diff --git a/sqlite-cloud/sdks/c/SQCloudArrayValueType.mdx b/sqlite-cloud/sdks/c/SQCloudArrayValueType.mdx index 15c0f37..195f0a3 100644 --- a/sqlite-cloud/sdks/c/SQCloudArrayValueType.mdx +++ b/sqlite-cloud/sdks/c/SQCloudArrayValueType.mdx @@ -10,11 +10,11 @@ SQCLOUD_VALUE_TYPE SQCloudArrayValueType (SQCloudResult *result, uint32_t index) ``` ### Description -If the result of the function [SQCloudResultType](/docs/sdk/c/sqcloudresulttype) is RESULT_ARRAY then use this function to retrieve the type of each array item. +If the result of the function [SQCloudResultType](/docs/sqlite-cloud/sdks/c/sqcloudresulttype) is RESULT_ARRAY then use this function to retrieve the type of each array item. ### Parameters * **result**: A valid SQCloudResult pointer returned by an SQCloud function. -* **index**: An array index (from 0 to [SQCloudArrayCount](/docs/sdk/c/sqcloudarraycount)-1) +* **index**: An array index (from 0 to [SQCloudArrayCount](/docs/sqlite-cloud/sdks/c/sqcloudarraycount)-1) ### Return value An `int` represented by the SQCLOUD_VALUE_TYPE enum type: diff --git a/sqlite-cloud/sdks/c/SQCloudBlobBytes.mdx b/sqlite-cloud/sdks/c/SQCloudBlobBytes.mdx index c6d6db4..9985677 100644 --- a/sqlite-cloud/sdks/c/SQCloudBlobBytes.mdx +++ b/sqlite-cloud/sdks/c/SQCloudBlobBytes.mdx @@ -13,10 +13,10 @@ int SQCloudBlobBytes (SQCloudBlob *blob); This function returns the size in bytes of the BLOB accessible via the successfully opened BLOB handle in its only argument. The incremental blob I/O routines can only read or overwriting existing blob content; they cannot change the size of a blob. -This function resembles the [sqlite3_blob_bytes](https://www.sqlite.org/c3ref/blob_bytes.html) SQLite API. +This function resembles the sqlite3_blob_bytes SQLite API. ### Parameters -* **blob**: a valid SQCloudBlob opaque datatype obtained by [SQCloudBlobOpen](/docs/sdk/c/sqcloudblobopen) +* **blob**: a valid SQCloudBlob opaque datatype obtained by [SQCloudBlobOpen](/docs/sqlite-cloud/sdks/c/sqcloudblobopen) ### Return value An `int` value with the size in bytes of the BLOB. diff --git a/sqlite-cloud/sdks/c/SQCloudBlobClose.mdx b/sqlite-cloud/sdks/c/SQCloudBlobClose.mdx index bd237f8..4040283 100644 --- a/sqlite-cloud/sdks/c/SQCloudBlobClose.mdx +++ b/sqlite-cloud/sdks/c/SQCloudBlobClose.mdx @@ -10,10 +10,10 @@ bool SQCloudBlobClose (SQCloudBlob *blob); ``` ### Description -This function closes an open BLOB handle. The BLOB handle is closed unconditionally. Even if this routine returns an error code, the handle is still closed. This function resembles the [sqlite3_blob_close](https://www.sqlite.org/c3ref/blob_close.html) SQLite API. +This function closes an open BLOB handle. The BLOB handle is closed unconditionally. Even if this routine returns an error code, the handle is still closed. This function resembles the sqlite3_blob_close SQLite API. ### Parameters -* **blob**: a valid SQCloudBlob opaque datatype obtained by [SQCloudBlobOpen](/docs/sdk/c/sqcloudblobopen) +* **blob**: a valid SQCloudBlob opaque datatype obtained by [SQCloudBlobOpen](/docs/sqlite-cloud/sdks/c/sqcloudblobopen) ### Return value `true` if operation succed, otherwise `false` diff --git a/sqlite-cloud/sdks/c/SQCloudBlobOpen.mdx b/sqlite-cloud/sdks/c/SQCloudBlobOpen.mdx index c62d397..d5cf26b 100644 --- a/sqlite-cloud/sdks/c/SQCloudBlobOpen.mdx +++ b/sqlite-cloud/sdks/c/SQCloudBlobOpen.mdx @@ -22,10 +22,10 @@ This function fails if any of the following conditions are true: * Column **colname** is part of an index, PRIMARY KEY or UNIQUE constraint and the blob is being opened for read/write access * Foreign key constraints are enabled, column **colname** is part of a child key definition and the blob is being opened for read/write access -This function resembles the [sqlite3_blob_open](https://www.sqlite.org/c3ref/blob_open.html) SQLite API. +This function resembles the sqlite3_blob_open SQLite API. ### Parameters -* **connection**: a valid connection object obtained by [SQCloudConnect](/docs/sdk/c/sqcloudconnect) or [SQCloudConnectWithString](/docs/sdk/c/sqcloudconnectwithstring) +* **connection**: a valid connection object obtained by [SQCloudConnect](/docs/sqlite-cloud/sdks/c/sqcloudconnect) or [SQCloudConnectWithString](/docs/sqlite-cloud/sdks/c/sqcloudconnectwithstring) * **dbname**: symbolic name of the database (usually `main`, if NULL `main` is used) * **tablename**: table name that contains the BLOB column * **colname**: name of the BLOB column diff --git a/sqlite-cloud/sdks/c/SQCloudBlobReOpen.mdx b/sqlite-cloud/sdks/c/SQCloudBlobReOpen.mdx index a25a270..bf827c1 100644 --- a/sqlite-cloud/sdks/c/SQCloudBlobReOpen.mdx +++ b/sqlite-cloud/sdks/c/SQCloudBlobReOpen.mdx @@ -12,10 +12,10 @@ bool SQCloudBlobReOpen (SQCloudBlob *blob, int64_t rowid); ### Description This function is used to move an existing BLOB handle so that it points to a different row of the same database table. The new row is identified by the **rowid** value passed as the second argument. Only the row can be changed. The database, table and column on which the blob handle is open remain the same. -This function resembles the [sqlite3_blob_reopen](https://www.sqlite.org/c3ref/blob_reopen.html) SQLite API. +This function resembles the sqlite3_blob_reopen SQLite API. ### Parameters -* **blob**: a valid SQCloudBlob opaque datatype obtained by [SQCloudBlobOpen](/docs/sdk/c/sqcloudblobopen) +* **blob**: a valid SQCloudBlob opaque datatype obtained by [SQCloudBlobOpen](/docs/sqlite-cloud/sdks/c/sqcloudblobopen) * **rowid**: rowid of the BLOB to open diff --git a/sqlite-cloud/sdks/c/SQCloudBlobRead.mdx b/sqlite-cloud/sdks/c/SQCloudBlobRead.mdx index 48b2854..0ec896a 100644 --- a/sqlite-cloud/sdks/c/SQCloudBlobRead.mdx +++ b/sqlite-cloud/sdks/c/SQCloudBlobRead.mdx @@ -12,10 +12,10 @@ int SQCloudBlobRead (SQCloudBlob *blob, void *buffer, int blen, int offset); ### Description The **SQCloudBlobRead** function is used to read data from an open BLOB handle into a caller-supplied buffer. **blen** bytes of data are copied into buffer **buffer** from the open BLOB, starting at offset **offset**. -This function resembles the [sqlite3_blob_read](https://www.sqlite.org/c3ref/blob_read.html) SQLite API. +This function resembles the sqlite3_blob_read SQLite API. ### Parameters -* **blob**: a valid SQCloudBlob opaque datatype obtained by [SQCloudBlobOpen](/docs/sdk/c/sqcloudblobopen) +* **blob**: a valid SQCloudBlob opaque datatype obtained by [SQCloudBlobOpen](/docs/sqlite-cloud/sdks/c/sqcloudblobopen) * **buffer**: an user-supplied pre-allocated buffer * **blen**: the length of the input buffer * **offset**: the offset value set to where to start the read operation diff --git a/sqlite-cloud/sdks/c/SQCloudBlobWrite.mdx b/sqlite-cloud/sdks/c/SQCloudBlobWrite.mdx index 9e77167..d42ee93 100644 --- a/sqlite-cloud/sdks/c/SQCloudBlobWrite.mdx +++ b/sqlite-cloud/sdks/c/SQCloudBlobWrite.mdx @@ -13,10 +13,10 @@ int SQCloudBlobWrite (SQCloudBlob *blob, const void *buffer, int blen, int offse The **SQCloudBlobWrite** function is used to write data into an open BLOB handle from a caller-supplied buffer. **blen** bytes of data are copied from the buffer **buffer**into the open BLOB, starting at offset **offset**. -This function resembles the [sqlite3_blob_write](https://www.sqlite.org/c3ref/blob_write.html) SQLite API. +This function resembles the sqlite3_blob_write SQLite API. ### Parameters -* **blob**: a valid SQCloudBlob opaque datatype obtained by [SQCloudBlobOpen](/docs/sdk/c/sqcloudblobopen) +* **blob**: a valid SQCloudBlob opaque datatype obtained by [SQCloudBlobOpen](/docs/sqlite-cloud/sdks/c/sqcloudblobopen) * **buffer**: an user-supplied pre-allocated buffer * **blen**: the length of the input buffer * **offset**: the offset value set to where to start the write operation diff --git a/sqlite-cloud/sdks/c/SQCloudConfig.mdx b/sqlite-cloud/sdks/c/SQCloudConfig.mdx index bffb389..d49319c 100644 --- a/sqlite-cloud/sdks/c/SQCloudConfig.mdx +++ b/sqlite-cloud/sdks/c/SQCloudConfig.mdx @@ -7,7 +7,7 @@ status: publish ### Description -The **SQCloudConfig** struct is used in the [SQCloudConnect](/docs/sdk/c/sqcloudconnect) and in the [SQCloudConnectWithString](/docs/sdk/c/sqcloudconnectwithstring) functions to set connection specific configuration parameters. +The **SQCloudConfig** struct is used in the [SQCloudConnect](/docs/sqlite-cloud/sdks/c/sqcloudconnect) and in the [SQCloudConnectWithString](/docs/sqlite-cloud/sdks/c/sqcloudconnectwithstring) functions to set connection specific configuration parameters. ### SQCloudConfig diff --git a/sqlite-cloud/sdks/c/SQCloudConnect.mdx b/sqlite-cloud/sdks/c/SQCloudConnect.mdx index 3839466..d144d64 100644 --- a/sqlite-cloud/sdks/c/SQCloudConnect.mdx +++ b/sqlite-cloud/sdks/c/SQCloudConnect.mdx @@ -15,7 +15,7 @@ Initiate a new connection to a database node specified by hostname and port. Thi ### Parameters * **hostname**: a NULL terminated string that contains host name or host ip address * **port**: database server port (you can use the `SQCLOUD_DEFAULT_PORT` macro) -* **config**: a pointer to a [SQCloudConfig struct](/docs/sdk/c/sqcloudconfig) (cannot be NULL) +* **config**: a pointer to a [SQCloudConfig struct](/docs/sqlite-cloud/sdks/c/sqcloudconfig) (cannot be NULL) ### Return value A pointer to an opaque **SQCloudConnection** struct. diff --git a/sqlite-cloud/sdks/c/SQCloudConnectWithString.mdx b/sqlite-cloud/sdks/c/SQCloudConnectWithString.mdx index a64c76d..84284ac 100644 --- a/sqlite-cloud/sdks/c/SQCloudConnectWithString.mdx +++ b/sqlite-cloud/sdks/c/SQCloudConnectWithString.mdx @@ -16,7 +16,7 @@ Initiate a new connection to a database node specified by a connection string. T String `s` must be an URL encoded string with the following format: `sqlitecloud://user:pass@host.com:port/dbname?timeout=10&key2=value2&key3=value3`. -An easy way to obtain a valid connection string is to click on the node address in the [Dashboard Nodes](/docs/introduction/nodes) section. A valid connection string will be copied in your clipboard. +An easy way to obtain a valid connection string is to click on the node address in the [Dashboard Nodes](/docs/architecture) section. A valid connection string will be copied in your clipboard. Key(s) can be: @@ -34,11 +34,11 @@ Key(s) can be: * client_certificate * client_certificate_key -These key(s) are equivalent to the fields specified in the [SQCloudConfig struct](/docs/sdk/c/sqcloudconfig). +These key(s) are equivalent to the fields specified in the [SQCloudConfig struct](/docs/sqlite-cloud/sdks/c/sqcloudconfig). ### Parameters * **s**: an URL encoded NULL terminated string that contains connection info -* **pconfig**: a pointer to a [SQCloudConfig struct](/docs/sdk/c/sqcloudconfig) (can be NULL) used to override configurations found in the connection string +* **pconfig**: a pointer to a [SQCloudConfig struct](/docs/sqlite-cloud/sdks/c/sqcloudconfig) (can be NULL) used to override configurations found in the connection string ### Return value A pointer to an opaque **SQCloudConnection** struct. diff --git a/sqlite-cloud/sdks/c/SQCloudDisconnect.mdx b/sqlite-cloud/sdks/c/SQCloudDisconnect.mdx index 83f8042..87194b4 100644 --- a/sqlite-cloud/sdks/c/SQCloudDisconnect.mdx +++ b/sqlite-cloud/sdks/c/SQCloudDisconnect.mdx @@ -13,7 +13,7 @@ void SQCloudDisconnect (SQCloudConnection *connection); Closes the connection to the server. Also frees memory used by the SQCloudConnection object. ### Parameters -* **connection**: a valid connection object obtained by [SQCloudConnect](/docs/sdk/c/sqcloudconnect) or [SQCloudConnectWithString](/docs/sdk/c/sqcloudconnectwithstring) +* **connection**: a valid connection object obtained by [SQCloudConnect](/docs/sqlite-cloud/sdks/c/sqcloudconnect) or [SQCloudConnectWithString](/docs/sqlite-cloud/sdks/c/sqcloudconnectwithstring) ### Return value Nothing. diff --git a/sqlite-cloud/sdks/c/SQCloudDownloadDatabase.mdx b/sqlite-cloud/sdks/c/SQCloudDownloadDatabase.mdx index 8f6f321..3944308 100644 --- a/sqlite-cloud/sdks/c/SQCloudDownloadDatabase.mdx +++ b/sqlite-cloud/sdks/c/SQCloudDownloadDatabase.mdx @@ -14,7 +14,7 @@ bool SQCloudDownloadDatabase (SQCloudConnection *connection, const char *dbname, Initiate an SQLite database download from an already connected SQLite Cloud node. ### Parameters -* **connection**: a valid connection object obtained by [SQCloudConnect](/docs/sdk/c/sqcloudconnect) or [SQCloudConnectWithString](/docs/sdk/c/sqcloudconnectwithstring) +* **connection**: a valid connection object obtained by [SQCloudConnect](/docs/sqlite-cloud/sdks/c/sqcloudconnect) or [SQCloudConnectWithString](/docs/sqlite-cloud/sdks/c/sqcloudconnectwithstring) * **dbname**: the name of the database to download * **xdata**: a pointer to an opaque datatype that will be passed as-is to the callback * **xcallback**: callback that will be automatically called to read from the input database file diff --git a/sqlite-cloud/sdks/c/SQCloudError.mdx b/sqlite-cloud/sdks/c/SQCloudError.mdx index ebad0de..5d140b3 100644 --- a/sqlite-cloud/sdks/c/SQCloudError.mdx +++ b/sqlite-cloud/sdks/c/SQCloudError.mdx @@ -16,17 +16,17 @@ const char *SQCloudErrorMsg (SQCloudConnection *connection); ### Description If the most recent API call associated with with database connection failed, then this APIs return information about the error. -These functions resemble the [sqlite3_error_*](https://www.sqlite.org/c3ref/errcode.html) SQLite APIs. +These functions resemble the sqlite3_error_* SQLite APIs. ### Parameters -* **connection**: a valid connection object obtained by [SQCloudConnect](/docs/sdk/c/sqcloudconnect) or [SQCloudConnectWithString](/docs/sdk/c/sqcloudconnectwithstring) +* **connection**: a valid connection object obtained by [SQCloudConnect](/docs/sqlite-cloud/sdks/c/sqcloudconnect) or [SQCloudConnectWithString](/docs/sqlite-cloud/sdks/c/sqcloudconnectwithstring) ### Return value * **SQLiteIsError** returns `true` if the most recent API call failed. * **SQCloudIsSQLiteError** returns `true` if the most recent error is related to an SQLite operation. * **SQCloudErrorCode** returns the numeric error code (or 0 if no error). -* **SQCloudExtendedErrorCode** returns the numeric [extended error code](https://www.sqlite.org/rescode.html#extrc) related to the failed SQLite operation. +* **SQCloudExtendedErrorCode** returns the numeric extended error code related to the failed SQLite operation. * **SQCloudErrorOffset** returns the byte offset of the start of the most recent error references a specific token in the input SQL (if any). If the most recent error does not reference a specific token in the input SQL, then the **SQCloudErrorOffset** function returns -1. * **SQCloudErrorMsg** return English-language text that describes the error. diff --git a/sqlite-cloud/sdks/c/SQCloudExec.mdx b/sqlite-cloud/sdks/c/SQCloudExec.mdx index a76653c..5b4b5da 100644 --- a/sqlite-cloud/sdks/c/SQCloudExec.mdx +++ b/sqlite-cloud/sdks/c/SQCloudExec.mdx @@ -10,14 +10,14 @@ SQCloudResult *SQCloudExec (SQCloudConnection *connection, const char *command); ``` ### Description -Submits a command to the server and waits for the result. The command can be any SQLite statement or any built-in [SQLite Cloud command](/docs/commands). +Submits a command to the server and waits for the result. The command can be any SQLite statement or any built-in [SQLite Cloud command](/docs/server-side-commands). ### Parameters -* **connection**: a valid connection object obtained by [SQCloudConnect](/docs/sdk/c/sqcloudconnect) or [SQCloudConnectWithString](/docs/sdk/c/sqcloudconnectwithstring) +* **connection**: a valid connection object obtained by [SQCloudConnect](/docs/sqlite-cloud/sdks/c/sqcloudconnect) or [SQCloudConnectWithString](/docs/sqlite-cloud/sdks/c/sqcloudconnectwithstring) * **command**: a NULL terminated string with the command to execute (multiple commands can be sent if separated by the semicolon character) ### Return value -A pointer to an opaque **SQCloudResult** struct that must be explicitly deallocated with [SQCloudResultFree](/docs/sdk/c/sqcloudresultfree) +A pointer to an opaque **SQCloudResult** struct that must be explicitly deallocated with [SQCloudResultFree](/docs/sqlite-cloud/sdks/c/sqcloudresultfree) ### Example ```c @@ -44,4 +44,4 @@ int main (int argc, const char * argv[]) { // perform multiple SQL statements (no error check here) SQCloudResult *r3 = SQCloudExec(conn, "INSERT INTO mytable (col1) VALUES ('value1'); INSERT INTO mytable (col1) VALUES ('value2'); SELECT * FROM mytable;"); } -``` \ No newline at end of file +``` diff --git a/sqlite-cloud/sdks/c/SQCloudExecArray.mdx b/sqlite-cloud/sdks/c/SQCloudExecArray.mdx index 1023d5c..9289ea5 100644 --- a/sqlite-cloud/sdks/c/SQCloudExecArray.mdx +++ b/sqlite-cloud/sdks/c/SQCloudExecArray.mdx @@ -10,10 +10,10 @@ SQCloudResult *SQCloudExecArray (SQCloudConnection *connection, const char *comm ``` ### Description -Submits a command to the server and waits for the result. The command can be any SQLite statement or any built-in [SQLite Cloud command](/docs/commands). This function is equivalent to the [SQCloudExec](/docs/sdk/c/sqcloudexec) function but special placeholders can be used to bind values to the statement (most of the time avoiding the need to perform copies and to encode data). +Submits a command to the server and waits for the result. The command can be any SQLite statement or any built-in [SQLite Cloud command](/docs/server-side-commands). This function is equivalent to the [SQCloudExec](/docs/sqlite-cloud/sdks/c/sqcloudexec) function but special placeholders can be used to bind values to the statement (most of the time avoiding the need to perform copies and to encode data). ### Parameters -* **connection**: a valid connection object obtained by [SQCloudConnect](/docs/sdk/c/sqcloudconnect) or [SQCloudConnectWithString](/docs/sdk/c/sqcloudconnectwithstring) +* **connection**: a valid connection object obtained by [SQCloudConnect](/docs/sqlite-cloud/sdks/c/sqcloudconnect) or [SQCloudConnectWithString](/docs/sqlite-cloud/sdks/c/sqcloudconnectwithstring) * **command**: a NULL terminated string with the command to execute * **values**: an array of n values * **len**: an array of n length @@ -21,7 +21,7 @@ Submits a command to the server and waits for the result. The command can be any * **n** number of array elements ### Return value -A pointer to an opaque **SQCloudResult** struct that must be explicitly deallocated with [SQCloudResultFree](/docs/sdk/c/sqcloudresultfree) +A pointer to an opaque **SQCloudResult** struct that must be explicitly deallocated with [SQCloudResultFree](/docs/sqlite-cloud/sdks/c/sqcloudresultfree) ### Example ```c @@ -57,4 +57,4 @@ int main (int argc, const char * argv[]) { // ... } -``` \ No newline at end of file +``` diff --git a/sqlite-cloud/sdks/c/SQCloudResultDouble.mdx b/sqlite-cloud/sdks/c/SQCloudResultDouble.mdx index ad91dea..06e8859 100644 --- a/sqlite-cloud/sdks/c/SQCloudResultDouble.mdx +++ b/sqlite-cloud/sdks/c/SQCloudResultDouble.mdx @@ -10,7 +10,7 @@ double SQCloudResultDouble (SQCloudResult *result); ``` ### Description -If the result of the function [SQCloudResultType](/docs/sdk/c/sqcloudresulttype) is RESULT_FLOAT then use this function to retrieve a Double value. +If the result of the function [SQCloudResultType](/docs/sqlite-cloud/sdks/c/sqcloudresulttype) is RESULT_FLOAT then use this function to retrieve a Double value. ### Parameters * **result**: A valid SQCloudResult pointer returned by an SQCloud function. diff --git a/sqlite-cloud/sdks/c/SQCloudResultDump.mdx b/sqlite-cloud/sdks/c/SQCloudResultDump.mdx index deb2514..c78ef36 100644 --- a/sqlite-cloud/sdks/c/SQCloudResultDump.mdx +++ b/sqlite-cloud/sdks/c/SQCloudResultDump.mdx @@ -13,7 +13,7 @@ void SQCloudResultDump (SQCloudConnection *connection, SQCloudResult *result); Print the result on standard output. ### Parameters -* **connection**: a valid connection object obtained by [SQCloudConnect](/docs/sdk/c/sqcloudconnect) or [SQCloudConnectWithString](/docs/sdk/c/sqcloudconnectwithstring) +* **connection**: a valid connection object obtained by [SQCloudConnect](/docs/sqlite-cloud/sdks/c/sqcloudconnect) or [SQCloudConnectWithString](/docs/sqlite-cloud/sdks/c/sqcloudconnectwithstring) * **result**: A valid SQCloudResult pointer returned by an SQCloud function. ### Return value diff --git a/sqlite-cloud/sdks/c/SQCloudResultFloat.mdx b/sqlite-cloud/sdks/c/SQCloudResultFloat.mdx index 4fa8b70..e958871 100644 --- a/sqlite-cloud/sdks/c/SQCloudResultFloat.mdx +++ b/sqlite-cloud/sdks/c/SQCloudResultFloat.mdx @@ -10,7 +10,7 @@ float SQCloudResultFloat (SQCloudResult *result); ``` ### Description -If the result of the function [SQCloudResultType](/docs/sdk/c/sqcloudresulttype) is RESULT_FLOAT then use this function to retrieve a Float value. +If the result of the function [SQCloudResultType](/docs/sqlite-cloud/sdks/c/sqcloudresulttype) is RESULT_FLOAT then use this function to retrieve a Float value. ### Parameters * **result**: A valid SQCloudResult pointer returned by an SQCloud function. diff --git a/sqlite-cloud/sdks/c/SQCloudResultInt32.mdx b/sqlite-cloud/sdks/c/SQCloudResultInt32.mdx index 567e946..966ccca 100644 --- a/sqlite-cloud/sdks/c/SQCloudResultInt32.mdx +++ b/sqlite-cloud/sdks/c/SQCloudResultInt32.mdx @@ -10,7 +10,7 @@ int32_t SQCloudResultInt32 (SQCloudResult *result); ``` ### Description -If the result of the function [SQCloudResultType](/docs/sdk/c/sqcloudresulttype) is RESULT_INTEGER then use this function to retrieve an Int32 value. +If the result of the function [SQCloudResultType](/docs/sqlite-cloud/sdks/c/sqcloudresulttype) is RESULT_INTEGER then use this function to retrieve an Int32 value. ### Parameters * **result**: A valid SQCloudResult pointer returned by an SQCloud function. diff --git a/sqlite-cloud/sdks/c/SQCloudResultInt64.mdx b/sqlite-cloud/sdks/c/SQCloudResultInt64.mdx index dc78c43..dfab2b8 100644 --- a/sqlite-cloud/sdks/c/SQCloudResultInt64.mdx +++ b/sqlite-cloud/sdks/c/SQCloudResultInt64.mdx @@ -10,7 +10,7 @@ int64_t SQCloudResultInt64 (SQCloudResult *result); ``` ### Description -If the result of the function [SQCloudResultType](/docs/sdk/c/sqcloudresulttype) is RESULT_INTEGER then use this function to retrieve an Int64 value. +If the result of the function [SQCloudResultType](/docs/sqlite-cloud/sdks/c/sqcloudresulttype) is RESULT_INTEGER then use this function to retrieve an Int64 value. ### Parameters * **result**: A valid SQCloudResult pointer returned by an SQCloud function. diff --git a/sqlite-cloud/sdks/c/SQCloudRowsetCols.mdx b/sqlite-cloud/sdks/c/SQCloudRowsetCols.mdx index fba7236..e8e1974 100644 --- a/sqlite-cloud/sdks/c/SQCloudRowsetCols.mdx +++ b/sqlite-cloud/sdks/c/SQCloudRowsetCols.mdx @@ -10,7 +10,7 @@ uint32_t SQCloudRowsetCols (SQCloudResult *result); ``` ### Description -If the result of the function [SQCloudResultType](/docs/sdk/c/sqcloudresulttype) is RESULT_ROWSET then use this function to retrieve the number of columns in the Rowset. +If the result of the function [SQCloudResultType](/docs/sqlite-cloud/sdks/c/sqcloudresulttype) is RESULT_ROWSET then use this function to retrieve the number of columns in the Rowset. ### Parameters * **result**: A valid SQCloudResult pointer returned by an SQCloud function. diff --git a/sqlite-cloud/sdks/c/SQCloudRowsetColumnName.mdx b/sqlite-cloud/sdks/c/SQCloudRowsetColumnName.mdx index 54f1f95..2792b25 100644 --- a/sqlite-cloud/sdks/c/SQCloudRowsetColumnName.mdx +++ b/sqlite-cloud/sdks/c/SQCloudRowsetColumnName.mdx @@ -10,11 +10,11 @@ char *SQCloudRowsetColumnName (SQCloudResult *result, uint32_t col, uint32_t *le ``` ### Description -If the result of the function [SQCloudResultType](/docs/sdk/c/sqcloudresulttype) is RESULT_ROWSET then use this function to retrieve the name of a column. +If the result of the function [SQCloudResultType](/docs/sqlite-cloud/sdks/c/sqcloudresulttype) is RESULT_ROWSET then use this function to retrieve the name of a column. ### Parameters * **result**: A valid SQCloudResult pointer returned by an SQCloud function. -* **col**: A column index (from 0 to [SQCloudRowsetCols](/docs/sdk/c/sqcloudrowsetcols)-1) +* **col**: A column index (from 0 to [SQCloudRowsetCols](/docs/sqlite-cloud/sdks/c/sqcloudrowsetcols)-1) * **len**: On output the column name length ### Return value diff --git a/sqlite-cloud/sdks/c/SQCloudRowsetDoubleValue.mdx b/sqlite-cloud/sdks/c/SQCloudRowsetDoubleValue.mdx index fddc77e..df3f89c 100644 --- a/sqlite-cloud/sdks/c/SQCloudRowsetDoubleValue.mdx +++ b/sqlite-cloud/sdks/c/SQCloudRowsetDoubleValue.mdx @@ -10,12 +10,12 @@ double SQCloudRowsetDoubleValue (SQCloudResult *result, uint32_t row, uint32_t c ``` ### Description -If the result of the function [SQCloudResultType](/docs/sdk/c/sqcloudresulttype) is RESULT_ROWSET then use this function to retrieve the Double value of the item at row/col. +If the result of the function [SQCloudResultType](/docs/sqlite-cloud/sdks/c/sqcloudresulttype) is RESULT_ROWSET then use this function to retrieve the Double value of the item at row/col. ### Parameters * **result**: A valid SQCloudResult pointer returned by an SQCloud function. -* **row**: A row index (from 0 to [SQCloudRowsetRows](/docs/sdk/c/sqcloudrowsetrows)-1) -* **col**: A column index (from 0 to [SQCloudRowsetCols](/docs/sdk/c/sqcloudrowsetcols)-1) +* **row**: A row index (from 0 to [SQCloudRowsetRows](/docs/sqlite-cloud/sdks/c/sqcloudrowsetrows)-1) +* **col**: A column index (from 0 to [SQCloudRowsetCols](/docs/sqlite-cloud/sdks/c/sqcloudrowsetcols)-1) ### Return value A `double` value. diff --git a/sqlite-cloud/sdks/c/SQCloudRowsetFloatValue.mdx b/sqlite-cloud/sdks/c/SQCloudRowsetFloatValue.mdx index cef4dae..fcbbbcc 100644 --- a/sqlite-cloud/sdks/c/SQCloudRowsetFloatValue.mdx +++ b/sqlite-cloud/sdks/c/SQCloudRowsetFloatValue.mdx @@ -10,12 +10,12 @@ float SQCloudRowsetFloatValue (SQCloudResult *result, uint32_t row, uint32_t col ``` ### Description -If the result of the function [SQCloudResultType](/docs/sdk/c/sqcloudresulttype) is RESULT_ROWSET then use this function to retrieve the Float value of the item at row/col. +If the result of the function [SQCloudResultType](/docs/sqlite-cloud/sdks/c/sqcloudresulttype) is RESULT_ROWSET then use this function to retrieve the Float value of the item at row/col. ### Parameters * **result**: A valid SQCloudResult pointer returned by an SQCloud function. -* **row**: A row index (from 0 to [SQCloudRowsetRows](/docs/sdk/c/sqcloudrowsetrows)-1) -* **col**: A column index (from 0 to [SQCloudRowsetCols](/docs/sdk/c/sqcloudrowsetcols)-1) +* **row**: A row index (from 0 to [SQCloudRowsetRows](/docs/sqlite-cloud/sdks/c/sqcloudrowsetrows)-1) +* **col**: A column index (from 0 to [SQCloudRowsetCols](/docs/sqlite-cloud/sdks/c/sqcloudrowsetcols)-1) ### Return value A `float` value. diff --git a/sqlite-cloud/sdks/c/SQCloudRowsetInt32Value.mdx b/sqlite-cloud/sdks/c/SQCloudRowsetInt32Value.mdx index dec580a..5714c6d 100644 --- a/sqlite-cloud/sdks/c/SQCloudRowsetInt32Value.mdx +++ b/sqlite-cloud/sdks/c/SQCloudRowsetInt32Value.mdx @@ -10,12 +10,12 @@ int32_t SQCloudRowsetInt32Value (SQCloudResult *result, uint32_t row, uint32_t c ``` ### Description -If the result of the function [SQCloudResultType](/docs/sdk/c/sqcloudresulttype) is RESULT_ROWSET then use this function to retrieve the `int32_t` value of the item at row/col. +If the result of the function [SQCloudResultType](/docs/sqlite-cloud/sdks/c/sqcloudresulttype) is RESULT_ROWSET then use this function to retrieve the `int32_t` value of the item at row/col. ### Parameters * **result**: A valid SQCloudResult pointer returned by an SQCloud function. -* **row**: A row index (from 0 to [SQCloudRowsetRows](/docs/sdk/c/sqcloudrowsetrows)-1) -* **col**: A column index (from 0 to [SQCloudRowsetCols](/docs/sdk/c/sqcloudrowsetcols)-1) +* **row**: A row index (from 0 to [SQCloudRowsetRows](/docs/sqlite-cloud/sdks/c/sqcloudrowsetrows)-1) +* **col**: A column index (from 0 to [SQCloudRowsetCols](/docs/sqlite-cloud/sdks/c/sqcloudrowsetcols)-1) ### Return value An `int32_t` value. diff --git a/sqlite-cloud/sdks/c/SQCloudRowsetInt64Value.mdx b/sqlite-cloud/sdks/c/SQCloudRowsetInt64Value.mdx index ba2a731..9808f14 100644 --- a/sqlite-cloud/sdks/c/SQCloudRowsetInt64Value.mdx +++ b/sqlite-cloud/sdks/c/SQCloudRowsetInt64Value.mdx @@ -10,12 +10,12 @@ int64_t SQCloudRowsetInt64Value (SQCloudResult *result, uint32_t row, uint32_t c ``` ### Description -If the result of the function [SQCloudResultType](/docs/sdk/c/sqcloudresulttype) is RESULT_ROWSET then use this function to retrieve the `int64_t` value of the item at row/col. +If the result of the function [SQCloudResultType](/docs/sqlite-cloud/sdks/c/sqcloudresulttype) is RESULT_ROWSET then use this function to retrieve the `int64_t` value of the item at row/col. ### Parameters * **result**: A valid SQCloudResult pointer returned by an SQCloud function. -* **row**: A row index (from 0 to [SQCloudRowsetRows](/docs/sdk/c/sqcloudrowsetrows)-1) -* **col**: A column index (from 0 to [SQCloudRowsetCols](/docs/sdk/c/sqcloudrowsetcols)-1) +* **row**: A row index (from 0 to [SQCloudRowsetRows](/docs/sqlite-cloud/sdks/c/sqcloudrowsetrows)-1) +* **col**: A column index (from 0 to [SQCloudRowsetCols](/docs/sqlite-cloud/sdks/c/sqcloudrowsetcols)-1) ### Return value An `int64_t` value. diff --git a/sqlite-cloud/sdks/c/SQCloudRowsetRows.mdx b/sqlite-cloud/sdks/c/SQCloudRowsetRows.mdx index 96bb0fa..386d711 100644 --- a/sqlite-cloud/sdks/c/SQCloudRowsetRows.mdx +++ b/sqlite-cloud/sdks/c/SQCloudRowsetRows.mdx @@ -10,7 +10,7 @@ uint32_t SQCloudRowsetRows (SQCloudResult *result); ``` ### Description -If the result of the function [SQCloudResultType](/docs/sdk/c/sqcloudresulttype) is RESULT_ROWSET then use this function to retrieve the number of rows in the Rowset. +If the result of the function [SQCloudResultType](/docs/sqlite-cloud/sdks/c/sqcloudresulttype) is RESULT_ROWSET then use this function to retrieve the number of rows in the Rowset. ### Parameters * **result**: A valid SQCloudResult pointer returned by an SQCloud function. diff --git a/sqlite-cloud/sdks/c/SQCloudRowsetValue.mdx b/sqlite-cloud/sdks/c/SQCloudRowsetValue.mdx index 4fcbdfe..7b3d03c 100644 --- a/sqlite-cloud/sdks/c/SQCloudRowsetValue.mdx +++ b/sqlite-cloud/sdks/c/SQCloudRowsetValue.mdx @@ -10,12 +10,12 @@ char *SQCloudRowsetValue (SQCloudResult *result, uint32_t row, uint32_t col, uin ``` ### Description -If the result of the function [SQCloudResultType](/docs/sdk/c/sqcloudresulttype) is RESULT_ROWSET then use this function to retrieve a pointer and a length for a rowset item identified by a given row and column index. +If the result of the function [SQCloudResultType](/docs/sqlite-cloud/sdks/c/sqcloudresulttype) is RESULT_ROWSET then use this function to retrieve a pointer and a length for a rowset item identified by a given row and column index. ### Parameters * **result**: A valid SQCloudResult pointer returned by an SQCloud function. -* **row**: A row index (from 0 to [SQCloudRowsetRows](/docs/sdk/c/sqcloudrowsetrows)-1) -* **col**: A column index (from 0 to [SQCloudRowsetCols](/docs/sdk/c/sqcloudrowsetcols)-1) +* **row**: A row index (from 0 to [SQCloudRowsetRows](/docs/sqlite-cloud/sdks/c/sqcloudrowsetrows)-1) +* **col**: A column index (from 0 to [SQCloudRowsetCols](/docs/sqlite-cloud/sdks/c/sqcloudrowsetcols)-1) * **len**: On output the length of the returned buffer ### Return value @@ -50,7 +50,7 @@ int main (int argc, const char * argv[]) { // print column names for (uint32_t i=0; isqlite3_bind_* SQLite APIs. ### Parameters -* **vm**: A valid VM obtained by [SQCloudVMCompile](/docs/sdk/c/sqcloudvmcompile). -* **index**: Represents the index of the SQL parameter to be set. The leftmost SQL parameter has an index of 1. When the same named SQL parameter is used more than once, second and subsequent occurrences have the same index as the first occurrence. The index for named parameters can be looked up using the [SQCloudVMBindParameterIndex](/docs/sdk/c/sqcloudvmbindparameterindex) API if desired. The index for "?NNN" parameters is the value of NNN. +* **vm**: A valid VM obtained by [SQCloudVMCompile](/docs/sqlite-cloud/sdks/c/sqcloudvmcompile). +* **index**: Represents the index of the SQL parameter to be set. The leftmost SQL parameter has an index of 1. When the same named SQL parameter is used more than once, second and subsequent occurrences have the same index as the first occurrence. The index for named parameters can be looked up using the [SQCloudVMBindParameterIndex](/docs/sqlite-cloud/sdks/c/sqcloudvmbindparameterindex) API if desired. The index for "?NNN" parameters is the value of NNN. * **value**: The the value to bind to the parameter. * **len**: The number of bytes in the parameter. To be clear: the value is the number of bytes in the value, not the number of characters. diff --git a/sqlite-cloud/sdks/c/SQCloudVMBindParameterCount.mdx b/sqlite-cloud/sdks/c/SQCloudVMBindParameterCount.mdx index a1ab262..f1b5e47 100644 --- a/sqlite-cloud/sdks/c/SQCloudVMBindParameterCount.mdx +++ b/sqlite-cloud/sdks/c/SQCloudVMBindParameterCount.mdx @@ -12,10 +12,10 @@ int SQCloudVMBindParameterCount (SQCloudVM *vm); ### Description This routine can be used to find the number of SQL parameters in a prepared statement. SQL parameters are tokens of the form "?", "?NNN", ":AAA", "$AAA", or "@AAA" that serve as placeholders for values that are bound to the parameters at a later time. This routine actually returns the index of the largest (rightmost) parameter. For all forms except ?NNN, this will correspond to the number of unique parameters. If parameters of the ?NNN form are used, there may be gaps in the list. -This function resembles the [bind_parameter_count](https://www.sqlite.org/c3ref/bind_parameter_count.html) SQLite API. +This function resembles the bind_parameter_count SQLite API. ### Parameters -* **vm**: A valid VM obtained by [SQCloudVMCompile](/docs/sdk/c/sqcloudvmcompile). +* **vm**: A valid VM obtained by [SQCloudVMCompile](/docs/sqlite-cloud/sdks/c/sqcloudvmcompile). ### Return value diff --git a/sqlite-cloud/sdks/c/SQCloudVMBindParameterIndex.mdx b/sqlite-cloud/sdks/c/SQCloudVMBindParameterIndex.mdx index be06db1..0ba61e5 100644 --- a/sqlite-cloud/sdks/c/SQCloudVMBindParameterIndex.mdx +++ b/sqlite-cloud/sdks/c/SQCloudVMBindParameterIndex.mdx @@ -10,12 +10,12 @@ int SQCloudVMBindParameterIndex (SQCloudVM *vm, const char *name); ``` ### Description -Return the index of an SQL parameter given its name. The index value returned is suitable for use as the second parameter to [SQCloudVMBind](/docs/sdk/c/sqcloudvmbind). A zero is returned if no matching parameter is found. +Return the index of an SQL parameter given its name. The index value returned is suitable for use as the second parameter to [SQCloudVMBind](/docs/sqlite-cloud/sdks/c/sqcloudvmbind). A zero is returned if no matching parameter is found. -This function resembles the [bind_parameter_index](https://www.sqlite.org/c3ref/bind_parameter_index.html) SQLite API. +This function resembles the bind_parameter_index SQLite API. ### Parameters -* **vm**: A valid VM obtained by [SQCloudVMCompile](/docs/sdk/c/sqcloudvmcompile). +* **vm**: A valid VM obtained by [SQCloudVMCompile](/docs/sqlite-cloud/sdks/c/sqcloudvmcompile). * **name**: The SQL parameter name. ### Return value diff --git a/sqlite-cloud/sdks/c/SQCloudVMBindParameterName.mdx b/sqlite-cloud/sdks/c/SQCloudVMBindParameterName.mdx index dce7a6f..78a47a0 100644 --- a/sqlite-cloud/sdks/c/SQCloudVMBindParameterName.mdx +++ b/sqlite-cloud/sdks/c/SQCloudVMBindParameterName.mdx @@ -15,10 +15,10 @@ The **SQCloudVMBindParameterName** interface returns the name of the N-th SQL pa The first host parameter has an index of 1, not 0. If the value of index is out of range or if the N-th parameter is nameless, then NULL is returned. -This function resembles the [bind_parameter_name](https://www.sqlite.org/c3ref/bind_parameter_name.html) SQLite API. +This function resembles the bind_parameter_name SQLite API. ### Parameters -* **vm**: A valid VM obtained by [SQCloudVMCompile](/docs/sdk/c/sqcloudvmcompile). +* **vm**: A valid VM obtained by [SQCloudVMCompile](/docs/sqlite-cloud/sdks/c/sqcloudvmcompile). * **index**: The SQL parameter index. ### Return value diff --git a/sqlite-cloud/sdks/c/SQCloudVMChanges.mdx b/sqlite-cloud/sdks/c/SQCloudVMChanges.mdx index 479a979..9d7672b 100644 --- a/sqlite-cloud/sdks/c/SQCloudVMChanges.mdx +++ b/sqlite-cloud/sdks/c/SQCloudVMChanges.mdx @@ -18,7 +18,7 @@ If you need to get the changes from a SQCloudConnection object you can send a `D ### Parameters -* **vm**: A valid VM obtained by [SQCloudVMCompile](/docs/sdk/c/sqcloudvmcompile). +* **vm**: A valid VM obtained by [SQCloudVMCompile](/docs/sqlite-cloud/sdks/c/sqcloudvmcompile). ### Return value diff --git a/sqlite-cloud/sdks/c/SQCloudVMClose.mdx b/sqlite-cloud/sdks/c/SQCloudVMClose.mdx index b2a6c15..5b5595b 100644 --- a/sqlite-cloud/sdks/c/SQCloudVMClose.mdx +++ b/sqlite-cloud/sdks/c/SQCloudVMClose.mdx @@ -11,11 +11,11 @@ bool SQCloudVMClose (SQCloudVM *vm); ### Description Frees the storage associated with a SQCloudVM. The application must finalize every compiled statement in order to avoid resource leaks. -This function resembles the [sqlite3_finalize](https://www.sqlite.org/c3ref/finalize.html) SQLite API. +This function resembles the sqlite3_finalize SQLite API. ### Parameters -* **vm**: A valid VM obtained by [SQCloudVMCompile](/docs/sdk/c/sqcloudvmcompile). +* **vm**: A valid VM obtained by [SQCloudVMCompile](/docs/sqlite-cloud/sdks/c/sqcloudvmcompile). ### Return value diff --git a/sqlite-cloud/sdks/c/SQCloudVMColumn.mdx b/sqlite-cloud/sdks/c/SQCloudVMColumn.mdx index 0dac957..13d47dc 100644 --- a/sqlite-cloud/sdks/c/SQCloudVMColumn.mdx +++ b/sqlite-cloud/sdks/c/SQCloudVMColumn.mdx @@ -17,12 +17,12 @@ SQCLOUD_VALUE_TYPE SQCloudVMColumnType (SQCloudVM *vm, int index); ### Description These routines return information about a single column of the current result row of a query. -These functions resemble the [sqlite3_column_*](https://www.sqlite.org/c3ref/column_blob.html) SQLite APIs. +These functions resemble the sqlite3_column_* SQLite APIs. ### Parameters -* **vm**: A valid VM obtained by [SQCloudVMCompile](/docs/sdk/c/sqcloudvmcompile). -* **index**: The index of the column for which information should be returned. The leftmost column of the result set has the index 0. The number of columns in the result can be determined using [SQCloudVMColumnCount](/docs/sdk/c/sqcloudvmcolumncount). +* **vm**: A valid VM obtained by [SQCloudVMCompile](/docs/sqlite-cloud/sdks/c/sqcloudvmcompile). +* **index**: The index of the column for which information should be returned. The leftmost column of the result set has the index 0. The number of columns in the result can be determined using [SQCloudVMColumnCount](/docs/sqlite-cloud/sdks/c/sqcloudvmcolumncount). * **len**: The number of bytes of the returned value. The **SQCloudVMColumnType** routine returns the datatype code for the initial data type of the result column. The returned value is one of following: diff --git a/sqlite-cloud/sdks/c/SQCloudVMColumnCount.mdx b/sqlite-cloud/sdks/c/SQCloudVMColumnCount.mdx index ef01411..9317ed8 100644 --- a/sqlite-cloud/sdks/c/SQCloudVMColumnCount.mdx +++ b/sqlite-cloud/sdks/c/SQCloudVMColumnCount.mdx @@ -12,11 +12,11 @@ int SQCloudVMColumnCount (SQCloudVM *vm); ### Description The **SQCloudVMColumnCount** returns the number of columns in the result set returned by the prepared statement. If this routine returns 0, that means the prepared statement returns no data (for example an UPDATE). However, just because this routine returns a positive number does not mean that one or more rows of data will be returned. A SELECT statement will always have a positive **SQCloudVMColumnCount** but depending on the WHERE clause constraints and the table content, it might return no rows. -This function resembles the [sqlite3_column_count](https://sqlite.org/c3ref/column_count.html) SQLite APIs. +This function resembles the sqlite3_column_count SQLite APIs. ### Parameters -* **vm**: A valid VM obtained by [SQCloudVMCompile](/docs/sdk/c/sqcloudvmcompile). +* **vm**: A valid VM obtained by [SQCloudVMCompile](/docs/sqlite-cloud/sdks/c/sqcloudvmcompile). Return value An `int` with the number of columns. diff --git a/sqlite-cloud/sdks/c/SQCloudVMCompile.mdx b/sqlite-cloud/sdks/c/SQCloudVMCompile.mdx index f278c1a..2c43e47 100644 --- a/sqlite-cloud/sdks/c/SQCloudVMCompile.mdx +++ b/sqlite-cloud/sdks/c/SQCloudVMCompile.mdx @@ -11,10 +11,10 @@ SQCloudVM *SQCloudVMCompile (SQCloudConnection *connection, const char *sql, int ### Description Compile an SQL statement into a byte-code virtual machine. -This function resembles the [sqlite3_prepare](https://www.sqlite.org/c3ref/prepare.html) SQLite API. +This function resembles the sqlite3_prepare SQLite API. ### Parameters -* **connection**: A valid connection object obtained by [SQCloudConnect](/docs/sdk/c/sqcloudconnect) or [SQCloudConnectWithString](/docs/sdk/c/sqcloudconnectwithstring) +* **connection**: A valid connection object obtained by [SQCloudConnect](/docs/sqlite-cloud/sdks/c/sqcloudconnect) or [SQCloudConnectWithString](/docs/sqlite-cloud/sdks/c/sqcloudconnectwithstring) * **sql**: The statement to be compiled. * **len**: If the len argument is negative, then sql is read up to the first zero terminator. If len is positive, then it is the number of bytes read from sql. * **tail**: If the tail argument is not NULL then *tail is made to point to the first byte past the end of the first SQL statement in sql. SQCloudVMCompile compiles only the first statement in sql, so *tail is left pointing to what remains uncompiled. diff --git a/sqlite-cloud/sdks/c/SQCloudVMErrorCode.mdx b/sqlite-cloud/sdks/c/SQCloudVMErrorCode.mdx index b6421ed..4fff303 100644 --- a/sqlite-cloud/sdks/c/SQCloudVMErrorCode.mdx +++ b/sqlite-cloud/sdks/c/SQCloudVMErrorCode.mdx @@ -14,7 +14,7 @@ Retrieve the latest error code (if any) from the associated vm. ### Parameters -* **vm**: A valid VM obtained by [SQCloudVMCompile](/docs/sdk/c/sqcloudvmcompile). +* **vm**: A valid VM obtained by [SQCloudVMCompile](/docs/sqlite-cloud/sdks/c/sqcloudvmcompile). ### Return value diff --git a/sqlite-cloud/sdks/c/SQCloudVMErrorMsg.mdx b/sqlite-cloud/sdks/c/SQCloudVMErrorMsg.mdx index 5c3c44f..080e116 100644 --- a/sqlite-cloud/sdks/c/SQCloudVMErrorMsg.mdx +++ b/sqlite-cloud/sdks/c/SQCloudVMErrorMsg.mdx @@ -14,7 +14,7 @@ Retrieve the latest error message (if any) from the associated vm. ### Parameters -* **vm**: A valid VM obtained by [SQCloudVMCompile](/docs/sdk/c/sqcloudvmcompile). +* **vm**: A valid VM obtained by [SQCloudVMCompile](/docs/sqlite-cloud/sdks/c/sqcloudvmcompile). ### Return value diff --git a/sqlite-cloud/sdks/c/SQCloudVMIsExplain.mdx b/sqlite-cloud/sdks/c/SQCloudVMIsExplain.mdx index 3cc8e16..bafe737 100644 --- a/sqlite-cloud/sdks/c/SQCloudVMIsExplain.mdx +++ b/sqlite-cloud/sdks/c/SQCloudVMIsExplain.mdx @@ -10,10 +10,10 @@ int SQCloudVMIsExplain (SQCloudVM *vm); ``` ### Description -The **SQCloudVMIsExplain** interface returns 1 if the prepared statement S is an EXPLAIN statement, or 2 if the statement S is an EXPLAIN QUERY PLAN. **SQCloudVMIsExplain** interface returns 0 if the statement is an ordinary statement or a NULL pointer. This function resembles the [sqlite3_stmt_isexplain](https://www.sqlite.org/c3ref/stmt_isexplain.html) SQLite API. +The **SQCloudVMIsExplain** interface returns 1 if the prepared statement S is an EXPLAIN statement, or 2 if the statement S is an EXPLAIN QUERY PLAN. **SQCloudVMIsExplain** interface returns 0 if the statement is an ordinary statement or a NULL pointer. This function resembles the sqlite3_stmt_isexplain SQLite API. ### Parameters -* **vm**: A valid VM obtained by [SQCloudVMCompile](/docs/sdk/c/sqcloudvmcompile). +* **vm**: A valid VM obtained by [SQCloudVMCompile](/docs/sqlite-cloud/sdks/c/sqcloudvmcompile). ### Return value An `int` value representing if the original statement was an EXPLAIN. diff --git a/sqlite-cloud/sdks/c/SQCloudVMIsFinalized.mdx b/sqlite-cloud/sdks/c/SQCloudVMIsFinalized.mdx index 4491e59..f79741e 100644 --- a/sqlite-cloud/sdks/c/SQCloudVMIsFinalized.mdx +++ b/sqlite-cloud/sdks/c/SQCloudVMIsFinalized.mdx @@ -10,11 +10,11 @@ bool SQCloudVMIsFinalized (SQCloudVM *vm); ``` ### Description -The **SQCloudVMIsFinalized** interface returns true if the prepared statement bound to the vm has been stepped at least once using [SQCloudVMStep](/docs/sdk/c/sqcloudvmstep) but has neither run to completion nor been reset. This function resembles the [sqlite3_stmt_busy](https://www.sqlite.org/c3ref/stmt_busy.html) SQLite API. +The **SQCloudVMIsFinalized** interface returns true if the prepared statement bound to the vm has been stepped at least once using [SQCloudVMStep](/docs/sqlite-cloud/sdks/c/sqcloudvmstep) but has neither run to completion nor been reset. This function resembles the sqlite3_stmt_busy SQLite API. ### Parameters -* **vm**: A valid VM obtained by [SQCloudVMCompile](/docs/sdk/c/sqcloudvmcompile). +* **vm**: A valid VM obtained by [SQCloudVMCompile](/docs/sqlite-cloud/sdks/c/sqcloudvmcompile). ### Return value diff --git a/sqlite-cloud/sdks/c/SQCloudVMIsReadOnly.mdx b/sqlite-cloud/sdks/c/SQCloudVMIsReadOnly.mdx index 5aca6d9..08ef626 100644 --- a/sqlite-cloud/sdks/c/SQCloudVMIsReadOnly.mdx +++ b/sqlite-cloud/sdks/c/SQCloudVMIsReadOnly.mdx @@ -10,10 +10,10 @@ bool SQCloudVMIsReadOnly (SQCloudVM *vm); ``` ### Description -The **SQCloudVMIsReadOnly** interface returns true if and only if the prepared statement bound to vm makes no direct changes to the content of the database file. This routine returns false if there is any possibility that the statement might change the database file. A false return does not guarantee that the statement will change the database file. This function resembles the [sqlite3_stmt_readonly](https://www.sqlite.org/c3ref/stmt_readonly.html) SQLite API. +The **SQCloudVMIsReadOnly** interface returns true if and only if the prepared statement bound to vm makes no direct changes to the content of the database file. This routine returns false if there is any possibility that the statement might change the database file. A false return does not guarantee that the statement will change the database file. This function resembles the sqlite3_stmt_readonly SQLite API. ### Parameters -* **vm**: A valid VM obtained by [SQCloudVMCompile](/docs/sdk/c/sqcloudvmcompile). +* **vm**: A valid VM obtained by [SQCloudVMCompile](/docs/sqlite-cloud/sdks/c/sqcloudvmcompile). ### Return value diff --git a/sqlite-cloud/sdks/c/SQCloudVMLastRowID.mdx b/sqlite-cloud/sdks/c/SQCloudVMLastRowID.mdx index 84fda71..da5661d 100644 --- a/sqlite-cloud/sdks/c/SQCloudVMLastRowID.mdx +++ b/sqlite-cloud/sdks/c/SQCloudVMLastRowID.mdx @@ -21,7 +21,7 @@ If you need to get the last inserted rowid from a SQCloudConnection object you c ### Parameters -* **vm**: A valid VM obtained by [SQCloudVMCompile](/docs/sdk/c/sqcloudvmcompile). +* **vm**: A valid VM obtained by [SQCloudVMCompile](/docs/sqlite-cloud/sdks/c/sqcloudvmcompile). ### Return value diff --git a/sqlite-cloud/sdks/c/SQCloudVMResult.mdx b/sqlite-cloud/sdks/c/SQCloudVMResult.mdx index de15189..ff39a73 100644 --- a/sqlite-cloud/sdks/c/SQCloudVMResult.mdx +++ b/sqlite-cloud/sdks/c/SQCloudVMResult.mdx @@ -13,7 +13,7 @@ SQCloudResult *SQCloudVMResult (SQCloudVM *vm); Retrieve the raw SQCloudResult associated with the VM. You can then use the SQCloudResult API to further process the SQCloudResult. ### Parameters -* **vm**: A valid VM obtained by [SQCloudVMCompile](/docs/sdk/c/sqcloudvmcompile). +* **vm**: A valid VM obtained by [SQCloudVMCompile](/docs/sqlite-cloud/sdks/c/sqcloudvmcompile). ### Return value diff --git a/sqlite-cloud/sdks/c/SQCloudVMStep.mdx b/sqlite-cloud/sdks/c/SQCloudVMStep.mdx index 507ed3d..8271d28 100644 --- a/sqlite-cloud/sdks/c/SQCloudVMStep.mdx +++ b/sqlite-cloud/sdks/c/SQCloudVMStep.mdx @@ -10,11 +10,11 @@ SQCLOUD_RESULT_TYPE SQCloudVMStep (SQCloudVM *vm); ``` ### Description -Evaluate an SQL statement previously compiled by [SQCloudVMCompile](/docs/sdk/c/sqcloudvmcompile). -This function resembles the [sqlite3_step](https://www.sqlite.org/c3ref/step.html) SQLite API. +Evaluate an SQL statement previously compiled by [SQCloudVMCompile](/docs/sqlite-cloud/sdks/c/sqcloudvmcompile). +This function resembles the sqlite3_step SQLite API. ### Parameters -* **vm**: A valid VM obtained by [SQCloudVMCompile](/docs/sdk/c/sqcloudvmcompile). +* **vm**: A valid VM obtained by [SQCloudVMCompile](/docs/sqlite-cloud/sdks/c/sqcloudvmcompile). ### Return value diff --git a/sqlite-cloud/sdks/c/SQCloudVMTotalChanges.mdx b/sqlite-cloud/sdks/c/SQCloudVMTotalChanges.mdx index 333c7b6..38684a2 100644 --- a/sqlite-cloud/sdks/c/SQCloudVMTotalChanges.mdx +++ b/sqlite-cloud/sdks/c/SQCloudVMTotalChanges.mdx @@ -19,7 +19,7 @@ If you need to get the total changes from a SQCloudConnection object you can sen ### Parameters -* **vm**: A valid VM obtained by [SQCloudVMCompile](/docs/sdk/c/sqcloudvmcompile). +* **vm**: A valid VM obtained by [SQCloudVMCompile](/docs/sqlite-cloud/sdks/c/sqcloudvmcompile). ### Return value An `int64_t` with the number of total changes. diff --git a/sqlite-cloud/sdks/c/getting-started.mdx b/sqlite-cloud/sdks/c/getting-started.mdx index fa14c1b..547249f 100644 --- a/sqlite-cloud/sdks/c/getting-started.mdx +++ b/sqlite-cloud/sdks/c/getting-started.mdx @@ -3,9 +3,10 @@ title: C description: SQCloud C Interface category: sdks status: publish +slug: sdk-c-introduction --- -SQCloud is the C application programmer's interface to SQLite Cloud. SQCloud is a set of library functions that allow client programs to pass queries and SQL commands to the SQLite Cloud backend server and to receive the results of these queries. In addition to the standard SQLite statements, several other [commands](/docs/commands) are supported. +SQCloud is the C application programmer's interface to SQLite Cloud. SQCloud is a set of library functions that allow client programs to pass queries and SQL commands to the SQLite Cloud backend server and to receive the results of these queries. In addition to the standard SQLite statements, several other [commands](server-side-commands) are supported. The following files are required when compiling a C application: * sqcloud.c/.h @@ -14,6 +15,6 @@ The following files are required when compiling a C application: The header file `sqcloud.h` must be included in your C application. -All the communications between the client and the server are encrypted and so, you are required to link the LibreSSL (libtls) library with your client. More information about LibreSSL and how to compile it can be found in the official [LibreSSL](http://www.libressl.org) website. +All the communications between the client and the server are encrypted and so, you are required to link the LibreSSL (libtls) library with your client. More information about LibreSSL and how to compile it can be found in the official LibreSSL website. -The SQCloud APIs implement the [SQLiteCloud Serialization Protocol](https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md). \ No newline at end of file +The SQCloud APIs implement the SQLiteCloud Serialization Protocol. \ No newline at end of file diff --git a/sqlite-cloud/sdks/go/getting-started.mdx b/sqlite-cloud/sdks/go/getting-started.mdx deleted file mode 100644 index 096d0c5..0000000 --- a/sqlite-cloud/sdks/go/getting-started.mdx +++ /dev/null @@ -1,95 +0,0 @@ ---- -title: GO SDK Getting Started -description: Here's the how gettting started to use the SQLite Cloud in your Go code. -customClass: sdk-doc badge-doc go-doc -category: sdks -status: publish ---- - -## Use the SQLite Cloud SDK in your Go code - -1. Import the package in your Go source code: - - ```go - import sqlitecloud "github.com/sqlitecloud/sqlitecloud-go" - ``` - -2. Download the package, and run the [`go mod tidy` command](https://go.dev/ref/mod#go-mod-tidy) to synchronize your module's dependencies: - - ```bash - $ go mod tidy - go: downloading github.com/sqlitecloud/sqlitecloud-go v1.0.0 - ``` - -3. Connect to a SQLite Cloud database with a valid [connection string](#get-a-connection-string): - - ```go - db, err := sqlitecloud.Connect("sqlitecloud://user:pass@host.sqlite.cloud:port/dbname") - ``` - -4. Execute queries using a [method](#api-documentation) defined on the `SQCloud` struct, for example `Select`: - - ```go - result, _ := db.Select("SELECT * FROM table1;") - ``` - -The following example shows how to print the content of the table `table1`: - -```go -package main - -import ( - "fmt" - "strings" - - sqlitecloud "github.com/sqlitecloud/sqlitecloud-go" -) - -const connectionString = "sqlitecloud://admin:password@host.sqlite.cloud:8860/dbname.sqlite" - -func main() { - db, err := sqlitecloud.Connect(connectionString) - if err != nil { - fmt.Println("Connect error: ", err) - } - - tables, _ := db.ListTables() - fmt.Printf("Tables:\n\t%s\n", strings.Join(tables, "\n\t")) - - fmt.Printf("Table1:\n") - result, _ := db.Select("SELECT * FROM t1;") - for r := uint64(0); r < result.GetNumberOfRows(); r++ { - id, _ := result.GetInt64Value(r, 0) - value, _ := result.GetStringValue(r, 1) - fmt.Printf("\t%d: %s\n", id, value) - } -} -``` - -## Get a connection string - -You can connect to any cloud database using a special connection string in the form: - -``` -sqlitecloud://user:pass@host.com:port/dbname?timeout=10&key2=value2&key3=value3 -``` - -To get a valid connection string, follow these instructions: - -- Get a [SQLite Cloud](https://sqlitecloud.io/) account. See the [documentation](https://docs.sqlitecloud.io/docs/introduction/login) for details. -- Create a [SQLite Cloud project](https://docs.sqlitecloud.io/docs/introduction/projects) -- Create a [SQLite Cloud database](https://docs.sqlitecloud.io/docs/introduction/databases) -- Get the connection string by clicking on the node address in the [Dashboard Nodes](https://docs.sqlitecloud.io/docs/introduction/nodes) section. A valid connection string will be copied to your clipboard. -- Add the database name to your connection string. - -## API Documentation - -The complete documentation is available at: [https://pkg.go.dev/github.com/sqlitecloud/sqlitecloud-go](https://pkg.go.dev/github.com/sqlitecloud/sqlitecloud-go) - -[![Test and QA](https://github.com/sqlitecloud/sqlitecloud-go/actions/workflows/testing.yaml/badge.svg?branch=main)](https://github.com/sqlitecloud/sqlitecloud-go/actions/workflows/testing.yaml) -[![codecov](https://codecov.io/gh/sqlitecloud/sqlitecloud-go/graph/badge.svg?token=5MAG3G4X01)](https://codecov.io/gh/sqlitecloud/sqlitecloud-go) -[![GitHub Tag](https://img.shields.io/github/v/tag/sqlitecloud/sqlitecloud-go?label=version&link=https%3A%2F%2Fpkg.go.dev%2Fgithub.com%2Fsqlitecloud%2Fsqlitecloud-go)](https://pkg.go.dev/github.com/sqlitecloud/sqlitecloud-go) -[![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/sqlitecloud/sqlitecloud-go?link=https%3A%2F%2Fpkg.go.dev%2Fgithub.com%2Fsqlitecloud%2Fsqlitecloud-go)](https://pkg.go.dev/github.com/sqlitecloud/sqlitecloud-go) - -[SQLite Cloud](https://sqlitecloud.io) for Go is a powerful package that allows you to interact with the SQLite Cloud database seamlessly. It provides methods for various database operations. This package is designed to simplify database operations in Go applications, making it easier than ever to work with SQLite Cloud. In addition to the standard SQLite statements, several other [commands](https://docs.sqlitecloud.io/docs/commands) are supported. - diff --git a/sqlite-cloud/sdks/go/introduction.mdx b/sqlite-cloud/sdks/go/introduction.mdx new file mode 100644 index 0000000..c7d49c0 --- /dev/null +++ b/sqlite-cloud/sdks/go/introduction.mdx @@ -0,0 +1,112 @@ +--- +title: GO SDK Getting Started +description: Here's the how gettting started to use the SQLite Cloud in your Go code. +category: sdks +status: publish +slug: sdk-go-introduction +--- + +## Use the SQLite Cloud SDK in your Go code + +1. Import the package in your Go source code: + + ```go + import sqlitecloud "github.com/sqlitecloud/sqlitecloud-go" + ``` + +2. Download the package, and run the `go mod tidy` command to synchronize your module's dependencies: + + ```bash + $ go mod tidy + go: downloading github.com/sqlitecloud/sqlitecloud-go v1.0.0 + ``` + +3. Connect to a SQLite Cloud database with a valid [connection string](#get-a-connection-string): + + ```go + db, err := sqlitecloud.Connect("sqlitecloud://user:pass@host.sqlite.cloud:port/dbname") + ``` + +4. Execute queries using a [method](#api-documentation) defined on the `SQCloud` struct, for example `Select`: + + ```go + result, _ := db.Select("SELECT * FROM table1;") + ``` + +The following example shows how to print the content of the table `table1`: + +```go +package main + +import ( + "fmt" + "strings" + + sqlitecloud "github.com/sqlitecloud/sqlitecloud-go" +) + +const connectionString = "sqlitecloud://admin:password@host.sqlite.cloud:8860/dbname.sqlite" + +func main() { + db, err := sqlitecloud.Connect(connectionString) + if err != nil { + fmt.Println("Connect error: ", err) + } + + tables, _ := db.ListTables() + fmt.Printf("Tables:\n\t%s\n", strings.Join(tables, "\n\t")) + + fmt.Printf("Table1:\n") + result, _ := db.Select("SELECT * FROM t1;") + for r := uint64(0); r < result.GetNumberOfRows(); r++ { + id, _ := result.GetInt64Value(r, 0) + value, _ := result.GetStringValue(r, 1) + fmt.Printf("\t%d: %s\n", id, value) + } +} +``` + +## Get a connection string + +You can connect to any cloud database using a special connection string in the form: + +``` +sqlitecloud://user:pass@host.com:port/dbname?timeout=10&key2=value2&key3=value3 +``` + +To get a valid connection string, follow these instructions: + +- Get a SQLite Cloud account. See the documentation for details. +- Create a SQLite Cloud project +- Create a SQLite Cloud database +- Get the connection string by clicking on the node address in the Dashboard Nodes section. A valid connection string will be copied to your clipboard. +- Add the database name to your connection string. + +## API Documentation + +The complete documentation is available +here. + + + Test and QA + + +
    + + + codecov + + +
    + + + GitHub Tag + + +
    + + + GitHub go.mod Go version + + +SQLite Cloud for Go is a powerful package that allows you to interact with the SQLite Cloud database seamlessly. It provides methods for various database operations. This package is designed to simplify database operations in Go applications, making it easier than ever to work with SQLite Cloud. In addition to the standard SQLite statements, several other [commands](server-side-commands) are supported. \ No newline at end of file diff --git a/sqlite-cloud/sdks/js/classes/Database.md b/sqlite-cloud/sdks/js/classes/Database.md index 6c138ca..c625d9a 100644 --- a/sqlite-cloud/sdks/js/classes/Database.md +++ b/sqlite-cloud/sdks/js/classes/Database.md @@ -1,7 +1,7 @@ --- title: Database description: SQLite Cloud Javascript SDK -customClass: sdk-doc badge-doc js-doc +customClass: sdk-doc js-doc category: sdks status: publish --- @@ -84,7 +84,7 @@ EventEmitter.constructor #### Defined in -[src/drivers/database.ts:33](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/database.ts#L33) +src/drivers/database.ts:33 • **new Database**(`config`, `mode?`, `callback?`): [`Database`](database) @@ -106,7 +106,7 @@ EventEmitter.constructor #### Defined in -[src/drivers/database.ts:34](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/database.ts#L34) +src/drivers/database.ts:34 ## Properties @@ -118,7 +118,7 @@ Configuration used to open database connections #### Defined in -[src/drivers/database.ts:57](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/database.ts#L57) +src/drivers/database.ts:57 ___ @@ -130,7 +130,7 @@ Database connections #### Defined in -[src/drivers/database.ts:60](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/database.ts#L60) +src/drivers/database.ts:60 ___ @@ -215,7 +215,7 @@ calls to retrieve a previously unknown amount of rows. #### Defined in -[src/drivers/database.ts:273](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/database.ts#L273) +src/drivers/database.ts:273 ▸ **all**\<`T`\>(`sql`, `params`, `callback?`): [`Database`](database) @@ -239,7 +239,7 @@ calls to retrieve a previously unknown amount of rows. #### Defined in -[src/drivers/database.ts:274](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/database.ts#L274) +src/drivers/database.ts:274 ___ @@ -266,7 +266,7 @@ parameters is emitted, regardless of whether a callback was provided or not. #### Defined in -[src/drivers/database.ts:394](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/database.ts#L394) +src/drivers/database.ts:394 ___ @@ -289,7 +289,7 @@ Set a configuration option for the database #### Defined in -[src/drivers/database.ts:190](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/database.ts#L190) +src/drivers/database.ts:190 ___ @@ -330,7 +330,7 @@ way to abort execution. #### Defined in -[src/drivers/database.ts:312](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/database.ts#L312) +src/drivers/database.ts:312 ▸ **each**\<`T`\>(`sql`, `params`, `callback?`, `complete?`): [`Database`](database) @@ -355,7 +355,7 @@ way to abort execution. #### Defined in -[src/drivers/database.ts:313](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/database.ts#L313) +src/drivers/database.ts:313 ___ @@ -411,7 +411,7 @@ Emits given event with optional arguments on the next tick so callbacks can comp #### Defined in -[src/drivers/database.ts:160](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/database.ts#L160) +src/drivers/database.ts:160 ___ @@ -462,7 +462,7 @@ will be emitted on the database object. #### Defined in -[src/drivers/database.ts:368](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/database.ts#L368) +src/drivers/database.ts:368 ___ @@ -498,7 +498,7 @@ the only supported way is by column name. #### Defined in -[src/drivers/database.ts:235](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/database.ts#L235) +src/drivers/database.ts:235 ▸ **get**\<`T`\>(`sql`, `params`, `callback?`): [`Database`](database) @@ -522,7 +522,7 @@ the only supported way is by column name. #### Defined in -[src/drivers/database.ts:236](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/database.ts#L236) +src/drivers/database.ts:236 ___ @@ -542,7 +542,7 @@ A configuration object #### Defined in -[src/drivers/database.ts:176](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/database.ts#L176) +src/drivers/database.ts:176 ___ @@ -564,7 +564,7 @@ Returns first available connection from connection pool #### Defined in -[src/drivers/database.ts:67](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/database.ts#L67) +src/drivers/database.ts:67 ___ @@ -588,7 +588,7 @@ Handles an error by closing the connection, calling the callback and/or emitting #### Defined in -[src/drivers/database.ts:117](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/database.ts#L117) +src/drivers/database.ts:117 ___ @@ -607,7 +607,7 @@ open to use this function. #### Defined in -[src/drivers/database.ts:429](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/database.ts#L429) +src/drivers/database.ts:429 ___ @@ -688,7 +688,7 @@ Loads a compiled SQLite extension into the database connection object. #### Defined in -[src/drivers/database.ts:413](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/database.ts#L413) +src/drivers/database.ts:413 ___ @@ -822,7 +822,7 @@ they are bound to the prepared statement before calling the callback. #### Defined in -[src/drivers/database.ts:353](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/database.ts#L353) +src/drivers/database.ts:353 ___ @@ -854,7 +854,7 @@ https://github.com/TryGhost/node-sqlite3/wiki/API#runsql--param---callback #### Defined in -[src/drivers/database.ts:141](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/database.ts#L141) +src/drivers/database.ts:141 ___ @@ -948,7 +948,7 @@ which it was called to allow for function chaining. #### Defined in -[src/drivers/database.ts:202](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/database.ts#L202) +src/drivers/database.ts:202 ▸ **run**\<`T`\>(`sql`, `params`, `callback?`): [`Database`](database) @@ -972,7 +972,7 @@ which it was called to allow for function chaining. #### Defined in -[src/drivers/database.ts:203](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/database.ts#L203) +src/drivers/database.ts:203 ___ @@ -1001,7 +1001,7 @@ metadata in case of insert, update, delete. #### Defined in -[src/drivers/database.ts:447](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/database.ts#L447) +src/drivers/database.ts:447 ___ @@ -1017,4 +1017,4 @@ Enable verbose mode #### Defined in -[src/drivers/database.ts:181](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/database.ts#L181) +src/drivers/database.ts:181 diff --git a/sqlite-cloud/sdks/js/classes/SQLiteCloudConnection.md b/sqlite-cloud/sdks/js/classes/SQLiteCloudConnection.md index e929584..d428d66 100644 --- a/sqlite-cloud/sdks/js/classes/SQLiteCloudConnection.md +++ b/sqlite-cloud/sdks/js/classes/SQLiteCloudConnection.md @@ -1,7 +1,7 @@ --- title: SQLiteCloudConnection description: SQLite Cloud Javascript SDK -customClass: sdk-doc badge-doc js-doc +customClass: sdk-doc js-doc category: sdks status: publish --- @@ -55,7 +55,7 @@ Parse and validate provided connectionString or configuration #### Defined in -[src/drivers/connection.ts:16](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/connection.ts#L16) +src/drivers/connection.ts:16 ## Properties @@ -67,7 +67,7 @@ Configuration passed by client or extracted from connection string #### Defined in -[src/drivers/connection.ts:28](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/connection.ts#L28) +src/drivers/connection.ts:28 ___ @@ -79,7 +79,7 @@ Operations are serialized by waiting an any pending promises #### Defined in -[src/drivers/connection.ts:31](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/connection.ts#L31) +src/drivers/connection.ts:31 ## Accessors @@ -95,7 +95,7 @@ Returns true if connection is open #### Defined in -[src/drivers/connection.ts:74](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/connection.ts#L74) +src/drivers/connection.ts:74 ## Methods @@ -111,7 +111,7 @@ Disconnect from server, release transport. #### Defined in -[src/drivers/connection.ts:100](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/connection.ts#L100) +src/drivers/connection.ts:100 ___ @@ -133,7 +133,7 @@ Connect will establish a tls or websocket transport to the server based on confi #### Defined in -[src/drivers/connection.ts:38](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/connection.ts#L38) +src/drivers/connection.ts:38 ___ @@ -154,7 +154,7 @@ ___ #### Defined in -[src/drivers/connection.ts:56](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/connection.ts#L56) +src/drivers/connection.ts:56 ___ @@ -177,7 +177,7 @@ Will log to console if verbose mode is enabled #### Defined in -[src/drivers/connection.ts:62](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/connection.ts#L62) +src/drivers/connection.ts:62 ___ @@ -200,7 +200,7 @@ Will enquee a command to be executed and callback with the resulting rowset/resu #### Defined in -[src/drivers/connection.ts:82](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/connection.ts#L82) +src/drivers/connection.ts:82 ___ @@ -223,7 +223,7 @@ Send a command, return the rowset/result or throw an error #### Defined in -[src/drivers/connection.ts:59](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/connection.ts#L59) +src/drivers/connection.ts:59 ___ @@ -239,4 +239,4 @@ Enable verbose logging for debug purposes #### Defined in -[src/drivers/connection.ts:77](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/connection.ts#L77) +src/drivers/connection.ts:77 diff --git a/sqlite-cloud/sdks/js/classes/SQLiteCloudError.md b/sqlite-cloud/sdks/js/classes/SQLiteCloudError.md index f080ec1..eea1af3 100644 --- a/sqlite-cloud/sdks/js/classes/SQLiteCloudError.md +++ b/sqlite-cloud/sdks/js/classes/SQLiteCloudError.md @@ -1,7 +1,7 @@ --- title: SQLiteCloudError description: SQLite Cloud Javascript SDK -customClass: sdk-doc badge-doc js-doc +customClass: sdk-doc js-doc category: sdks status: publish --- @@ -59,7 +59,7 @@ Error.constructor #### Defined in -[src/drivers/types.ts:102](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/types.ts#L102) +src/drivers/types.ts:102 ## Properties @@ -75,7 +75,7 @@ Error.cause #### Defined in -[src/drivers/types.ts:111](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/types.ts#L111) +src/drivers/types.ts:111 ___ @@ -87,7 +87,7 @@ Error code returned by drivers or server #### Defined in -[src/drivers/types.ts:113](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/types.ts#L113) +src/drivers/types.ts:113 ___ @@ -99,7 +99,7 @@ Additional error code #### Defined in -[src/drivers/types.ts:115](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/types.ts#L115) +src/drivers/types.ts:115 ___ @@ -139,7 +139,7 @@ Additional offset code in commands #### Defined in -[src/drivers/types.ts:117](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/types.ts#L117) +src/drivers/types.ts:117 ___ diff --git a/sqlite-cloud/sdks/js/classes/SQLiteCloudRow.md b/sqlite-cloud/sdks/js/classes/SQLiteCloudRow.md index 104ae7f..d0eea36 100644 --- a/sqlite-cloud/sdks/js/classes/SQLiteCloudRow.md +++ b/sqlite-cloud/sdks/js/classes/SQLiteCloudRow.md @@ -1,7 +1,7 @@ --- title: SQLiteCloudRow description: SQLite Cloud Javascript SDK -customClass: sdk-doc badge-doc js-doc +customClass: sdk-doc js-doc category: sdks status: publish --- @@ -50,7 +50,7 @@ Column values are accessed by column name #### Defined in -[src/drivers/rowset.ts:9](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/rowset.ts#L9) +src/drivers/rowset.ts:9 ## Properties @@ -60,7 +60,7 @@ Column values are accessed by column name #### Defined in -[src/drivers/rowset.ts:21](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/rowset.ts#L21) +src/drivers/rowset.ts:21 ___ @@ -70,7 +70,7 @@ ___ #### Defined in -[src/drivers/rowset.ts:18](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/rowset.ts#L18) +src/drivers/rowset.ts:18 ## Methods @@ -86,7 +86,7 @@ Returns rowset data as a plain array of values #### Defined in -[src/drivers/rowset.ts:31](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/rowset.ts#L31) +src/drivers/rowset.ts:31 ___ @@ -102,4 +102,4 @@ Returns the rowset that this row belongs to #### Defined in -[src/drivers/rowset.ts:25](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/rowset.ts#L25) +src/drivers/rowset.ts:25 diff --git a/sqlite-cloud/sdks/js/classes/SQLiteCloudRowset.md b/sqlite-cloud/sdks/js/classes/SQLiteCloudRowset.md index 2bb6c4e..472551d 100644 --- a/sqlite-cloud/sdks/js/classes/SQLiteCloudRowset.md +++ b/sqlite-cloud/sdks/js/classes/SQLiteCloudRowset.md @@ -1,7 +1,7 @@ --- title: SQLiteCloudRowset description: SQLite Cloud Javascript SDK -customClass: sdk-doc badge-doc js-doc +customClass: sdk-doc js-doc category: sdks status: publish --- @@ -98,7 +98,7 @@ Array\<SQLiteCloudRow\>.constructor #### Defined in -[src/drivers/rowset.ts:41](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/rowset.ts#L41) +src/drivers/rowset.ts:41 ## Properties @@ -110,7 +110,7 @@ Actual data organized in rows #### Defined in -[src/drivers/rowset.ts:72](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/rowset.ts#L72) +src/drivers/rowset.ts:72 ___ @@ -122,7 +122,7 @@ Metadata contains number of rows and columns, column names, types, etc. #### Defined in -[src/drivers/rowset.ts:69](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/rowset.ts#L69) +src/drivers/rowset.ts:69 ___ @@ -168,7 +168,7 @@ Array of columns names #### Defined in -[src/drivers/rowset.ts:93](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/rowset.ts#L93) +src/drivers/rowset.ts:93 ___ @@ -184,7 +184,7 @@ Get rowset metadata #### Defined in -[src/drivers/rowset.ts:98](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/rowset.ts#L98) +src/drivers/rowset.ts:98 ___ @@ -200,7 +200,7 @@ Number of columns in row set #### Defined in -[src/drivers/rowset.ts:88](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/rowset.ts#L88) +src/drivers/rowset.ts:88 ___ @@ -216,7 +216,7 @@ Number of rows in row set #### Defined in -[src/drivers/rowset.ts:83](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/rowset.ts#L83) +src/drivers/rowset.ts:83 ___ @@ -236,7 +236,7 @@ https://github.com/sqlitecloud/sdk/blob/master/PROTOCOL.md #### Defined in -[src/drivers/rowset.ts:78](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/rowset.ts#L78) +src/drivers/rowset.ts:78 ## Methods @@ -522,7 +522,7 @@ Array.filter #### Defined in -[src/drivers/rowset.ts:141](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/rowset.ts#L141) +src/drivers/rowset.ts:141 ___ @@ -726,7 +726,7 @@ Return value of item at given row and column #### Defined in -[src/drivers/rowset.ts:103](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/rowset.ts#L103) +src/drivers/rowset.ts:103 ___ @@ -877,7 +877,7 @@ Array.map #### Defined in -[src/drivers/rowset.ts:131](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/rowset.ts#L131) +src/drivers/rowset.ts:131 ___ @@ -1145,7 +1145,7 @@ Array.slice #### Defined in -[src/drivers/rowset.ts:113](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/rowset.ts#L113) +src/drivers/rowset.ts:113 ___ diff --git a/sqlite-cloud/sdks/js/classes/Statement.md b/sqlite-cloud/sdks/js/classes/Statement.md index 0fa438a..efbb082 100644 --- a/sqlite-cloud/sdks/js/classes/Statement.md +++ b/sqlite-cloud/sdks/js/classes/Statement.md @@ -1,7 +1,7 @@ --- title: Statement description: SQLite Cloud Javascript SDK -customClass: sdk-doc badge-doc js-doc +customClass: sdk-doc js-doc category: sdks status: publish --- @@ -60,7 +60,7 @@ A statement generated by Database.prepare used to prepare SQL with ? bindings #### Defined in -[src/drivers/statement.ts:13](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/statement.ts#L13) +src/drivers/statement.ts:13 ## Properties @@ -72,7 +72,7 @@ Statement belongs to this database #### Defined in -[src/drivers/statement.ts:25](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/statement.ts#L25) +src/drivers/statement.ts:25 ___ @@ -84,7 +84,7 @@ The SQL statement with binding values applied #### Defined in -[src/drivers/statement.ts:31](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/statement.ts#L31) +src/drivers/statement.ts:31 ___ @@ -96,7 +96,7 @@ The SQL statement with ? binding placeholders #### Defined in -[src/drivers/statement.ts:28](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/statement.ts#L28) +src/drivers/statement.ts:28 ## Methods @@ -120,7 +120,7 @@ for function chaining. The parameters are the same as the Statement#run function #### Defined in -[src/drivers/statement.ts:121](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/statement.ts#L121) +src/drivers/statement.ts:121 ▸ **all**(`params`, `callback?`): [`Statement`](statement)\<`T`\> @@ -137,7 +137,7 @@ for function chaining. The parameters are the same as the Statement#run function #### Defined in -[src/drivers/statement.ts:122](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/statement.ts#L122) +src/drivers/statement.ts:122 ___ @@ -165,7 +165,7 @@ are escaped client side and turned into literals before being executed on the se #### Defined in -[src/drivers/statement.ts:42](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/statement.ts#L42) +src/drivers/statement.ts:42 ___ @@ -190,7 +190,7 @@ are the same as the Database#each function. #### Defined in -[src/drivers/statement.ts:147](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/statement.ts#L147) +src/drivers/statement.ts:147 ▸ **each**(`params`, `callback?`, `complete?`): [`Statement`](statement)\<`T`\> @@ -208,7 +208,7 @@ are the same as the Database#each function. #### Defined in -[src/drivers/statement.ts:148](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/statement.ts#L148) +src/drivers/statement.ts:148 ___ @@ -235,7 +235,7 @@ the second parameter is undefined, otherwise it is an object containing the valu #### Defined in -[src/drivers/statement.ts:95](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/statement.ts#L95) +src/drivers/statement.ts:95 ▸ **get**(`params`, `callback?`): [`Statement`](statement)\<`T`\> @@ -252,7 +252,7 @@ the second parameter is undefined, otherwise it is an object containing the valu #### Defined in -[src/drivers/statement.ts:96](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/statement.ts#L96) +src/drivers/statement.ts:96 ___ @@ -279,7 +279,7 @@ can run it multiple times. #### Defined in -[src/drivers/statement.ts:66](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/statement.ts#L66) +src/drivers/statement.ts:66 ▸ **run**(`params`, `callback?`): [`Statement`](statement)\<`T`\> @@ -296,4 +296,4 @@ can run it multiple times. #### Defined in -[src/drivers/statement.ts:67](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/statement.ts#L67) +src/drivers/statement.ts:67 diff --git a/sqlite-cloud/sdks/js/getting-started.mdx b/sqlite-cloud/sdks/js/getting-started.mdx deleted file mode 100644 index ead3f32..0000000 --- a/sqlite-cloud/sdks/js/getting-started.mdx +++ /dev/null @@ -1,58 +0,0 @@ ---- -title: JS SDK Introduction -description: SQLite Cloud Javascript SDK -customClass: sdk-doc badge-doc js-doc -category: sdks -status: publish ---- - -[![npm package][npm-img]][npm-url] -[![Build Status][build-img]][build-url] -[![Downloads][downloads-img]][downloads-url] -[![Issues][issues-img]][issues-url] -[![codecov](https://codecov.io/gh/sqlitecloud/sqlitecloud-js/graph/badge.svg?token=ZOKE9WFH62)](https://codecov.io/gh/sqlitecloud/sqlitecloud-js) - -## Install - -```bash -npm install @sqlitecloud/drivers -``` - -## Usage - -```ts -import { Database } from '@sqlitecloud/drivers' - -let database = new Database('sqlitecloud://user:password@xxx.sqlite.cloud:8860/chinook.db') - -let name = 'Breaking The Rules' - -let results = await database.sql`SELECT * FROM tracks WHERE name = ${name}` -// => returns [{ AlbumId: 1, Name: 'Breaking The Rules', Composer: 'Angus Young... }] -``` - -Use [Database.sql](/docs/sdk/js/classes/database#sql) to execute prepared statements or plain SQL queries asynchronously. This method returns an array of rows for SELECT queries and supports the standard syntax for UPDATE, INSERT, and DELETE. - -We aim for full compatibility with the established [sqlite3 API](https://www.npmjs.com/package/sqlite3), with the primary distinction being that our driver connects to SQLiteCloud databases. This allows you to migrate your [SQLite to the cloud](https://sqlitecloud.io) while continuing to use your existing codebase. - -The package is developed entirely in TypeScript and is fully compatible with JavaScript. It doesn't require any native libraries. This makes it a straightforward and effective tool for managing cloud-based databases in a familiar SQLite environment. - -## More - -How do I deploy SQLite in the cloud? -[https://sqlitecloud.io](https://sqlitecloud.io) - -How do I connect SQLite cloud with Javascript? -[https://sqlitecloud.github.io/sqlitecloud-js/](https://sqlitecloud.github.io/sqlitecloud-js/) - -How can I contribute or suggest features? -[https://github.com/sqlitecloud/sqlitecloud-js/issues](https://github.com/sqlitecloud/sqlitecloud-js/issues) - -[build-img]: https://github.com/sqlitecloud/sqlitecloud-js/actions/workflows/build-test-deploy.yml/badge.svg -[build-url]: https://github.com/sqlitecloud/sqlitecloud-js/actions/workflows/build-test-deploy.yml -[downloads-img]: https://img.shields.io/npm/dt/@sqlitecloud/drivers -[downloads-url]: https://www.npmtrends.com/@sqlitecloud/drivers -[npm-img]: https://img.shields.io/npm/v/@sqlitecloud/drivers -[npm-url]: https://www.npmjs.com/package/@sqlitecloud/drivers -[issues-img]: https://img.shields.io/github/issues/sqlitecloud/sqlitecloud-js -[issues-url]: https://github.com/sqlitecloud/sqlitecloud-js/issues diff --git a/sqlite-cloud/sdks/js/interfaces/SQLCloudRowsetMetadata.md b/sqlite-cloud/sdks/js/interfaces/SQLCloudRowsetMetadata.md index c89ad0a..91bcd89 100644 --- a/sqlite-cloud/sdks/js/interfaces/SQLCloudRowsetMetadata.md +++ b/sqlite-cloud/sdks/js/interfaces/SQLCloudRowsetMetadata.md @@ -1,7 +1,7 @@ --- title: SQLCloudRowsetMetadata description: SQLite Cloud Javascript SDK -customClass: sdk-doc badge-doc js-doc +customClass: sdk-doc js-doc category: sdks status: publish --- @@ -27,7 +27,7 @@ Columns' metadata #### Defined in -[src/drivers/types.ts:77](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/types.ts#L77) +src/drivers/types.ts:77 ___ @@ -39,7 +39,7 @@ Number of columns #### Defined in -[src/drivers/types.ts:74](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/types.ts#L74) +src/drivers/types.ts:74 ___ @@ -51,7 +51,7 @@ Number of rows #### Defined in -[src/drivers/types.ts:72](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/types.ts#L72) +src/drivers/types.ts:72 ___ @@ -63,4 +63,4 @@ Rowset version 1 has column's name, version 2 has extended metadata #### Defined in -[src/drivers/types.ts:70](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/types.ts#L70) +src/drivers/types.ts:70 diff --git a/sqlite-cloud/sdks/js/interfaces/SQLiteCloudConfig.md b/sqlite-cloud/sdks/js/interfaces/SQLiteCloudConfig.md index 32e3ff0..e96a76e 100644 --- a/sqlite-cloud/sdks/js/interfaces/SQLiteCloudConfig.md +++ b/sqlite-cloud/sdks/js/interfaces/SQLiteCloudConfig.md @@ -1,7 +1,7 @@ --- title: SQLiteCloudConfig description: SQLite Cloud Javascript SDK -customClass: sdk-doc badge-doc js-doc +customClass: sdk-doc js-doc category: sdks status: publish --- @@ -45,7 +45,7 @@ Optional identifier used for verbose logging #### Defined in -[src/drivers/types.ts:62](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/types.ts#L62) +src/drivers/types.ts:62 ___ @@ -55,7 +55,7 @@ ___ #### Defined in -[src/drivers/types.ts:41](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/types.ts#L41) +src/drivers/types.ts:41 ___ @@ -67,7 +67,7 @@ Connection string in the form of sqlitecloud://user:password@host:port/database? #### Defined in -[src/drivers/types.ts:15](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/types.ts#L15) +src/drivers/types.ts:15 ___ @@ -79,7 +79,7 @@ Create the database if it doesn't exist? #### Defined in -[src/drivers/types.ts:37](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/types.ts#L37) +src/drivers/types.ts:37 ___ @@ -91,7 +91,7 @@ Name of database to open #### Defined in -[src/drivers/types.ts:34](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/types.ts#L34) +src/drivers/types.ts:34 ___ @@ -103,7 +103,7 @@ Database will be created in memory #### Defined in -[src/drivers/types.ts:39](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/types.ts#L39) +src/drivers/types.ts:39 ___ @@ -115,7 +115,7 @@ Url where we can connect to a SQLite Cloud Gateway that has a socket.io deamon w #### Defined in -[src/drivers/types.ts:59](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/types.ts#L59) +src/drivers/types.ts:59 ___ @@ -127,7 +127,7 @@ Host name is required unless connectionString is provided, eg: xxx.sqlitecloud.i #### Defined in -[src/drivers/types.ts:25](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/types.ts#L25) +src/drivers/types.ts:25 ___ @@ -139,7 +139,7 @@ Connect using plain TCP port, without TLS encryption, NOT RECOMMENDED, TEST ONLY #### Defined in -[src/drivers/types.ts:29](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/types.ts#L29) +src/drivers/types.ts:29 ___ @@ -151,7 +151,7 @@ Do not send columns with more than max_data bytes #### Defined in -[src/drivers/types.ts:47](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/types.ts#L47) +src/drivers/types.ts:47 ___ @@ -163,7 +163,7 @@ Server should chunk responses with more than maxRows #### Defined in -[src/drivers/types.ts:49](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/types.ts#L49) +src/drivers/types.ts:49 ___ @@ -175,7 +175,7 @@ Server should limit total number of rows in a set to maxRowset #### Defined in -[src/drivers/types.ts:51](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/types.ts#L51) +src/drivers/types.ts:51 ___ @@ -187,7 +187,7 @@ Server should send BLOB columns #### Defined in -[src/drivers/types.ts:45](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/types.ts#L45) +src/drivers/types.ts:45 ___ @@ -199,7 +199,7 @@ Request for immediate responses from the server node without waiting for lineriz #### Defined in -[src/drivers/types.ts:43](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/types.ts#L43) +src/drivers/types.ts:43 ___ @@ -211,7 +211,7 @@ Password is required unless connection string is provided #### Defined in -[src/drivers/types.ts:20](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/types.ts#L20) +src/drivers/types.ts:20 ___ @@ -223,7 +223,7 @@ True if password is hashed, default is false #### Defined in -[src/drivers/types.ts:22](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/types.ts#L22) +src/drivers/types.ts:22 ___ @@ -235,7 +235,7 @@ Port number for tls socket #### Defined in -[src/drivers/types.ts:27](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/types.ts#L27) +src/drivers/types.ts:27 ___ @@ -247,7 +247,7 @@ Optional query timeout passed directly to TLS socket #### Defined in -[src/drivers/types.ts:32](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/types.ts#L32) +src/drivers/types.ts:32 ___ @@ -259,7 +259,7 @@ Custom options and configurations for tls socket, eg: additional certificates #### Defined in -[src/drivers/types.ts:54](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/types.ts#L54) +src/drivers/types.ts:54 ___ @@ -271,7 +271,7 @@ True if we should force use of SQLite Cloud Gateway and websocket connections, d #### Defined in -[src/drivers/types.ts:57](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/types.ts#L57) +src/drivers/types.ts:57 ___ @@ -283,7 +283,7 @@ User name is required unless connectionString is provided #### Defined in -[src/drivers/types.ts:18](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/types.ts#L18) +src/drivers/types.ts:18 ___ @@ -295,4 +295,4 @@ True if connection should enable debug logs #### Defined in -[src/drivers/types.ts:64](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/types.ts#L64) +src/drivers/types.ts:64 diff --git a/sqlite-cloud/sdks/js/introduction.mdx b/sqlite-cloud/sdks/js/introduction.mdx new file mode 100644 index 0000000..b0af687 --- /dev/null +++ b/sqlite-cloud/sdks/js/introduction.mdx @@ -0,0 +1,61 @@ +--- +title: JS SDK Introduction +description: SQLite Cloud Javascript SDK +customClass: sdk-doc js-doc +category: sdks +status: publish +slug: sdk-js-introduction +--- + + + npm package + +
    + + Build Status + +
    + + Downloads + +
    + + Issues + +
    + + codecov + + +## Install + +```bash +npm install @sqlitecloud/drivers +``` + +## Usage + +```ts +import { Database } from '@sqlitecloud/drivers' + +let database = new Database('sqlitecloud://user:password@xxx.sqlite.cloud:8860/chinook.db') + +let name = 'Breaking The Rules' + +let results = await database.sql`SELECT * FROM tracks WHERE name = ${name}` +// => returns [{ AlbumId: 1, Name: 'Breaking The Rules', Composer: 'Angus Young... }] +``` + +Use [Database.sql](/docs/sqlite-cloud/sdks/js/classes/database#sql) to execute prepared statements or plain SQL queries asynchronously. This method returns an array of rows for SELECT queries and supports the standard syntax for UPDATE, INSERT, and DELETE. + +We aim for full compatibility with the established sqlite3 API, with the primary distinction being that our driver connects to SQLiteCloud databases. This allows you to migrate your SQLite to the cloud while continuing to use your existing codebase. + +The package is developed entirely in TypeScript and is fully compatible with JavaScript. It doesn't require any native libraries. This makes it a straightforward and effective tool for managing cloud-based databases in a familiar SQLite environment. + +## More + +How do I deploy SQLite in the cloud? +
    +How do I connect SQLite cloud with Javascript? +
    +How can I contribute or suggest features? diff --git a/sqlite-cloud/sdks/js/modules.md b/sqlite-cloud/sdks/js/modules.md index 23c8f07..4b9c81d 100644 --- a/sqlite-cloud/sdks/js/modules.md +++ b/sqlite-cloud/sdks/js/modules.md @@ -1,26 +1,27 @@ --- title: Modules description: SQLite Cloud Javascript SDK -customClass: sdk-doc badge-doc js-doc +customClass: sdk-doc js-doc category: sdks status: publish +slug: sdk-js-modules --- ## Table of contents ### Classes -- [Database](classes/database) -- [SQLiteCloudConnection](classes/sqlitecloudconnection) -- [SQLiteCloudError](classes/sqliteclouderror) -- [SQLiteCloudRow](classes/sqlitecloudrow) -- [SQLiteCloudRowset](classes/sqlitecloudrowset) -- [Statement](classes/statement) +- [Database](sqlite-cloud/sdks/js/classes/database) +- [SQLiteCloudConnection](sqlite-cloud/sdks/js/classes/sqlitecloudconnection) +- [SQLiteCloudError](sqlite-cloud/sdks/js/classes/sqliteclouderror) +- [SQLiteCloudRow](sqlite-cloud/sdks/js/classes/sqlitecloudrow) +- [SQLiteCloudRowset](sqlite-cloud/sdks/js/classes/sqlitecloudrowset) +- [Statement](sqlite-cloud/sdks/js/classes/statement) ### Interfaces -- [SQLCloudRowsetMetadata](interfaces/sqlcloudrowsetmetadata) -- [SQLiteCloudConfig](interfaces/sqlitecloudconfig) +- [SQLCloudRowsetMetadata](sqlite-cloud/sdks/js/interfaces/sqlcloudrowsetmetadata) +- [SQLiteCloudConfig](sqlite-cloud/sdks/js/interfaces/sqlitecloudconfig) ### Type Aliases @@ -55,7 +56,7 @@ status: publish #### Defined in -[src/drivers/types.ts:120](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/types.ts#L120) +src/drivers/types.ts:120 ## Functions @@ -77,7 +78,7 @@ Takes a generic value and escapes it so it can replace ? as a binding in a prepa #### Defined in -[src/drivers/utilities.ts:70](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/utilities.ts#L70) +src/drivers/utilities.ts:70 ___ @@ -99,7 +100,7 @@ Parse connectionString like sqlitecloud://username:password@host:port/database?o #### Defined in -[src/drivers/utilities.ts:210](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/utilities.ts#L210) +src/drivers/utilities.ts:210 ___ @@ -122,7 +123,7 @@ Take a sql statement and replaces ? or $named parameters that are properly seria #### Defined in -[src/drivers/utilities.ts:105](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/utilities.ts#L105) +src/drivers/utilities.ts:105 ___ @@ -144,4 +145,4 @@ Validate configuration, apply defaults, throw if something is missing or misconf #### Defined in -[src/drivers/utilities.ts:173](https://github.com/sqlitecloud/sqlitecloud-js/blob/f7cd658/src/drivers/utilities.ts#L173) +src/drivers/utilities.ts:173 diff --git a/sqlite-cloud/sdks/php/getting-started.mdx b/sqlite-cloud/sdks/php/getting-started.mdx deleted file mode 100644 index bdf9084..0000000 --- a/sqlite-cloud/sdks/php/getting-started.mdx +++ /dev/null @@ -1,75 +0,0 @@ ---- -title: PHP SDK Getting Started -description: Get started with SQLite Cloud using PHP. -customClass: sdk-doc badge-doc php-doc -category: sdks -status: publish ---- - - -[![Test and QA][test-qa-img]][test-qa-url] -[![codecov][codecov-img]][codecov-url] -[![Packagist Version][packagist-version-img]][packagist-url] -[![PHP][php-img]][packagist-url] - -## Install - -```bash -$ composer require sqlitecloud/sqlitecloud -``` - -SQLite Cloud is a powerful PHP package that allows you to interact with the SQLite Cloud database seamlessly. It provides methods for various database operations. -This package is designed to simplify database operations in PHP applications, making it easier than ever to work with SQLite Cloud. - -## Example - -```php -connectWithString('sqlitecloud://myhost.sqlite.cloud:8860?apikey=myapikey'); - -// You can autoselect the database during the connect call -// by adding the database name as path of the SQLite Cloud -// connection string, eg: -// $sqlite->connectWithString("sqlitecloud://myhost.sqlite.cloud:8860/mydatabase?apikey=myapikey"); -$db_name = 'chinook.sqlite'; -$sqlite->execute("USE DATABASE {$db_name}"); - - /** @var SQLiteCloudRowset */ -$rowset = $sqlite->execute('SELECT * FROM albums WHERE ArtistId = 2'); - -printf('%d rows' . PHP_EOL, $rowset->nrows); -printf('%s | %s | %s' . PHP_EOL, $rowset->name(0), $rowset->name(1), $rowset->name(2)); -for ($i = 0; $i < $rowset->nrows; $i++) { - printf('%s | %s | %s' . PHP_EOL, $rowset->value($i, 0), $rowset->value($i, 1), $rowset->value($i, 2)); -} - -$sqlite->disconnect(); -``` - -## PHP Admin -To better understand the PHP APIs usage we developed a simple PHP Admin interface that can be used to administer any SQLite Cloud node. - -You can login using admin credentials: -![PHP Admin Login](@docs-website-assets/php/admin_login.png) - -And then administer your node with a convenient user interface: -![PHP Admin Overview](@docs-website-assets/php/admin_overview.png) - -PHP Admin source code is available in a [GitHub repo](https://github.com/sqlitecloud/sqlitecloud-php/tree/main/admin). - -## More -[test-qa-img]: https://github.com/sqlitecloud/sqlitecloud-php/actions/workflows/deploy.yaml/badge.svg?branch=main -[test-qa-url]: https://github.com/sqlitecloud/sqlitecloud-php/actions/workflows/deploy.yaml -[codecov-img]: https://codecov.io/gh/sqlitecloud/sqlitecloud-php/graph/badge.svg?token=3FFHULGCOY -[codecov-url]: https://codecov.io/gh/sqlitecloud/sqlitecloud-php -[packagist-version-img]: https://img.shields.io/packagist/v/sqlitecloud/sqlitecloud -[packagist-url]: https://packagist.org/packages/sqlitecloud/sqlitecloud -[php-img]: https://img.shields.io/packagist/dependency-v/sqlitecloud/sqlitecloud/php \ No newline at end of file diff --git a/sqlite-cloud/sdks/php/introduction.mdx b/sqlite-cloud/sdks/php/introduction.mdx new file mode 100644 index 0000000..2d9603a --- /dev/null +++ b/sqlite-cloud/sdks/php/introduction.mdx @@ -0,0 +1,100 @@ +--- +title: PHP SDK Getting Started +description: Get started with SQLite Cloud using PHP. +category: sdks +status: publish +slug: sdk-php-introduction +--- + +This powerful package provides methods that simplify performing database operations in PHP applications, making it easier than ever to work with SQLite in the cloud. We encourage all users to log encountered issues in the SDK’s issues backlog. + +## Install + + - Run the following command to initialize a PHP project and install the SDK. + +```bash +$ composer require sqlitecloud/sqlitecloud +``` + +## Configure your database connection + + - In your SQLite Cloud account dashboard, click on `Show connection strings`, copy the Connection String, and replace `` below. + +```php +$sqlite->connectWithString(""); +``` + + - You can modify the connection string to include the name of the database to query. + - Here, the provided port (`8860`) and database (`chinook.sqlite`) will query the sample dataset that comes pre-loaded with SQLite Cloud. Replace to query your own datasets. + +```php +$sqlite->connectWithString('sqlitecloud://{hostname}:8860/chinook.sqlite?apikey={apikey}'); +``` + +## Connect and query + + - Include the following snippet in a new `example.php` file. + - NOTE: `$sqlite->execute("USE DATABASE {$db_name}");` is only necessary if your connection string does NOT specify the name of the database to query. + +```php +connectWithString(""); + +$db_name = 'chinook.sqlite'; +$sqlite->execute("USE DATABASE {$db_name}"); + +/** @var SQLiteCloudRowset */ +$rowset = $sqlite->execute('SELECT * FROM albums WHERE ArtistId = 2'); + +printf('%d rows' . PHP_EOL, $rowset->nrows); +printf('%s | %s | %s' . PHP_EOL, $rowset->name(0), $rowset->name(1), $rowset->name(2)); +for ($i = 0; $i < $rowset->nrows; $i++) { + printf('%s | %s | %s' . PHP_EOL, $rowset->value($i, 0), $rowset->value($i, 1), $rowset->value($i, 2)); +} + +$sqlite->disconnect(); +``` + + - Run your app! + +``` +php example.php +``` + +## PHP Admin Dashboard + +You can use SQLite Cloud's simplified PHP Admin interface to administer any node. + + - Clone the PHP SDK, install lock file dependencies, and run the dashboard locally. + +```bash +git clone https://github.com/sqlitecloud/sqlitecloud-php.git + +composer update # or composer install +cd admin +php -S localhost:8000 +``` + + - Login as your admin user. + - In your SQLite Cloud account dashboard, click on `Show connection strings`, copy the Deployment string, and paste in `Hostname`. + - In your dashboard left nav, select Settings, then Users. Copy your admin user's username and paste in `Username`. + - In your User's row, click the down chevron, then Edit. Enter a Password and Save. Paste in `Password`. + +![PHP Admin Login](@docs-website-assets/php/admin_login.png) + +![PHP Admin Overview](@docs-website-assets/php/admin_overview.png) + +[test-qa-img]: https://github.com/sqlitecloud/sqlitecloud-php/actions/workflows/deploy.yaml/badge.svg?branch=main +[test-qa-url]: https://github.com/sqlitecloud/sqlitecloud-php/actions/workflows/deploy.yaml +[codecov-img]: https://codecov.io/gh/sqlitecloud/sqlitecloud-php/graph/badge.svg?token=3FFHULGCOY +[codecov-url]: https://codecov.io/gh/sqlitecloud/sqlitecloud-php +[packagist-version-img]: https://img.shields.io/packagist/v/sqlitecloud/sqlitecloud +[packagist-url]: https://packagist.org/packages/sqlitecloud/sqlitecloud +[php-img]: https://img.shields.io/packagist/dependency-v/sqlitecloud/sqlitecloud/php \ No newline at end of file diff --git a/sqlite-cloud/sdks/php/methods.mdx b/sqlite-cloud/sdks/php/methods.mdx index 6aa8c79..1d43eea 100644 --- a/sqlite-cloud/sdks/php/methods.mdx +++ b/sqlite-cloud/sdks/php/methods.mdx @@ -1,9 +1,9 @@ --- title: PHP SDK Methods description: Methods available in the SQLite Cloud PHP SDK. -customClass: sdk-doc badge-doc php-doc category: sdks status: publish +slug: sdk-php-methods --- @@ -71,7 +71,7 @@ return true; SQLiteCloudClient.execute($command) ``` -Submits a command to the server and waits for the result. The command can be any SQLite statement or any built-in [SQLite Cloud command](/docs/commands). +Submits a command to the server and waits for the result. The command can be any SQLite statement or any built-in [SQLite Cloud command](/docs/server-side-commands). ### Return value * `false` is returned in case of an error @@ -179,4 +179,4 @@ $sqlitecloud = new SQLiteCloudClient(); $sqlitecloud->connectWithString('sqlitecloud://myhost.sqlite.cloud:8860/mydatabase?apikey=myapikey') $sqlitecloud->disconnect(); -``` \ No newline at end of file +``` diff --git a/sqlite-cloud/sdks/python/introduction.mdx b/sqlite-cloud/sdks/python/introduction.mdx index 516dfdd..885af17 100644 --- a/sqlite-cloud/sdks/python/introduction.mdx +++ b/sqlite-cloud/sdks/python/introduction.mdx @@ -1,7 +1,7 @@ --- title: Python SDK Introduction description: SQLite Cloud Python SDK -customClass: sdk-doc badge-doc js-doc +customClass: sdk-doc js-doc category: sdks status: publish slug: sdk-python-introduction @@ -15,7 +15,7 @@ pip install sqlitecloud ## Basic Usage -We aim for full compatibility with the established [sqlite3 API](https://docs.python.org/3/library/sqlite3.html), with the primary distinction being that our driver connects to SQLite Cloud databases. This allows you to migrate your [SQLite to the cloud](https://sqlitecloud.io) while continuing to use your existing codebase. +We aim for full compatibility with the established sqlite3 API, with the primary distinction being that our driver connects to SQLite Cloud databases. This allows you to migrate your SQLite to the cloud while continuing to use your existing codebase. ```python import sqlitecloud @@ -57,6 +57,7 @@ dfprices = pd.read_csv( ) ) +# Your SQLite Cloud connection string conn = sqlitecloud.connect("sqlitecloud://myhost.sqlite.cloud:8860/mydatabase.sqlite?apikey=myapikey") conn.executemany("DROP TABLE IF EXISTS ?", [("PRICES",)]) @@ -76,3 +77,61 @@ query_result = df_actual_prices.query("PRICE > 50.00") print(query_result) ``` +## Using SQLite Cloud with SQLAlchemy + +```bash +pip install sqlalchemy-sqlitecloud +``` + +```python +import sqlalchemy +from sqlalchemy import Column, ForeignKey, Integer, String +from sqlalchemy.dialects import registry +from sqlalchemy.orm import backref, declarative_base, relationship, sessionmaker + +Base = declarative_base() + + +class Artist(Base): + __tablename__ = "artists" + + ArtistId = Column("ArtistId", Integer, primary_key=True) + Name = Column("Name", String) + Albums = relationship("Album", backref=backref("artist")) + + +class Album(Base): + __tablename__ = "albums" + + AlbumId = Column("AlbumId", Integer, primary_key=True) + ArtistId = Column("ArtistId", Integer, ForeignKey("artists.ArtistId")) + Title = Column("Title", String) + +# Your SQLite Cloud connection string +connection_string = "sqlitecloud://myhost.sqlite.cloud:8860/mydatabase.sqlite?apikey=myapikey" + +engine = sqlalchemy.create_engine(connection_string) +Session = sessionmaker(bind=engine) +session = Session() + +name = "John Doe" +query = sqlalchemy.insert(Artist).values(Name=name) +result_insert = session.execute(query) + +title = "The Album" +query = sqlalchemy.insert(Album).values( + ArtistId=result_insert.lastrowid, Title=title +) +session.execute(query) + +query = ( + sqlalchemy.select(Artist, Album) + .join(Album, Artist.ArtistId == Album.ArtistId) + .where(Artist.ArtistId == result_insert.lastrowid) +) + +result = session.execute(query).fetchone() + +print("Artist Name: " + result[0].Name) +print("Album Title: " + result[1].Title) +``` \ No newline at end of file diff --git a/sqlite-cloud/sdks/swift/introduction.mdx b/sqlite-cloud/sdks/swift/introduction.mdx new file mode 100644 index 0000000..6d7b0b7 --- /dev/null +++ b/sqlite-cloud/sdks/swift/introduction.mdx @@ -0,0 +1,91 @@ +--- +title: Swift SDK Introduction +description: Get started with SQLite Cloud using Swift. +category: sdks +status: publish +slug: sdk-swift-introduction +--- + +This powerful package provides methods that perform DB operations, and enables real-time notifications in Swift apps, making it easier than ever to work with SQLite in the cloud. We encourage all users to log encountered issues in the SDK's issues backlog. + +## Install + + - In `Package.swift`, add the `swift` package to `dependencies`. + +```swift +let package = Package( + ..., + dependencies: [ + ..., + .package(url: "https://github.com/sqlitecloud/swift.git", from: "0.2.1") + ], + ... +) +``` + +## 3 ways to configure your database connection + +1. **RECOMMENDED**: Use the `apikey` connection string. + + - In your SQLite Cloud account dashboard, click on `Show connection strings`, copy the Connection String, and replace `` below. + +```swift +let configuration = SQLiteCloudConfig(connectionString: "") +``` + + - You can modify the connection string to include the name of the database to query. + +```swift +let configuration = SQLiteCloudConfig(connectionString: "sqlitecloud://{hostname}:8860/{database}?apikey={apikey}") +``` + +2. Use a parameterized connection string. + + - In your SQLite Cloud account dashboard, click on `Show connection strings`, copy the Deployment string, and replace `{hostname}` below. + - In your dashboard left nav, select Settings, then Users. Copy your username and replace `{username}`. + - In your User's row, click the down chevron, then Edit. Enter a Password and Save. Replace `{password}`. + - Here, the provided port (`8860`) and database (`chinook.sqlite`) will query the sample dataset that comes pre-loaded with SQLite Cloud. Replace to query your own datasets. + +```swift +let configuration = SQLiteCloudConfig(connectionString: "sqlitecloud://{username}:{password}@{hostname}:8860/chinook.sqlite") +``` + +3. Pass each connection string parameter explicitly. + +```swift +let configuration = SQLiteCloudConfig(hostname: {hostname}, username: {username}, password: {password}, port: .default) +``` + +## Connect and query + + - The following snippet includes variable types, which may be optional for your app. + - NOTE: `USE DATABASE chinook.sqlite;` is only necessary in the query if your `configuration` does not specify the name of the database to query. + - Once you've incorporated the following, build and run your app! + +```swift +import SQLiteCloud + +let configuration: SQLiteCloudConfig? = SQLiteCloudConfig(connectionString: "") + +let sqliteCloud: SQLiteCloud = SQLiteCloud(config: configuration!) + +do { + try await sqliteCloud.connect() + debugPrint("connected") + + let sqlQuery: String = "USE DATABASE chinook.sqlite; SELECT albums.AlbumId as id, albums.Title as title, artists.name as artist FROM albums INNER JOIN artists WHERE artists.ArtistId = albums.ArtistId LIMIT 20;" + + let result: SQLiteCloudResult = try await sqliteCloud.execute(query: sqlQuery) + + try await sqliteCloud.disconnect() + + return result.stringValue! +} catch { + return "Connection error" +} +``` + +## Troubleshooting + + - If you get errors indicating SQLite Cloud-specific constructs are out of scope (i.e. `error: cannot find 'SQLiteCloudConfig' in scope`), verify the `SQLiteCloud` package is correctly imported. + - Confirm `https://github.com/sqlitecloud/swift` package is listed in `Package.resolved`. \ No newline at end of file diff --git a/sqlite-cloud/sqlite-ai/ai-overview.mdx b/sqlite-cloud/sqlite-ai/ai-overview.mdx new file mode 100644 index 0000000..42743f4 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/ai-overview.mdx @@ -0,0 +1,76 @@ +--- +title: Getting Started with SQLite AI +description: SQLite AI brings local AI, vector search, sync, analytics, memory, and JavaScript extensions directly into SQLite. +category: getting-started +status: publish +slug: ai-overview +--- + +## Overview + +**SQLite AI** is a local-first stack of SQLite extensions for building AI-enabled applications close to the data. It keeps inference, retrieval, memory, analytics, sync, and custom logic inside the same SQLite workflow, so applications can run offline, preserve privacy, and still connect to SQLite Cloud when they need managed sync, auth, or shared infrastructure. + +## Extension Stack + +- **[SQLite-AI](/docs/sqlite-ai)** runs local LLM inference, embeddings, chat, audio transcription, and multimodal image analysis from SQL. +- **[SQLite-Memory](/docs/sqlite-memory)** adds persistent, searchable memory for AI agents with markdown-aware chunking, hybrid vector and FTS search, and optional sync. +- **[SQLite-Vector](/docs/sqlite-vector)** stores embeddings in ordinary SQLite tables and performs fast nearest-neighbor search with quantization support. +- **[SQLite-Sync](/docs/sqlite-sync-introduction)** keeps local SQLite databases synchronized across devices and users with CRDT-based conflict resolution. +- **[SQLite-Columnar](/docs/sqlite-columnar)** adds column-oriented virtual tables and analytical helpers for fast local OLAP-style queries. +- **[SQLite-JS](/docs/sqlite-js)** lets you define scalar, aggregate, window, and collation functions in JavaScript. + +## Common Workflows + +### Local RAG + +```sql +-- Generate embeddings with SQLite-AI. +SELECT llm_model_load('./models/nomic-embed-text-v1.5-Q8_0.gguf', 'gpu_layers=99'); +SELECT llm_context_create_embedding('embedding_type=FLOAT32'); + +CREATE TABLE documents ( + id INTEGER PRIMARY KEY, + body TEXT, + embedding BLOB +); + +INSERT INTO documents (body, embedding) +VALUES ( + 'SQLite stores data in a single portable database file.', + llm_embed_generate('SQLite stores data in a single portable database file.') +); + +-- Search them with SQLite-Vector. +SELECT vector_init('documents', 'embedding', 'type=FLOAT32,dimension=768,distance=COSINE'); +SELECT vector_quantize('documents', 'embedding'); +``` + +### Agent Memory + +```sql +SELECT memory_set_model('local', './models/nomic-embed-text-v1.5.Q8_0.gguf'); +SELECT memory_add_text('The user prefers concise Python examples.', 'conversation'); + +SELECT path, snippet, ranking +FROM memory_search +WHERE query = 'what style should I use for code examples?' +ORDER BY ranking DESC; +``` + +### Offline-First AI Apps + +```sql +CREATE TABLE notes ( + id TEXT PRIMARY KEY NOT NULL, + body TEXT NOT NULL DEFAULT '' +); + +SELECT cloudsync_init('notes'); +INSERT INTO notes VALUES (cloudsync_uuid(), 'Draft generated locally'); +SELECT cloudsync_network_sync(); +``` + +## Tools + +- **[MCP Server](/docs/mcp-server)** connects AI agents and MCP-compatible clients to SQLite Cloud databases. +- **[AI-Powered Docs Search](/docs/aisearch-documents)** shows how to build semantic documentation search with GitHub Actions, SQLite Cloud, and an Edge Function. diff --git a/sqlite-cloud/sqlite-ai/aisearch-documents.mdx b/sqlite-cloud/sqlite-ai/aisearch-documents.mdx new file mode 100644 index 0000000..e3f7588 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/aisearch-documents.mdx @@ -0,0 +1,133 @@ +--- +title: Build AI Search for Your Documentation +description: SQLite AI Search for your documents and files +category: platform +status: publish +slug: aisearch-documents +--- + +import Callout from "@commons-components/Information/Callout.astro"; + +This guide shows you how to set up a ready-to-use AI semantic search for your documents and files. +Using the [sqlite-aisearch-action](https://github.com/sqliteai/sqlite-aisearch-action), you can integrate document processing into your GitHub workflow and set up a chatbot on your site in just a few steps. + +The semantic search is powered by [SQLite RAG](https://github.com/sqliteai/sqlite-rag). + +## Step 1: Set Up Your GitHub Workflow + +1. **Get Your Connection String**: Ensure you have a project on the [SQLite Cloud dashboard](https://dashboard.sqlitecloud.io). If not, sign up for [SQLite AI](https://sqlite.ai) to create one for free. + +2. **Set GitHub Secret**: Add your connection string as `SQLITECLOUD_CONNECTION_STRING` in your repository secrets. + +3. **Add to Workflow**: Create or update your GitHub workflow: + +```yaml +name: AI Search Index + +on: + push: + branches: [main] + workflow_dispatch: + +jobs: + build-search: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Build AI Search Database + uses: sqliteai/sqlite-aisearch-action@v1 + with: + connection_string: ${{ secrets.SQLITECLOUD_CONNECTION_STRING }} + base_url: https://docs.yoursite.com + database_name: aidocs_search.db + source_files: ./path/to/documents +``` + +## Step 2: Create the Search Edge Function + +To enable search functionality on your indexed database, create an Edge Function using the provided template: + +1. Access your dashboard at https://dashboard.sqlitecloud.io +2. Navigate to the same project where your database was uploaded +3. Go to the **Edge Functions** section + ![AISearch Edge Function](@docs-website-assets/aisearch-docs/edgefn_aisearch.png) +4. Create a new `Javascript Function` and copy the code from [aisearch-docs.js](https://github.com/sqliteai/sqlite-aisearch-action/blob/main/search_edge_function_template/aisearch-docs.js) into the editor +5. Deploy and test + +### How to Perform a Search + +1. Go to **Details** in the Edge Function panel and copy the **Function URL** + ![AISearch Edge Function Details](@docs-website-assets/aisearch-docs/edgefn_aisearch_details.png) +2. Execute a GET request with a URL-encoded query as the `query` parameter + + Example: + + ``` + GET https://myproject.cloud/v2/functions/aisearch-docs?query=what%27s+Offsync%3F + ``` + +## Step 3: Integrate the Docs Chatbot in Your Website + +Once you have your search edge function deployed, you can easily add an interactive AI chatbot to your website. The chatbot provides a user-friendly interface for your documentation search, powered by the indexed content. + +![Docs Chatbot](@docs-website-assets/aisearch-docs/docs_chatbot.png) + +### React Integration + +Install the chatbot package: + +```bash +npm install @sqliteai/docs-chatbot +``` + +Then add it to your React application: + +```tsx +import { DocsChatbot } from "@sqliteai/docs-chatbot"; +import "@sqliteai/docs-chatbot/style.css"; + +function App() { + return ( + + ); +} +``` + + + - Replace the `searchUrl` with your **Function URL** from Step 2 + - For the `apiKey`, you need to use an API key with read + permissions on your AI docs database. Learn how to create and manage API keys + in the [API Key documentation](/docs/apikey). + + +### Vanilla JavaScript + +For non-React applications, use the web component: + +```html + + + + + + + + + + + + + +``` + +By default, the chatbot displays as a floating button in the bottom-right corner. +For advanced configuration options including custom triggers, theming, and API reference, see the [full docs chatbot documentation](https://github.com/sqliteai/docs-chatbot). diff --git a/sqlite-cloud/sqlite-ai/mcp-server.mdx b/sqlite-cloud/sqlite-ai/mcp-server.mdx new file mode 100644 index 0000000..089c429 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/mcp-server.mdx @@ -0,0 +1,147 @@ +--- +title: AI - Model Context Protocol (MCP) +description: MCP Server for SQLite Cloud to interact with SQLite Cloud databases using the AI models +category: platform +status: publish +slug: mcp-server +--- + +The Model Context Protocol (MCP) is a standard for connecting various data sources (like your SQLite Cloud database) to Large Language Models (LLMs). The MCP Server for SQLite Cloud provides tools for executing queries, managing schemas, and analyzing query performance. + +## Features + +- **Query Execution**: Perform `SELECT`, `INSERT`, `UPDATE`, and `DELETE` SQL operations on SQLite Cloud databases. +- **Schema Management**: Create tables, list existing ones, and retrieve schema details. +- **Command Execution**: Run predefined commands supported by SQLite Cloud. +- **Performance Analysis**: Identify slow queries, analyze query plans, and reset query statistics. + +Explore the available tools here. + +## Getting Started + +To use the MCP Server, create a free account on SQLite Cloud and obtain your **Connection String**. + +### Requirements + +You need Node.js installed on your computer to run the MCP Server. To check if Node.js is installed, open a terminal: + +- **Linux**: Open the terminal from the Applications menu. +- **macOS**: Open the Terminal app from the Applications folder or use Spotlight Search (`Cmd+Space`) and type "Terminal." +- **Windows**: Press `Win + R`, type `cmd`, and press Enter to open the Command Prompt. Alternatively, search for "Command Prompt" in the Start menu. + +Then type the following command and press Enter: + +```bash +node --version +``` + +If the command returns a version number, Node.js is installed. If you see an error like "command not found" or "node is not recognized," download and install Node.js from nodejs.org. + +## Configure the AI Agent + +This guide explains how to connect the MCP Server for SQLite Cloud to common AI agents that support MCP. +Find a list of supported tools and IDEs here. + +After configuring your AI agent, try asking it questions about your SQLite Cloud database, such as: + +> What’s in my database on SQLite Cloud?" +"What are the three most popular tracks by revenue in my SQLite Cloud database? + +Explore or manipulate your database using natural language queries. + +### Claude Desktop + +Refer to the official documentation for detailed instructions. + +1. Open Claude Desktop and navigate to **Settings**. +2. Go to the **Developer** section and click on **Edit Config** to open the configuration file. +3. Add the following configuration: + + ```json + { + "mcpServers": { + "sqlitecloud-mcp-server": { + "type": "stdio", + "command": "npx", + "args": [ + "-y", + "@sqlitecloud/mcp-server", + "--connectionString", + "" + ] + } + } + } + ``` + + Replace `` with your Connection String. + +4. Save the configuration file and restart Claude Desktop. +5. You should see a _Hammer_ icon in the bottom-right corner of the input box. Click the icon to view the list of discovered tools. + +### Cursor + +Refer to the official documentation for detailed instructions. + +1. In the root of your project, create the file `.cursor/mcp.json`. +2. Add the following configuration: + + ```json + { + "mcpServers": { + "sqlitecloud-mcp-server": { + "type": "stdio", + "command": "npx", + "args": [ + "-y", + "@sqlitecloud/mcp-server", + "--connectionString", + "" + ] + } + } + } + ``` + + Replace `` with your Connection String. + +3. Save the `mcp.json` file. +4. Open the **Settings** page and navigate to the **MCP** section. You should see the MCP server with a green status indicator. +5. In the Chat panel, select the "Agent" mode to interact with the AI model using the MCP Server. + +### VSCode Copilot + +Refer to the official documentation for detailed instructions. + +1. In the root of your project, create the file `.vscode/mcp.json`. +2. Add the following configuration: + + ```json + { + "mcp": { + "inputs": [ + { + "type": "promptString", + "id": "sqlitecloud-connection-string", + "description": "Set the SQLite Cloud Connection String", + "password": true + } + ], + "servers": { + "sqlitecloud-mcp-server": { + "type": "stdio", + "command": "npx", + "args": [ + "-y", + "@sqlitecloud/mcp-server", + "--connectionString", + "${input:sqlitecloud-connection-string}" + ] + } + } + } + } + ``` + +3. Save the `mcp.json` file. +4. Open Copilot Chat and select the **Agent** mode from the menu near the **Send** button. A tool icon will appear, showing the discovered tools. Before starting the server, VSCode will prompt you to enter your Connection String. diff --git a/sqlite-cloud/sqlite-ai/sqlite-ai-api-reference.md b/sqlite-cloud/sqlite-ai/sqlite-ai-api-reference.md new file mode 100644 index 0000000..eb76ab6 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-ai-api-reference.md @@ -0,0 +1,931 @@ +--- +title: "SQLite-AI API Reference" +description: "Reference for SQLite-AI SQL functions, LLM contexts, samplers, embeddings, chat, vision, and audio." +category: platform +status: publish +slug: sqlite-ai-api-reference +--- + +This document provides reference-level documentation for all public SQLite-AI functions, virtual tables, and metadata properties exposed to SQL. +These functions enable loading and interacting with LLMs, configuring samplers, generating embeddings and text, and managing chat sessions. + +--- + +## `ai_version()` + +**Returns:** `TEXT` + +**Description:** +Returns the current version of the SQLite-AI extension. + +**Example:** + +```sql +SELECT ai_version(); +-- e.g., '1.0.0' +``` + +--- + +## `ai_log_info(extended_enable BOOLEAN)` + +**Returns:** `NULL` + +**Description:** +Enables or disables extended logging information. Use `1` to enable, `0` to disable. + +**Example:** + +```sql +SELECT ai_log_info(1); +``` + +--- + +## `llm_model_load(path TEXT, options TEXT)` + +**Returns:** `NULL` + +**Description:** +Loads a GGUF model from the specified file path with optional comma separated key=value configuration. +If no options are provided the following default value is used: `gpu_layers=99` + +The following keys are available: +``` +gpu_layers=N (N is the number of layers to store in VRAM) +main_gpu=K (K is the GPU that is used for the entire model when split_mode is 0) +split_mode=N (how to split the model across multiple GPUs, 0 means none, 1 means layer, 2 means rows) +vocab_only=1/0 (only load the vocabulary, no weights) +use_mmap=1/0 (use mmap if possible) +use_mlock=1/0 (force system to keep model in RAM) +check_tensors=1/0 (validate model tensor data) +log_info=1/0 (enable/disable the logging of info) +``` + +**Example:** + +```sql +SELECT llm_model_load('./models/llama.gguf', 'gpu_layers=99'); +``` + +--- + +## `llm_model_free()` + +**Returns:** `NULL` + +**Description:** +Unloads the current model and frees associated memory. + +**Example:** + +```sql +SELECT llm_model_free(); +``` + +--- + +## `llm_context_create(context_settings TEXT)` + +**Parameters:** context_settings: comma-separated key=value pairs (see [context settings](#context settings)). + +**Returns:** `NULL` + +**Description:** +Creates a new inference context with comma separated key=value configuration. + +**Context must explicitly created before performing any AI operation!** + +## context_settings +The following keys are available in context_settings: + +### General + +| Key | Type | Meaning | +| ------------------------| -------- | ---------------------------------------------------------------- | +| `generate_embedding` | `1 or 0` | Force the model to generate embeddings. | +| `normalize_embedding` | `1 or 0` | Force normalization during embedding generation (default to 1). | +| `json_output` | `1 or 0` | Force JSON output in embedding generation (default to 0). | +| `max_tokens` | `number` | Set a maximum number of tokens in input. If input is too large then an error is returned. | +| `n_predict` | `number` | Control the maximum number of tokens generated during text generation. | +| `embedding_type` | `FLOAT32, FLOAT16, BFLOAT16, UINT8, INT8` | Set the model native type, mandatory during embedding generation. | + +### Core sizing & threading + +| Key | Type | Meaning | +| ------------------------ | -------- | ---------------------------------------------------------------- | +| `context_size` | `number` | Equivalent to n_ctx = N and n_batch = N. | +| `n_ctx` | `number` | Text context length (tokens). `0` = from model. | +| `n_batch` | `number` | **Logical** max batch size submitted to `llama_decode`. | +| `n_ubatch` | `number` | **Physical** max micro-batch size. | +| `n_seq_max` | `number` | Max concurrent sequences (parallel states for recurrent models). | +| `n_threads` | `number` | Threads for generation. | +| `n_threads_batch` | `number` | Threads for batch processing. | + +### Attention, pooling & flash-attention + +| Key | Type | Meaning | +| ----------------- | ---------------------------- | ------------------------------------------------- | +| `pooling_type` | `none, unspecified, mean, cls, last or rank` | How to aggregate token embeddings (e.g., `mean`). | +| `attention_type` | `unspecified, causal, non_causal` | Attention algorithm for embeddings. | +| `flash_attn_type` | `auto, disabled, enabled` | Controls when/if Flash-Attention is used. | + +### RoPE & YaRN (positional scaling) + +| Key | Type | Meaning | +| ------------------- | ------------------------------ | ------------------------------------------------- | +| `rope_scaling_type` | `unspecified, none, linear, yarn, longrope` | RoPE scaling strategy. | +| `rope_freq_base` | `float number` | RoPE base frequency. `0` = from model. | +| `rope_freq_scale` | `float number` | RoPE frequency scaling factor. `0` = from model. | +| `yarn_ext_factor` | `float number` | YaRN extrapolation mix factor. `<0` = from model. | +| `yarn_attn_factor` | `float number` | YaRN magnitude scaling. | +| `yarn_beta_fast` | `float number` | YaRN low correction dimension. | +| `yarn_beta_slow` | `float number` | YaRN high correction dimension. | +| `yarn_orig_ctx` | `number` | YaRN original context size. | + +### KV cache types (experimental) + +| Key | Type | Meaning | +| -------- | ---------------- | ---------------------- | +| `type_k` | [ggml_type](https://github.com/ggml-org/llama.cpp/blob/00681dfc16ba4cebb9c7fbd2cf2656e06a0692a4/ggml/include/ggml.h#L377) | Data type for K cache. | +| `type_v` | [ggml_type](https://github.com/ggml-org/llama.cpp/blob/00681dfc16ba4cebb9c7fbd2cf2656e06a0692a4/ggml/include/ggml.h#L377) | Data type for V cache. | + +### Flags + +> Place booleans at the end of your option string if you’re copy-by-value mirroring a struct; otherwise order doesn’t matter. + +| Key | Type | Meaning | +| -------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------ | +| `embeddings` | `1 or 0` | If `1`, extract embeddings (with logits). Used by the embedding preset. | +| `offload_kqv` | `1 or 0` | Offload KQV ops (incl. KV cache) to GPU. | +| `no_perf` | `1 or 0` | Disable performance timing. | +| `op_offload` | `1 or 0` | Offload host tensor ops to device. | +| `swa_full` | `1 or 0` | Use full-size SWA cache. When `false` and `n_seq_max > 1`, performance may degrade. | +| `kv_unified` | `1 or 0` | Use a unified buffer across input sequences during attention. Try disabling when `n_seq_max > 1` and sequences do not share a long prefix. | +| `defrag_thold` | `float number` | **Deprecated.** Defragment KV cache if `holes/size > thold`. `<= 0` disables. | + +--- + + +**Example:** + +```sql +SELECT llm_context_create('n_ctx=2048,n_threads=6,n_batch=256'); +``` + +--- + +## `llm_context_create_embedding(context_settings TEXT)` + +**Parameters:** **`context_settings` (optional):** Comma-separated `key=value` pairs to override or extend default settings (see [context settings](#context_settings) in `llm_context_create`). + +**Returns:** `NULL` + +**Description:** +Creates a new inference context specifically set for embedding generation. + +It is equivalent to `SELECT llm_context_create('generate_embedding=1,normalize_embedding=1,pooling_type=mean');` + +**Context must explicitly created before performing any AI operation!** + +**Example:** + +```sql +SELECT llm_context_create_embedding(); +``` + +--- + +## `llm_context_create_chat(context_settings TEXT)` + +**Parameters:** **`context_settings` (optional):** Comma-separated `key=value` pairs to override or extend default settings (see [context settings](#context_settings) in `llm_context_create`). + +**Returns:** `NULL` + +**Description:** +Creates a new inference context specifically set for chat conversation. + +It is equivalent to `SELECT llm_context_create('context_size=4096');` + +Context must explicitly created before performing any AI operation! + +**Example:** + +```sql +SELECT llm_context_create_chat(); +``` + +--- + +## `llm_context_create_textgen(context_settings TEXT)` + +**Parameters:** **`context_settings` (optional):** Comma-separated `key=value` pairs to override or extend default settings (see [context settings](#context_settings) in `llm_context_create`). + +**Returns:** `NULL` + +**Description:** +Creates a new inference context specifically set for text generation. + +It is equivalent to `SELECT llm_context_create('context_size=4096');` + +Context must explicitly created before performing any AI operation! + +**Example:** + +```sql +SELECT llm_context_create_textgen(); +``` + +--- + +## `llm_context_free()` + +**Returns:** `NULL` + +**Description:** +Frees the current inference context. + +**Example:** + +```sql +SELECT llm_context_free(); +``` + +--- +## `llm_context_size()` + +**Returns:** `INTEGER` + +**Description**: +Returns the total token capacity (context window) of the current llama context. Use this after `llm_context_create` to confirm the configured `context_size`. Raises an error if no context is active. + +```sql +SELECT llm_context_size(); +-- 4096 +``` + +--- + +## `llm_context_used()` + +**Returns:** `INTEGER` + +**Description:** +Returns how many tokens of the current llama context have already been consumed. Combine this with `llm_context_size()` to monitor usage. Raises an error if no context is active. + +**Example:** + +```sql +SELECT llm_context_used(); +-- 1024 +``` + +--- + +## `llm_sampler_create()` + +**Returns:** `NULL` + +**Description:** +Initializes a new sampling strategy for text generation. +A sampler is the mechanism that determines how the model selects the next token (word or subword) during text generation. +If no sampler is explicitly created, one will be created automatically when needed. + +**Example:** + +```sql +SELECT llm_sampler_create(); +``` + +--- + +## `llm_sampler_free()` + +**Returns:** `NULL` + +**Description:** +Frees resources associated with the current sampler. + +**Example:** + +```sql +SELECT llm_sampler_free(); +``` + +--- + +## `llm_lora_load(path TEXT, scale REAL)` + +**Returns:** `NULL` + +**Description:** +Loads a LoRA adapter from the given file path with a mandatory scale value. +LoRA (Low-Rank Adaptation) is a technique to inject trainable, low-rank layers into a pre-trained model. + +**Example:** + +```sql +SELECT llm_lora_load('./adapters/adapter.lora', 1.0); +``` + +--- + +## `llm_lora_free()` + +**Returns:** `NULL` + +**Description:** +Unloads any currently loaded LoRA adapter. + +**Example:** + +```sql +SELECT llm_lora_free(); +``` + +--- + +## `llm_sampler_init_greedy()` + +**Returns:** `NULL` + +**Description:** +Configures the sampler to use greedy decoding (always pick most probable token). + +**Example:** + +```sql +SELECT llm_sampler_init_greedy(); +``` + +--- + +## `llm_sampler_init_dist(seed INT)` + +**Returns:** `NULL` + +**Description:** +Initializes a random distribution-based sampler with the given seed. +If a seed value in not specified, a default 0xFFFFFFFF value will be used. + +**Example:** + +```sql +SELECT llm_sampler_init_dist(42); +``` + +--- + +## `llm_sampler_init_top_k(k INT)` + +**Returns:** `NULL` + +**Description:** +Limits sampling to the top `k` most likely tokens. +Top-K sampling described in academic paper "The Curious Case of Neural Text Degeneration" https://arxiv.org/abs/1904.09751 + +**Example:** + +```sql +SELECT llm_sampler_init_top_k(40); +``` + +--- + +## `llm_sampler_init_top_p(p REAL, min_keep INT)` + +**Returns:** `NULL` + +**Description:** +Top-p sampling retains tokens with cumulative probability >= `p`. Always keeps at least `min_keep` tokens. +Nucleus sampling described in academic paper "The Curious Case of Neural Text Degeneration" https://arxiv.org/abs/1904.09751 + +**Example:** + +```sql +SELECT llm_sampler_init_top_p(0.9, 1); +``` + +--- + +## `llm_sampler_init_min_p(p REAL, min_keep INT)` + +**Returns:** `NULL` + +**Description:** +Like top-p but with a minimum token probability threshold `p`. +Minimum P sampling as described in https://github.com/ggml-org/llama.cpp/pull/3841 + +**Example:** + +```sql +SELECT llm_sampler_init_min_p(0.05, 1); +``` + +--- + +## `llm_sampler_init_typical(p REAL, min_keep INT)` + +**Returns:** `NULL` + +**Description:** +Typical sampling prefers tokens near the expected entropy level. +Locally Typical Sampling implementation described in the paper https://arxiv.org/abs/2202.00666 + +**Example:** + +```sql +SELECT llm_sampler_init_typical(0.95, 1); +``` + +--- + +## `llm_sampler_init_temp(t REAL)` + +**Returns:** `NULL` + +**Description:** +Adjusts the sampling temperature to control randomness. + +**Example:** + +```sql +SELECT llm_sampler_init_temp(0.8); +``` + +--- + +## `llm_sampler_init_temp_ext(t REAL, delta REAL, exponent REAL)` + +**Returns:** `NULL` + +**Description:** +Advanced temperature control using exponential scaling. +Dynamic temperature implementation (a.k.a. entropy) described in the paper https://arxiv.org/abs/2309.02772 + +**Example:** + +```sql +SELECT llm_sampler_init_temp_ext(0.8, 0.1, 2.0); +``` + +--- + +## `llm_sampler_init_xtc(p REAL, t REAL, min_keep INT, seed INT)` + +**Returns:** `NULL` + +**Description:** +Combines top-p, temperature, and seed-based sampling with a minimum token count. +XTC sampler as described in https://github.com/oobabooga/text-generation-webui/pull/6335 + +**Example:** + +```sql +SELECT llm_sampler_init_xtc(0.9, 0.8, 1, 42); +``` + +--- + +## `llm_sampler_init_top_n_sigma(n REAL)` + +**Returns:** `NULL` + +**Description:** +Limits sampling to tokens within `n` standard deviations. +Top n sigma sampling as described in academic paper "Top-nσ: Not All Logits Are You Need" https://arxiv.org/pdf/2411.07641 + +**Example:** + +```sql +SELECT llm_sampler_init_top_n_sigma(1.5); +``` + +--- + +## `llm_sampler_init_mirostat(seed INT, tau REAL, eta REAL, m INT)` + +**Returns:** `NULL` + +**Description:** +Initializes Mirostat sampling with entropy control. +Mirostat 1.0 algorithm described in the paper https://arxiv.org/abs/2007.14966. Uses tokens instead of words. + +**Example:** + +```sql +SELECT llm_sampler_init_mirostat(42, 5.0, 0.1, 100); +``` + +--- + +## `llm_sampler_init_mirostat_v2(seed INT, tau REAL, eta REAL)` + +**Returns:** `NULL` + +**Description:** +Mirostat v2 entropy-based sampling. +Mirostat 2.0 algorithm described in the paper https://arxiv.org/abs/2007.14966. Uses tokens instead of words. + +**Example:** + +```sql +SELECT llm_sampler_init_mirostat_v2(42, 5.0, 0.1); +``` + +--- + +## `llm_sampler_init_grammar(grammar_str TEXT, grammar_root TEXT)` + +**Returns:** `NULL` + +**Description:** +Constrains output to match a specified grammar. +Grammar syntax described in https://github.com/ggml-org/llama.cpp/tree/master/grammars + +**Example:** + +```sql +SELECT llm_sampler_init_grammar('...BNF...', 'root'); +``` + +--- + +## `llm_sampler_init_infill()` + +**Returns:** `NULL` + +**Description:** +Enables infill (prefix-suffix) mode for completions. + +**Example:** + +```sql +SELECT llm_sampler_init_infill(); +``` + +--- + +## `llm_sampler_init_penalties(n INT, repeat REAL, freq REAL, present REAL)` + +**Returns:** `NULL` + +**Description:** +Applies repetition, frequency, and presence penalties. + +**Example:** + +```sql +SELECT llm_sampler_init_penalties(64, 1.2, 0.5, 0.8); +``` + +--- + +## `llm_token_count(text TEXT)` + +**Returns:** `INTEGER` + +**Description:** +Returns how many tokens the current model would consume for the supplied `text`, using the active context’s vocabulary. Requires a context created via `llm_context_create`. + +**Example:** + +```sql +SELECT llm_token_count('Hello world!'); +-- 5 +``` + +--- + +## `llm_embed_generate(text TEXT, options TEXT)` + +**Returns:** `BLOB` or `TEXT` + +**Description:** +Generates a text embedding as a BLOB vector, with optional configuration provided as a comma-separated list of key=value pairs. +By default, the embedding is normalized unless `normalize_embedding=0` is specified. +If `json_output=1` is set, the function returns a JSON object instead of a BLOB. + +**Example:** + +```sql +SELECT llm_embed_generate('hello world', 'json_output=1'); +``` + +--- + +## `llm_text_generate(text TEXT, [image1, image2, ...], options TEXT)` + +**Returns:** `TEXT` + +**Description:** +Generates a full-text completion based on input, with optional configuration provided as a comma-separated list of key=value pairs. + +When a vision model is loaded via `llm_vision_load()`, you can pass one or more images as additional arguments. Images can be file paths (TEXT) or raw image data (BLOB). Supported image formats: JPG, PNG, BMP, GIF. + +**Examples:** + +```sql +-- Text-only generation +SELECT llm_text_generate('Once upon a time', 'n_predict=1024'); + +-- Vision: describe an image +SELECT llm_text_generate('Describe this image', './photos/cat.jpg'); + +-- Vision: compare multiple images +SELECT llm_text_generate('What is different between these images?', './img1.jpg', './img2.jpg'); + +-- Vision: image from BLOB column +SELECT llm_text_generate('What do you see?', image_data) FROM photos WHERE id = 1; +``` + +--- + +## `llm_chat(prompt TEXT)` + +**Returns:** `VIRTUAL TABLE` + +**Description:** +Streams a chat-style reply one token per row. + +**Example:** + +```sql +SELECT reply FROM llm_chat('Tell me a joke.'); +``` + +--- + +## `llm_chat_create()` + +**Returns:** `TEXT` + +**Description:** +Starts a new in-memory chat session. +Returns unique chat UUIDv7 value. +If no chat is explicitly created, one will be created automatically when needed. + +**Example:** + +```sql +SELECT llm_chat_create(); +``` + +--- + +## `llm_chat_free()` + +**Returns:** `NULL` + +**Description:** +Ends the current chat session. + +**Example:** + +```sql +SELECT llm_chat_free(); +``` + +--- + +## `llm_chat_save(title TEXT, meta TEXT)` + +**Returns:** `TEXT` + +**Description:** +Saves the current chat session with optional title and meta into the ai_chat_history and ai_chat_messages tables and returns a UUID. + +**Example:** + +```sql +SELECT llm_chat_save('Support Chat', '{"user": "Marco"}'); +``` + +--- + +## `llm_chat_restore(uuid TEXT)` + +**Returns:** `NULL` + +**Description:** +Restores a previously saved chat session by UUID. + +**Example:** + +```sql +SELECT llm_chat_restore('b59e...'); +``` + +--- + +## `llm_chat_respond(text TEXT, [image1, image2, ...])` + +**Returns:** `TEXT` + +**Description:** +Generates a context-aware reply using chat memory, returned as a single, complete response. +For a streaming model reply, use the llm_chat virtual table. + +When a vision model is loaded via `llm_vision_load()`, you can pass one or more images as additional arguments. Images can be file paths (TEXT) or raw image data (BLOB). Supported image formats: JPG, PNG, BMP, GIF. + +**Examples:** + +```sql +-- Text-only chat +SELECT llm_chat_respond('What are the most visited cities in Italy?'); + +-- Vision: ask about an image +SELECT llm_chat_respond('What is in this photo?', './photos/landscape.jpg'); + +-- Vision: multiple images +SELECT llm_chat_respond('Compare these two charts', './chart1.png', './chart2.png'); +``` + +--- + +## `llm_chat_system_prompt(text TEXT)` + +**Returns:** `TEXT` or `NULL` + +**Description:** +Gets or sets the system prompt for chat sessions. When called without arguments, returns the current system prompt (or `NULL` if none is set). When called with a text argument, sets the system prompt and returns `NULL`. The system prompt is automatically prepended as a system-role message at the beginning of chat conversations. + +**Example:** + +```sql +-- Set a system prompt +SELECT llm_chat_system_prompt('You are a helpful assistant that speaks Italian.'); + +-- Get the current system prompt +SELECT llm_chat_system_prompt(); +``` + +--- + +## Vision Functions + +### `llm_vision_load(path TEXT, options TEXT)` + +**Returns:** `NULL` + +**Description:** +Loads a multimodal projector (mmproj) model for vision capabilities. This requires a text model to already be loaded via `llm_model_load()`. The mmproj file is a separate GGUF file that contains the vision encoder and projector weights. + +Once loaded, vision capabilities are available through `llm_text_generate()` and `llm_chat_respond()` by passing image arguments. + +The following option keys are available: + +| Key | Type | Default | Meaning | +| ------------------ | --------------------------------- | ------- | -------------------------------------------------------------------- | +| `use_gpu` | `1 or 0` | `1` | Use GPU for vision encoding. | +| `n_threads` | `number` | `4` | Number of threads for vision processing. | +| `warmup` | `1 or 0` | `1` | Run a warmup pass on load for faster first use. | +| `flash_attn_type` | `auto, disabled, enabled` | `auto` | Controls Flash Attention for the vision encoder. | +| `image_min_tokens` | `number` | `0` | Minimum image tokens for dynamic resolution models (0 = from model). | +| `image_max_tokens` | `number` | `0` | Maximum image tokens for dynamic resolution models (0 = from model). | + +**Example:** + +```sql +-- Load text model first +SELECT llm_model_load('./models/Gemma-3-4B-IT-Q4_K_M.gguf', 'gpu_layers=99'); +SELECT llm_context_create_textgen(); + +-- Load vision projector +SELECT llm_vision_load('./models/mmproj-Gemma-3-4B-IT-f16.gguf'); + +-- Now use vision with llm_text_generate or llm_chat_respond +SELECT llm_text_generate('Describe this image', './photos/cat.jpg'); +``` + +--- + +### `llm_vision_free()` + +**Returns:** `NULL` + +**Description:** +Unloads the current vision (mmproj) model and frees associated memory. The text model remains loaded. + +**Example:** + +```sql +SELECT llm_vision_free(); +``` + +--- + +## Audio Functions + +### `audio_model_load(path TEXT, options TEXT)` + +**Returns:** `NULL` + +**Description:** +Loads a Whisper model from the specified file path with optional comma-separated key=value configuration. The model is used for audio transcription via `audio_model_transcribe`. Only one whisper model can be loaded at a time per connection. + +**Example:** + +```sql +-- Load with defaults +SELECT audio_model_load('./models/ggml-tiny.bin'); + +-- Load with options +SELECT audio_model_load('./models/ggml-base.bin', 'gpu_layers=0'); +``` + +--- + +### `audio_model_free()` + +**Returns:** `NULL` + +**Description:** +Unloads the current Whisper model and frees associated memory. + +**Example:** + +```sql +SELECT audio_model_free(); +``` + +--- + +### `audio_model_transcribe(input TEXT/BLOB, options TEXT)` + +**Returns:** `TEXT` + +**Description:** +Transcribes audio to text using the loaded Whisper model. The input can be either: +- **TEXT**: A file path to an audio file (WAV, MP3, or FLAC) +- **BLOB**: Raw audio data (format auto-detected from magic bytes) + +An optional second parameter accepts comma-separated key=value pairs to configure transcription behavior. + +Supported audio formats: WAV, MP3, FLAC. Audio is automatically converted to mono 16kHz PCM as required by Whisper. + +**Transcription options:** + +| Key | Type | Default | Meaning | +| ------------------ | -------- | ------- | ---------------------------------------------------------- | +| `language` | `text` | `en` | Language code (e.g., `en`, `it`, `fr`, `de`). | +| `translate` | `1 or 0` | `0` | Translate to English. | +| `n_threads` | `number` | `4` | Number of threads for decoding. | +| `offset_ms` | `number` | `0` | Start transcription at this offset (milliseconds). | +| `duration_ms` | `number` | `0` | Transcribe only this duration (0 = full audio). | +| `no_timestamps` | `1 or 0` | `0` | Suppress timestamps in output. | +| `single_segment` | `1 or 0` | `0` | Force single segment output. | +| `token_timestamps` | `1 or 0` | `0` | Enable token-level timestamps. | +| `initial_prompt` | `text` | | Initial prompt to guide the model. | +| `temperature` | `float` | `0.0` | Sampling temperature. | +| `beam_size` | `number` | `-1` | Beam search size (-1 = use default). | +| `audio_ctx` | `number` | `0` | Audio context size (0 = use default). | +| `suppress_regex` | `text` | | Regex pattern for suppressing tokens. | +| `max_len` | `number` | `0` | Maximum segment length in characters (0 = no limit). | +| `print_timestamps` | `1 or 0` | `0` | Include timestamps in transcribed text. | + +**Examples:** + +```sql +-- Transcribe from a file path +SELECT audio_model_transcribe('./audio/speech.wav'); + +-- Transcribe from a BLOB column +SELECT audio_model_transcribe(audio_data) FROM recordings WHERE id = 1; + +-- Transcribe with options +SELECT audio_model_transcribe('./audio/speech.mp3', 'language=it,translate=1'); + +-- Transcribe a single segment with no timestamps +SELECT audio_model_transcribe('./audio/clip.flac', 'single_segment=1,no_timestamps=1'); +``` + +--- + +## Model Metadata + +These functions return internal model properties: + +```sql +SELECT + llm_model_n_params(), + llm_model_size(), + llm_model_n_ctx_train(), + llm_model_n_embd(), + llm_model_n_layer(), + llm_model_n_head(), + llm_model_n_head_kv(), + llm_model_n_swa(), + llm_model_rope_freq_scale_train(), + llm_model_n_cls_out(), + llm_model_cls_label(), + llm_model_desc(), + llm_model_has_encoder(), + llm_model_has_decoder(), + llm_model_is_recurrent(), + llm_model_chat_template(); +``` + +All return `INTEGER`, `REAL`, or `TEXT` values depending on the property. + +--- diff --git a/sqlite-cloud/sqlite-ai/sqlite-ai-embedding-notes.md b/sqlite-cloud/sqlite-ai/sqlite-ai-embedding-notes.md new file mode 100644 index 0000000..3e03cf4 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-ai-embedding-notes.md @@ -0,0 +1,140 @@ +--- +title: "SQLite-AI Embedding Notes" +description: "Notes about embedding pooling, output shape, and model compatibility in SQLite-AI." +category: platform +status: publish +slug: sqlite-ai-embedding-notes +--- + +## Are there cases where llama.cpp can produce more than one embedding from a single text input? + +In **llama.cpp**, whether you get **one embedding** or **multiple embeddings** from a text input depends on: + +1. **Pooling type (`llama_pooling_type`)** + + * `LLAMA_POOLING_TYPE_NONE` → no pooling is applied. + + * You get an embedding **per token** (so length = number of tokens). + * You retrieve it with `llama_get_embeddings(ctx)` after `llama_encode()` or `llama_decode()`. + * `LLAMA_POOLING_TYPE_MEAN`, `LLAMA_POOLING_TYPE_CLS`, `LLAMA_POOLING_TYPE_LAST` → pooling is applied. + + * You get **one embedding per sequence ID**. + * You retrieve it with `llama_get_embeddings_seq(ctx, seq_id)`. + +2. **Number of sequence IDs (`seq_id`) in the batch** + + * Each sequence in the batch (distinguished by `seq_id`) can produce its own pooled embedding if pooling is enabled. + * Example: if you feed 3 sentences in parallel with `seq_id = 0,1,2` and pooling = MEAN, you’ll get **3 embeddings**. + +3. **How you mark logits/outputs in the batch** + + * With pooling enabled, you only need to request an output on one token per sequence (often the last token). + * Without pooling, you must request logits for every token you want embeddings for. + +--- + +So, to directly answer: + +* **Single text input, pooling enabled** → **1 embedding** (sequence-level). +* **Single text input, pooling disabled** → **N embeddings** (token-level, one per token). +* **Multiple texts in one batch** → **N embeddings** (one per sequence if pooling, or token-level if not). + +--- + +In your embedding use case (sounds like you’re doing what `llama.cpp` calls **sentence embedding**), you probably want **pooling enabled** (MEAN or CLS) and therefore **one embedding per text input**. + +## Is there a way to force one embedding (sentence embedding)? + +Yes, in **llama.cpp** you can force sentence-level embeddings by enabling a **pooling mode** in the context parameters. That way you’ll always get exactly **one embedding per sequence ID**, regardless of how many tokens the text expands into. + +--- + +### How to do it + +When you create the context (`llama_context_params`), set: + +```c +struct llama_context_params cparams = llama_context_default_params(); + +// choose your pooling mode: +cparams.pooling_type = LLAMA_POOLING_TYPE_MEAN; // common for sentence embeddings +// or: LLAMA_POOLING_TYPE_CLS +// or: LLAMA_POOLING_TYPE_LAST + +struct llama_context *ctx = llama_new_context_with_model(model, cparams); +``` + +Then, when you process text with `llama_encode()` or `llama_decode()`: + +* Use a single `seq_id` for that text (e.g. `seq_id = 0`). +* After the call, retrieve the **sequence embedding**: + +```c +const float *embedding = llama_get_embeddings_seq(ctx, seq_id); +// embedding size = llama_n_embd(model) +``` + +That’s it: you’ll get **one embedding vector** for the entire input string. + +--- + +### Contrast with token-level embeddings + +* If `pooling_type == LLAMA_POOLING_TYPE_NONE` → `llama_get_embeddings(ctx)` gives you **token-level embeddings** (matrix: tokens × dim). +* If `pooling_type != NONE` → `llama_get_embeddings_seq(ctx, seq_id)` gives you **sentence-level embeddings** (one vector per sequence). + +--- + +**So the way to force one embedding per text is:** + +* Set `pooling_type` in the context params (`MEAN`, `CLS`, or `LAST`). +* Use `llama_get_embeddings_seq()` instead of `llama_get_embeddings()`. + +--- + +## Is the pooling_type related to the model? Can I be sure that all models support all the pooling types? + + +The **pooling\_type** in **llama.cpp** is **not a property of the model itself** – it’s purely how **llama.cpp** aggregates the **token embeddings** it already computes. All decoder-only LLaMA-style models output a hidden state per token, so pooling is just a post-processing step that the library offers. + +--- + +### What this means + +* Any model you load with **llama.cpp** produces **per-token embeddings**. +* Pooling (`MEAN`, `CLS`, `LAST`) is applied on top of those token embeddings to compress them into **one vector**. +* So yes: **all models supported by llama.cpp can use all pooling types**. +* The only requirement is that you create the context with `cparams.pooling_type` set, so llama.cpp knows to allocate memory for pooled embeddings. + +--- + +### Differences between pooling modes + +* **MEAN** → average of all token embeddings in the sequence. + + * Default / most common for sentence embeddings & semantic search. +* **CLS** → use the embedding of the first token (analogous to `[CLS]` in BERT-style models). + + * Works, but LLaMA models weren’t trained with a `[CLS]` objective, so performance may vary. +* **LAST** → use the embedding of the final token. + + * Sometimes useful for autoregressive tasks; not typically the best for embeddings. + +--- + +### Important + +The quality of the **sentence embedding** you get *does* depend on the **model training objective**: + +* Models explicitly trained for embedding tasks (e.g. `all-MiniLM-L6-v2`, `text-embedding-ada-002`, `nomic-embed`) will usually outperform a raw LLaMA model, even if you apply pooling. +* LLaMA-style models with pooling still give you usable vectors, but they weren’t optimized for semantic similarity. + +--- + +So in summary: + +* Pooling is **always available** in llama.cpp. +* All models supported by llama.cpp can use **MEAN / CLS / LAST** pooling. +* The *choice of pooling* affects embedding quality, but you won’t get an error from the library. + +--- diff --git a/sqlite-cloud/sqlite-ai/sqlite-ai-examples.md b/sqlite-cloud/sqlite-ai/sqlite-ai-examples.md new file mode 100644 index 0000000..2400a71 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-ai-examples.md @@ -0,0 +1,89 @@ +--- +title: "SQLite-AI Examples" +description: "SQLite-AI SQL examples for text generation, embeddings, chat, audio, and vision workflows." +category: platform +status: publish +slug: sqlite-ai-examples +--- + +## Getting Started + +```bash +## Start SQLite CLI +sqlite3 myapp.db +``` + + +### Text Generation + +```sql +-- Load a text generation model +SELECT llm_model_load('./models/Qwen2.5-3B-Q4_K_M.gguf', 'gpu_layers=99'); +SELECT llm_context_create_textgen(); + +-- Generate text +SELECT llm_text_generate('What is the most beautiful city in Italy?'); +``` + +### Embedding Generation + +```sql +-- Load an embedding model +SELECT llm_model_load('./models/nomic-embed-text-v1.5-Q8_0.gguf', 'gpu_layers=99'); +SELECT llm_context_create_embedding('embedding_type=FLOAT32'); + +-- Generate an embedding vector +SELECT llm_embed_generate('Hello world'); + +-- Generate an embedding as JSON +SELECT llm_embed_generate('Hello world', 'json_output=1'); +``` + +### Chat + +```sql +-- Load a chat model +SELECT llm_model_load('./models/Llama-3.2-3B-Instruct-Q4_K_M.gguf', 'gpu_layers=99'); +SELECT llm_context_create_chat(); + +-- Send a message and get a complete response +SELECT llm_chat_respond('Tell me a joke.'); + +-- Or stream the reply token by token +SELECT reply FROM llm_chat('Tell me another joke.'); +``` + +### Audio Transcription + +```sql +-- Load a Whisper model +SELECT audio_model_load('./models/ggml-tiny.bin'); + +-- Transcribe from a file path +SELECT audio_model_transcribe('./audio/speech.wav'); + +-- Transcribe with options +SELECT audio_model_transcribe('./audio/speech.mp3', 'language=it,translate=1'); + +-- Transcribe from a BLOB column +SELECT audio_model_transcribe(audio_data) FROM recordings WHERE id = 1; +``` + +### Vision / Multimodal + +```sql +-- Load a multimodal model and its vision projector +SELECT llm_model_load('./models/Gemma-3-4B-IT-Q4_K_M.gguf', 'gpu_layers=99'); +SELECT llm_context_create_textgen(); +SELECT llm_vision_load('./models/mmproj-Gemma-3-4B-IT-f16.gguf'); + +-- Describe an image +SELECT llm_text_generate('Describe this image', './photos/cat.jpg'); + +-- Use vision in a chat conversation +SELECT llm_context_create_chat(); +SELECT llm_chat_respond('What do you see in this photo?', './photos/landscape.jpg'); + +-- Analyze multiple images +SELECT llm_text_generate('Compare these two images', './img1.jpg', './img2.jpg'); +``` diff --git a/sqlite-cloud/sqlite-ai/sqlite-ai-getting-started.md b/sqlite-cloud/sqlite-ai/sqlite-ai-getting-started.md new file mode 100644 index 0000000..ca5cf4e --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-ai-getting-started.md @@ -0,0 +1,90 @@ +--- +title: "SQLite-AI Getting Started" +description: "Run local model inference, embeddings, audio transcription, and multimodal AI from SQL." +category: platform +status: publish +slug: sqlite-ai-getting-started +--- + +## Getting Started + +```bash +## Start SQLite CLI +sqlite3 myapp.db +``` + + +### Text Generation + +```sql +-- Load a text generation model +SELECT llm_model_load('./models/Qwen2.5-3B-Q4_K_M.gguf', 'gpu_layers=99'); +SELECT llm_context_create_textgen(); + +-- Generate text +SELECT llm_text_generate('What is the most beautiful city in Italy?'); +``` + +### Embedding Generation + +```sql +-- Load an embedding model +SELECT llm_model_load('./models/nomic-embed-text-v1.5-Q8_0.gguf', 'gpu_layers=99'); +SELECT llm_context_create_embedding('embedding_type=FLOAT32'); + +-- Generate an embedding vector +SELECT llm_embed_generate('Hello world'); + +-- Generate an embedding as JSON +SELECT llm_embed_generate('Hello world', 'json_output=1'); +``` + +### Chat + +```sql +-- Load a chat model +SELECT llm_model_load('./models/Llama-3.2-3B-Instruct-Q4_K_M.gguf', 'gpu_layers=99'); +SELECT llm_context_create_chat(); + +-- Send a message and get a complete response +SELECT llm_chat_respond('Tell me a joke.'); + +-- Or stream the reply token by token +SELECT reply FROM llm_chat('Tell me another joke.'); +``` + +### Audio Transcription + +```sql +-- Load a Whisper model +SELECT audio_model_load('./models/ggml-tiny.bin'); + +-- Transcribe from a file path +SELECT audio_model_transcribe('./audio/speech.wav'); + +-- Transcribe with options +SELECT audio_model_transcribe('./audio/speech.mp3', 'language=it,translate=1'); + +-- Transcribe from a BLOB column +SELECT audio_model_transcribe(audio_data) FROM recordings WHERE id = 1; +``` + +### Vision / Multimodal + +```sql +-- Load a multimodal model and its vision projector +SELECT llm_model_load('./models/Gemma-3-4B-IT-Q4_K_M.gguf', 'gpu_layers=99'); +SELECT llm_context_create_textgen(); +SELECT llm_vision_load('./models/mmproj-Gemma-3-4B-IT-f16.gguf'); + +-- Describe an image +SELECT llm_text_generate('Describe this image', './photos/cat.jpg'); + +-- Use vision in a chat conversation +SELECT llm_context_create_chat(); +SELECT llm_chat_respond('What do you see in this photo?', './photos/landscape.jpg'); + +-- Analyze multiple images +SELECT llm_text_generate('Compare these two images', './img1.jpg', './img2.jpg'); +``` + diff --git a/sqlite-cloud/sqlite-ai/sqlite-ai.mdx b/sqlite-cloud/sqlite-ai/sqlite-ai.mdx new file mode 100644 index 0000000..a374ba5 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-ai.mdx @@ -0,0 +1,29 @@ +--- +title: "SQLite-AI" +description: "Run LLM inference, embeddings, chat, audio transcription, and multimodal AI directly inside SQLite." +category: platform +status: publish +slug: sqlite-ai +--- + +**SQLite-AI** is an extension for SQLite that brings artificial intelligence capabilities directly into the database. It enables developers to run, fine-tune, and serve AI models from within SQLite using simple SQL queries — ideal for on-device and edge applications where low-latency and offline inference are critical. The extension is actively developed by [SQLite AI](https://sqlite.ai), some API and features are still evolving. + + + +## Features + +* **Embedded AI Inference**: Run transformer models directly from SQL queries. +* **Streaming I/O**: Token-by-token streaming via SQL aggregate functions. +* **Fine-tuning & Embedding**: On-device model customization and vector embedding. +* **Full On-Device Support**: Works on iOS, Android, Linux, macOS, and Windows. +* **Offline-First**: No server dependencies or internet connection required. +* **Composable SQL Interface**: AI + relational logic in a single unified layer. +* **Audio Transcription**: Speech-to-text via Whisper models (WAV, MP3, FLAC). +* **Vision / Multimodal**: Analyze images via multimodal models (JPG, PNG, BMP, GIF). +* **Supports any GGUF model**: available on Huggingface; Qwen, Gemma, Llama, DeepSeek and more + +SQLite-AI supports **text embedding generation** for search and classification, a **chat-like interface with history and token streaming**, **automatic context save and restore** across sessions, **audio transcription** via Whisper models, and **vision/multimodal** image understanding — making it ideal for building conversational agents, memory-aware assistants, and voice-enabled applications. diff --git a/sqlite-cloud/sqlite-ai/sqlite-columnar-api-reference.md b/sqlite-cloud/sqlite-ai/sqlite-columnar-api-reference.md new file mode 100644 index 0000000..c4070ac --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-columnar-api-reference.md @@ -0,0 +1,294 @@ +--- +title: "SQLite-Columnar API Reference" +description: "Reference for SQLite-Columnar virtual tables, scalar functions, and grouped table-valued functions." +category: platform +status: publish +slug: sqlite-columnar-api-reference +--- + +This document lists the SQL API exposed by the `columnar` loadable extension. + +Examples assume the extension is loaded and this table exists: + +```sql + +CREATE VIRTUAL TABLE sales USING columnar( + id INTEGER, + region TEXT, + category TEXT, + amount REAL, + cost REAL +); + +INSERT INTO sales VALUES + (1, 'north', 'hardware', 10.0, 4.0), + (2, 'north', 'software', 20.0, 8.0), + (3, 'south', 'hardware', 5.0, 2.0); +``` + +Every API argument named `table` accepts either `table` for the main database +or `db.table` for an attached database schema. + +## Virtual Table + +### `CREATE VIRTUAL TABLE ... USING columnar(...)` + +Creates a column-oriented virtual table. Each declared column is stored in its +own shadow table, with separate rowid, stats, chunk, dirty, and metadata shadow +tables. + +```sql +CREATE VIRTUAL TABLE metrics USING columnar( + ts INTEGER, + host TEXT, + cpu REAL +); +``` + +## Scalar Functions + +### `columnar_version()` + +Returns the extension version as TEXT. + +```sql +SELECT columnar_version(); +``` + +### `columnar_analyze(table)` + +Builds or refreshes per-column stats and chunk zone maps for a columnar table. +The return value is the number of column/chunk entries analyzed. If metadata is +valid and no chunks are dirty, it returns `0`. + +```sql +SELECT columnar_analyze('sales'); +``` + +```sql +ATTACH 'analytics.db' AS analytics; +SELECT columnar_analyze('analytics.sales'); +``` + +### `columnar_sum(table, column)` + +Returns `sum(column)` for a columnar table. Uses analyzed stats when available, +otherwise scans the requested column. + +```sql +SELECT columnar_sum('sales', 'amount'); +``` + +```sql +SELECT columnar_sum('analytics.sales', 'amount'); +``` + +### `columnar_avg(table, column)` + +Returns `avg(column)` for a columnar table. Uses analyzed stats when available, +otherwise scans the requested column. + +```sql +SELECT columnar_avg('sales', 'amount'); +``` + +```sql +SELECT columnar_avg('analytics.sales', 'amount'); +``` + +### `columnar_count(table)` + +Returns the row count for a columnar table. Uses analyzed stats when available, +otherwise scans the rowid shadow table. + +```sql +SELECT columnar_count('sales'); +``` + +```sql +SELECT columnar_count('analytics.sales'); +``` + +### `columnar_count(table, column)` + +Returns `count(column)` for a columnar table. Uses analyzed stats when +available, otherwise scans the requested column. + +```sql +SELECT columnar_count('sales', 'amount'); +``` + +```sql +SELECT columnar_count('analytics.sales', 'amount'); +``` + +### `columnar_sum_where_range(table, value_column, filter_column, low, high)` + +Returns `sum(value_column)` for rows where `filter_column BETWEEN low AND high`. +Uses chunk zone maps to skip disjoint chunks after `columnar_analyze()`. + +```sql +SELECT columnar_sum_where_range('sales', 'amount', 'id', 1, 2); +``` + +```sql +SELECT columnar_sum_where_range('analytics.sales', 'amount', 'id', 1, 2); +``` + +### `columnar_avg_where_range(table, value_column, filter_column, low, high)` + +Returns `avg(value_column)` for rows where `filter_column BETWEEN low AND high`. + +```sql +SELECT columnar_avg_where_range('sales', 'amount', 'id', 1, 2); +``` + +```sql +SELECT columnar_avg_where_range('analytics.sales', 'amount', 'id', 1, 2); +``` + +### `columnar_count_where_range(table, value_column, filter_column, low, high)` + +Returns `count(value_column)` for rows where `filter_column BETWEEN low AND +high`. + +```sql +SELECT columnar_count_where_range('sales', 'amount', 'id', 1, 2); +``` + +```sql +SELECT columnar_count_where_range('analytics.sales', 'amount', 'id', 1, 2); +``` + +## Grouped Table-Valued Functions + +Grouped helpers return rows with a grouping key column named `k` plus one or +more aggregate output columns. Quote aggregate column names such as `"sum"` and +`"count"` in SQL. + +### `columnar_group_sum(table, key_column, value_column)` + +Returns one row per key with `k` and `"sum"`. + +```sql +SELECT k, "sum" + FROM columnar_group_sum('sales', 'region', 'amount') + ORDER BY k; +``` + +### `columnar_group_avg(table, key_column, value_column)` + +Returns one row per key with `k` and `"avg"`. + +```sql +SELECT k, "avg" + FROM columnar_group_avg('sales', 'region', 'amount') + ORDER BY k; +``` + +### `columnar_group_count(table, key_column)` + +Returns one row per key with `k` and `"count"`, counting rows in each group. + +```sql +SELECT k, "count" + FROM columnar_group_count('sales', 'region') + ORDER BY k; +``` + +### `columnar_group_count(table, key_column, value_column)` + +Returns one row per key with `k` and `"count"`, counting non-NULL values in +`value_column` for each group. + +```sql +SELECT k, "count" + FROM columnar_group_count('sales', 'region', 'amount') + ORDER BY k; +``` + +### `columnar_group_sum_avg_count(table, key_column, value_column)` + +Returns one row per key with `k`, `"sum"`, `"avg"`, and `"count"` in one pass. + +```sql +SELECT k, "sum", "avg", "count" + FROM columnar_group_sum_avg_count('sales', 'region', 'amount') + ORDER BY k; +``` + +### `columnar_group_min(table, key_column, value_column)` + +Returns one row per key with `k` and `"min"`. + +```sql +SELECT k, "min" + FROM columnar_group_min('sales', 'region', 'amount') + ORDER BY k; +``` + +### `columnar_group_max(table, key_column, value_column)` + +Returns one row per key with `k` and `"max"`. + +```sql +SELECT k, "max" + FROM columnar_group_max('sales', 'region', 'amount') + ORDER BY k; +``` + +### `columnar_group_min_max_count(table, key_column, value_column)` + +Returns one row per key with `k`, `"min"`, `"max"`, and `"count"` in one pass. + +```sql +SELECT k, "min", "max", "count" + FROM columnar_group_min_max_count('sales', 'region', 'amount') + ORDER BY k; +``` + +### `columnar_group_range(table, key_column, max_column, min_column)` + +Returns one row per key with `k`, `"range"`, `"max"`, `"min"`, and `"count"`. +The `"range"` column is `max(max_column) - min(min_column)`. +The `"count"` column counts rows where either `max_column` or `min_column` is +non-NULL. + +```sql +SELECT k, "range", "max", "min", "count" + FROM columnar_group_range('sales', 'region', 'amount', 'cost') + ORDER BY k; +``` + +### `columnar_group_sum_where_range(table, key_column, value_column, filter_column, low, high)` + +Returns grouped sums for rows where `filter_column BETWEEN low AND high`. +Uses chunk zone maps to skip disjoint chunks after `columnar_analyze()`. + +```sql +SELECT k, "sum" + FROM columnar_group_sum_where_range('sales', 'region', 'amount', 'id', 1, 2) + ORDER BY k; +``` + +### `columnar_group_sum_avg_count_where_range(table, key_column, value_column, filter_column, low, high)` + +Returns grouped sum, average, and count for rows where +`filter_column BETWEEN low AND high`. + +```sql +SELECT k, "sum", "avg", "count" + FROM columnar_group_sum_avg_count_where_range( + 'sales', 'region', 'amount', 'id', 1, 2 + ) + ORDER BY k; +``` + +## Notes + +- `columnar_analyze()` creates and refreshes the stats and chunk metadata used + by the specialized helpers. +- Group keys preserve SQLite storage classes for `NULL`, integer, real, text, + and blob values. +- Shadow tables named `__columnar_*` are implementation details, not + stable public API. diff --git a/sqlite-cloud/sqlite-ai/sqlite-columnar-benchmarks.md b/sqlite-cloud/sqlite-ai/sqlite-columnar-benchmarks.md new file mode 100644 index 0000000..8785a6f --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-columnar-benchmarks.md @@ -0,0 +1,156 @@ +--- +title: "SQLite-Columnar Benchmarks" +description: "Benchmark notes and performance results for SQLite-Columnar analytical workloads." +category: platform +status: publish +slug: sqlite-columnar-benchmarks +--- + +## sqlite-columnar Benchmark + +Date: 2026-05-10 + +Single-run command: + +```sh +make +make benchmarks +build/columnar-analytics-bench ./columnar 10000000 256 +``` + +For variance-aware runs, use the repeatable benchmark suite: + +```sh +make variance-bench VARIANCE_REPEATS=9 \ + VARIANCE_DATASETS="small:10000:64 medium:50000:128 wide:50000:512" +``` + +The variance suite emits machine-readable lines: + +- `dataset,...` records load/analyze time, storage size, and zone-map coverage. +- `query,...` records row-store and columnar median/p95 timings, median/p95 + speedups, result row count, and normalized result hash. + +Each query is warmed once before sampling and every sample verifies that the +columnar result hash matches the row-store result hash. + +## Variance Benchmark Results + +Command: + +```sh +make variance-bench VARIANCE_REPEATS=3 \ + VARIANCE_DATASETS='large100k:100000:128 large1m:1000000:128 large10m:10000000:256' +``` + +With three repeats, `p95` is effectively the slowest sampled run. Use more +repeats for publishable tail-latency claims. + +Load and analyze: + +| Dataset | Row populate ms | Columnar populate ms | Analyze ms | Row bytes | Columnar bytes | Selected chunks | +|---|---:|---:|---:|---:|---:|---:| +| `large100k` | 112.364 | 482.392 | 479.474 | 31,596,544 | 42,725,376 | 1 / 2 | +| `large1m` | 908.474 | 4,514.633 | 5,287.540 | 315,879,424 | 428,773,376 | 1 / 16 | +| `large10m` | 23,528.265 | 65,145.171 | 67,766.382 | 5,867,487,232 | 7,038,214,144 | 3 / 153 | + +10M query medians: + +| Query | Row median ms | Columnar median ms | Median speedup | Row p95 ms | Columnar p95 ms | p95 speedup | +|---|---:|---:|---:|---:|---:|---:| +| `columnar_sum(v1)` | 4,176.359 | 0.032 | 130,582.95x | 4,492.231 | 0.139 | 32,337.75x | +| `columnar_avg(v3)` | 4,135.865 | 0.032 | 129,316.82x | 4,188.948 | 0.045 | 92,745.57x | +| `columnar_count(v1)` | 4,003.996 | 0.032 | 125,193.65x | 4,028.505 | 0.038 | 106,456.49x | +| Generic columnar `GROUP BY id1, sum(v1)` | 8,701.082 | 5,773.005 | 1.51x | 9,863.331 | 6,944.527 | 1.42x | +| `columnar_group_sum(id1, v1)` | 7,985.574 | 1,322.187 | 6.04x | 8,156.254 | 1,322.539 | 6.17x | +| `columnar_group_count(id1)` | 7,921.773 | 560.804 | 14.13x | 7,935.962 | 561.124 | 14.14x | +| `columnar_group_sum_avg_count(id1, v1)` | 8,476.238 | 1,320.321 | 6.42x | 8,592.908 | 1,339.498 | 6.42x | +| `columnar_group_min_max_count(id3, v1)` | 6,078.397 | 1,410.172 | 4.31x | 6,141.314 | 1,416.834 | 4.33x | +| Specialized clustered `WHERE ts BETWEEN 100000 AND 200000` | 4,302.623 | 17.287 | 248.89x | 4,892.107 | 17.294 | 282.88x | +| Specialized clustered `GROUP BY id1, sum/avg/count(v1)` | 3,962.001 | 14.502 | 273.20x | 4,122.624 | 14.648 | 281.45x | + +Median speedup by dataset size: + +| Query | 100k | 1M | 10M | +|---|---:|---:|---:| +| `columnar_sum(v1)` | 449.32x | 4,243.82x | 130,582.95x | +| `columnar_avg(v3)` | 536.95x | 4,484.11x | 129,316.82x | +| `columnar_count(v1)` | 480.88x | 4,060.56x | 125,193.65x | +| `columnar_group_sum(id1, v1)` | 2.13x | 2.89x | 6.04x | +| `columnar_group_count(id1)` | 4.15x | 6.74x | 14.13x | +| Specialized clustered range filter | 1.45x | 15.45x | 248.89x | +| Specialized clustered grouped `sum/avg/count` | 2.96x | 37.23x | 273.20x | + +## Single-Run Analytical Benchmark + +Dataset: + +- Rows: 10,000,000 +- Wide fact table with dimensions `ts`, `id1`..`id6`, measures `v1`..`v3`, + and cold unused payload columns. +- Cold text payload: 2 columns x 256 bytes. +- `ts` is clustered/monotonic, which lets chunk zone maps prune rowid ranges. +- Chunk size: 65,536 rowids. + +Load and analyze: + +| Metric | Value | +|---|---:| +| Row-store populate | 17,523.098 ms | +| Columnar populate | 62,640.616 ms | +| Initial `columnar_analyze()` with global stats + chunk zone maps | 66,763.592 ms | +| Incremental `columnar_analyze()` no-op | 2.114 ms | +| Incremental `columnar_analyze()` after one inserted row | 82.998 ms | +| Row-store bytes | 5,867,487,232 | +| Columnar bytes | 7,038,214,144 | +| Metadata after initial analyze | row_count=10,000,000, chunk_count=153, dirty_count=0, stats_valid=1 | +| `ts` zone-map chunks selected | 3 / 153 | +| `ts` full-cover chunks eligible for aggregate pushdown | 1 / 153 | +| Dirty entries after one inserted row | 14 | +| Metadata dirty count after one inserted row | 14 | +| Dirty entries after incremental analyze | 0 | +| Metadata after incremental analyze | row_count=10,000,001, chunk_count=153, dirty_count=0, stats_valid=1 | + +Query results: + +| Query | Row-store ms | Columnar ms | Speedup | +|---|---:|---:|---:| +| `sum(v1)` via `columnar_sum` | 4,014.135 | 0.049 | 81,800.48x | +| `avg(v3)` via `columnar_avg` | 3,771.010 | 0.032 | 117,908.83x | +| `count(v1)` via `columnar_count` | 3,621.597 | 0.031 | 116,803.63x | +| Generic columnar `GROUP BY id1, sum(v1)` | 8,243.531 | 7,116.800 | 1.16x | +| `columnar_group_sum(id1, v1)` | 7,927.167 | 1,325.468 | 5.98x | +| `columnar_group_avg(id1, v3)` | 7,837.215 | 1,456.862 | 5.38x | +| `columnar_group_count(id1)` | 7,483.165 | 575.004 | 13.01x | +| `columnar_group_sum_avg_count(id1, v1)` | 7,802.118 | 1,383.348 | 5.64x | +| Generic `GROUP BY id3, sum(v1), avg(v3)` | 5,921.353 | 5,385.596 | 1.10x | +| Generic `GROUP BY id3, max(v1)-min(v2)` | 5,744.765 | 6,754.225 | 0.85x | +| `columnar_group_min_max_count(id3, v1)` | 6,171.251 | 1,754.662 | 3.52x | +| `columnar_group_range(id3, v1, v2)` | 6,119.328 | 3,485.148 | 1.76x | +| Generic `WHERE id2 BETWEEN 10 AND 20` | 4,428.708 | 3,461.585 | 1.28x | +| Specialized `WHERE id2 BETWEEN 10 AND 20` | 3,982.078 | 1,477.895 | 2.69x | +| Generic clustered `WHERE ts BETWEEN 100000 AND 200000` | 3,931.485 | 3,133.416 | 1.25x | +| Specialized clustered `WHERE ts BETWEEN 100000 AND 200000` | 3,819.239 | 24.971 | 152.95x | +| Specialized clustered `GROUP BY id1, sum(v1)` | 3,932.212 | 18.469 | 212.91x | +| Specialized clustered `GROUP BY id1, sum/avg/count(v1)` | 3,691.288 | 14.654 | 251.90x | + +Interpretation: + +- Global `sum`/`avg`/`count` are accelerated by precomputed stats. +- Generic virtual-table scans benefit from reading fewer columns but still pay + SQLite row materialization and generic aggregation costs. +- Specialized grouped functions avoid generic row materialization. +- Range-filtered functions use chunk zone maps. They help modestly on uniformly + distributed filters such as `id2`, and dramatically on clustered filters such + as `ts`, where only 3 of 153 chunks are scanned. +- Scalar range-filtered aggregates use precomputed chunk `sum`/`count` for + full-cover chunks. In this run, 1 of the 3 selected `ts` chunks is served from + chunk stats instead of row scans. +- `columnar_analyze()` is incremental after the initial bootstrap. Persistent + metadata tracks `row_count`, `chunk_count`, `dirty_count`, and `stats_valid`. + A no-op analyze on this 10M-row table now returns from metadata in 2.114 ms, + and reanalyzing the dirty metadata after a single inserted row took 82.998 ms. +- The current weak spots remain load time, `columnar_analyze()` cost, and larger + on-disk size due to one SQLite B-tree per column plus zone-map metadata. The + expensive analyze cost now applies primarily to the first bootstrap or to + large dirty ranges. diff --git a/sqlite-cloud/sqlite-ai/sqlite-columnar-getting-started.md b/sqlite-cloud/sqlite-ai/sqlite-columnar-getting-started.md new file mode 100644 index 0000000..572dcdd --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-columnar-getting-started.md @@ -0,0 +1,33 @@ +--- +title: "SQLite-Columnar Getting Started" +description: "Query SQLite-Columnar virtual tables for embedded analytics." +category: platform +status: publish +slug: sqlite-columnar-getting-started +--- + +## Getting Started + +```sql +CREATE VIRTUAL TABLE sales USING columnar( + id INTEGER, + region TEXT, + amount REAL +); + +INSERT INTO sales VALUES + (1, 'north', 10.0), + (2, 'north', 20.0), + (3, 'south', 5.0); + +SELECT columnar_analyze('sales'); +SELECT columnar_sum('sales', 'amount'); + +SELECT k, "sum", "avg", "count" + FROM columnar_group_sum_avg_count('sales', 'region', 'amount') + ORDER BY k; +``` + +See [API.md](/docs/sqlite-columnar-api-reference) for the complete SQL API reference with examples for every +function and table-valued helper. + diff --git a/sqlite-cloud/sqlite-ai/sqlite-columnar.md b/sqlite-cloud/sqlite-ai/sqlite-columnar.md new file mode 100644 index 0000000..6fa7aae --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-columnar.md @@ -0,0 +1,97 @@ +--- +title: "SQLite-Columnar" +description: "Column-oriented analytics inside SQLite for fast local scans, aggregations, and grouped summaries." +category: platform +status: publish +slug: sqlite-columnar +--- + +`sqlite-columnar` brings column-oriented analytics to SQLite as a self-contained +extension. It lets applications keep the operational simplicity of +SQLite while adding a storage and execution path built for analytical scans, +aggregations, and grouped summaries over wide datasets. + +It does not patch SQLite's pager, btree, parser, VDBE, or shell. Use it to +create columnar virtual tables for the parts of your application that behave +more like analytics than OLTP. + +
    + + Installed by default in SQLite Cloud + + + GitHub: https://github.com/sqliteai/sqlite-columnar + +
    + +## Why Columnar SQLite? + +Traditional SQLite tables are row-oriented, which is excellent for point +lookups, small updates, and transactional application state. Analytical +workloads are different: they often read a few columns across many rows, compute +aggregates, group by dimensions, and filter by ranges. In those cases, reading +entire rows means paying I/O and CPU cost for data the query never uses. + +`sqlite-columnar` stores each column separately, tracks chunk-level metadata, +and provides specialized aggregate helpers that avoid generic row +materialization for common analytical queries. + +## Performance Highlights + +On the included 10 million row variance benchmark, `sqlite-columnar` shows +large median speedups over standard row-oriented SQLite for operations that +benefit from columnar layout and precomputed metadata: + +- `sum(v1)` with `columnar_sum`: **130,583x faster** +- `avg(v3)` with `columnar_avg`: **129,317x faster** +- `count(v1)` with `columnar_count`: **125,194x faster** +- grouped `sum` by dimension: **6.04x faster** +- grouped `count` by dimension: **14.13x faster** +- grouped `sum/avg/count` by dimension: **6.42x faster** +- clustered range filter on `ts`: **248.89x faster** +- clustered range filter plus grouped `sum/avg/count`: **273.20x faster** + +These numbers are workload-specific. They are strongest when queries scan a +small subset of columns, use aggregate metadata, group over low-cardinality +dimensions, or filter on clustered/range-friendly columns. See +[BENCHMARK.md](/docs/sqlite-columnar-benchmarks) for the full dataset, commands, timings, and +interpretation. + +## Common Use Cases + +`sqlite-columnar` is useful when an embedded application needs analytical +queries without moving data into a separate database server. + +Good fits include: + +- embedded dashboards over local event, telemetry, or product analytics data +- time-series rollups where queries filter by timestamp ranges +- IoT and edge analytics over wide sensor records +- desktop or mobile apps with local reporting and summary views +- feature stores or ML preprocessing jobs that scan a few feature columns at a + time +- audit logs and observability data where users aggregate by service, region, + status, or time bucket +- SaaS tenant-local analytics where a single-file SQLite database is still the + preferred deployment model +- ETL validation workloads that repeatedly compute counts, sums, min/max, and + grouped quality checks + +Row-oriented SQLite remains the better default for highly transactional +workloads, point lookups, and frequent single-row updates. `sqlite-columnar` is +intended for the analytical tables in the same application. + +## How It Works + +Each columnar virtual table owns shadow tables for rowids, column values, +global stats, chunk zone maps, dirty chunks, and table-level metadata. + +`columnar_analyze()` builds the metadata used by specialized analytical +functions. After the initial bootstrap, analyze is incremental: inserts, +updates, and deletes mark touched chunks dirty, and later analyze calls rebuild +only those chunks. If metadata says stats are valid and there are no dirty +chunks, analyze returns immediately. + +Range-filtered helpers use chunk min/max summaries to skip rowid ranges that +cannot match a filter. Grouped helpers perform hash aggregation in C over only +the required column shadow tables. diff --git a/sqlite-cloud/sqlite-ai/sqlite-js-api-reference.md b/sqlite-cloud/sqlite-ai/sqlite-js-api-reference.md new file mode 100644 index 0000000..c336f74 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-js-api-reference.md @@ -0,0 +1,287 @@ +--- +title: "SQLite-JS API Reference" +description: "Reference for SQLite-JS scalar, aggregate, window, collation, eval, utility, and update functions." +category: platform +status: publish +slug: sqlite-js-api-reference +--- + +## Functions Overview + +SQLite-JS provides several ways to extend SQLite functionality with JavaScript: + +| Function Type | Description | +|---------------|-------------| +| Scalar Functions | Process individual rows and return a single value | +| Aggregate Functions | Process multiple rows and return a single aggregated result | +| Window Functions | Similar to aggregates but can access the full dataset | +| Collation Sequences | Define custom sort orders for text values | +| JavaScript Evaluation | Directly evaluate JavaScript code within SQLite | + +## Scalar Functions + +Scalar functions process one row at a time and return a single value. They are useful for data transformation, calculations, text manipulation, etc. + +### Usage + +```sql +SELECT js_create_scalar('function_name', 'function_code'); +``` + +### Parameters + +- **function_name**: The name of your custom function (see [Function Naming Rules](#function-naming-rules)) +- **function_code**: JavaScript code that defines your function. Must be in the form `function(args) { /* your code here */ }` + +### Example + +```sql +-- Create a custom function to calculate age from birth date +SELECT js_create_scalar('age', '(function(args) { + const birthDate = new Date(args[0]); + const today = new Date(); + let age = today.getFullYear() - birthDate.getFullYear(); + const m = today.getMonth() - birthDate.getMonth(); + if (m < 0 || (m === 0 && today.getDate() < birthDate.getDate())) { + age--; + } + return age; +})'); + +-- Use the function +SELECT name, age(birth_date) FROM people; +``` + +## Aggregate Functions + +Aggregate functions process multiple rows and compute a single result. Examples include SUM, AVG, and COUNT in standard SQL. + +### Usage + +```sql +SELECT js_create_aggregate('function_name', 'init_code', 'step_code', 'final_code'); +``` + +### Parameters + +- **function_name**: The name of your custom aggregate function (see [Function Naming Rules](#function-naming-rules)) +- **init_code**: JavaScript code that initializes variables for the aggregation +- **step_code**: JavaScript code that processes each row. Must be in the form `function(args) { /* your code here */ }` +- **final_code**: JavaScript code that computes the final result. Must be in the form `function() { /* your code here */ }` + +### Example + +```sql +-- Create a median function +SELECT js_create_aggregate('median', + -- Init code: initialize an array to store values + 'values = [];', + + -- Step code: collect values from each row + '(function(args) { + values.push(args[0]); + })', + + -- Final code: calculate the median + '(function() { + values.sort((a, b) => a - b); + const mid = Math.floor(values.length / 2); + if (values.length % 2 === 0) { + return (values[mid-1] + values[mid]) / 2; + } else { + return values[mid]; + } + })' +); + +-- Use the function +SELECT median(salary) FROM employees; +``` + +## Window Functions + +Window functions, like aggregate functions, operate on a set of rows. However, they can access all rows in the current window without collapsing them into a single output row. + +### Usage + +```sql +SELECT js_create_window('function_name', 'init_code', 'step_code', 'final_code', 'value_code', 'inverse_code'); +``` + +### Parameters + +- **function_name**: The name of your custom window function (see [Function Naming Rules](#function-naming-rules)) +- **init_code**: JavaScript code that initializes variables +- **step_code**: JavaScript code that processes each row. Must be in the form `function(args) { /* your code here */ }` +- **final_code**: JavaScript code that computes the final result. Must be in the form `function() { /* your code here */ }` +- **value_code**: JavaScript code that returns the current value. Must be in the form `function() { /* your code here */ }` +- **inverse_code**: JavaScript code that removes a row from the current window. Must be in the form `function(args) { /* your code here */ }` + +### Example + +```sql +-- Create a moving average window function +SELECT js_create_window('moving_avg', + -- Init code + 'sum = 0; count = 0;', + + -- Step code: process each row + '(function(args) { + sum += args[0]; + count++; + })', + + -- Final code: not needed for this example + '(function() { })', + + -- Value code: return current average + '(function() { + return count > 0 ? sum / count : null; + })', + + -- Inverse code: remove a value from the window + '(function(args) { + sum -= args[0]; + count--; + })' +); + +-- Use the function +SELECT id, value, moving_avg(value) OVER (ORDER BY id ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) +FROM measurements; +``` + +## Collation Sequences + +Collation sequences determine how text values are compared and sorted in SQLite. Custom collations enable advanced sorting capabilities like natural sorting, locale-specific sorting, etc. + +### Usage + +```sql +SELECT js_create_collation('collation_name', 'collation_function'); +``` + +### Parameters + +- **collation_name**: The name of your custom collation (see [Function Naming Rules](#function-naming-rules)) +- **collation_function**: JavaScript code that compares two strings. Must return a negative number if the first string is less than the second, zero if they are equal, or a positive number if the first string is greater than the second. + +### Example + +```sql +-- Create a case-insensitive natural sort collation +SELECT js_create_collation('natural_nocase', '(function(a, b) { + // Extract numbers for natural comparison + const splitA = a.toLowerCase().split(/(\d+)/); + const splitB = b.toLowerCase().split(/(\d+)/); + + for (let i = 0; i < Math.min(splitA.length, splitB.length); i++) { + if (splitA[i] !== splitB[i]) { + if (!isNaN(splitA[i]) && !isNaN(splitB[i])) { + return parseInt(splitA[i]) - parseInt(splitB[i]); + } + return splitA[i].localeCompare(splitB[i]); + } + } + return splitA.length - splitB.length; +})'); + +-- Use the collation +SELECT * FROM files ORDER BY name COLLATE natural_nocase; +``` + +## Syncing Across Devices + +When used with [sqlite-sync](https://github.com/sqliteai/sqlite-sync/), user-defined functions created via sqlite-js are automatically replicated across the SQLite Cloud cluster, ensuring that all connected peers share the same logic and behavior — even offline. To enable automatic persistence and sync the special `js_init_table` function must be executed. + +### Usage +```sql +SELECT js_init_table(); -- Create table if needed (no loading) +SELECT js_init_table(1); -- Create table and load all stored functions +``` + +## JavaScript Evaluation + +The extension also provides a way to directly evaluate JavaScript code within SQLite queries. + +### Usage + +```sql +SELECT js_eval('javascript_code'); +``` + +### Parameters + +- **javascript_code**: Any valid JavaScript code to evaluate + +### Example + +```sql +-- Perform a calculation +SELECT js_eval('Math.PI * Math.pow(5, 2)'); + +-- Format a date +SELECT js_eval('new Date(1629381600000).toLocaleDateString()'); +``` + +## Utility Functions + +### js_version + +Returns the extension version string, or the internal QuickJS engine version when called with an argument. + +```sql +SELECT js_version(); -- Returns the SQLite-JS version (e.g. '1.3.0') +SELECT js_version(1); -- Returns the QuickJS engine version +``` + +### js_load_text / js_load_blob + +Load file contents into SQLite — as text or as a blob. + +```sql +SELECT js_load_text('/path/to/file.txt'); -- Returns file contents as text +SELECT js_load_blob('/path/to/file.bin'); -- Returns file contents as a blob +``` + +### js_set_max_stack_size + +Configures the maximum stack size (in bytes) for the JavaScript engine. + +```sql +SELECT js_set_max_stack_size(1048576); -- Set max stack size to 1 MB +``` + +## Update Functions + +Due to a constraint in [SQLite](https://www3.sqlite.org/src/info/cabab62bc10568d4), it is not possible to update or redefine a user-defined function using the same database connection that was used to initially register it. To modify an existing JavaScript function, the update must be performed through a separate database connection. + +## Function Naming Rules + +Function names must comply with SQLite identifier rules and must be unique within the database and its schema. + +### Unquoted Identifiers +These must follow typical SQL naming conventions: +- Must begin with a letter (A-Z or a-z) or an underscore `_` +- May contain letters, digits (0-9), and underscores `_` +- Are case-insensitive +- Cannot match a reserved keyword unless quoted + +**Examples:** +- Valid: `identifier1`, `_temp`, `user_name` +- Invalid: `123abc`, `select`, `identifier-name` + +### Quoted Identifiers +SQLite supports delimited identifiers, which allow almost any character, as long as the identifier is properly quoted. + +You can use: +- Double quotes: `"identifier name"` +- Square brackets (Microsoft-style): `[identifier name]` +- Backticks (MySQL-style): `` `identifier name` `` + +These quoting styles are interchangeable in SQLite. Inside a quoted identifier, you can include: +- Spaces: `"my column"` +- Special characters: `"name@domain"`, `"price€"`, `"weird!name"` +- Reserved SQL keywords: `"select"`, `"group"` + +Quoted identifiers are case-sensitive. diff --git a/sqlite-cloud/sqlite-ai/sqlite-js-examples.md b/sqlite-cloud/sqlite-ai/sqlite-js-examples.md new file mode 100644 index 0000000..6373c77 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-js-examples.md @@ -0,0 +1,82 @@ +--- +title: "SQLite-JS Examples" +description: "SQLite-JS examples for custom SQL logic written in JavaScript." +category: platform +status: publish +slug: sqlite-js-examples +--- + +## Examples + +### Example 1: String Manipulation + +```sql +-- Create a function to extract domain from email +SELECT js_create_scalar('get_domain', '(function(args) { + const email = args[0]; + return email.split("@")[1] || null; +})'); + +-- Use it in a query +SELECT email, get_domain(email) AS domain FROM users; +``` + +### Example 2: Statistical Aggregation + +```sql +-- Create a function to calculate standard deviation +SELECT js_create_aggregate('stddev', + 'sum = 0; sumSq = 0; count = 0;', + + '(function(args) { + const val = args[0]; + sum += val; + sumSq += val * val; + count++; + })', + + '(function() { + if (count < 2) return null; + const variance = (sumSq - (sum * sum) / count) / (count - 1); + return Math.sqrt(variance); + })' +); + +-- Use it in a query +SELECT department, stddev(salary) FROM employees GROUP BY department; +``` + +### Example 3: Custom Window Function + +```sql +-- Create a window function to calculate percentile within a window +SELECT js_create_window('percentile_rank', + 'values = [];', + + '(function(args) { + values.push(args[0]); + })', + + '(function() { + values.sort((a, b) => a - b); + })', + + '(function() { + const current = values[values.length - 1]; + const rank = values.indexOf(current); + return (rank / (values.length - 1)) * 100; + })', + + '(function(args) { + const index = values.indexOf(args[0]); + if (index !== -1) { + values.splice(index, 1); + } + })' +); + +-- Use it in a query +SELECT name, score, + percentile_rank(score) OVER (ORDER BY score) +FROM exam_results; +``` diff --git a/sqlite-cloud/sqlite-ai/sqlite-js-getting-started.md b/sqlite-cloud/sqlite-ai/sqlite-js-getting-started.md new file mode 100644 index 0000000..de66931 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-js-getting-started.md @@ -0,0 +1,46 @@ +--- +title: "SQLite-JS Getting Started" +description: "Create custom SQLite functions with JavaScript from SQL." +category: platform +status: publish +slug: sqlite-js-getting-started +--- + +## Getting Started + +SQLite-JS lets you define scalar, aggregate, window, and collation functions directly from SQL. + +### Scalar Function + +```sql +SELECT js_create_scalar('get_domain', '(function(args) { + const email = args[0]; + return email.split("@")[1] || null; +})'); + +SELECT email, get_domain(email) AS domain +FROM users; +``` + +### Aggregate Function + +```sql +SELECT js_create_aggregate('stddev', + 'sum = 0; sumSq = 0; count = 0;', + '(function(args) { + const val = args[0]; + sum += val; + sumSq += val * val; + count++; + })', + '(function() { + if (count < 2) return null; + const variance = (sumSq - (sum * sum) / count) / (count - 1); + return Math.sqrt(variance); + })' +); + +SELECT department, stddev(salary) +FROM employees +GROUP BY department; +``` diff --git a/sqlite-cloud/sqlite-ai/sqlite-js.mdx b/sqlite-cloud/sqlite-ai/sqlite-js.mdx new file mode 100644 index 0000000..b3e2f78 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-js.mdx @@ -0,0 +1,18 @@ +--- +title: "SQLite-JS" +description: "Write SQLite scalar, aggregate, window, and collation functions in JavaScript." +category: platform +status: publish +slug: sqlite-js +--- + +**SQLite JS** is a powerful extension that brings JavaScript capabilities to SQLite. With this extension, you can create custom SQLite functions, aggregates, window functions, and collation sequences using JavaScript code, allowing for flexible and powerful data manipulation directly within your SQLite database. + +
    + + {"Installed by default in SQLite Cloud"} + + + {"GitHub: https://github.com/sqliteai/sqlite-js"} + +
    diff --git a/sqlite-cloud/sqlite-ai/sqlite-memory-api-reference.md b/sqlite-cloud/sqlite-ai/sqlite-memory-api-reference.md new file mode 100644 index 0000000..4bc5ab1 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-memory-api-reference.md @@ -0,0 +1,799 @@ +--- +title: "SQLite-Memory API Reference" +description: "Reference for sqlite-memory SQL functions, search virtual table, configuration, sync, and C API." +category: platform +status: publish +slug: sqlite-memory-api-reference +--- + +A SQLite extension that provides semantic memory capabilities with hybrid search (vector similarity + full-text search). + +## Table of Contents + +- [Overview](#overview) +- [Sync Behavior](#sync-behavior) +- [SQL Functions](#sql-functions) + - [General Functions](#general-functions) + - [Configuration Functions](#configuration-functions) + - [Memory Management Functions](#memory-management-functions) + - [Deletion Functions](#deletion-functions) + - [Sync Functions](#sync-functions) +- [Virtual Table Module](#virtual-table-module) +- [C API](#c-api) +- [Configuration Options](#configuration-options) +- [Timestamps](#timestamps) +- [Examples](#examples) + +--- + +## Overview + +sqlite-memory enables semantic search over text content stored in SQLite. It: + +1. **Chunks** text content using semantic parsing (markdown-aware) +2. **Generates embeddings** for each chunk using the built-in llama.cpp engine (`"local"` provider) or the [vectors.space](https://vectors.space) remote service +3. **Stores** embeddings and full-text content for hybrid search +4. **Searches** using vector similarity combined with FTS5 full-text search + +--- + +## Sync Behavior + +All `memory_add_*` functions use **content-hash change detection** to avoid redundant embedding computation. Each piece of content is hashed before processing — if the hash already exists in the database, the content is skipped. + +### Change Detection + +| Scenario | Behavior | +|----------|----------| +| New content | Chunked, embedded, and indexed | +| Unchanged content | Skipped (hash match) | +| Modified file | Old entry atomically deleted, new content reindexed | +| Deleted file | Entry removed during directory sync | + +### Transactional Safety + +Every sync operation is wrapped in a SQLite **SAVEPOINT** transaction. If any step fails (embedding error, disk issue, constraint violation), the entire operation rolls back. This guarantees: + +- **No partially-indexed files** — content is either fully indexed or not at all +- **No orphaned chunks** — embeddings and FTS entries are always consistent with `dbmem_content` +- **Safe to retry** — a failed sync leaves the database in its previous valid state + +This makes all sync functions idempotent and safe to call repeatedly (e.g., on a schedule or at application startup). + +--- + +## SQL Functions + +### General Functions + +#### `memory_version()` + +Returns the extension version string. + +**Parameters:** None + +**Returns:** TEXT - Version string (e.g., "0.5.0") + +**Example:** +```sql +SELECT memory_version(); +-- Returns: "0.5.0" +``` + +--- + +### Configuration Functions + +#### `memory_set_model(provider TEXT, model TEXT)` + +Configures the embedding model to use. + +**Parameters:** +| Parameter | Type | Description | +|-----------|------|-------------| +| `provider` | TEXT | `"local"` for built-in llama.cpp engine, or any other name (e.g., `"openai"`) for [vectors.space](https://vectors.space) remote service | +| `model` | TEXT | For local: full path to GGUF model file. For remote: model identifier supported by vectors.space | + +**Returns:** INTEGER - 1 on success + +**Notes:** +- When `provider` is `"local"`, the extension uses the built-in llama.cpp engine and verifies the model file exists +- When `provider` is anything other than `"local"`, the extension uses the [vectors.space](https://vectors.space) remote embedding service +- Remote embedding requires a free API key from [vectors.space](https://vectors.space) (set via `memory_set_apikey`) +- Settings are persisted in `dbmem_settings` table +- For local models, the embedding engine is initialized immediately +- **Automatic reindex**: If a model was previously configured and the new provider/model differs, all existing content is automatically re-embedded with the new model. File-based entries are re-read from disk; text-based entries are re-embedded from stored content. Errors on individual entries are silently skipped (best-effort) + +**Example:** +```sql +-- Local embedding model (uses built-in llama.cpp engine) +SELECT memory_set_model('local', '/path/to/nomic-embed-text-v1.5.Q8_0.gguf'); + +-- Remote embedding via vectors.space (requires free API key) +SELECT memory_set_model('openai', 'text-embedding-3-small'); +SELECT memory_set_apikey('your-vectorspace-api-key'); +``` + +--- + +#### `memory_set_apikey(key TEXT)` + +Sets the API key for the [vectors.space](https://vectors.space) remote embedding service. + +**Parameters:** +| Parameter | Type | Description | +|-----------|------|-------------| +| `key` | TEXT | API key obtained from [vectors.space](https://vectors.space) (free account) | + +**Returns:** INTEGER - 1 on success + +**Notes:** +- API key is stored in memory only, not persisted to disk +- Required when using any provider other than `"local"` +- Get a free API key by creating an account at [vectors.space](https://vectors.space) + +**Example:** +```sql +SELECT memory_set_apikey('your-vectorspace-api-key'); +``` + +--- + +#### `memory_set_option(key TEXT, value ANY)` + +Sets a configuration option. + +**Parameters:** +| Parameter | Type | Description | +|-----------|------|-------------| +| `key` | TEXT | Option name (see [Configuration Options](#configuration-options)) | +| `value` | ANY | Option value (type depends on the option) | + +**Returns:** INTEGER - 1 on success + +**Example:** +```sql +-- Set maximum tokens per chunk +SELECT memory_set_option('max_tokens', 512); + +-- Enable engine warmup +SELECT memory_set_option('engine_warmup', 1); + +-- Set minimum score threshold +SELECT memory_set_option('min_score', 0.75); +``` + +--- + +#### `memory_get_option(key TEXT)` + +Retrieves a configuration option value. + +**Parameters:** +| Parameter | Type | Description | +|-----------|------|-------------| +| `key` | TEXT | Option name | + +**Returns:** ANY - Option value, or NULL if not set + +**Example:** +```sql +SELECT memory_get_option('max_tokens'); +-- Returns: 400 + +SELECT memory_get_option('provider'); +-- Returns: "local" +``` + +--- + +### Memory Management Functions + +#### `memory_add_text(content TEXT [, context TEXT])` + +Syncs text content to memory. Duplicate content (same hash) is skipped automatically. + +**Parameters:** +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `content` | TEXT | Yes | Text content to store and index | +| `context` | TEXT | No | Optional context label for grouping memories | + +**Returns:** INTEGER - 1 on success + +**Notes:** +- Content is chunked based on `max_tokens` and `overlay_tokens` settings +- Each chunk is embedded and stored in `dbmem_vault` +- Content hash prevents duplicate storage — calling with the same content is a no-op +- Runs inside a SAVEPOINT transaction (see [Sync Behavior](#sync-behavior)) +- Sets `created_at` timestamp automatically + +**Example:** +```sql +-- Add text without context +SELECT memory_add_text('SQLite is a C-language library that implements a small, fast, self-contained SQL database engine.'); + +-- Add text with context +SELECT memory_add_text('Important meeting notes from 2024-01-15...', 'meetings'); +``` + +--- + +#### `memory_add_file(path TEXT [, context TEXT])` + +Syncs a file to memory. Unchanged files are skipped; modified files are atomically replaced. + +**Parameters:** +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `path` | TEXT | Yes | Full path to the file | +| `context` | TEXT | No | Optional context label for grouping memories | + +**Returns:** INTEGER - 1 on success + +**Notes:** +- Only processes files matching configured extensions (default: `md,mdx`) +- File path is stored in `dbmem_content.path` +- If the file was previously indexed with different content, the old entry (chunks, embeddings, FTS) is deleted and new content is reindexed — all within a single SAVEPOINT transaction (see [Sync Behavior](#sync-behavior)) +- Not available when compiled with `DBMEM_OMIT_IO` + +**Example:** +```sql +SELECT memory_add_file('/docs/readme.md'); +SELECT memory_add_file('/docs/api.md', 'documentation'); +``` + +--- + +#### `memory_add_directory(path TEXT [, context TEXT])` + +Synchronizes a directory with memory. Adds new files, reindexes modified files, and removes entries for deleted files. + +**Parameters:** +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `path` | TEXT | Yes | Full path to the directory | +| `context` | TEXT | No | Optional context label applied to all files | + +**Returns:** INTEGER - Number of new files processed + +**Notes:** +- Recursively scans subdirectories +- Only processes files matching configured extensions +- **Phase 1 — Cleanup**: Removes entries for files that no longer exist on disk +- **Phase 2 — Scan**: Processes all matching files: + - **New files** are chunked, embedded, and added to the index + - **Unchanged files** are skipped (content hash match) + - **Modified files** have their old entries atomically replaced with new content +- Each file is processed inside its own SAVEPOINT transaction (see [Sync Behavior](#sync-behavior)) +- Safe to call repeatedly — only changed content triggers embedding computation +- Not available when compiled with `DBMEM_OMIT_IO` + +**Example:** +```sql +SELECT memory_add_directory('/path/to/docs'); +-- Returns: 42 (number of new files processed) + +SELECT memory_add_directory('/project/notes', 'project-notes'); + +-- Safe to call again — unchanged files are skipped +SELECT memory_add_directory('/path/to/docs'); +-- Returns: 0 (nothing changed) +``` + +--- + +### Deletion Functions + +#### `memory_delete(hash INTEGER)` + +Deletes a specific memory by its hash. + +**Parameters:** +| Parameter | Type | Description | +|-----------|------|-------------| +| `hash` | INTEGER | The hash identifier of the memory to delete | + +**Returns:** INTEGER - Number of content entries deleted (0 or 1) + +**Notes:** +- Atomically deletes from `dbmem_content`, `dbmem_vault`, and `dbmem_vault_fts` +- Uses SAVEPOINT transaction for atomicity +- Hash can be obtained from `dbmem_content` table or search results + +**Example:** +```sql +-- Get hash from content table +SELECT hash FROM dbmem_content WHERE path LIKE '%readme%'; + +-- Delete by hash +SELECT memory_delete(1234567890); +``` + +--- + +#### `memory_delete_context(context TEXT)` + +Deletes all memories with a specific context. + +**Parameters:** +| Parameter | Type | Description | +|-----------|------|-------------| +| `context` | TEXT | The context label to match | + +**Returns:** INTEGER - Number of content entries deleted + +**Notes:** +- Deletes all entries where `context` matches exactly +- Cascades to chunks and FTS entries + +**Example:** +```sql +-- Delete all memories with context 'meetings' +SELECT memory_delete_context('meetings'); +-- Returns: 15 +``` + +--- + +#### `memory_clear()` + +Deletes all memories from the database. + +**Parameters:** None + +**Returns:** INTEGER - 1 on success + +**Notes:** +- Clears `dbmem_content`, `dbmem_vault`, and `dbmem_vault_fts` +- Does not delete settings from `dbmem_settings` +- Does not clear the embedding cache (`dbmem_cache`) +- Uses SAVEPOINT transaction for atomicity + +**Example:** +```sql +SELECT memory_clear(); +``` + +--- + +#### `memory_cache_clear([provider TEXT, model TEXT])` + +Clears the embedding cache. + +**Parameters:** +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `provider` | TEXT | No | Provider name to clear cache for | +| `model` | TEXT | No | Model name to clear cache for | + +**Returns:** INTEGER - Number of cache entries deleted + +**Notes:** +- With 0 arguments: clears the entire embedding cache +- With 2 arguments: clears cache entries for a specific provider/model combination +- The embedding cache stores computed embeddings keyed by (text hash, provider, model) to avoid redundant computation +- Safe to call at any time — does not affect stored memories + +**Example:** +```sql +-- Clear entire cache +SELECT memory_cache_clear(); + +-- Clear cache for a specific provider/model +SELECT memory_cache_clear('openai', 'text-embedding-3-small'); +``` + +--- + +### Sync Functions + +Require [sqlite-sync](https://github.com/sqliteai/sqlite-sync) to be loaded before use. + +#### `memory_enable_sync([context TEXT, ...])` + +Enables CRDT-based synchronization for `dbmem_content` via sqlite-sync. Uses the CLS algorithm with block-level LWW on the `value` column for fine-grained conflict resolution. + +**Parameters:** Zero or more TEXT context names. If no arguments are given, all memory is synced. If one or more context names are provided, only rows matching those contexts are synced. + +**Returns:** INTEGER - 1 on success + +**Notes:** +- Requires sqlite-sync to be loaded; returns an error otherwise +- Idempotent: safe to call multiple times — each call is a full reconfiguration +- With no arguments, any previously-set context filter is cleared (sync all) +- With arguments, sets a row-level filter: only the specified contexts are replicated +- Block-level LWW on `value` enables line-level conflict resolution for text content +- All other columns use the default CLS algorithm + +**Example:** +```sql +-- Sync all memory +SELECT memory_enable_sync(); + +-- Sync only specific contexts +SELECT memory_enable_sync('conversation', 'project-docs'); +``` + +--- + +#### `memory_disable_sync()` + +Removes synchronization infrastructure from `dbmem_content`, disabling all replication. The table data is preserved. + +**Parameters:** None + +**Returns:** INTEGER - 1 on success + +**Notes:** +- Requires sqlite-sync to be loaded; returns an error otherwise +- Safe to call even if sync was never enabled + +**Example:** +```sql +SELECT memory_disable_sync(); +``` + +--- + +### `memory_search` + +A virtual table for performing hybrid semantic search. + +**Query Format:** +```sql +SELECT * FROM memory_search WHERE query = 'search text'; +``` + +**Hidden filter columns (used in WHERE):** +| Column | Type | Required | Description | +|--------|------|----------|-------------| +| `query` | TEXT | Yes | The search query | +| `max_entries` | INTEGER | No | Override `max_results` setting for this query only | +| `context` | TEXT | No | Restrict results to a specific context label | + +**Output columns:** +| Column | Type | Description | +|--------|------|-------------| +| `hash` | INTEGER | Content hash identifier | +| `seq` | INTEGER | Chunk sequence number within the document (0-based) | +| `ranking` | REAL | Combined similarity score (0.0 - 1.0) | +| `path` | TEXT | Source file path or generated UUID for text content | +| `snippet` | TEXT | Text snippet from the matching chunk | + +**Notes:** +- Requires sqlite-vector extension loaded first +- Performs hybrid search combining vector similarity and FTS5 +- Results are ranked by combined score +- Limited by `max_results` setting (default: 20), overridable per-query with `max_entries` +- Filtered by `min_score` setting (default: 0.7) +- Updates `last_accessed` timestamp if `update_access` is enabled + +**Example:** +```sql +-- Basic search +SELECT path, snippet, ranking FROM memory_search WHERE query = 'database indexing strategies'; + +-- Search with ranking filter +SELECT path, snippet, ranking +FROM memory_search +WHERE query = 'how to optimize queries' +AND ranking > 0.8; + +-- Restrict to a specific context +SELECT path, snippet, ranking +FROM memory_search +WHERE query = 'meeting action items' +AND context = 'meetings'; + +-- Override result limit for this query only +SELECT path, snippet, ranking +FROM memory_search +WHERE query = 'architecture overview' +AND max_entries = 5; + +-- Get the chunk sequence number (useful for reconstructing document order) +SELECT path, seq, snippet, ranking +FROM memory_search +WHERE query = 'setup steps'; +``` + +--- + +## C API + +In addition to the SQL interface, sqlite-memory exposes a C API for embedding custom providers directly from application code. + +### `sqlite3_memory_register_provider` + +```c +int sqlite3_memory_register_provider( + sqlite3 *db, + const char *provider_name, + const dbmem_provider_t *provider +); +``` + +Registers a custom embedding engine for a specific database connection. Once registered, calling `memory_set_model(provider_name, model)` from SQL will use your engine instead of the built-in local or remote engines. + +**Parameters:** +| Parameter | Type | Description | +|-----------|------|-------------| +| `db` | `sqlite3 *` | The database connection to register the provider on | +| `provider_name` | `const char *` | Name used to activate the provider via `memory_set_model()` | +| `provider` | `const dbmem_provider_t *` | Pointer to a struct containing the engine callbacks | + +**Returns:** `SQLITE_OK` on success, or a SQLite error code. + +**`dbmem_provider_t` struct:** +```c +typedef struct { + // Called when memory_set_model(provider_name, model) is executed. + // api_key is the value set via memory_set_apikey() (may be NULL). + // xdata is the user pointer from this struct. + // Return an opaque engine pointer on success, or NULL on error (fill err_msg). + void *(*init)(const char *model, const char *api_key, void *xdata, char err_msg[1024]); + + // Compute the embedding for the given text. + // Return 0 on success, non-zero on error. + int (*compute)(void *engine, const char *text, int text_len, void *xdata, dbmem_embedding_result_t *result); + + // Free the engine. Called on context teardown or when the model changes. + // May be NULL if no cleanup is needed. + void (*free)(void *engine, void *xdata); + + // Optional user-supplied pointer passed to all three callbacks. + void *xdata; +} dbmem_provider_t; +``` + +**`dbmem_embedding_result_t` struct:** +```c +typedef struct { + int n_tokens; // Number of processed tokens (0 if unknown) + bool truncated; // True when the input was truncated before embedding + int n_embd; // Embedding dimension + float *embedding; // Embedding vector (engine-owned, valid until next call or free) +} dbmem_embedding_result_t; +``` + +**Notes:** +- Works regardless of `DBMEM_OMIT_LOCAL_ENGINE` / `DBMEM_OMIT_REMOTE_ENGINE` compile flags +- The `embedding` buffer in `dbmem_embedding_result_t` must remain valid until the next `compute` call or `free` — it is engine-owned, not copied by the caller +- `n_tokens` is metadata about the processed input when the engine can provide it; `truncated` is a boolean flag, not a truncated-token count +- Only one custom provider can be registered per connection at a time; registering again replaces the previous one +- The provider struct is copied by value; the caller does not need to keep it alive after registration + +**Example:** +```c +#include "sqlite-memory.h" + +typedef struct { int dimension; } MyEngine; + +static void *my_init(const char *model, const char *api_key, void *xdata, char err_msg[1024]) { + MyEngine *e = malloc(sizeof(MyEngine)); + e->dimension = 384; + return e; +} + +static int my_compute(void *engine, const char *text, int text_len, void *xdata, + dbmem_embedding_result_t *result) { + MyEngine *e = (MyEngine *)engine; + static float vec[384]; + // ... fill vec with your embedding ... + result->n_embd = e->dimension; + result->n_tokens = text_len / 4; + result->truncated = false; + result->embedding = vec; + return 0; +} + +static void my_free(void *engine, void *xdata) { + free(engine); +} + +// Register before using the database +dbmem_provider_t provider = { + .init = my_init, + .compute = my_compute, + .free = my_free, + .xdata = NULL, +}; +sqlite3_memory_register_provider(db, "my-engine", &provider); + +// Then from SQL: +// SELECT memory_set_model('my-engine', 'my-model-name'); +// SELECT memory_add_text('some text to embed'); +``` + +--- + +## Configuration Options + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `provider` | TEXT | - | Embedding provider (`"local"` for llama.cpp, otherwise vectors.space) | +| `model` | TEXT | - | Model path (local) or identifier (remote) | +| `dimension` | INTEGER | - | Embedding dimension (auto-detected) | +| `max_tokens` | INTEGER | 400 | Maximum tokens per chunk | +| `overlay_tokens` | INTEGER | 80 | Token overlap between consecutive chunks | +| `chars_per_tokens` | INTEGER | 4 | Estimated characters per token | +| `save_content` | INTEGER | 1 | Store original content (1=yes, 0=no) | +| `skip_semantic` | INTEGER | 0 | Skip markdown parsing, treat as raw text | +| `skip_html` | INTEGER | 1 | Strip HTML tags when parsing | +| `extensions` | TEXT | "md,mdx" | Comma-separated file extensions to process | +| `engine_warmup` | INTEGER | 0 | Warm up engine on model load (compiles GPU shaders) | +| `max_results` | INTEGER | 20 | Maximum search results | +| `fts_enabled` | INTEGER | 1 | Enable FTS5 in hybrid search | +| `vector_weight` | REAL | 0.5 | Weight for vector similarity in scoring | +| `text_weight` | REAL | 0.5 | Weight for FTS in scoring | +| `min_score` | REAL | 0.7 | Minimum score threshold for results | +| `update_access` | INTEGER | 1 | Update last_accessed on search | +| `embedding_cache` | INTEGER | 1 | Cache embeddings to avoid redundant computation | +| `cache_max_entries` | INTEGER | 0 | Max cache entries (0 = no limit). When exceeded, oldest entries are evicted | +| `search_oversample` | INTEGER | 0 | Search oversampling multiplier (0 = no oversampling). When set, retrieves N * multiplier candidates from each index before merging down to N final results | + +--- + +## Timestamps + +The extension tracks two timestamps for each memory: + +### `created_at` + +- Set automatically when content is added via `memory_add_text`, `memory_add_file`, or `memory_add_directory` +- Stored as Unix timestamp (seconds since 1970-01-01 00:00:00 UTC) +- Never updated after initial creation + +### `last_accessed` + +- Updated when content appears in search results (if `update_access=1`) +- Stored as Unix timestamp (seconds since 1970-01-01 00:00:00 UTC) +- Can be disabled by setting `update_access` to 0 + +**Displaying timestamps in local time:** +```sql +SELECT + path, + datetime(created_at, 'unixepoch', 'localtime') as created, + datetime(last_accessed, 'unixepoch', 'localtime') as accessed +FROM dbmem_content; +``` + +--- + +## Examples + +### Complete Setup and Usage + +```sql +-- Check version +SELECT memory_version(); + +-- Configure local embedding model +SELECT memory_set_model('local', '/models/nomic-embed-text-v1.5.Q8_0.gguf'); + +-- Configure options +SELECT memory_set_option('max_tokens', 512); +SELECT memory_set_option('min_score', 0.75); + +-- Add content +SELECT memory_add_text('SQLite is a C library that provides a lightweight disk-based database.', 'sqlite-docs'); +SELECT memory_add_directory('/docs/sqlite', 'sqlite-docs'); + +-- Search +SELECT path, snippet, ranking +FROM memory_search +WHERE query = 'how does SQLite store data on disk'; + +-- View all memories with timestamps +SELECT + hash, + path, + context, + datetime(created_at, 'unixepoch', 'localtime') as created, + datetime(last_accessed, 'unixepoch', 'localtime') as last_used +FROM dbmem_content +ORDER BY last_accessed DESC; + +-- Delete by context +SELECT memory_delete_context('old-docs'); + +-- Clear all +SELECT memory_clear(); +``` + +### Working with Contexts + +```sql +-- Add memories with different contexts +SELECT memory_add_text('Meeting notes...', 'meetings'); +SELECT memory_add_text('API documentation...', 'api-docs'); +SELECT memory_add_text('Tutorial content...', 'tutorials'); + +-- Search within a context +SELECT * FROM memory_search +WHERE query = 'authentication' +AND context = 'api-docs'; + +-- List all contexts +SELECT context, COUNT(*) as count +FROM dbmem_content +GROUP BY context; + +-- Delete a context +SELECT memory_delete_context('old-meetings'); +``` + +### Memory Statistics + +```sql +-- Total memories and chunks +SELECT + (SELECT COUNT(*) FROM dbmem_content) as total_memories, + (SELECT COUNT(*) FROM dbmem_vault) as total_chunks; + +-- Storage usage +SELECT + SUM(length(embedding)) as embedding_bytes, + SUM(length) as content_bytes +FROM dbmem_vault; + +-- Memories by context +SELECT + COALESCE(context, '(none)') as context, + COUNT(*) as count +FROM dbmem_content +GROUP BY context; + +-- Recently accessed +SELECT path, datetime(last_accessed, 'unixepoch', 'localtime') as last_used +FROM dbmem_content +WHERE last_accessed > 0 +ORDER BY last_accessed DESC +LIMIT 10; + +-- Tokens consumed and truncation per context +-- (n_tokens / truncated were added in schema version 2) +SELECT + COALESCE(c.context, '(none)') as context, + SUM(v.n_tokens) as tokens_processed, + SUM(v.truncated) as truncated_chunks +FROM dbmem_vault v +JOIN dbmem_content c ON c.hash = v.hash +GROUP BY c.context; + +-- Chunks that the embedding model truncated on input +SELECT hash, seq, length, n_tokens +FROM dbmem_vault +WHERE truncated = 1; +``` + +--- + +## Compilation Options + +| Option | Description | +|--------|-------------| +| `DBMEM_OMIT_IO` | Omit file/directory functions (for WASM) | +| `DBMEM_OMIT_LOCAL_ENGINE` | Omit llama.cpp local engine (for remote-only builds) | +| `DBMEM_OMIT_REMOTE_ENGINE` | Omit vectors.space remote engine (for local-only builds) | +| `SQLITE_CORE` | Compile as part of SQLite core (not as loadable extension) | + +--- + +## Error Handling + +All functions return an error if: +- Required parameters are missing or of wrong type +- Database operations fail +- Model file not found (for local provider) +- Embedding dimension mismatch + +Errors can be caught using standard SQLite error handling mechanisms. + +```sql +-- Example error handling in application code +SELECT memory_add_text(123); -- Error: expects TEXT parameter +SELECT memory_delete('abc'); -- Error: expects INTEGER parameter +``` diff --git a/sqlite-cloud/sqlite-ai/sqlite-memory-cli.md b/sqlite-cloud/sqlite-ai/sqlite-memory-cli.md new file mode 100644 index 0000000..cd0ab8a --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-memory-cli.md @@ -0,0 +1,376 @@ +--- +title: "SQLite-Memory CLI" +description: "sqlmem command-line workflow and examples for managing sqlite-memory projects." +category: platform +status: publish +slug: sqlite-memory-cli +--- + +## sqlmem + +`sqlmem` manages SQLite Memory databases backed by Markdown sources. +The CLI handles project config, optional PDF conversion cache, watch mode, and MCP. Markdown parsing, chunking, embedding, schema, FTS, and vector search stay inside the `sqlite-memory` extension. + + +## Quick Start + +```sh +sqlmem init --model /path/to/nomic-embed-text-v1.5.Q8_0.gguf +sqlmem add ./docs +sqlmem search -q "sqlite vector search" --limit 5 +``` + +Remote embeddings use vectors.space when an API key is present: + +```sh +sqlmem init --api-key "$sqlmem_API_KEY" --model text-embedding-3-small +``` + +API key precedence is: CLI flag, `sqlmem_API_KEY`, config. + +## Config + +`sqlmem init` creates `.sqlmem.json` in the project root. Edit it manually or use: + +```sh +sqlmem config +sqlmem config set options.max_results 10 +``` + +If no config is found, commands fail with: + +```text +No .sqlmem.json found. Run `sqlmem init` first. +``` + +## PDF + +PDF indexing is disabled by default because it needs a separate conversion/OCR step. Enable it explicitly before adding PDF files: + +```sh +sqlmem config set pdf.enabled true +``` + +PDFs are then converted to Markdown before indexing. The default converter shells out to `glm-ocr` and stores cache entries under the global PDF cache: + +```text +// + source.json + content.md +``` + +Override with `--pdf-cache-dir` or `sqlmem_PDF_CACHE_DIR`. + +## Commands + +```sh +sqlmem add ./docs +sqlmem add ./file.pdf +sqlmem add -s ./docs -s ./file.pdf +sqlmem search -q "query" --json +sqlmem watch +sqlmem mcp --transport stdio +sqlmem mcp --transport http --addr 127.0.0.1:8765 +sqlmem status +sqlmem clear +sqlmem reindex +sqlmem remove ./docs +sqlmem reset +``` + +Running `sqlmem` without arguments opens an interactive prompt with command history and arrow-key navigation. + + +## sqlmem Examples + +Practical examples for common `sqlmem` workflows. + +## Initialize A Project + +Create `.sqlmem.json`, create the SQLite database, and configure the embedding model. + +```sh +sqlmem init --model /models/nomic-embed-text-v1.5.Q8_0.gguf +``` + +Use a custom extension cache directory: + +```sh +sqlmem init \ + --extensions-dir ~/.cache/sqlmem/extensions \ + --model /models/nomic-embed-text-v1.5.Q8_0.gguf +``` + +## Use Remote Embeddings + +When an API key is present, `sqlmem` configures sqlite-memory for remote embeddings. + +```sh +sqlmem init \ + --api-key "$sqlmem_API_KEY" \ + --model text-embedding-3-small +``` + +You can also set the API key through the environment: + +```sh +export sqlmem_API_KEY="..." +sqlmem init --model text-embedding-3-small +``` + +Precedence is: + +1. `--api-key` +2. `sqlmem_API_KEY` +3. `.sqlmem.json` + +## Add Sources + +Add a directory: + +```sh +sqlmem add ./docs +``` + +Add one Markdown file: + +```sh +sqlmem add ./README.md +``` + +Add multiple sources in one command: + +```sh +sqlmem add ./docs ./notes/project.md +``` + +Use repeated `--source` flags: + +```sh +sqlmem add -s ./docs -s ./notes/project.md +``` + +Attach a context label to added content: + +```sh +sqlmem add ./docs --context product-docs +``` + +## Add PDFs + +PDF indexing is disabled by default because it requires a separate conversion/OCR step. Enable it explicitly first: + +```sh +sqlmem config set pdf.enabled true +``` + +PDF files are then converted to Markdown before indexing. + +```sh +sqlmem add ./papers/sqlite-memory-overview.pdf +``` + +Use a custom PDF cache directory: + +```sh +sqlmem --pdf-cache-dir ~/.cache/sqlmem/pdf add ./papers/report.pdf +``` + +Disable PDF support again: + +```sh +sqlmem config set pdf.enabled false +``` + +## Search + +Search with a positional query: + +```sh +sqlmem search "hybrid search with sqlite" +``` + +Search with flags: + +```sh +sqlmem search -q "embedding cache behavior" --limit 5 +``` + +Return JSON for scripts: + +```sh +sqlmem search -q "vector extension load order" --limit 10 --json +``` + +Pipe JSON to `jq`: + +```sh +sqlmem search -q "pdf cache" --json | jq '.[].path' +``` + +## Watch Sources + +Watch sources already stored in `.sqlmem.json`: + +```sh +sqlmem watch +``` + +Watch explicit paths for the current session: + +```sh +sqlmem watch ./docs ./notes/project.md +``` + +Use a shorter debounce window: + +```sh +sqlmem watch --debounce 200ms +``` + +## Inspect Status + +Show database path, source count, embedding selection, PDF cache, and indexed counts: + +```sh +sqlmem status +``` + +Show the full configuration: + +```sh +sqlmem config +``` + +## Edit Configuration + +Set the default search limit: + +```sh +sqlmem config set options.max_results 10 +``` + +Lower the minimum score: + +```sh +sqlmem config set options.min_score 0.65 +``` + +Disable embedding cache: + +```sh +sqlmem config set options.embedding_cache false +``` + +Set supported indexed file extensions: + +```sh +sqlmem config set options.extensions "md,mdx,txt" +``` + +Opt into reStructuredText explicitly: + +```sh +sqlmem config set options.extensions "md,mdx,txt,rst" +``` + +## MCP Server + +Start the MCP server over stdio: + +```sh +sqlmem mcp --transport stdio +``` + +Start the MCP server over HTTP: + +```sh +sqlmem mcp --transport http --addr 127.0.0.1:8765 +``` + +Available MCP tools: + +```text +memory_search +memory_add_file +memory_add_directory +memory_add_text +memory_clear +memory_delete +memory_delete_context +memory_reindex +memory_status +``` + +## Remove Sources + +Remove a configured source from `.sqlmem.json`: + +```sh +sqlmem remove ./docs +``` + +## Reindex Or Clear + +Reindex all stored memory: + +```sh +sqlmem reindex +``` + +Clear all memory content: + +```sh +sqlmem clear +``` + +Reset the project by deleting the configured database and `.sqlmem.json`: + +```sh +sqlmem reset +``` + +## Interactive Mode + +Run without a subcommand to open the interactive prompt: + +```sh +sqlmem +``` + +Inside the prompt: + +```text +sqlmem> status +sqlmem> search "release notes" +sqlmem> add ./notes +sqlmem> quit +``` + +Command history is available with the up and down arrow keys. + +## Script Examples + +Fail if no results are returned: + +```sh +results="$(sqlmem search -q "database migration" --json)" +count="$(printf '%s' "$results" | jq 'length')" +test "$count" -gt 0 +``` + +Index all Markdown files changed in the current Git branch: + +```sh +git diff --name-only main...HEAD -- '*.md' '*.mdx' | +while IFS= read -r file; do + [ -f "$file" ] && sqlmem add "$file" +done +``` + +Create a project-local database name: + +```sh +sqlmem init --model /models/nomic-embed-text-v1.5.Q8_0.gguf +sqlmem config set database ".cache/project-memory.sqlite" +``` diff --git a/sqlite-cloud/sqlite-ai/sqlite-memory-examples.md b/sqlite-cloud/sqlite-ai/sqlite-memory-examples.md new file mode 100644 index 0000000..fb01212 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-memory-examples.md @@ -0,0 +1,371 @@ +--- +title: "SQLite-Memory Examples" +description: "Examples for building AI agents with persistent memory and syncing memory across agents." +category: platform +status: publish +slug: sqlite-memory-examples +--- + +## Intelligent Sync + +All `memory_add_*` functions use content-hash change detection to avoid redundant work: + +- **`memory_add_text`**: Computes a hash of the content. If the same content was already indexed, it is skipped entirely. No duplicate embeddings are ever created. +- **`memory_add_file`**: Reads the file and hashes its content. If the file was previously indexed with different content, the old entry (chunks, embeddings, FTS) is atomically replaced. Unchanged files are skipped. +- **`memory_add_directory`**: Performs a full two-phase sync: + 1. **Cleanup**: Removes database entries for files that no longer exist on disk + 2. **Scan**: Recursively processes all matching files - adding new ones, replacing modified ones, and skipping unchanged ones + +`memory_add_text()` and `memory_add_file()` each run inside a SQLite SAVEPOINT transaction. `memory_add_directory()` performs its cleanup pass transactionally and then processes each file in its own transaction. If one file fails, that file rolls back cleanly and previously-committed files remain valid; there are no partially-indexed rows or orphaned chunk/FTS entries for the failed file. + +This makes all sync functions safe to call repeatedly - for example, on a cron schedule or at agent startup - with minimal overhead. + +## Agent Memory Sync + +Multiple agents can share and merge knowledge without any coordination. Each agent works independently with its own local SQLite database, syncing through a shared [SQLiteCloud](https://sqlitecloud.io/) managed database when connectivity is available. + +Enable sync on a database connection before ingesting content: + +```sql +-- Enable CRDT sync (optionally scoped to a specific context) +SELECT memory_enable_sync(); -- sync all memory +SELECT memory_enable_sync('project-x'); -- sync only the 'project-x' context + +-- Connect to the shared cloud database +SELECT cloudsync_network_init('your-managed-database-id'); +SELECT cloudsync_network_set_apikey('your-api-key'); + +-- Ingest content normally — CRDT tracks every write +SELECT memory_add_text('Agent A findings...', 'research'); + +-- Push local changes and pull remote ones (call twice for full bidirectional exchange) +SELECT cloudsync_network_sync(500, 3); +SELECT cloudsync_network_sync(500, 3); + +-- Generate embeddings for any content received from other agents +SELECT memory_reindex(); +``` + +Each piece of text added to the database is parsed into chunks and tracked by a [block-level LWW CRDT algorithm](https://github.com/sqliteai/sqlite-sync?tab=readme-ov-file#block-level-lww), which merges line-level changes from concurrent agents without conflicts. Only the `dbmem_content` table is synced — embeddings are always generated locally after receiving new content. + +### Why This Matters for AI Systems + +The combination of local-first memory and CRDT sync enables agent architectures that are not possible with centralized databases: + +- **No single point of failure** — each agent has a complete, queryable copy of shared memory +- **Offline-capable** — agents ingest and search without network access; sync catches up when connectivity returns +- **Selective sharing** — `memory_enable_sync('context')` limits sync to a named context, so agents can keep private memory separate from shared memory +- **Scales to many agents** — agents running on different nodes accumulate knowledge in parallel and merge into a single consistent corpus without coordination + +### Working Example + +[`test/sync/`](https://github.com/sqliteai/sqlite-memory/tree/main/test/sync) contains a full integration test that walks through the entire flow: + +- Agent A indexes knowledge about the James Webb Space Telescope +- Agent B indexes knowledge about the Great Barrier Reef +- After sync, **both agents can answer questions about both topics** — knowledge each agent never directly indexed + +See [`test/sync/README.md`](https://github.com/sqliteai/sqlite-memory/tree/main/test/sync) for the complete integration test flow and SQLite Cloud account configuration. + +## Use Cases + +- **AI Assistants**: Maintain conversation history and user preferences +- **Documentation Search**: Semantic search over markdown documentation +- **Knowledge Bases**: Build searchable knowledge repositories +- **Note-Taking Apps**: Find notes by meaning, not just keywords +- **Code Understanding**: Index and search code documentation +- **Personal Memory**: Store and retrieve personal knowledge + +## sqlmem Examples + +Practical examples for common `sqlmem` workflows. + +## Initialize A Project + +Create `.sqlmem.json`, create the SQLite database, and configure the embedding model. + +```sh +sqlmem init --model /models/nomic-embed-text-v1.5.Q8_0.gguf +``` + +Use a custom extension cache directory: + +```sh +sqlmem init \ + --extensions-dir ~/.cache/sqlmem/extensions \ + --model /models/nomic-embed-text-v1.5.Q8_0.gguf +``` + +## Use Remote Embeddings + +When an API key is present, `sqlmem` configures sqlite-memory for remote embeddings. + +```sh +sqlmem init \ + --api-key "$sqlmem_API_KEY" \ + --model text-embedding-3-small +``` + +You can also set the API key through the environment: + +```sh +export sqlmem_API_KEY="..." +sqlmem init --model text-embedding-3-small +``` + +Precedence is: + +1. `--api-key` +2. `sqlmem_API_KEY` +3. `.sqlmem.json` + +## Add Sources + +Add a directory: + +```sh +sqlmem add ./docs +``` + +Add one Markdown file: + +```sh +sqlmem add ./README.md +``` + +Add multiple sources in one command: + +```sh +sqlmem add ./docs ./notes/project.md +``` + +Use repeated `--source` flags: + +```sh +sqlmem add -s ./docs -s ./notes/project.md +``` + +Attach a context label to added content: + +```sh +sqlmem add ./docs --context product-docs +``` + +## Add PDFs + +PDF indexing is disabled by default because it requires a separate conversion/OCR step. Enable it explicitly first: + +```sh +sqlmem config set pdf.enabled true +``` + +PDF files are then converted to Markdown before indexing. + +```sh +sqlmem add ./papers/sqlite-memory-overview.pdf +``` + +Use a custom PDF cache directory: + +```sh +sqlmem --pdf-cache-dir ~/.cache/sqlmem/pdf add ./papers/report.pdf +``` + +Disable PDF support again: + +```sh +sqlmem config set pdf.enabled false +``` + +## Search + +Search with a positional query: + +```sh +sqlmem search "hybrid search with sqlite" +``` + +Search with flags: + +```sh +sqlmem search -q "embedding cache behavior" --limit 5 +``` + +Return JSON for scripts: + +```sh +sqlmem search -q "vector extension load order" --limit 10 --json +``` + +Pipe JSON to `jq`: + +```sh +sqlmem search -q "pdf cache" --json | jq '.[].path' +``` + +## Watch Sources + +Watch sources already stored in `.sqlmem.json`: + +```sh +sqlmem watch +``` + +Watch explicit paths for the current session: + +```sh +sqlmem watch ./docs ./notes/project.md +``` + +Use a shorter debounce window: + +```sh +sqlmem watch --debounce 200ms +``` + +## Inspect Status + +Show database path, source count, embedding selection, PDF cache, and indexed counts: + +```sh +sqlmem status +``` + +Show the full configuration: + +```sh +sqlmem config +``` + +## Edit Configuration + +Set the default search limit: + +```sh +sqlmem config set options.max_results 10 +``` + +Lower the minimum score: + +```sh +sqlmem config set options.min_score 0.65 +``` + +Disable embedding cache: + +```sh +sqlmem config set options.embedding_cache false +``` + +Set supported indexed file extensions: + +```sh +sqlmem config set options.extensions "md,mdx,txt" +``` + +Opt into reStructuredText explicitly: + +```sh +sqlmem config set options.extensions "md,mdx,txt,rst" +``` + +## MCP Server + +Start the MCP server over stdio: + +```sh +sqlmem mcp --transport stdio +``` + +Start the MCP server over HTTP: + +```sh +sqlmem mcp --transport http --addr 127.0.0.1:8765 +``` + +Available MCP tools: + +```text +memory_search +memory_add_file +memory_add_directory +memory_add_text +memory_clear +memory_delete +memory_delete_context +memory_reindex +memory_status +``` + +## Remove Sources + +Remove a configured source from `.sqlmem.json`: + +```sh +sqlmem remove ./docs +``` + +## Reindex Or Clear + +Reindex all stored memory: + +```sh +sqlmem reindex +``` + +Clear all memory content: + +```sh +sqlmem clear +``` + +Reset the project by deleting the configured database and `.sqlmem.json`: + +```sh +sqlmem reset +``` + +## Interactive Mode + +Run without a subcommand to open the interactive prompt: + +```sh +sqlmem +``` + +Inside the prompt: + +```text +sqlmem> status +sqlmem> search "release notes" +sqlmem> add ./notes +sqlmem> quit +``` + +Command history is available with the up and down arrow keys. + +## Script Examples + +Fail if no results are returned: + +```sh +results="$(sqlmem search -q "database migration" --json)" +count="$(printf '%s' "$results" | jq 'length')" +test "$count" -gt 0 +``` + +Index all Markdown files changed in the current Git branch: + +```sh +git diff --name-only main...HEAD -- '*.md' '*.mdx' | +while IFS= read -r file; do + [ -f "$file" ] && sqlmem add "$file" +done +``` + +Create a project-local database name: + +```sh +sqlmem init --model /models/nomic-embed-text-v1.5.Q8_0.gguf +sqlmem config set database ".cache/project-memory.sqlite" +``` diff --git a/sqlite-cloud/sqlite-ai/sqlite-memory-getting-started.md b/sqlite-cloud/sqlite-ai/sqlite-memory-getting-started.md new file mode 100644 index 0000000..ef022ce --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-memory-getting-started.md @@ -0,0 +1,85 @@ +--- +title: "SQLite-Memory Getting Started" +description: "Configure sqlite-memory, load embeddings, ingest content, and run semantic memory search." +category: platform +status: publish +slug: sqlite-memory-getting-started +--- + +## Getting Started + +> [!IMPORTANT] +> Databases created with sqlite-memory versions earlier than `1.0.0` must be rebuilt before use with `1.0.0+`, because the internal schema changed. + +### Quick Start + +```sql +-- Configure embedding model (choose one): + +-- Option 1: Local embedding with llama.cpp (no internet required) +SELECT memory_set_model('local', '/path/to/nomic-embed-text-v1.5.Q8_0.gguf'); + +-- Option 2: Remote embedding via vectors.space (requires free API key from https://vectors.space) +-- The provider name 'openai' selects the vectors.space OpenAI-compatible endpoint. +-- SELECT memory_set_apikey('your-vectorspace-api-key'); +-- SELECT memory_set_model('openai', 'text-embedding-3-small'); + +-- Add some knowledge +SELECT memory_add_text('SQLite is a C-language library that implements a small, fast, +self-contained, high-reliability, full-featured, SQL database engine. SQLite is the +most used database engine in the world.', 'sqlite-docs'); + +SELECT memory_add_text('Vector databases store data as high-dimensional vectors, +enabling similarity search. They are essential for semantic search, recommendation +systems, and AI applications.', 'concepts'); + +-- Add an entire documentation directory +SELECT memory_add_directory('/path/to/docs', 'project-docs'); + +-- Search your memory semantically +SELECT path, snippet, ranking +FROM memory_search +WHERE query = 'how do databases store information efficiently'; + +-- Results ranked by semantic similarity + keyword matching +-- ┌──────────────┬─────────────────────────────────────┬─────────┐ +-- │ path │ snippet │ ranking │ +-- ├──────────────┼─────────────────────────────────────┼─────────┤ +-- │ (uuid) │ SQLite is a C-language library... │ 0.89 │ +-- │ (uuid) │ Vector databases store data as... │ 0.82 │ +-- └──────────────┴─────────────────────────────────────┴─────────┘ +``` + +### Example: Building an AI Agent with Memory + +```python +import sqlite3 + +## Connect to your memory database +conn = sqlite3.connect('agent_memory.db') + +## One-time setup +conn.execute("SELECT memory_set_model('local', './models/nomic-embed-text-v1.5.Q8_0.gguf')") + +## Store conversation context +def remember(content, context="conversation"): + conn.execute("SELECT memory_add_text(?, ?)", (content, context)) + conn.commit() + +## Retrieve relevant memories +def recall(query, min_score=0.7): + cursor = conn.execute(""" + SELECT snippet, ranking FROM memory_search + WHERE query = ? AND ranking > ? + ORDER BY ranking DESC + """, (query, min_score)) + return cursor.fetchall() + +## Use in your agent +remember("User prefers concise responses and uses Python primarily.") +remember("Project deadline is March 15th, focusing on API integration.") + +## Later, when the user asks about the project... +memories = recall("what's the project timeline") +## Returns relevant context about March 15th deadline +``` diff --git a/sqlite-cloud/sqlite-ai/sqlite-memory.md b/sqlite-cloud/sqlite-ai/sqlite-memory.md new file mode 100644 index 0000000..165b3bb --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-memory.md @@ -0,0 +1,75 @@ +--- +title: "SQLite-Memory" +description: "Persistent, searchable memory for AI agents using SQLite, vector search, FTS5, and markdown-aware chunking." +category: platform +status: publish +slug: sqlite-memory +--- + +A SQLite extension that gives AI agents persistent, searchable memory, optimized for markdown content. Features hybrid semantic search (vector similarity + FTS5), markdown-aware chunking, and local embedding via llama.cpp. + +Agent memory databases can be synchronized between agents using **offline-first technology** via [sqlite-sync](https://github.com/sqliteai/sqlite-sync). Each agent works independently and syncs when connected, making it ideal for distributed AI systems, edge deployments, and collaborative agent architectures. + +
    + + Installed by default in SQLite Cloud + + + GitHub: https://github.com/sqliteai/sqlite-memory + +
    + +## The Future of AI Agent Memory + +Modern AI agents need persistent, searchable memory to maintain context across conversations and tasks. Inspired by [OpenClaw's memory architecture](https://docs.openclaw.ai/concepts/memory), sqlite-memory implements what we believe will become the de facto standard for AI agent memory systems: **markdown files as the source of truth**. + +In this paradigm: +- **Markdown files** serve as human-readable, version-controllable knowledge bases +- **Embeddings** enable semantic understanding and retrieval +- **Hybrid search** combines the precision of full-text search with the intelligence of vector similarity + +sqlite-memory bridges these concepts, allowing any SQLite-powered application to ingest, store, and semantically search over knowledge bases. + +## Why sqlite-memory? + +### For AI Agent Developers + +- **Persistent Memory**: Give your agents long-term memory that survives restarts +- **Semantic Recall**: Retrieve relevant context based on meaning, not just keywords +- **Context Isolation**: Organize memories by context (projects, conversations, topics) +- **Local-First**: Run entirely on-device with local embedding models - no API costs, no latency, no data leaving your system + +### For Application Developers + +- **Zero Infrastructure**: No vector database servers to deploy - it's just SQLite +- **Single File**: Your entire knowledge base lives in one portable `.db` file +- **SQL Interface**: Query your semantic memory using familiar SQL +- **Embeddable**: Works anywhere SQLite works - mobile, desktop, edge, WASM + +### Technical Advantages + +- **Hybrid Search**: Combines vector similarity (cosine distance) with FTS5 full-text search for superior retrieval +- **Smart Chunking**: Markdown-aware parsing preserves semantic boundaries +- **Intelligent Sync**: Content-hash change detection skips unchanged files, atomically replaces modified ones, and cleans up deleted ones +- **Transactional Safety**: Text/file ingests run inside SAVEPOINT transactions, and directory sync uses transactional cleanup plus per-file transactional updates so failed files do not leave partial rows behind +- **Efficient Storage**: Binary embeddings with configurable dimensions +- **Embedding Cache**: Automatically caches computed embeddings, so re-indexing the same text skips redundant API calls and computation +- **Flexible Embedding**: Use local models (llama.cpp) or [vectors.space](https://vectors.space) remote API + +## Architecture + +``` +┌─────────────────────────────────────────────────────────────┐ +│ Your Application │ +├─────────────────────────────────────────────────────────────┤ +│ sqlite-memory │ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │ +│ │ Parser │ │ Embedding │ │ Hybrid Search │ │ +│ │ (md4c) │ │ (llama.cpp) │ │ (vector + FTS5) │ │ +│ └─────────────┘ └─────────────┘ └─────────────────────┘ │ +├─────────────────────────────────────────────────────────────┤ +│ sqlite-vector │ +├─────────────────────────────────────────────────────────────┤ +│ SQLite │ +└─────────────────────────────────────────────────────────────┘ +``` diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference.md b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference.md new file mode 100644 index 0000000..9d0886c --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference.md @@ -0,0 +1,698 @@ +--- +title: "Client API Reference" +description: "Reference for the SQLite Sync client runtime functions for configuration, filters, block-level LWW, helpers, schema changes, and networking." +category: platform +status: publish +slug: sqlite-sync-api-reference +--- + +This document provides a reference for the SQLite functions provided by the `sqlite-sync` extension. + +## Index + +- [Configuration Functions](#configuration-functions) + - [`cloudsync_init()`](#cloudsync_inittable_name-crdt_algo-init_flags) + - [`cloudsync_enable()`](#cloudsync_enabletable_name) + - [`cloudsync_disable()`](#cloudsync_disabletable_name) + - [`cloudsync_is_enabled()`](#cloudsync_is_enabledtable_name) + - [`cloudsync_set_filter()`](#cloudsync_set_filtertable_name-filter_expr) + - [`cloudsync_clear_filter()`](#cloudsync_clear_filtertable_name) + - [`cloudsync_cleanup()`](#cloudsync_cleanuptable_name) + - [`cloudsync_terminate()`](#cloudsync_terminate) +- [Block-Level LWW Functions](#block-level-lww-functions) + - [`cloudsync_set_column()`](#cloudsync_set_columntable_name-col_name-key-value) + - [`cloudsync_text_materialize()`](#cloudsync_text_materializetable_name-col_name-pk_values) +- [Helper Functions](#helper-functions) + - [`cloudsync_version()`](#cloudsync_version) + - [`cloudsync_siteid()`](#cloudsync_siteid) + - [`cloudsync_db_version()`](#cloudsync_db_version) + - [`cloudsync_uuid()`](#cloudsync_uuid) +- [Schema Alteration Functions](#schema-alteration-functions) + - [`cloudsync_begin_alter()`](#cloudsync_begin_altertable_name) + - [`cloudsync_commit_alter()`](#cloudsync_commit_altertable_name) +- [Network Functions](#network-functions) + - [`cloudsync_network_init()`](#cloudsync_network_initmanageddatabaseid) + - [`cloudsync_network_cleanup()`](#cloudsync_network_cleanup) + - [`cloudsync_network_set_token()`](#cloudsync_network_set_tokentoken) + - [`cloudsync_network_set_apikey()`](#cloudsync_network_set_apikeyapikey) + - [`cloudsync_network_send_changes()`](#cloudsync_network_send_changes) + - [`cloudsync_network_receive_changes()`](#cloudsync_network_receive_changesmax_chunks) + - [`cloudsync_network_check_changes()`](#cloudsync_network_check_changesmax_chunks) (deprecated) + - [`cloudsync_network_sync()`](#cloudsync_network_syncwait_ms-max_retries) + - [`cloudsync_network_reset_sync_version()`](#cloudsync_network_reset_sync_version) + - [`cloudsync_network_has_unsent_changes()`](#cloudsync_network_has_unsent_changes) + - [`cloudsync_network_logout()`](#cloudsync_network_logout) + +--- + +## Configuration Functions + +### `cloudsync_init(table_name, [crdt_algo], [init_flags])` + +**Description:** Initializes a table for `sqlite-sync` synchronization. This function is idempotent and needs to be called only once per table on each site; configurations are stored in the database and automatically loaded with the extension. + +Before initialization, `cloudsync_init` performs schema sanity checks to ensure compatibility with CRDT requirements and best practices. These checks include: +- Primary keys should not be auto-incrementing integers; GUIDs (UUIDs, ULIDs) are highly recommended to prevent multi-node collisions. +- All non-primary key `NOT NULL` columns must have a `DEFAULT` value. +- **Note:** Any write operation that includes a NULL value for a primary key column will be rejected with an error, even if SQLite would normally allow it due to a legacy behavior. + +**Schema Design Considerations:** + +When designing your database schema for SQLite Sync, follow these essential requirements: + +- **Primary Keys**: Use TEXT primary keys with `cloudsync_uuid()` for globally unique identifiers. Avoid auto-incrementing integers. +- **Column Constraints**: All NOT NULL columns (except primary keys) must have DEFAULT values to prevent synchronization errors. +- **UNIQUE Constraints**: In multi-tenant scenarios, use composite UNIQUE constraints (e.g., `UNIQUE(tenant_id, email)`) instead of global uniqueness. +- **Foreign Key Compatibility**: Be aware of potential conflicts during CRDT merge operations and RLS policy interactions. +- **Trigger Compatibility**: Triggers may cause duplicate operations or be called multiple times due to column-by-column processing. + +For comprehensive guidelines, see the [Database Schema Recommendations](/docs/sqlite-sync-best-practices). + +The function supports three overloads: +- `cloudsync_init(table_name)`: Uses the default 'cls' CRDT algorithm. +- `cloudsync_init(table_name, crdt_algo)`: Specifies a CRDT algorithm ('cls', 'dws', 'aws', 'gos'). +- `cloudsync_init(table_name, crdt_algo, init_flags)`: Specifies an algorithm and a bitmask of initialization flags to control which schema sanity checks are skipped. + +**Parameters:** + +- `table_name` (TEXT): The name of the table to initialize. +- `crdt_algo` (TEXT, optional): The CRDT algorithm to use. Can be `"cls"`, `"dws"`, `"aws"`, `"gos"`. Defaults to `"cls"`. +- `init_flags` (INTEGER, optional): A bitmask of flags that control initialization behavior. Defaults to `0` (no flags). Available flags: + - `0` — No flags; all sanity checks are performed (default). + - `1` (`CLOUDSYNC_INIT_FLAG_SKIP_INT_PK_CHECK`) — Skip the check that prevents the use of a single-column INTEGER primary key. Use with caution; globally unique primary keys (UUID/ULID) are strongly recommended. + - `2` (`CLOUDSYNC_INIT_FLAG_SKIP_NOT_NULL_DEFAULT_CHECK`) — Skip the check that requires all NOT NULL non-PK columns to have a DEFAULT value. + - `4` (`CLOUDSYNC_INIT_FLAG_SKIP_NOT_NULL_PRIKEYS_CHECK`) — Skip the check that rejects NULL primary key values. + - Flags can be combined with bitwise OR (e.g., `3` skips both the integer PK check and the NOT NULL default check). + +**Returns:** None. + +**Example:** + +```sql +-- Initialize a table with the default CLS algorithm +SELECT cloudsync_init('my_table'); + +-- Initialize a table with the Delete-Wins Set algorithm +SELECT cloudsync_init('my_table', 'dws'); + +-- Initialize a table with an integer primary key (skip the integer PK check) +SELECT cloudsync_init('my_table', 'cls', 1); +``` + +--- + +### `cloudsync_enable(table_name)` + +**Description:** Enables synchronization for the specified table. + +**Parameters:** + +- `table_name` (TEXT): The name of the table to enable. + +**Returns:** None. + +**Example:** + +```sql +SELECT cloudsync_enable('my_table'); +``` + +--- + +### `cloudsync_disable(table_name)` + +**Description:** Disables synchronization for the specified table. + +**Parameters:** + +- `table_name` (TEXT): The name of the table to disable. + +**Returns:** None. + +**Example:** + +```sql +SELECT cloudsync_disable('my_table'); +``` + +--- + +### `cloudsync_is_enabled(table_name)` + +**Description:** Checks if synchronization is enabled for the specified table. + +**Parameters:** + +- `table_name` (TEXT): The name of the table to check. + +**Returns:** 1 if enabled, 0 otherwise. + +**Example:** + +```sql +SELECT cloudsync_is_enabled('my_table'); +``` + +--- + +### `cloudsync_set_filter(table_name, filter_expr)` + +**Description:** Sets a row-level filter expression on a synchronized table. Only rows that match the filter are tracked by the sync triggers; changes to rows that do not satisfy the expression are ignored and never replicated. + +The filter expression is a standard SQL boolean expression written using bare column names (without a table or alias prefix). The extension automatically rewrites it with `NEW.` for INSERT/UPDATE triggers and `OLD.` for DELETE triggers. The expression is evaluated inside the trigger `WHEN` clause. + +This function stores the filter in the table's settings and immediately recreates the sync triggers to apply it. The filter persists across database reopens. Use [`cloudsync_clear_filter()`](#cloudsync_clear_filtertable_name) to remove it. + +**Parameters:** + +- `table_name` (TEXT): The name of the synchronized table. +- `filter_expr` (TEXT): A SQL boolean expression referencing column names of the table. Only rows for which this expression evaluates to true are tracked for sync. + +**Returns:** `1` on success. + +**Example:** + +```sql +-- Only sync tasks that are not marked as drafts +SELECT cloudsync_set_filter('tasks', "is_draft = 0"); + +-- Only sync rows belonging to a specific tenant +SELECT cloudsync_set_filter('orders', "tenant_id = 'acme'"); + +-- Combine conditions +SELECT cloudsync_set_filter('messages', "deleted = 0 AND type != 'ephemeral'"); +``` + +--- + +### `cloudsync_clear_filter(table_name)` + +**Description:** Removes the row-level filter previously set with [`cloudsync_set_filter()`](#cloudsync_set_filtertable_name-filter_expr). After clearing, all row changes in the table are tracked and replicated regardless of column values. + +This function updates the stored settings and immediately recreates the sync triggers without a filter condition. + +**Parameters:** + +- `table_name` (TEXT): The name of the synchronized table. + +**Returns:** `1` on success. + +**Example:** + +```sql +SELECT cloudsync_clear_filter('tasks'); +``` + +--- + +### `cloudsync_cleanup(table_name)` + +**Description:** Removes the `sqlite-sync` synchronization mechanism from a specified table or all tables. This operation drops the associated `_cloudsync` metadata table and removes triggers from the target table(s). Use this function when synchronization is no longer desired for a table. + +**Parameters:** + +- `table_name` (TEXT): The name of the table to clean up. + +**Returns:** None. + +**Example:** + +```sql +-- Clean up a single table +SELECT cloudsync_cleanup('my_table'); + +``` + +--- + +### `cloudsync_terminate()` + +**Description:** Releases all internal resources used by the `sqlite-sync` extension for the current database connection. This function should be called before closing the database connection to ensure that all prepared statements and allocated memory are freed. Failing to call this function can result in memory leaks or a failed `sqlite3_close` operation due to pending statements. + +**Parameters:** None. + +**Returns:** None. + +**Example:** + +```sql +-- Before closing the database connection +SELECT cloudsync_terminate(); +``` + +--- + +## Block-Level LWW Functions + +### `cloudsync_set_column(table_name, col_name, key, value)` + +**Description:** Configures per-column settings for a synchronized table. This function is primarily used to enable **block-level LWW** on text columns, allowing fine-grained conflict resolution at the line (or paragraph) level instead of the entire cell. + +When block-level LWW is enabled on a column, INSERT and UPDATE operations automatically split the text into blocks using a delimiter (default: newline `\n`) and track each block independently. During sync, changes are merged block-by-block, so concurrent edits to different parts of the same text are preserved. + +**Parameters:** + +- `table_name` (TEXT): The name of the synchronized table. +- `col_name` (TEXT): The name of the text column to configure. +- `key` (TEXT): The setting key. Supported keys: + - `'algo'` — Set the column algorithm. Use value `'block'` to enable block-level LWW. + - `'delimiter'` — Set the block delimiter string. Only applies to columns with block-level LWW enabled. +- `value` (TEXT): The setting value. + +**Returns:** None. + +**Example:** + +```sql +-- Enable block-level LWW on a column (splits text by newline by default) +SELECT cloudsync_set_column('notes', 'body', 'algo', 'block'); + +-- Set a custom delimiter (e.g., double newline for paragraph-level tracking) +SELECT cloudsync_set_column('notes', 'body', 'delimiter', ' + +'); +``` + +--- + +### `cloudsync_text_materialize(table_name, col_name, pk_values...)` + +**Description:** Reconstructs the full text of a block-level LWW column from its individual blocks and writes the result back to the base table column. This is useful after a merge operation to ensure the column contains the up-to-date materialized text. + +After a sync/merge, the column is updated automatically. This function is primarily useful for manual materialization or debugging. + +**Parameters:** + +- `table_name` (TEXT): The name of the table. +- `col_name` (TEXT): The name of the block-level LWW column. +- `pk_values...` (variadic): The primary key values identifying the row. For composite primary keys, pass each key value as a separate argument in declaration order. + +**Returns:** `1` on success. + +**Example:** + +```sql +-- Materialize the body column for a specific row +SELECT cloudsync_text_materialize('notes', 'body', 'note-001'); + +-- With a composite primary key (e.g., PRIMARY KEY (tenant_id, doc_id)) +SELECT cloudsync_text_materialize('docs', 'body', 'tenant-1', 'doc-001'); + +-- Read the materialized text +SELECT body FROM notes WHERE id = 'note-001'; +``` + +--- + +## Helper Functions + +### `cloudsync_version()` + +**Description:** Returns the version of the `sqlite-sync` library. + +**Parameters:** None. + +**Returns:** The library version as a string. + +**Example:** +```sql +SELECT cloudsync_version(); +-- e.g., '1.0.0' +``` + +--- + +### `cloudsync_siteid()` + +**Description:** Returns the unique ID of the local site. + +**Parameters:** None. + +**Returns:** The site ID as a BLOB. + +**Example:** + +```sql +SELECT cloudsync_siteid(); +``` + +--- + +### `cloudsync_db_version()` + +**Description:** Returns the current database version. + +**Parameters:** None. + +**Returns:** The database version as an INTEGER. + +**Example:** + +```sql +SELECT cloudsync_db_version(); +``` + +--- + +### `cloudsync_uuid()` + +**Description:** Generates a new universally unique identifier (UUIDv7). This is useful for creating globally unique primary keys for new records, which is a best practice for CRDTs. + +**Parameters:** None. + +**Returns:** A new UUID as a TEXT value. + +**Example:** + +```sql +INSERT INTO products (id, name) VALUES (cloudsync_uuid(), 'New Product'); +``` + +--- + +## Schema Alteration Functions + +### `cloudsync_begin_alter(table_name)` + +**Description:** Prepares a synchronized table for schema changes. This function must be called before altering the table. Failure to use `cloudsync_begin_alter` and `cloudsync_commit_alter` can lead to synchronization errors and data divergence. + +**Parameters:** + +- `table_name` (TEXT): The name of the table that will be altered. + +**Returns:** None. + +**Example:** + +```sql +SELECT cloudsync_init('my_table'); +-- ... later +SELECT cloudsync_begin_alter('my_table'); +ALTER TABLE my_table ADD COLUMN new_column TEXT; +SELECT cloudsync_commit_alter('my_table'); +``` + +--- + +### `cloudsync_commit_alter(table_name)` + +**Description:** Finalizes schema changes for a synchronized table. This function must be called after altering the table's schema, completing the process initiated by `cloudsync_begin_alter` and ensuring CRDT data consistency. + +**Parameters:** + +- `table_name` (TEXT): The name of the table that was altered. + +**Returns:** None. + +**Example:** + +```sql +SELECT cloudsync_init('my_table'); +-- ... later +SELECT cloudsync_begin_alter('my_type'); +ALTER TABLE my_table ADD COLUMN new_column TEXT; +SELECT cloudsync_commit_alter('my_table'); +``` + +--- + +## Network Functions + +### `cloudsync_network_init(managedDatabaseId)` + +**Description:** Initializes the `sqlite-sync` network component. This function configures the endpoints for the CloudSync service and initializes the cURL library. + +**Parameters:** + +- `managedDatabaseId` (TEXT): The managed database identifier returned by the CloudSync service when a new database is registered for sync. For SQLiteCloud projects, this value can be obtained from the project's CloudSync page on the dashboard. + +**Returns:** None. + +**Example:** + +```sql +SELECT cloudsync_network_init('your-managed-database-id'); +``` + +--- + +### `cloudsync_network_cleanup()` + +**Description:** Cleans up the `sqlite-sync` network component, releasing all resources allocated by `cloudsync_network_init` (memory, cURL handles). + +**Parameters:** None. + +**Returns:** None. + +**Example:** + +```sql +SELECT cloudsync_network_cleanup(); +``` + +--- + +### `cloudsync_network_set_token(token)` + +**Description:** Sets the authentication token to be used for network requests. This token will be included in the `Authorization` header of all subsequent requests. For more information, refer to the [Access Tokens documentation](https://docs.sqlitecloud.io/docs/access-tokens). + +**Parameters:** + +- `token` (TEXT): The authentication token. + +**Returns:** None. + +**Example:** + +```sql +SELECT cloudsync_network_set_token('your_auth_token'); +``` + +--- + +### `cloudsync_network_set_apikey(apikey)` + +**Description:** Sets the API key for network requests. This key is included in the `Authorization` header of all subsequent requests. + +**Parameters:** + +- `apikey` (TEXT): The API key. + +**Returns:** None. + +**Example:** + +```sql +SELECT cloudsync_network_set_apikey('your_api_key'); +``` + +--- + +### Error handling + +The sync functions follow a consistent error-handling contract: + +| Error type | Behavior | +|---|---| +| **Endpoint/network errors** (server unreachable, auth failure, bad URL) | SQL error — the function could not execute. | +| **Apply errors** (`cloudsync_payload_apply` failures — unknown schema hash, invalid checksum, decompression error) | Structured JSON — a `receive.error` string field is included in the response. | +| **Server-reported apply job failures** (the server processed the request but its own apply job failed) | Structured JSON — a `send.lastFailure` object is included in the response. | +| **Server-reported check job failures** (the server failed to encode a changeset for the client) | Structured JSON — a `receive.lastFailure` object is included in the response. | + +This means: if you get JSON back, the server was reachable and the network protocol ran. If you get a SQL error, connectivity or configuration is broken. + +--- + +### `cloudsync_network_send_changes()` + +**Description:** Sends all unsent local changes to the remote server. + +The send path streams payloads through `cloudsync_payload_chunks()`, so `payload_max_chunk_size` also limits the payloads generated for network transport. Each generated chunk is uploaded/applied independently; the local send checkpoint is advanced only after the chunk stream completes successfully. + +Chunk transport is transparent to the CloudSync backend. Each chunk is sent as a normal `/apply` payload, either inline as a base64 `blob` or through the upload `url` path. There is no separate chunk flag: old payloads, monolithic payloads, and v3 fragment payloads are distinguished by the payload format itself. + +**Parameters:** None. + +**Returns:** A JSON string with the send result: + +```json +{"send": {"status": "synced|syncing|out-of-sync|error", "localVersion": N, "serverVersion": N, "chunks": C, "bytes": B, "lastFailure": {...}}} +``` + +- `send.status`: The current sync state — `"synced"` (all changes confirmed), `"syncing"` (changes sent but not yet confirmed), `"out-of-sync"` (local changes pending or gaps detected), or `"error"`. +- `send.localVersion`: The latest local database version. +- `send.serverVersion`: The latest version confirmed by the server. +- `send.chunks`: The number of payload chunks sent this call (a large push is split into multiple transport chunks bounded by `payload_max_chunk_size`). `0` when there were no local changes to send. +- `send.bytes`: The total serialized payload bytes sent this call (uncompressed cloudsync payload size, summed across chunks; not the compressed wire size). +- `send.lastFailure` (optional): Present only when the server reports a failed apply job. Forwarded verbatim from the server's `failures.apply` and typically includes `jobId`, `code`, `stage`, `message`, `retryable`, and `failedAt`. It is emitted regardless of `status` so callers can detect server-side failures during `"syncing"` or even after the state has nominally recovered. This function is **send/apply-scoped**: server-reported check-job failures (`failures.check`) are not surfaced here — see [`cloudsync_network_receive_changes()`](#cloudsync_network_receive_changesmax_chunks) and [`cloudsync_network_sync()`](#cloudsync_network_syncwait_ms-max_retries). + +**Example:** + +```sql +SELECT cloudsync_network_send_changes(); +-- '{"send":{"status":"synced","localVersion":5,"serverVersion":5,"chunks":1,"bytes":2048}}' + +-- With a server-reported failure (e.g. unknown schema hash on the server side): +-- '{"send":{"status":"out-of-sync","localVersion":1,"serverVersion":0,"chunks":1,"bytes":512,"lastFailure":{"jobId":44961,"code":"internal_error","stage":"apply_payload","message":"cloudsync operation failed: Cannot apply the received payload because the schema hash is unknown 4288148391734624266.","retryable":true,"failedAt":"2026-04-15T22:21:09.018606Z"}}}' +``` + +--- + +### `cloudsync_network_receive_changes([max_chunks])` + +**Description:** Receives new changes from the remote server and applies them to the local database. (Formerly `cloudsync_network_check_changes()`, which remains available as a deprecated alias — see below.) + +If changes are already prepared for the local site, they are downloaded and applied. If nothing is ready yet, the server starts preparing a package asynchronously and this call returns having applied nothing; a later call retrieves it. This function does **not** wait/poll for preparation to finish — it applies what is available now. To force an update and wait for not-yet-ready changes, use [`cloudsync_network_sync(wait_ms, max_retries)`](#cloudsync_network_syncwait_ms-max_retries). + +By default this function **drains all currently-available chunks** in one call. Pass `max_chunks` to cap how many chunks are applied per call, for caller-driven progress or traffic control: + +```sql +-- Drain at most 5 chunks, loop until the stream is complete +SELECT cloudsync_network_receive_changes(5) ->> '$.receive.complete'; +``` + +The drain position (the per-stream page cursor) is held **in memory** on the network context, so a capped drain resumes where it left off on the next call — the caller does not manage any cursor; it just loops while `receive.complete` is `false`. If the connection is closed or the process restarts mid-drain, the cursor is lost and the next call safely restarts the drain from the beginning of the stream: already-applied chunks are re-downloaded and re-applied idempotently, so **no rows are skipped** — only redundant download is incurred. This is safe because the durable receive checkpoint (`check_dbversion`/`check_seq`) only advances after a stream has been **fully** applied, never in the middle of a source `db_version`. + +If the network is misconfigured or the remote server is unreachable, the function raises a SQL error. If the received payload cannot be applied locally (for example because of an unknown schema hash), the error is returned as a `receive.error` field in the JSON response. If the server reports an unresolved failed check job (e.g. an `encode_changes` failure), that failure is forwarded as a `receive.lastFailure` object. + +**Parameters:** + +- `max_chunks` (INTEGER, optional): Maximum number of chunks to apply this call. Omit or pass `0` (or negative) to drain everything available. A positive value caps the drain; `receive.complete` will be `false` when the cap stops a drain that still has pending chunks. + +**Returns:** A JSON string with the receive result: + +```json +{"receive": {"rows": N, "tables": ["table1", "table2"], "chunks": C, "bytes": B, "complete": true, "error": "...", "lastFailure": {...}}} +``` + +- `receive.rows`: The total number of rows received and applied to the local database, summed across all chunks drained this call. `0` when the receive phase failed, when nothing was available, or when only intermediate fragments were staged without completing a value. +- `receive.tables`: An array of table names that received changes (the union across all drained chunks). Empty (`[]`) if no changes were applied or the receive phase failed. +- `receive.chunks`: The number of payload chunks applied by this call. `0` when nothing was ready, `1` for a single monolithic/inline page, and `N` for a drained `N`-chunk stream (bounded by `max_chunks` if given). +- `receive.bytes`: The total serialized payload bytes received this call (uncompressed cloudsync payload size, summed across chunks; transport-independent, not the compressed wire size). Useful for byte-budgeted draining together with `max_chunks`. +- `receive.complete` (boolean): `true` when the receive stream is fully drained (nothing pending), `false` when more chunks remain — because `max_chunks` capped the drain, or it stopped early. When `false`, call this function again to continue. +- `receive.error` (optional, string): Present when client-side `cloudsync_payload_apply` failed. Contains a human-readable error message describing why the received payload could not be applied. +- `receive.lastFailure` (optional, object): Present only when the server reports a failed check job. Forwarded verbatim from the server's `failures.check` and typically includes `jobId`, `dbVersion`, `seq`, `code`, `stage`, `message`, `retryable`, and `failedAt`. Distinct from `receive.error`: `receive.error` describes a client-side apply failure (string), while `receive.lastFailure` describes a server-side check-job failure (object). Both can coexist in the same response. This function is **check-scoped**: server-reported apply-job failures (`failures.apply`) are not surfaced here — see [`cloudsync_network_send_changes()`](#cloudsync_network_send_changes) and [`cloudsync_network_sync()`](#cloudsync_network_syncwait_ms-max_retries). + +**Example:** + +```sql +SELECT cloudsync_network_receive_changes(); +-- '{"receive":{"rows":3,"tables":["tasks"],"chunks":1,"bytes":820,"complete":true}}' + +-- Capped drain with more pending (call again to continue): +-- '{"receive":{"rows":40,"tables":["docs"],"chunks":5,"bytes":1310720,"complete":false}}' + +-- With a client-side apply error: +-- '{"receive":{"rows":0,"tables":[],"chunks":0,"bytes":0,"complete":true,"error":"Cannot apply the received payload because the schema hash is unknown 7218827471400075525."}}' + +-- With a server-reported check-job failure: +-- '{"receive":{"rows":0,"tables":[],"chunks":0,"bytes":0,"complete":true,"lastFailure":{"jobId":456,"dbVersion":15,"seq":1,"code":"tenant_unreachable","stage":"encode_changes","message":"tenant check failed","retryable":true,"failedAt":"2026-04-24T10:22:00Z"}}}' +``` + +--- + +### `cloudsync_network_check_changes([max_chunks])` + +> **Deprecated:** use [`cloudsync_network_receive_changes()`](#cloudsync_network_receive_changesmax_chunks). This name is retained as a thin alias for backward compatibility and will be removed in a future major version. It behaves identically, including the optional `max_chunks` argument and all returned fields. + +--- + +### `cloudsync_network_sync([wait_ms], [max_retries])` + +**Description:** Performs a full synchronization cycle. This function has two overloads: + +- `cloudsync_network_sync()`: Performs one send operation and one check operation. +- `cloudsync_network_sync(wait_ms, max_retries)`: Performs one send operation and then downloads remote changes. + +When the server delivers changes as a stream of chunks, this function drains the **whole stream in a single call**: as long as the next chunk is already available it is fetched back-to-back with no delay. `wait_ms` and `max_retries` are spent only while the server payload is **not yet ready** (the server is still preparing a package): in that case the function waits `wait_ms` and retries up to `max_retries` times. They are not consumed while paging through chunks that are already available. + +**Parameters:** + +- `wait_ms` (INTEGER, optional): The time to wait in milliseconds between retries while the server payload is not yet ready. Defaults to 100. +- `max_retries` (INTEGER, optional): The maximum number of poll attempts while the server payload is not yet ready. Defaults to 1. + +**Returns:** A JSON string with the full sync result, combining send and receive: + +```json +{ + "send": {"status": "synced|syncing|out-of-sync|error", "localVersion": N, "serverVersion": N, "chunks": C, "bytes": B, "lastFailure": {...}}, + "receive": {"rows": N, "tables": ["table1", "table2"], "chunks": C, "bytes": B, "complete": true, "error": "...", "lastFailure": {...}} +} +``` + +- `send.status`: The current sync state — `"synced"`, `"syncing"`, `"out-of-sync"`, or `"error"`. +- `send.localVersion`: The latest local database version. +- `send.serverVersion`: The latest version confirmed by the server. +- `send.chunks` / `send.bytes`: Number of payload chunks sent and total serialized payload bytes sent during the send phase. Same semantics as in [`cloudsync_network_send_changes()`](#cloudsync_network_send_changes). +- `send.lastFailure` (optional): Same semantics as in [`cloudsync_network_send_changes()`](#cloudsync_network_send_changes) — forwarded verbatim from the server's `failures.apply` whenever a failed apply job is reported, regardless of `status`. +- `receive.rows`: The **total** number of rows received and applied during the receive phase, summed across **all** chunks drained in this call. `0` when the receive phase failed. +- `receive.tables`: An array of table names that received changes (the union across all drained chunks). Empty (`[]`) if no changes were applied or the receive phase failed. +- `receive.chunks`: The number of payload chunks applied in this call. `0` when nothing was ready, `1` for a single monolithic/inline page, and `N` for a fully drained `N`-chunk stream. `cloudsync_network_sync()` always drains the whole stream (it does not cap chunks). +- `receive.bytes`: The total serialized payload bytes received this call (uncompressed cloudsync payload size, summed across chunks; not the compressed wire size). Same semantics as in [`cloudsync_network_receive_changes()`](#cloudsync_network_receive_changesmax_chunks). +- `receive.complete` (boolean): `true` when the server stream was fully drained, `false` when the download stopped before the final chunk (an error occurred, or an internal safety bound was reached). When `false`, call `cloudsync_network_sync()` again to resume; re-delivered rows are idempotent. +- `receive.error` (optional, string): Present when client-side `cloudsync_payload_apply` failed (for example `"Cannot apply the received payload because the schema hash is unknown 7218827471400075525."`). The send result is always preserved so the caller can tell that local changes reached the server even when applying incoming changes failed. The receive drain stops immediately on apply errors, since failures like schema-hash mismatches do not heal across retries. Endpoint/network errors during the receive phase raise a SQL error instead. +- `receive.lastFailure` (optional, object): Same semantics as in [`cloudsync_network_receive_changes()`](#cloudsync_network_receive_changesmax_chunks) — forwarded verbatim from the server's `failures.check` whenever a failed check job is reported. Distinct from `receive.error`. `cloudsync_network_sync()` reports both `send.lastFailure` and `receive.lastFailure` when present. + +**Example:** + +```sql +-- Perform a single synchronization cycle +SELECT cloudsync_network_sync(); +-- '{"send":{"status":"synced","localVersion":5,"serverVersion":5,"chunks":1,"bytes":2048},"receive":{"rows":3,"tables":["tasks"],"chunks":1,"bytes":820,"complete":true}}' + +-- Perform a synchronization cycle with custom retry settings +SELECT cloudsync_network_sync(500, 3); +-- A large download drained as a multi-chunk stream in a single call: +-- '{"send":{"status":"synced","localVersion":42,"serverVersion":42,"chunks":0,"bytes":0},"receive":{"rows":1200,"tables":["docs"],"chunks":7,"bytes":1835008,"complete":true}}' + +-- Receive phase failed but send phase completed — the error is surfaced in JSON, not as a SQL error: +-- '{"send":{"status":"synced","localVersion":5,"serverVersion":5,"chunks":1,"bytes":512},"receive":{"rows":0,"tables":[],"chunks":0,"bytes":0,"complete":false,"error":"Cannot apply the received payload because the schema hash is unknown 7218827471400075525."}}' +``` + +--- + +### `cloudsync_network_reset_sync_version()` + +**Description:** Resets local synchronization version numbers, forcing the next sync to fetch all changes from the server. + +**Parameters:** None. + +**Returns:** None. + +**Example:** + +```sql +SELECT cloudsync_network_reset_sync_version(); +``` + +--- + +### `cloudsync_network_has_unsent_changes()` + +**Description:** Checks if there are any local changes that have not yet been sent to the remote server. + +**Parameters:** None. + +**Returns:** 1 if there are unsent changes, 0 otherwise. + +**Example:** + +```sql +SELECT cloudsync_network_has_unsent_changes(); +``` + +--- + +### `cloudsync_network_logout()` + +**Description:** Logs out the current user and cleans up all local data from synchronized tables. This function deletes and then re-initializes synchronized tables, useful for switching users or resetting the local database. **Warning:** This function deletes all data from synchronized tables. Use with caution. Consider calling [`cloudsync_network_has_unsent_changes()`](#cloudsync_network_has_unsent_changes) before logout to check for unsent local changes and warn the user before data that has not been fully synchronized to the remote server is deleted. + +**Parameters:** None. + +**Returns:** None. + +**Example:** + +```sql +SELECT cloudsync_network_logout(); +``` diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_begin_alter.md b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_begin_alter.md new file mode 100644 index 0000000..c8ae507 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_begin_alter.md @@ -0,0 +1,29 @@ +--- +title: "cloudsync_begin_alter(table_name)" +description: "SQLite-Sync SQL function reference." +category: platform +status: publish +slug: sqlite-sync-api-cloudsync-begin-alter +--- + +## `cloudsync_begin_alter(table_name)` + +**Description:** Prepares a synchronized table for schema changes. This function must be called before altering the table. Failure to use `cloudsync_begin_alter` and `cloudsync_commit_alter` can lead to synchronization errors and data divergence. + +**Parameters:** + +- `table_name` (TEXT): The name of the table that will be altered. + +**Returns:** None. + +**Example:** + +```sql +SELECT cloudsync_init('my_table'); +-- ... later +SELECT cloudsync_begin_alter('my_table'); +ALTER TABLE my_table ADD COLUMN new_column TEXT; +SELECT cloudsync_commit_alter('my_table'); +``` + +--- diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_cleanup.md b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_cleanup.md new file mode 100644 index 0000000..d8065c6 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_cleanup.md @@ -0,0 +1,27 @@ +--- +title: "cloudsync_cleanup(table_name)" +description: "SQLite-Sync SQL function reference." +category: platform +status: publish +slug: sqlite-sync-api-cloudsync-cleanup +--- + +## `cloudsync_cleanup(table_name)` + +**Description:** Removes the `sqlite-sync` synchronization mechanism from a specified table or all tables. This operation drops the associated `_cloudsync` metadata table and removes triggers from the target table(s). Use this function when synchronization is no longer desired for a table. + +**Parameters:** + +- `table_name` (TEXT): The name of the table to clean up. + +**Returns:** None. + +**Example:** + +```sql +-- Clean up a single table +SELECT cloudsync_cleanup('my_table'); + +``` + +--- diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_clear_filter.md b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_clear_filter.md new file mode 100644 index 0000000..6a85dec --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_clear_filter.md @@ -0,0 +1,27 @@ +--- +title: "cloudsync_clear_filter(table_name)" +description: "SQLite-Sync SQL function reference." +category: platform +status: publish +slug: sqlite-sync-api-cloudsync-clear-filter +--- + +## `cloudsync_clear_filter(table_name)` + +**Description:** Removes the row-level filter previously set with [`cloudsync_set_filter()`](#cloudsync_set_filtertable_name-filter_expr). After clearing, all row changes in the table are tracked and replicated regardless of column values. + +This function updates the stored settings and immediately recreates the sync triggers without a filter condition. + +**Parameters:** + +- `table_name` (TEXT): The name of the synchronized table. + +**Returns:** `1` on success. + +**Example:** + +```sql +SELECT cloudsync_clear_filter('tasks'); +``` + +--- diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_commit_alter.md b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_commit_alter.md new file mode 100644 index 0000000..404c27b --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_commit_alter.md @@ -0,0 +1,31 @@ +--- +title: "cloudsync_commit_alter(table_name)" +description: "SQLite-Sync SQL function reference." +category: platform +status: publish +slug: sqlite-sync-api-cloudsync-commit-alter +--- + +## `cloudsync_commit_alter(table_name)` + +**Description:** Finalizes schema changes for a synchronized table. This function must be called after altering the table's schema, completing the process initiated by `cloudsync_begin_alter` and ensuring CRDT data consistency. + +**Parameters:** + +- `table_name` (TEXT): The name of the table that was altered. + +**Returns:** None. + +**Example:** + +```sql +SELECT cloudsync_init('my_table'); +-- ... later +SELECT cloudsync_begin_alter('my_type'); +ALTER TABLE my_table ADD COLUMN new_column TEXT; +SELECT cloudsync_commit_alter('my_table'); +``` + +--- + +## Network Functions diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_db_version.md b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_db_version.md new file mode 100644 index 0000000..7b3652e --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_db_version.md @@ -0,0 +1,23 @@ +--- +title: "cloudsync_db_version()" +description: "SQLite-Sync SQL function reference." +category: platform +status: publish +slug: sqlite-sync-api-cloudsync-db-version +--- + +## `cloudsync_db_version()` + +**Description:** Returns the current database version. + +**Parameters:** None. + +**Returns:** The database version as an INTEGER. + +**Example:** + +```sql +SELECT cloudsync_db_version(); +``` + +--- diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_disable.md b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_disable.md new file mode 100644 index 0000000..7a25eba --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_disable.md @@ -0,0 +1,25 @@ +--- +title: "cloudsync_disable(table_name)" +description: "SQLite-Sync SQL function reference." +category: platform +status: publish +slug: sqlite-sync-api-cloudsync-disable +--- + +## `cloudsync_disable(table_name)` + +**Description:** Disables synchronization for the specified table. + +**Parameters:** + +- `table_name` (TEXT): The name of the table to disable. + +**Returns:** None. + +**Example:** + +```sql +SELECT cloudsync_disable('my_table'); +``` + +--- diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_enable.md b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_enable.md new file mode 100644 index 0000000..47c4855 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_enable.md @@ -0,0 +1,25 @@ +--- +title: "cloudsync_enable(table_name)" +description: "SQLite-Sync SQL function reference." +category: platform +status: publish +slug: sqlite-sync-api-cloudsync-enable +--- + +## `cloudsync_enable(table_name)` + +**Description:** Enables synchronization for the specified table. + +**Parameters:** + +- `table_name` (TEXT): The name of the table to enable. + +**Returns:** None. + +**Example:** + +```sql +SELECT cloudsync_enable('my_table'); +``` + +--- diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_init.md b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_init.md new file mode 100644 index 0000000..0d56e5b --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_init.md @@ -0,0 +1,61 @@ +--- +title: "cloudsync_init(table_name, [crdt_algo], [init_flags])" +description: "SQLite-Sync SQL function reference." +category: platform +status: publish +slug: sqlite-sync-api-cloudsync-init +--- + +## `cloudsync_init(table_name, [crdt_algo], [init_flags])` + +**Description:** Initializes a table for `sqlite-sync` synchronization. This function is idempotent and needs to be called only once per table on each site; configurations are stored in the database and automatically loaded with the extension. + +Before initialization, `cloudsync_init` performs schema sanity checks to ensure compatibility with CRDT requirements and best practices. These checks include: +- Primary keys should not be auto-incrementing integers; GUIDs (UUIDs, ULIDs) are highly recommended to prevent multi-node collisions. +- All non-primary key `NOT NULL` columns must have a `DEFAULT` value. +- **Note:** Any write operation that includes a NULL value for a primary key column will be rejected with an error, even if SQLite would normally allow it due to a legacy behavior. + +**Schema Design Considerations:** + +When designing your database schema for SQLite Sync, follow these essential requirements: + +- **Primary Keys**: Use TEXT primary keys with `cloudsync_uuid()` for globally unique identifiers. Avoid auto-incrementing integers. +- **Column Constraints**: All NOT NULL columns (except primary keys) must have DEFAULT values to prevent synchronization errors. +- **UNIQUE Constraints**: In multi-tenant scenarios, use composite UNIQUE constraints (e.g., `UNIQUE(tenant_id, email)`) instead of global uniqueness. +- **Foreign Key Compatibility**: Be aware of potential conflicts during CRDT merge operations and RLS policy interactions. +- **Trigger Compatibility**: Triggers may cause duplicate operations or be called multiple times due to column-by-column processing. + +For comprehensive guidelines, see the [Database Schema Recommendations](/docs/sqlite-sync-best-practices). + +The function supports three overloads: +- `cloudsync_init(table_name)`: Uses the default 'cls' CRDT algorithm. +- `cloudsync_init(table_name, crdt_algo)`: Specifies a CRDT algorithm ('cls', 'dws', 'aws', 'gos'). +- `cloudsync_init(table_name, crdt_algo, init_flags)`: Specifies an algorithm and a bitmask of initialization flags to control which schema sanity checks are skipped. + +**Parameters:** + +- `table_name` (TEXT): The name of the table to initialize. +- `crdt_algo` (TEXT, optional): The CRDT algorithm to use. Can be `"cls"`, `"dws"`, `"aws"`, `"gos"`. Defaults to `"cls"`. +- `init_flags` (INTEGER, optional): A bitmask of flags that control initialization behavior. Defaults to `0` (no flags). Available flags: + - `0` — No flags; all sanity checks are performed (default). + - `1` (`CLOUDSYNC_INIT_FLAG_SKIP_INT_PK_CHECK`) — Skip the check that prevents the use of a single-column INTEGER primary key. Use with caution; globally unique primary keys (UUID/ULID) are strongly recommended. + - `2` (`CLOUDSYNC_INIT_FLAG_SKIP_NOT_NULL_DEFAULT_CHECK`) — Skip the check that requires all NOT NULL non-PK columns to have a DEFAULT value. + - `4` (`CLOUDSYNC_INIT_FLAG_SKIP_NOT_NULL_PRIKEYS_CHECK`) — Skip the check that rejects NULL primary key values. + - Flags can be combined with bitwise OR (e.g., `3` skips both the integer PK check and the NOT NULL default check). + +**Returns:** None. + +**Example:** + +```sql +-- Initialize a table with the default CLS algorithm +SELECT cloudsync_init('my_table'); + +-- Initialize a table with the Delete-Wins Set algorithm +SELECT cloudsync_init('my_table', 'dws'); + +-- Initialize a table with an integer primary key (skip the integer PK check) +SELECT cloudsync_init('my_table', 'cls', 1); +``` + +--- diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_is_enabled.md b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_is_enabled.md new file mode 100644 index 0000000..efdf326 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_is_enabled.md @@ -0,0 +1,25 @@ +--- +title: "cloudsync_is_enabled(table_name)" +description: "SQLite-Sync SQL function reference." +category: platform +status: publish +slug: sqlite-sync-api-cloudsync-is-enabled +--- + +## `cloudsync_is_enabled(table_name)` + +**Description:** Checks if synchronization is enabled for the specified table. + +**Parameters:** + +- `table_name` (TEXT): The name of the table to check. + +**Returns:** 1 if enabled, 0 otherwise. + +**Example:** + +```sql +SELECT cloudsync_is_enabled('my_table'); +``` + +--- diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_network_check_changes.md b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_network_check_changes.md new file mode 100644 index 0000000..17c6de3 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_network_check_changes.md @@ -0,0 +1,13 @@ +--- +title: "cloudsync_network_check_changes()" +description: "SQLite-Sync SQL function reference (deprecated alias of cloudsync_network_receive_changes)." +category: platform +status: publish +slug: sqlite-sync-api-cloudsync-network-check-changes +--- + +## `cloudsync_network_check_changes([max_chunks])` + +> **Deprecated:** use [`cloudsync_network_receive_changes()`](#cloudsync_network_receive_changesmax_chunks). This name is retained as a thin alias for backward compatibility and will be removed in a future major version. It behaves identically, including the optional `max_chunks` argument and all returned fields. + +--- diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_network_cleanup.md b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_network_cleanup.md new file mode 100644 index 0000000..adfaeb5 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_network_cleanup.md @@ -0,0 +1,23 @@ +--- +title: "cloudsync_network_cleanup()" +description: "SQLite-Sync SQL function reference." +category: platform +status: publish +slug: sqlite-sync-api-cloudsync-network-cleanup +--- + +## `cloudsync_network_cleanup()` + +**Description:** Cleans up the `sqlite-sync` network component, releasing all resources allocated by `cloudsync_network_init` (memory, cURL handles). + +**Parameters:** None. + +**Returns:** None. + +**Example:** + +```sql +SELECT cloudsync_network_cleanup(); +``` + +--- diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_network_has_unsent_changes.md b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_network_has_unsent_changes.md new file mode 100644 index 0000000..a3962f5 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_network_has_unsent_changes.md @@ -0,0 +1,23 @@ +--- +title: "cloudsync_network_has_unsent_changes()" +description: "SQLite-Sync SQL function reference." +category: platform +status: publish +slug: sqlite-sync-api-cloudsync-network-has-unsent-changes +--- + +## `cloudsync_network_has_unsent_changes()` + +**Description:** Checks if there are any local changes that have not yet been sent to the remote server. + +**Parameters:** None. + +**Returns:** 1 if there are unsent changes, 0 otherwise. + +**Example:** + +```sql +SELECT cloudsync_network_has_unsent_changes(); +``` + +--- diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_network_init.md b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_network_init.md new file mode 100644 index 0000000..27ca289 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_network_init.md @@ -0,0 +1,25 @@ +--- +title: "cloudsync_network_init(managedDatabaseId)" +description: "SQLite-Sync SQL function reference." +category: platform +status: publish +slug: sqlite-sync-api-cloudsync-network-init +--- + +## `cloudsync_network_init(managedDatabaseId)` + +**Description:** Initializes the `sqlite-sync` network component. This function configures the endpoints for the CloudSync service and initializes the cURL library. + +**Parameters:** + +- `managedDatabaseId` (TEXT): The managed database identifier returned by the CloudSync service when a new database is registered for sync. For SQLiteCloud projects, this value can be obtained from the project's CloudSync page on the dashboard. + +**Returns:** None. + +**Example:** + +```sql +SELECT cloudsync_network_init('your-managed-database-id'); +``` + +--- diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_network_logout.md b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_network_logout.md new file mode 100644 index 0000000..36366dc --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_network_logout.md @@ -0,0 +1,21 @@ +--- +title: "cloudsync_network_logout()" +description: "SQLite-Sync SQL function reference." +category: platform +status: publish +slug: sqlite-sync-api-cloudsync-network-logout +--- + +## `cloudsync_network_logout()` + +**Description:** Logs out the current user and cleans up all local data from synchronized tables. This function deletes and then re-initializes synchronized tables, useful for switching users or resetting the local database. **Warning:** This function deletes all data from synchronized tables. Use with caution. Consider calling [`cloudsync_network_has_unsent_changes()`](#cloudsync_network_has_unsent_changes) before logout to check for unsent local changes and warn the user before data that has not been fully synchronized to the remote server is deleted. + +**Parameters:** None. + +**Returns:** None. + +**Example:** + +```sql +SELECT cloudsync_network_logout(); +``` diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_network_receive_changes.md b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_network_receive_changes.md new file mode 100644 index 0000000..4f16c1a --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_network_receive_changes.md @@ -0,0 +1,60 @@ +--- +title: "cloudsync_network_receive_changes([max_chunks])" +description: "SQLite-Sync SQL function reference." +category: platform +status: publish +slug: sqlite-sync-api-cloudsync-network-receive-changes +--- + +## `cloudsync_network_receive_changes([max_chunks])` + +**Description:** Receives new changes from the remote server and applies them to the local database. (Formerly `cloudsync_network_check_changes()`, which remains available as a deprecated alias — see below.) + +If changes are already prepared for the local site, they are downloaded and applied. If nothing is ready yet, the server starts preparing a package asynchronously and this call returns having applied nothing; a later call retrieves it. This function does **not** wait/poll for preparation to finish — it applies what is available now. To force an update and wait for not-yet-ready changes, use [`cloudsync_network_sync(wait_ms, max_retries)`](#cloudsync_network_syncwait_ms-max_retries). + +By default this function **drains all currently-available chunks** in one call. Pass `max_chunks` to cap how many chunks are applied per call, for caller-driven progress or traffic control: + +```sql +-- Drain at most 5 chunks, loop until the stream is complete +SELECT cloudsync_network_receive_changes(5) ->> '$.receive.complete'; +``` + +The drain position (the per-stream page cursor) is held **in memory** on the network context, so a capped drain resumes where it left off on the next call — the caller does not manage any cursor; it just loops while `receive.complete` is `false`. If the connection is closed or the process restarts mid-drain, the cursor is lost and the next call safely restarts the drain from the beginning of the stream: already-applied chunks are re-downloaded and re-applied idempotently, so **no rows are skipped** — only redundant download is incurred. This is safe because the durable receive checkpoint (`check_dbversion`/`check_seq`) only advances after a stream has been **fully** applied, never in the middle of a source `db_version`. + +If the network is misconfigured or the remote server is unreachable, the function raises a SQL error. If the received payload cannot be applied locally (for example because of an unknown schema hash), the error is returned as a `receive.error` field in the JSON response. If the server reports an unresolved failed check job (e.g. an `encode_changes` failure), that failure is forwarded as a `receive.lastFailure` object. + +**Parameters:** + +- `max_chunks` (INTEGER, optional): Maximum number of chunks to apply this call. Omit or pass `0` (or negative) to drain everything available. A positive value caps the drain; `receive.complete` will be `false` when the cap stops a drain that still has pending chunks. + +**Returns:** A JSON string with the receive result: + +```json +{"receive": {"rows": N, "tables": ["table1", "table2"], "chunks": C, "bytes": B, "complete": true, "error": "...", "lastFailure": {...}}} +``` + +- `receive.rows`: The total number of rows received and applied to the local database, summed across all chunks drained this call. `0` when the receive phase failed, when nothing was available, or when only intermediate fragments were staged without completing a value. +- `receive.tables`: An array of table names that received changes (the union across all drained chunks). Empty (`[]`) if no changes were applied or the receive phase failed. +- `receive.chunks`: The number of payload chunks applied by this call. `0` when nothing was ready, `1` for a single monolithic/inline page, and `N` for a drained `N`-chunk stream (bounded by `max_chunks` if given). +- `receive.bytes`: The total serialized payload bytes received this call (uncompressed cloudsync payload size, summed across chunks; transport-independent, not the compressed wire size). Useful for byte-budgeted draining together with `max_chunks`. +- `receive.complete` (boolean): `true` when the receive stream is fully drained (nothing pending), `false` when more chunks remain — because `max_chunks` capped the drain, or it stopped early. When `false`, call this function again to continue. +- `receive.error` (optional, string): Present when client-side `cloudsync_payload_apply` failed. Contains a human-readable error message describing why the received payload could not be applied. +- `receive.lastFailure` (optional, object): Present only when the server reports a failed check job. Forwarded verbatim from the server's `failures.check` and typically includes `jobId`, `dbVersion`, `seq`, `code`, `stage`, `message`, `retryable`, and `failedAt`. Distinct from `receive.error`: `receive.error` describes a client-side apply failure (string), while `receive.lastFailure` describes a server-side check-job failure (object). Both can coexist in the same response. This function is **check-scoped**: server-reported apply-job failures (`failures.apply`) are not surfaced here — see [`cloudsync_network_send_changes()`](#cloudsync_network_send_changes) and [`cloudsync_network_sync()`](#cloudsync_network_syncwait_ms-max_retries). + +**Example:** + +```sql +SELECT cloudsync_network_receive_changes(); +-- '{"receive":{"rows":3,"tables":["tasks"],"chunks":1,"bytes":820,"complete":true}}' + +-- Capped drain with more pending (call again to continue): +-- '{"receive":{"rows":40,"tables":["docs"],"chunks":5,"bytes":1310720,"complete":false}}' + +-- With a client-side apply error: +-- '{"receive":{"rows":0,"tables":[],"chunks":0,"bytes":0,"complete":true,"error":"Cannot apply the received payload because the schema hash is unknown 7218827471400075525."}}' + +-- With a server-reported check-job failure: +-- '{"receive":{"rows":0,"tables":[],"chunks":0,"bytes":0,"complete":true,"lastFailure":{"jobId":456,"dbVersion":15,"seq":1,"code":"tenant_unreachable","stage":"encode_changes","message":"tenant check failed","retryable":true,"failedAt":"2026-04-24T10:22:00Z"}}}' +``` + +--- diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_network_reset_sync_version.md b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_network_reset_sync_version.md new file mode 100644 index 0000000..33ac39b --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_network_reset_sync_version.md @@ -0,0 +1,23 @@ +--- +title: "cloudsync_network_reset_sync_version()" +description: "SQLite-Sync SQL function reference." +category: platform +status: publish +slug: sqlite-sync-api-cloudsync-network-reset-sync-version +--- + +## `cloudsync_network_reset_sync_version()` + +**Description:** Resets local synchronization version numbers, forcing the next sync to fetch all changes from the server. + +**Parameters:** None. + +**Returns:** None. + +**Example:** + +```sql +SELECT cloudsync_network_reset_sync_version(); +``` + +--- diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_network_send_changes.md b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_network_send_changes.md new file mode 100644 index 0000000..7ce67f8 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_network_send_changes.md @@ -0,0 +1,42 @@ +--- +title: "cloudsync_network_send_changes()" +description: "SQLite-Sync SQL function reference." +category: platform +status: publish +slug: sqlite-sync-api-cloudsync-network-send-changes +--- + +## `cloudsync_network_send_changes()` + +**Description:** Sends all unsent local changes to the remote server. + +The send path streams payloads through `cloudsync_payload_chunks()`, so `payload_max_chunk_size` also limits the payloads generated for network transport. Each generated chunk is uploaded/applied independently; the local send checkpoint is advanced only after the chunk stream completes successfully. + +Chunk transport is transparent to the CloudSync backend. Each chunk is sent as a normal `/apply` payload, either inline as a base64 `blob` or through the upload `url` path. There is no separate chunk flag: old payloads, monolithic payloads, and v3 fragment payloads are distinguished by the payload format itself. + +**Parameters:** None. + +**Returns:** A JSON string with the send result: + +```json +{"send": {"status": "synced|syncing|out-of-sync|error", "localVersion": N, "serverVersion": N, "chunks": C, "bytes": B, "lastFailure": {...}}} +``` + +- `send.status`: The current sync state — `"synced"` (all changes confirmed), `"syncing"` (changes sent but not yet confirmed), `"out-of-sync"` (local changes pending or gaps detected), or `"error"`. +- `send.localVersion`: The latest local database version. +- `send.serverVersion`: The latest version confirmed by the server. +- `send.chunks`: The number of payload chunks sent this call (a large push is split into multiple transport chunks bounded by `payload_max_chunk_size`). `0` when there were no local changes to send. +- `send.bytes`: The total serialized payload bytes sent this call (uncompressed cloudsync payload size, summed across chunks; not the compressed wire size). +- `send.lastFailure` (optional): Present only when the server reports a failed apply job. Forwarded verbatim from the server's `failures.apply` and typically includes `jobId`, `code`, `stage`, `message`, `retryable`, and `failedAt`. It is emitted regardless of `status` so callers can detect server-side failures during `"syncing"` or even after the state has nominally recovered. This function is **send/apply-scoped**: server-reported check-job failures (`failures.check`) are not surfaced here — see [`cloudsync_network_receive_changes()`](#cloudsync_network_receive_changesmax_chunks) and [`cloudsync_network_sync()`](#cloudsync_network_syncwait_ms-max_retries). + +**Example:** + +```sql +SELECT cloudsync_network_send_changes(); +-- '{"send":{"status":"synced","localVersion":5,"serverVersion":5,"chunks":1,"bytes":2048}}' + +-- With a server-reported failure (e.g. unknown schema hash on the server side): +-- '{"send":{"status":"out-of-sync","localVersion":1,"serverVersion":0,"chunks":1,"bytes":512,"lastFailure":{"jobId":44961,"code":"internal_error","stage":"apply_payload","message":"cloudsync operation failed: Cannot apply the received payload because the schema hash is unknown 4288148391734624266.","retryable":true,"failedAt":"2026-04-15T22:21:09.018606Z"}}}' +``` + +--- diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_network_set_apikey.md b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_network_set_apikey.md new file mode 100644 index 0000000..affea2d --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_network_set_apikey.md @@ -0,0 +1,40 @@ +--- +title: "cloudsync_network_set_apikey(apikey)" +description: "SQLite-Sync SQL function reference." +category: platform +status: publish +slug: sqlite-sync-api-cloudsync-network-set-apikey +--- + +## `cloudsync_network_set_apikey(apikey)` + +**Description:** Sets the API key for network requests. This key is included in the `Authorization` header of all subsequent requests. + +**Parameters:** + +- `apikey` (TEXT): The API key. + +**Returns:** None. + +**Example:** + +```sql +SELECT cloudsync_network_set_apikey('your_api_key'); +``` + +--- + +### Error handling + +The sync functions follow a consistent error-handling contract: + +| Error type | Behavior | +|---|---| +| **Endpoint/network errors** (server unreachable, auth failure, bad URL) | SQL error — the function could not execute. | +| **Apply errors** (`cloudsync_payload_apply` failures — unknown schema hash, invalid checksum, decompression error) | Structured JSON — a `receive.error` string field is included in the response. | +| **Server-reported apply job failures** (the server processed the request but its own apply job failed) | Structured JSON — a `send.lastFailure` object is included in the response. | +| **Server-reported check job failures** (the server failed to encode a changeset for the client) | Structured JSON — a `receive.lastFailure` object is included in the response. | + +This means: if you get JSON back, the server was reachable and the network protocol ran. If you get a SQL error, connectivity or configuration is broken. + +--- diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_network_set_token.md b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_network_set_token.md new file mode 100644 index 0000000..4e83e82 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_network_set_token.md @@ -0,0 +1,25 @@ +--- +title: "cloudsync_network_set_token(token)" +description: "SQLite-Sync SQL function reference." +category: platform +status: publish +slug: sqlite-sync-api-cloudsync-network-set-token +--- + +## `cloudsync_network_set_token(token)` + +**Description:** Sets the authentication token to be used for network requests. This token will be included in the `Authorization` header of all subsequent requests. For more information, refer to the [Access Tokens documentation](https://docs.sqlitecloud.io/docs/access-tokens). + +**Parameters:** + +- `token` (TEXT): The authentication token. + +**Returns:** None. + +**Example:** + +```sql +SELECT cloudsync_network_set_token('your_auth_token'); +``` + +--- diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_network_sync.md b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_network_sync.md new file mode 100644 index 0000000..fb48a0c --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_network_sync.md @@ -0,0 +1,61 @@ +--- +title: "cloudsync_network_sync([wait_ms], [max_retries])" +description: "SQLite-Sync SQL function reference." +category: platform +status: publish +slug: sqlite-sync-api-cloudsync-network-sync +--- + +## `cloudsync_network_sync([wait_ms], [max_retries])` + +**Description:** Performs a full synchronization cycle. This function has two overloads: + +- `cloudsync_network_sync()`: Performs one send operation and one check operation. +- `cloudsync_network_sync(wait_ms, max_retries)`: Performs one send operation and then downloads remote changes. + +When the server delivers changes as a stream of chunks, this function drains the **whole stream in a single call**: as long as the next chunk is already available it is fetched back-to-back with no delay. `wait_ms` and `max_retries` are spent only while the server payload is **not yet ready** (the server is still preparing a package): in that case the function waits `wait_ms` and retries up to `max_retries` times. They are not consumed while paging through chunks that are already available. + +**Parameters:** + +- `wait_ms` (INTEGER, optional): The time to wait in milliseconds between retries while the server payload is not yet ready. Defaults to 100. +- `max_retries` (INTEGER, optional): The maximum number of poll attempts while the server payload is not yet ready. Defaults to 1. + +**Returns:** A JSON string with the full sync result, combining send and receive: + +```json +{ + "send": {"status": "synced|syncing|out-of-sync|error", "localVersion": N, "serverVersion": N, "chunks": C, "bytes": B, "lastFailure": {...}}, + "receive": {"rows": N, "tables": ["table1", "table2"], "chunks": C, "bytes": B, "complete": true, "error": "...", "lastFailure": {...}} +} +``` + +- `send.status`: The current sync state — `"synced"`, `"syncing"`, `"out-of-sync"`, or `"error"`. +- `send.localVersion`: The latest local database version. +- `send.serverVersion`: The latest version confirmed by the server. +- `send.chunks` / `send.bytes`: Number of payload chunks sent and total serialized payload bytes sent during the send phase. Same semantics as in [`cloudsync_network_send_changes()`](#cloudsync_network_send_changes). +- `send.lastFailure` (optional): Same semantics as in [`cloudsync_network_send_changes()`](#cloudsync_network_send_changes) — forwarded verbatim from the server's `failures.apply` whenever a failed apply job is reported, regardless of `status`. +- `receive.rows`: The **total** number of rows received and applied during the receive phase, summed across **all** chunks drained in this call. `0` when the receive phase failed. +- `receive.tables`: An array of table names that received changes (the union across all drained chunks). Empty (`[]`) if no changes were applied or the receive phase failed. +- `receive.chunks`: The number of payload chunks applied in this call. `0` when nothing was ready, `1` for a single monolithic/inline page, and `N` for a fully drained `N`-chunk stream. `cloudsync_network_sync()` always drains the whole stream (it does not cap chunks). +- `receive.bytes`: The total serialized payload bytes received this call (uncompressed cloudsync payload size, summed across chunks; not the compressed wire size). Same semantics as in [`cloudsync_network_receive_changes()`](#cloudsync_network_receive_changesmax_chunks). +- `receive.complete` (boolean): `true` when the server stream was fully drained, `false` when the download stopped before the final chunk (an error occurred, or an internal safety bound was reached). When `false`, call `cloudsync_network_sync()` again to resume; re-delivered rows are idempotent. +- `receive.error` (optional, string): Present when client-side `cloudsync_payload_apply` failed (for example `"Cannot apply the received payload because the schema hash is unknown 7218827471400075525."`). The send result is always preserved so the caller can tell that local changes reached the server even when applying incoming changes failed. The receive drain stops immediately on apply errors, since failures like schema-hash mismatches do not heal across retries. Endpoint/network errors during the receive phase raise a SQL error instead. +- `receive.lastFailure` (optional, object): Same semantics as in [`cloudsync_network_receive_changes()`](#cloudsync_network_receive_changesmax_chunks) — forwarded verbatim from the server's `failures.check` whenever a failed check job is reported. Distinct from `receive.error`. `cloudsync_network_sync()` reports both `send.lastFailure` and `receive.lastFailure` when present. + +**Example:** + +```sql +-- Perform a single synchronization cycle +SELECT cloudsync_network_sync(); +-- '{"send":{"status":"synced","localVersion":5,"serverVersion":5,"chunks":1,"bytes":2048},"receive":{"rows":3,"tables":["tasks"],"chunks":1,"bytes":820,"complete":true}}' + +-- Perform a synchronization cycle with custom retry settings +SELECT cloudsync_network_sync(500, 3); +-- A large download drained as a multi-chunk stream in a single call: +-- '{"send":{"status":"synced","localVersion":42,"serverVersion":42,"chunks":0,"bytes":0},"receive":{"rows":1200,"tables":["docs"],"chunks":7,"bytes":1835008,"complete":true}}' + +-- Receive phase failed but send phase completed — the error is surfaced in JSON, not as a SQL error: +-- '{"send":{"status":"synced","localVersion":5,"serverVersion":5,"chunks":1,"bytes":512},"receive":{"rows":0,"tables":[],"chunks":0,"bytes":0,"complete":false,"error":"Cannot apply the received payload because the schema hash is unknown 7218827471400075525."}}' +``` + +--- diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_set_column.md b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_set_column.md new file mode 100644 index 0000000..b3d5ab6 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_set_column.md @@ -0,0 +1,38 @@ +--- +title: "cloudsync_set_column(table_name, col_name, key, value)" +description: "SQLite-Sync SQL function reference." +category: platform +status: publish +slug: sqlite-sync-api-cloudsync-set-column +--- + +## `cloudsync_set_column(table_name, col_name, key, value)` + +**Description:** Configures per-column settings for a synchronized table. This function is primarily used to enable **block-level LWW** on text columns, allowing fine-grained conflict resolution at the line (or paragraph) level instead of the entire cell. + +When block-level LWW is enabled on a column, INSERT and UPDATE operations automatically split the text into blocks using a delimiter (default: newline `\n`) and track each block independently. During sync, changes are merged block-by-block, so concurrent edits to different parts of the same text are preserved. + +**Parameters:** + +- `table_name` (TEXT): The name of the synchronized table. +- `col_name` (TEXT): The name of the text column to configure. +- `key` (TEXT): The setting key. Supported keys: + - `'algo'` — Set the column algorithm. Use value `'block'` to enable block-level LWW. + - `'delimiter'` — Set the block delimiter string. Only applies to columns with block-level LWW enabled. +- `value` (TEXT): The setting value. + +**Returns:** None. + +**Example:** + +```sql +-- Enable block-level LWW on a column (splits text by newline by default) +SELECT cloudsync_set_column('notes', 'body', 'algo', 'block'); + +-- Set a custom delimiter (e.g., double newline for paragraph-level tracking) +SELECT cloudsync_set_column('notes', 'body', 'delimiter', ' + +'); +``` + +--- diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_set_filter.md b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_set_filter.md new file mode 100644 index 0000000..ac26c29 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_set_filter.md @@ -0,0 +1,37 @@ +--- +title: "cloudsync_set_filter(table_name, filter_expr)" +description: "SQLite-Sync SQL function reference." +category: platform +status: publish +slug: sqlite-sync-api-cloudsync-set-filter +--- + +## `cloudsync_set_filter(table_name, filter_expr)` + +**Description:** Sets a row-level filter expression on a synchronized table. Only rows that match the filter are tracked by the sync triggers; changes to rows that do not satisfy the expression are ignored and never replicated. + +The filter expression is a standard SQL boolean expression written using bare column names (without a table or alias prefix). The extension automatically rewrites it with `NEW.` for INSERT/UPDATE triggers and `OLD.` for DELETE triggers. The expression is evaluated inside the trigger `WHEN` clause. + +This function stores the filter in the table's settings and immediately recreates the sync triggers to apply it. The filter persists across database reopens. Use [`cloudsync_clear_filter()`](#cloudsync_clear_filtertable_name) to remove it. + +**Parameters:** + +- `table_name` (TEXT): The name of the synchronized table. +- `filter_expr` (TEXT): A SQL boolean expression referencing column names of the table. Only rows for which this expression evaluates to true are tracked for sync. + +**Returns:** `1` on success. + +**Example:** + +```sql +-- Only sync tasks that are not marked as drafts +SELECT cloudsync_set_filter('tasks', "is_draft = 0"); + +-- Only sync rows belonging to a specific tenant +SELECT cloudsync_set_filter('orders', "tenant_id = 'acme'"); + +-- Combine conditions +SELECT cloudsync_set_filter('messages', "deleted = 0 AND type != 'ephemeral'"); +``` + +--- diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_siteid.md b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_siteid.md new file mode 100644 index 0000000..ed002a0 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_siteid.md @@ -0,0 +1,23 @@ +--- +title: "cloudsync_siteid()" +description: "SQLite-Sync SQL function reference." +category: platform +status: publish +slug: sqlite-sync-api-cloudsync-siteid +--- + +## `cloudsync_siteid()` + +**Description:** Returns the unique ID of the local site. + +**Parameters:** None. + +**Returns:** The site ID as a BLOB. + +**Example:** + +```sql +SELECT cloudsync_siteid(); +``` + +--- diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_terminate.md b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_terminate.md new file mode 100644 index 0000000..e45c882 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_terminate.md @@ -0,0 +1,26 @@ +--- +title: "cloudsync_terminate()" +description: "SQLite-Sync SQL function reference." +category: platform +status: publish +slug: sqlite-sync-api-cloudsync-terminate +--- + +## `cloudsync_terminate()` + +**Description:** Releases all internal resources used by the `sqlite-sync` extension for the current database connection. This function should be called before closing the database connection to ensure that all prepared statements and allocated memory are freed. Failing to call this function can result in memory leaks or a failed `sqlite3_close` operation due to pending statements. + +**Parameters:** None. + +**Returns:** None. + +**Example:** + +```sql +-- Before closing the database connection +SELECT cloudsync_terminate(); +``` + +--- + +## Block-Level LWW Functions diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_text_materialize.md b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_text_materialize.md new file mode 100644 index 0000000..60eecbb --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_text_materialize.md @@ -0,0 +1,38 @@ +--- +title: "cloudsync_text_materialize(table_name, col_name, pk_values...)" +description: "SQLite-Sync SQL function reference." +category: platform +status: publish +slug: sqlite-sync-api-cloudsync-text-materialize +--- + +## `cloudsync_text_materialize(table_name, col_name, pk_values...)` + +**Description:** Reconstructs the full text of a block-level LWW column from its individual blocks and writes the result back to the base table column. This is useful after a merge operation to ensure the column contains the up-to-date materialized text. + +After a sync/merge, the column is updated automatically. This function is primarily useful for manual materialization or debugging. + +**Parameters:** + +- `table_name` (TEXT): The name of the table. +- `col_name` (TEXT): The name of the block-level LWW column. +- `pk_values...` (variadic): The primary key values identifying the row. For composite primary keys, pass each key value as a separate argument in declaration order. + +**Returns:** `1` on success. + +**Example:** + +```sql +-- Materialize the body column for a specific row +SELECT cloudsync_text_materialize('notes', 'body', 'note-001'); + +-- With a composite primary key (e.g., PRIMARY KEY (tenant_id, doc_id)) +SELECT cloudsync_text_materialize('docs', 'body', 'tenant-1', 'doc-001'); + +-- Read the materialized text +SELECT body FROM notes WHERE id = 'note-001'; +``` + +--- + +## Helper Functions diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_uuid.md b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_uuid.md new file mode 100644 index 0000000..bc88930 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_uuid.md @@ -0,0 +1,25 @@ +--- +title: "cloudsync_uuid()" +description: "SQLite-Sync SQL function reference." +category: platform +status: publish +slug: sqlite-sync-api-cloudsync-uuid +--- + +## `cloudsync_uuid()` + +**Description:** Generates a new universally unique identifier (UUIDv7). This is useful for creating globally unique primary keys for new records, which is a best practice for CRDTs. + +**Parameters:** None. + +**Returns:** A new UUID as a TEXT value. + +**Example:** + +```sql +INSERT INTO products (id, name) VALUES (cloudsync_uuid(), 'New Product'); +``` + +--- + +## Schema Alteration Functions diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_version.md b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_version.md new file mode 100644 index 0000000..f54d3a5 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/api-reference/cloudsync_version.md @@ -0,0 +1,23 @@ +--- +title: "cloudsync_version()" +description: "SQLite-Sync SQL function reference." +category: platform +status: publish +slug: sqlite-sync-api-cloudsync-version +--- + +## `cloudsync_version()` + +**Description:** Returns the version of the `sqlite-sync` library. + +**Parameters:** None. + +**Returns:** The library version as a string. + +**Example:** +```sql +SELECT cloudsync_version(); +-- e.g., '1.0.0' +``` + +--- diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/best-practices.md b/sqlite-cloud/sqlite-ai/sqlite-sync/best-practices.md new file mode 100644 index 0000000..f98eaf3 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/best-practices.md @@ -0,0 +1,99 @@ +--- +title: "SQLite-Sync Best Practices" +description: "SQLite-Sync Best Practices" +category: platform +status: publish +slug: sqlite-sync-best-practices +--- + +When designing your database schema for SQLite Sync, follow these guidelines to ensure correct CRDT behavior and conflict resolution. + +## Schema Consistency Across Devices + +All databases participating in the same sync (every client and the cloud database) **must have the same set of synced tables with identical structure**: + +- The same tables must be created on every participant. +- Each table must be initialized with `cloudsync_init()` on every participant. +- Column names, types, and constraints must match across participants. + +sqlite-sync computes a **schema hash** from the synced tables and includes it in every sync payload. The server rejects payloads whose schema hash it does not recognize, failing with an error like: + +``` +cloudsync operation failed: Cannot apply the received payload because the schema hash is unknown +``` + +If you need different clients to see different subsets of data (for example, per-tenant or per-workspace isolation), do **not** give each client a different table. Instead, use a single shared schema and scope the data with a column such as `tenant_id` or `workspace_id`, then enforce isolation server-side with [Row-Level Security](/docs/sqlite-sync-row-level-security). + +## Primary Key Requirements + +- **Use globally unique identifiers**: Always use TEXT primary keys with UUIDs or ULIDs. +- **Avoid auto-incrementing integers**: Integer primary keys cause conflicts across multiple devices. +- **Use `cloudsync_uuid()`**: Generates UUIDv7 identifiers optimized for distributed systems. +- **Note:** Any write operation with a NULL primary key value will be rejected with an error. + +```sql +-- Recommended: Globally unique TEXT primary key +CREATE TABLE users ( + id TEXT PRIMARY KEY, -- Use cloudsync_uuid() + name TEXT NOT NULL DEFAULT '', + email TEXT UNIQUE NOT NULL DEFAULT '' +); + +-- Avoid: Auto-incrementing integer primary key +CREATE TABLE users ( + id INTEGER PRIMARY KEY AUTOINCREMENT, -- Causes conflicts across devices + name TEXT NOT NULL DEFAULT '', + email TEXT UNIQUE NOT NULL DEFAULT '' +); +``` + +## Column Constraint Guidelines + +- All `NOT NULL` columns (except primary keys) **must** have `DEFAULT` values. +- For optional data, use nullable columns instead of empty strings. + +```sql +CREATE TABLE tasks ( + id TEXT PRIMARY KEY, + title TEXT NOT NULL DEFAULT '', + status TEXT NOT NULL DEFAULT 'pending', + priority INTEGER NOT NULL DEFAULT 1, + created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')), + assigned_to TEXT -- Nullable for optional data +); +``` + +## UNIQUE Constraint Considerations + +In multi-tenant scenarios with Row-Level Security, UNIQUE constraints must be globally unique across all tenants in the cloud database. Use composite UNIQUE constraints for per-tenant uniqueness: + +```sql +-- Multi-tenant: Composite unique constraint +CREATE TABLE users ( + id TEXT PRIMARY KEY, + tenant_id TEXT NOT NULL DEFAULT '', + email TEXT NOT NULL DEFAULT '', + UNIQUE(tenant_id, email) -- Unique email per tenant +); +``` + +## Foreign Key Compatibility + +Foreign key constraints may conflict with the CRDT merge algorithm: + +- CRDT changes are applied column-by-column during synchronization. Columns may be temporarily assigned DEFAULT values, so foreign key defaults must reference existing rows. +- RLS policies may block CASCADE DELETE/UPDATE operations on related rows. + +**Recommendations:** +- Prefer application-level cascade logic over database-level CASCADE actions. +- Use nullable foreign keys to avoid DEFAULT value issues. +- Test synchronization scenarios with foreign key constraints enabled. + +## Trigger Compatibility + +Triggers can cause issues during synchronization: + +- **Duplicate operations**: Triggers that modify synchronized tables may apply changes twice during merge. +- **Column-by-column processing**: UPDATE triggers may fire multiple times per row as each column is processed. + +Avoid triggers that write to synchronized tables. Use application-level logic instead. diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/block-lww.md b/sqlite-cloud/sqlite-ai/sqlite-sync/block-lww.md new file mode 100644 index 0000000..d50ae80 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/block-lww.md @@ -0,0 +1,130 @@ +--- +title: "SQLite-Sync Block-Level LWW" +description: "Configure block-level last-write-wins conflict resolution for collaborative text columns in SQLite-Sync." +category: platform +status: publish +slug: sqlite-sync-block-lww +--- + +Standard CRDT sync resolves conflicts at the **cell level**: if two devices edit the same column of the same row, one value wins entirely. This works for short values like names or statuses, but for longer text content (markdown documents, notes, agent memory files) the entire text is replaced even if edits were in different parts. + +**Block-Level LWW** (Last-Writer-Wins) solves this by splitting text columns into **blocks** (lines by default) and tracking each block independently. When two devices edit different lines of the same text, **both edits are preserved** after sync. Only when two devices edit the *same* line does LWW apply. + +This feature was specifically designed to keep **markdown files** in sync across devices and AI agents. Agents that independently edit different sections of a shared document (adding notes, updating status, appending logs) can do so without overwriting each other's work. + +## How It Works + +1. **Enable block tracking** on a text column using `cloudsync_set_column()`. +2. On INSERT or UPDATE, text is automatically split into blocks using a delimiter (default: newline `\n`). +3. Each block gets a unique fractional index position, enabling insertions between blocks without reindexing. +4. During sync, changes are merged block-by-block rather than replacing the whole cell. +5. The base column always contains the current full text, your queries work unchanged. + +## Setup + +```sql +-- Create a table with a text column for long-form content +CREATE TABLE notes ( + id TEXT PRIMARY KEY NOT NULL, + title TEXT NOT NULL DEFAULT '', + body TEXT NOT NULL DEFAULT '' +); + +-- Initialize sync on the table +SELECT cloudsync_init('notes'); + +-- Enable block-level LWW on the "body" column +SELECT cloudsync_set_column('notes', 'body', 'algo', 'block'); +``` + +## Example: Two-Device Merge + +```sql +-- Device A: create a note +INSERT INTO notes (id, title, body) VALUES ( + 'note-001', + 'Meeting Notes', + 'Line 1: Welcome +Line 2: Agenda +Line 3: Action items' +); + +-- Sync Device A -> Cloud -> Device B +-- Both devices now have the same 3-line note. +``` + +```sql +-- Device A (offline): edit line 1 +UPDATE notes SET body = 'Line 1: Welcome everyone +Line 2: Agenda +Line 3: Action items' WHERE id = 'note-001'; + +-- Device B (offline): edit line 3 +UPDATE notes SET body = 'Line 1: Welcome +Line 2: Agenda +Line 3: Action items - DONE' WHERE id = 'note-001'; +``` + +```sql +-- After both devices sync, the merged result: +-- 'Line 1: Welcome everyone +-- Line 2: Agenda +-- Line 3: Action items - DONE' +-- +-- Both edits are preserved because they affected different lines. +``` + +## Custom Delimiter + +For paragraph-level tracking (useful for long-form markdown documents), set a custom delimiter: + +```sql +-- Use double newline as delimiter (paragraph separator) +SELECT cloudsync_set_column('notes', 'body', 'delimiter', ' + +'); +``` + +## Materializing Text + +After a merge, the `body` column is updated automatically. You can also manually trigger materialization: + +```sql +-- Reconstruct body from blocks for a specific row +SELECT cloudsync_text_materialize('notes', 'body', 'note-001'); + +-- With a composite primary key (e.g., PRIMARY KEY (tenant_id, doc_id)) +SELECT cloudsync_text_materialize('docs', 'body', 'tenant-1', 'doc-001'); + +-- Then read normally +SELECT body FROM notes WHERE id = 'note-001'; +``` + +## Mixed Columns + +Block-level LWW can be enabled on specific columns while other columns use standard cell-level LWW: + +```sql +CREATE TABLE docs ( + id TEXT PRIMARY KEY NOT NULL, + title TEXT NOT NULL DEFAULT '', -- standard LWW (cell-level) + body TEXT NOT NULL DEFAULT '', -- block LWW (line-level) + status TEXT NOT NULL DEFAULT '' -- standard LWW (cell-level) +); + +SELECT cloudsync_init('docs'); +SELECT cloudsync_set_column('docs', 'body', 'algo', 'block'); + +-- Concurrent edits to "title" or "status" use normal LWW. +-- Concurrent edits to "body" merge at the line level. +``` + +## Key Properties + +- **Non-conflicting edits are preserved**: Two users editing different lines both see their changes after sync. +- **Same-line conflicts use LWW**: If two users edit the same line, the last writer wins. +- **Custom delimiters**: Use paragraph separators (`\n\n`), sentence boundaries, or any string. +- **Mixed columns**: A table can have both regular and block-level LWW columns. +- **Transparent reads**: The base column always contains the current full text. + +For API details, see the [Client API Reference](/docs/sqlite-sync-api-reference). diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/cloudsync-management-api.md b/sqlite-cloud/sqlite-ai/sqlite-sync/cloudsync-management-api.md new file mode 100644 index 0000000..611d66d --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/cloudsync-management-api.md @@ -0,0 +1,407 @@ +--- +title: "Management API" +description: "Register and manage SQLite Sync databases programmatically with a workspace-admin management API key." +category: platform +status: publish +slug: sqlite-sync-cloudsync-management-api +--- + +You can register and manage CloudSync databases programmatically without using the dashboard UI. + +## Authentication + +```http +Authorization: Bearer +``` + +- Base URL: `https://cloudsync.sqlite.ai` +- Use a management API key with the `workspace-admin` role. In the [SQLite Cloud Dashboard](https://dashboard.sqlitecloud.io/), go to your project, then **CloudSync** > **API Keys**. +- The workspace is derived from the key itself. + +Use this API from backend services, CI, or trusted automation. Client apps should use the [Client API Reference](/docs/sqlite-sync-api-reference) instead. + +## Request and Response Conventions + +- Send `Content-Type: application/json` for all `POST`, `PUT`, and `PATCH` bodies. +- Successful responses use the envelope `{"data": ...}`. +- List responses may also include a `meta` object. +- Error responses use a top-level `errors` array. + +Example error response: + +```json +{ + "errors": [ + { + "status": "404", + "code": "not_found", + "title": "Not Found", + "detail": "managed database not found" + } + ] +} +``` + +## Quickstart + +Start with an API key from your project's **CloudSync** > **API Keys** page in the dashboard: + +```bash +export BASE_URL="https://cloudsync.sqlite.ai" +export APIKEY="" +export PROJECT_ID="" +export DATABASE_NAME="appdb" +export SQLITECLOUD_HOST="" +export SQLITECLOUD_API_KEY="" +``` + +### 1. Register a Database + +This creates the managed database entry in CloudSync and returns the CloudSync Database ID as `managedDatabaseId`. + +```bash +curl --request POST "$BASE_URL/v1/databases" \ + --header "Authorization: Bearer $APIKEY" \ + --header "Content-Type: application/json" \ + --data '{ + "label": "Primary DB", + "connectionString": "sqlitecloud://'"$SQLITECLOUD_HOST"':8860?apikey='"$SQLITECLOUD_API_KEY"'", + "provider": "sqlitecloud", + "flavor": "sqlitecloud", + "projectId": "'"$PROJECT_ID"'", + "databaseName": "'"$DATABASE_NAME"'" + }' +``` + +Response: + +```json +{ + "data": { + "managedDatabaseId": "db_xxxxxxxxxxxxxxxxxxxxxxxx" + } +} +``` + +Use `managedDatabaseId` as `MGMT_DB_ID` in the next calls. The response also includes additional database metadata, such as `projectId`, `databaseName`, auth settings, and timestamps. + +```bash +export MGMT_DB_ID="db_xxxxxxxxxxxxxxxxxxxxxxxx" +``` + +### 2. List Registered Databases + +Useful when you want to recover the managed database ID later. + +```bash +curl --request GET "$BASE_URL/v1/databases" \ + --header "Authorization: Bearer $APIKEY" +``` + +### 3. Check Available CloudSync Tables + +```bash +curl --request GET "$BASE_URL/v1/databases/$MGMT_DB_ID/cloudsync/tables" \ + --header "Authorization: Bearer $APIKEY" +``` + +### 4. Enable CloudSync for Tables + +```bash +curl --request POST "$BASE_URL/v1/databases/$MGMT_DB_ID/cloudsync/enable" \ + --header "Authorization: Bearer $APIKEY" \ + --header "Content-Type: application/json" \ + --data '{ + "tables": ["users", "orders"] + }' +``` + +## Endpoint Summary + +| Area | Endpoints | +| --- | --- | +| Organization | `GET /v1/orgs` | +| Databases | `POST /v1/databases`, `GET /v1/databases`, `GET /v1/databases/:databaseID`, `PATCH /v1/databases/:databaseID`, `DELETE /v1/databases/:databaseID`, `GET /v1/databases/:databaseID/connection` | +| CloudSync tables | `GET /v1/databases/:databaseID/cloudsync/tables`, `POST /v1/databases/:databaseID/cloudsync/enable`, `POST /v1/databases/:databaseID/cloudsync/disable` | +| Notifications | `PUT /v1/databases/:databaseID/notifications/expo-access-token`, `GET /v1/databases/:databaseID/notifications/expo-access-token`, `DELETE /v1/databases/:databaseID/notifications/expo-access-token`, `GET /v1/databases/:databaseID/notifications/status` | +| Devices | `GET /v1/databases/:databaseID/devices`, `DELETE /v1/databases/:databaseID/devices/:siteId` | + +## Organization + +### `GET /v1/orgs` + +Returns the organization associated with the API key. + +```bash +curl "$BASE_URL/v1/orgs" \ + --header "Authorization: Bearer $APIKEY" +``` + +```json +{ + "data": { + "organizationId": "org_xxxxxxxxxxxxxxxxxxxxxxxx", + "slug": "acme", + "name": "Acme Corp", + "status": "active" + } +} +``` + +## Databases + +### `POST /v1/databases` + +Registers a new managed database. + +Required fields: + +- `label` +- `connectionString` +- `provider` — `postgres` or `sqlitecloud` +- `flavor` — for example `vanilla`, `supabase`, or `sqlitecloud` +- `projectId` — SQLite Cloud project identifier for the managed database. For SQLite Cloud connection strings, this must match the project ID parsed from the connection string. +- `databaseName` + +Optional fields: + +- `schemaName` — Postgres only +- `jwtAllowedIssuers` +- `jwtExpectedAudiences` +- `jwksUri` +- `jwtSecret` + +CloudSync verifies the tenant database connection before registration is persisted. If verification fails, the database is not registered. + +For SQLite Cloud databases, `databaseName` identifies the target database and CloudSync switches to it when running CloudSync operations. For Postgres databases, the `connectionString` must point to the target database. + +Common database failure codes include `database_paused`, `database_auth_failed`, `database_unreachable`, `database_permission_denied`, `database_cloudsync_not_ready`, and `database_error`. + +### `GET /v1/databases` + +Lists managed databases visible to the key. + +Query parameters: + +- `projectId` — filter by project ID +- `database` — filter by database name; requires `projectId` + +Example: + +```bash +curl "$BASE_URL/v1/databases" \ + --header "Authorization: Bearer $APIKEY" +``` + +Filtered example: + +```bash +curl "$BASE_URL/v1/databases?projectId=$PROJECT_ID&database=$DATABASE_NAME" \ + --header "Authorization: Bearer $APIKEY" +``` + +### `GET /v1/databases/:databaseID` + +Fetches a single managed database in the workspace. + +```bash +curl "$BASE_URL/v1/databases/$MGMT_DB_ID" \ + --header "Authorization: Bearer $APIKEY" +``` + +### `PATCH /v1/databases/:databaseID` + +Updates metadata, auth settings, and connection details. Only the fields you send are modified. + +Supported fields: + +- `label` +- `connectionString` +- `jwtAllowedIssuers` +- `jwtExpectedAudiences` +- `jwksUri` +- `jwtSecret` + +Notes: + +- when `connectionString` is provided, CloudSync verifies the new connection before storing it +- omitting `jwtSecret` leaves the current secret unchanged +- sending `"jwtSecret": ""` clears the current secret +- `jwtSecret` is write-only and is never returned by read endpoints + +Example: + +```bash +curl --request PATCH "$BASE_URL/v1/databases/$MGMT_DB_ID" \ + --header "Authorization: Bearer $APIKEY" \ + --header "Content-Type: application/json" \ + --data '{ + "label": "Primary DB (updated)", + "jwtAllowedIssuers": ["https://project.supabase.co/auth/v1"], + "jwtExpectedAudiences": ["authenticated"], + "jwksUri": "https://project.supabase.co/auth/v1/.well-known/jwks.json", + "jwtSecret": "" + }' +``` + +### `DELETE /v1/databases/:databaseID` + +Deletes a managed database record. + +Before removal, CloudSync attempts to: + +1. list CloudSync-managed tenant tables +2. disable enabled tables +3. delete pending jobs for the managed database + +Cleanup is best effort. The database record is still deleted even if one of those cleanup steps reports warnings. + +```bash +curl --request DELETE "$BASE_URL/v1/databases/$MGMT_DB_ID" \ + --header "Authorization: Bearer $APIKEY" +``` + +### `GET /v1/databases/:databaseID/connection` + +Runs a live connectivity check against the managed database's stored connection details. + +```bash +curl "$BASE_URL/v1/databases/$MGMT_DB_ID/connection" \ + --header "Authorization: Bearer $APIKEY" +``` + +Success response: + +```json +{ + "data": { + "ok": true, + "checkedAt": "2025-01-01T00:00:00Z" + } +} +``` + +Failure response: + +```json +{ + "data": { + "ok": false, + "checkedAt": "2025-01-01T00:00:00Z", + "failure": { + "code": "database_unreachable", + "message": "tenant database is unreachable", + "retryable": true + } + } +} +``` + +## CloudSync Tables + +### `GET /v1/databases/:databaseID/cloudsync/tables` + +Lists tables and whether CloudSync is enabled for each one. + +```bash +curl "$BASE_URL/v1/databases/$MGMT_DB_ID/cloudsync/tables" \ + --header "Authorization: Bearer $APIKEY" +``` + +```json +{ + "data": [ + { "name": "users", "enabled": true }, + { "name": "orders", "enabled": false } + ] +} +``` + +### `POST /v1/databases/:databaseID/cloudsync/enable` + +Enables CloudSync for a non-empty list of tables. + +```bash +curl --request POST "$BASE_URL/v1/databases/$MGMT_DB_ID/cloudsync/enable" \ + --header "Authorization: Bearer $APIKEY" \ + --header "Content-Type: application/json" \ + --data '{"tables": ["users", "orders"]}' +``` + +### `POST /v1/databases/:databaseID/cloudsync/disable` + +Disables CloudSync for a non-empty list of tables. + +```bash +curl --request POST "$BASE_URL/v1/databases/$MGMT_DB_ID/cloudsync/disable" \ + --header "Authorization: Bearer $APIKEY" \ + --header "Content-Type: application/json" \ + --data '{"tables": ["orders"]}' +``` + +## Notifications + +### `PUT /v1/databases/:databaseID/notifications/expo-access-token` + +Sets or rotates the Expo access token used to send push notifications. + +```bash +curl --request PUT "$BASE_URL/v1/databases/$MGMT_DB_ID/notifications/expo-access-token" \ + --header "Authorization: Bearer $APIKEY" \ + --header "Content-Type: application/json" \ + --data '{"expoAccessToken": "expo-access-token-value"}' +``` + +### `GET /v1/databases/:databaseID/notifications/expo-access-token` + +Returns metadata about the Expo access token, not the token value itself. + +```bash +curl "$BASE_URL/v1/databases/$MGMT_DB_ID/notifications/expo-access-token" \ + --header "Authorization: Bearer $APIKEY" +``` + +### `DELETE /v1/databases/:databaseID/notifications/expo-access-token` + +Removes the Expo access token from the database. + +```bash +curl --request DELETE "$BASE_URL/v1/databases/$MGMT_DB_ID/notifications/expo-access-token" \ + --header "Authorization: Bearer $APIKEY" +``` + +### `GET /v1/databases/:databaseID/notifications/status` + +Returns the current push notification status for a managed database. + +`status` can be `enabled`, `disabled`, or `paused`. When `status` is `paused`, `reason` explains why. Currently supported pause reasons include `expo_unauthorized`. + +```bash +curl "$BASE_URL/v1/databases/$MGMT_DB_ID/notifications/status" \ + --header "Authorization: Bearer $APIKEY" +``` + +## Devices + +### `GET /v1/databases/:databaseID/devices` + +Lists registered devices for a managed database. + +Query parameters: + +- `page` — default `1` +- `page_size` — default `50`, max `500` + +```bash +curl "$BASE_URL/v1/databases/$MGMT_DB_ID/devices?page=1&page_size=50" \ + --header "Authorization: Bearer $APIKEY" +``` + +### `DELETE /v1/databases/:databaseID/devices/:siteId` + +Removes a registered device by `siteId`. Associated push tokens are removed as well. + +```bash +curl --request DELETE "$BASE_URL/v1/databases/$MGMT_DB_ID/devices/site_123" \ + --header "Authorization: Bearer $APIKEY" +``` diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/getting-started.md b/sqlite-cloud/sqlite-ai/sqlite-sync/getting-started.md new file mode 100644 index 0000000..a1b5567 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/getting-started.md @@ -0,0 +1,112 @@ +--- +title: "SQLite-Sync Getting Started" +description: "SQLite-Sync Getting Started" +category: platform +status: publish +slug: sqlite-sync-getting-started +--- + +## Quick Start + +### 1. Install + +Install SQLite Sync for your platform first. See the [Installation guide](/docs/sqlite-sync-installation) for native, mobile, Expo, React Native, Flutter, and WASM setup. + +### 2. Create a table and enable sync + +```sql +CREATE TABLE tasks ( + id TEXT PRIMARY KEY, + title TEXT NOT NULL DEFAULT '', + done INTEGER NOT NULL DEFAULT 0 +); + +-- Enable CRDT sync on the table +SELECT cloudsync_init('tasks'); +``` + +### 3. Use your database normally + +```sql +INSERT INTO tasks (id, title) VALUES (cloudsync_uuid(), 'Buy groceries'); +INSERT INTO tasks (id, title) VALUES (cloudsync_uuid(), 'Review PR #42'); + +UPDATE tasks SET done = 1 WHERE title = 'Buy groceries'; + +SELECT * FROM tasks; +``` + +### 4. Sync with the cloud + +The example below uses SQLite Cloud CloudSync. If you are wiring up a self-hosted backend instead, use the [PostgreSQL quick start](/docs/sqlite-sync-postgresql-quick-start) or the [self-hosted Supabase quick start](/docs/sqlite-sync-supabase-self-hosted-quick-start). + +```sql +-- Connect to your SQLite Cloud managed database +-- (get the managed database ID from the CloudSync page on the SQLite Cloud dashboard) +SELECT cloudsync_network_init('your-managed-database-id'); +SELECT cloudsync_network_set_apikey('your-api-key'); + +-- Send local changes and receive remote changes +SELECT cloudsync_network_sync(); +-- Returns JSON: {"send":{"status":"synced","localVersion":3,"serverVersion":3},"receive":{"rows":0,"tables":[]}} + +-- Call periodically to stay in sync +SELECT cloudsync_network_sync(); + +-- Before closing the connection +SELECT cloudsync_terminate(); +``` + +### 5. Sync from another device + +On a second device (or a second database for testing), repeat the same setup: + +```sql +-- Device B: create the same table and init sync +CREATE TABLE tasks ( + id TEXT PRIMARY KEY, + title TEXT NOT NULL DEFAULT '', + done INTEGER NOT NULL DEFAULT 0 +); + +SELECT cloudsync_init('tasks'); + +-- Connect to the same cloud database +SELECT cloudsync_network_init('your-managed-database-id'); +SELECT cloudsync_network_set_apikey('your-api-key'); + +-- Pull changes from Device A +SELECT cloudsync_network_sync(); +-- Call again: the first call triggers package preparation, the second downloads it +SELECT cloudsync_network_sync(); + +-- Device A's tasks are now here +SELECT * FROM tasks; + +-- Add data from this device +INSERT INTO tasks (id, title) VALUES (cloudsync_uuid(), 'Call the dentist'); + +-- Send this device's changes to the cloud +SELECT cloudsync_network_sync(); + +-- Before closing the connection +SELECT cloudsync_terminate(); +``` + +Back on Device A, calling `cloudsync_network_sync()` will pull Device B's changes. The CRDT engine ensures all devices converge to the same data, automatically, with no conflicts. + +> **Note:** every device participating in the same sync must create **the same set of tables with the same structure** and initialize each one with `cloudsync_init()`. sqlite-sync derives a schema hash from the synced tables, and the server rejects payloads whose hash it does not recognize. For multi-tenant setups where each client should see only a subset of rows, use a shared schema with a tenant/scope column and enforce isolation with [Row-Level Security](/docs/sqlite-sync-row-level-security) — do not give each client a different table. + +## SQLite Cloud Setup + +If you are not using SQLite Cloud as the sync backend, see the [self-hosted PostgreSQL quick start](/docs/sqlite-sync-postgresql-quick-start) or the [self-hosted Supabase quick start](/docs/sqlite-sync-supabase-self-hosted-quick-start). + +1. Sign up at [SQLite Cloud](https://sqlitecloud.io/) and create a project. +2. Create a database and your tables in the [dashboard](https://dashboard.sqlitecloud.io/). +3. Enable synchronization: click **"CloudSync"** for your database and select the tables to sync. +4. Copy the managed database ID and API key from the dashboard. +5. Use `cloudsync_network_init()` and `cloudsync_network_set_apikey()` locally, then call `cloudsync_network_sync()`. + +For token-based authentication (required for RLS), use `cloudsync_network_set_token()` instead of `cloudsync_network_set_apikey()`. + +If you want to register the managed database and enable tables programmatically instead of using the dashboard, see [Management API](/docs/sqlite-sync-cloudsync-management-api). diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/installation.md b/sqlite-cloud/sqlite-ai/sqlite-sync/installation.md new file mode 100644 index 0000000..807f5c4 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/installation.md @@ -0,0 +1,151 @@ +--- +title: "SQLite-Sync Installation" +description: "Installation options for SQLite-Sync across native, mobile, Expo, React Native, Flutter, and WASM targets." +category: platform +status: publish +slug: sqlite-sync-installation +--- + +Download the appropriate pre-built binary for your platform from the official [Releases](https://github.com/sqliteai/sqlite-sync/releases) page: + +- Linux: x86_64 and arm64 (glibc and musl) +- macOS: x86_64 and arm64 +- Windows: x86_64 +- Android +- iOS + +## SQLite CLI / C + +```sql +-- In SQLite CLI +.load ./cloudsync + +-- In SQL +SELECT load_extension('./cloudsync'); +``` + +## Swift Package + +[Add this repository as a package dependency to your Swift project](https://developer.apple.com/documentation/xcode/adding-package-dependencies-to-your-app#Add-a-package-dependency). After adding the package, set up SQLite with extension loading by following steps 4 and 5 of [this guide](https://github.com/sqliteai/sqlite-extensions-guide/blob/main/platforms/ios.md#4-set-up-sqlite-with-extension-loading). + +```swift +import CloudSync + +var db: OpaquePointer? +sqlite3_open(":memory:", &db) +sqlite3_enable_load_extension(db, 1) +var errMsg: UnsafeMutablePointer? = nil +sqlite3_load_extension(db, CloudSync.path, nil, &errMsg) +var stmt: OpaquePointer? +sqlite3_prepare_v2(db, "SELECT cloudsync_version()", -1, &stmt, nil) +defer { sqlite3_finalize(stmt) } +sqlite3_step(stmt) +print("cloudsync_version(): \(String(cString: sqlite3_column_text(stmt, 0)))") +sqlite3_close(db) +``` + +## Android + +Add the [following](https://central.sonatype.com/artifact/ai.sqlite/sync) to your Gradle dependencies: + +```gradle +implementation 'ai.sqlite:sync:' +``` + +```java +SQLiteCustomExtension cloudsyncExtension = new SQLiteCustomExtension( + getApplicationInfo().nativeLibraryDir + "/cloudsync", null); +SQLiteDatabaseConfiguration config = new SQLiteDatabaseConfiguration( + getCacheDir().getPath() + "/cloudsync_test.db", + SQLiteDatabase.CREATE_IF_NECESSARY | SQLiteDatabase.OPEN_READWRITE, + Collections.emptyList(), + Collections.emptyList(), + Collections.singletonList(cloudsyncExtension) +); +SQLiteDatabase db = SQLiteDatabase.openDatabase(config, null, null); +``` + +For full implementation details, see the [complete Android example](https://github.com/sqliteai/sqlite-extensions-guide/blob/main/examples/android/README.md). + +## Expo + +Install the Expo package: + +```bash +npm install @sqliteai/sqlite-sync-expo +``` + +Add to your `app.json`: + +```json +{ + "expo": { + "plugins": ["@sqliteai/sqlite-sync-expo"] + } +} +``` + +Run prebuild: + +```bash +npx expo prebuild --clean +``` + +Load the extension: + +```typescript +import { Platform } from 'react-native'; +import { getDylibPath, open } from '@op-engineering/op-sqlite'; + +const db = open({ name: 'mydb.db' }); + +// Load SQLite Sync extension +if (Platform.OS === 'ios') { + const path = getDylibPath('ai.sqlite.cloudsync', 'CloudSync'); + db.loadExtension(path); +} else { + db.loadExtension('cloudsync'); +} +``` + +## React Native + +Install the React Native library: + +```bash +npm install @sqliteai/sqlite-sync-react-native +``` + +Then follow the instructions from the [README](https://www.npmjs.com/package/@sqliteai/sqlite-sync-react-native). + +## Flutter + +Add the [sqlite_sync](https://pub.dev/packages/sqlite_sync) package to your project: + +```bash +flutter pub add sqlite_sync # Flutter projects +dart pub add sqlite_sync # Dart projects +``` + +Requires Dart 3.10+ / Flutter 3.38+. + +```dart +import 'package:sqlite3/sqlite3.dart'; +import 'package:sqlite_sync/sqlite_sync.dart'; + +sqlite3.loadSqliteSyncExtension(); +final db = sqlite3.openInMemory(); +print(db.select('SELECT cloudsync_version()')); +``` + +For a complete example, see the [Flutter example](https://github.com/sqliteai/sqlite-extensions-guide/blob/main/examples/flutter/README.md). + +## WASM + +The WebAssembly version of SQLite with the SQLite Sync extension is available on npm: + +```bash +npm install @sqliteai/sqlite-wasm +``` + +See the [npm package](https://www.npmjs.com/package/@sqliteai/sqlite-wasm) for usage details. diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/introduction.md b/sqlite-cloud/sqlite-ai/sqlite-sync/introduction.md new file mode 100644 index 0000000..4076028 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/introduction.md @@ -0,0 +1,67 @@ +--- +title: "Introduction to SQLite-Sync" +description: "Introduction to SQLite-Sync" +category: platform +status: publish +slug: sqlite-sync-introduction +--- + +[![sqlite-sync coverage](https://img.shields.io/badge/dynamic/regex?url=https%3A%2F%2Fsqliteai.github.io%2Fsqlite-sync%2F&search=Functions%3A%3C%5C%2Ftd%3E%5Cs*%3Ctd%20class%3D%22headerCovTableEntry(?:Hi|Med|Lo)%22%3E(%5B%5Cd.%5D%2B)%26nbsp%3B%25&replace=%241%25&label=coverage&labelColor=rgb(85%2C%2085%2C%2085)%3B&color=rgb(167%2C%20252%2C%20157)%3B&link=https%3A%2F%2Fsqliteai.github.io%2Fsqlite-sync%2F)](https://sqliteai.github.io/sqlite-sync/) + +**SQLite Sync** is a multi-platform extension that turns any SQLite database into a **conflict-free, offline-first replica** that syncs automatically with **[SQLite Cloud](https://sqlitecloud.io/)** nodes, **PostgreSQL** servers, and **Supabase** instances. One function call is all it takes: no backend to build, no sync protocol to implement. + +
    + + Installed by default in SQLite Cloud + + + GitHub: https://github.com/sqliteai/sqlite-sync + +
    + +Built on **CRDT** (Conflict-free Replicated Data Types), it guarantees: + +- **No data loss.** Devices update independently, even offline, and all changes merge automatically. +- **No conflicts.** Deterministic merge, no manual conflict resolution, ever. +- **No extra infrastructure.** A globally distributed network of **CloudSync microservices** handles routing, packaging, and delivery of changes between SQLite and other DBMS nodes. + +> **Need a sync backend?** Plug into [PostgreSQL](/docs/sqlite-sync-postgresql-quick-start) or [self-hosted Supabase](/docs/sqlite-sync-supabase-self-hosted-quick-start), or use managed SQLite Cloud CloudSync. + +## Why SQLite Sync? + +**For offline-first apps** (mobile, desktop, IoT, edge): devices work with a local SQLite database and sync when connectivity is available. Changes queue locally and merge seamlessly on reconnect. + +**For AI agents**: agents that maintain memory, notes, or shared state in SQLite can sync across instances without coordination. **[Block-Level LWW](#block-level-lww)** was specifically designed to keep **markdown files** in sync: multiple agents editing different sections of the same document preserve all changes after sync. + +## What Can You Build with SQLite Sync? + +### Offline-First Apps +- **Shared To-Do Lists**: users independently update tasks and sync effortlessly. +- **Note-Taking Apps**: real-time collaboration with offline editing. +- **Field Data Collection**: for remote inspections, agriculture, or surveys. +- **Point-of-Sale Systems**: offline-first retail solutions with synced inventory. + +### AI Agent Sync +- **Agent Memory**: multiple agents share and update a common SQLite database, syncing state across instances without coordination. +- **Markdown Knowledge Bases**: agents independently edit different sections of shared markdown documents, with Block-Level LWW preserving all changes. +- **Distributed Pipelines**: agents running on different nodes accumulate results locally and merge them into a single consistent dataset. + +### Enterprise and Multi-Tenant +- **CRM Systems**: sync leads and clients per user with row-level access control. +- **SaaS Platforms**: row-level access for each user or team using a single shared database. +- **Project Management Tools**: offline-friendly planning and task management. + +### Personal Apps +- **Journaling and Diaries**: private entries that sync across devices. +- **Habit Trackers**: sync progress with data security and consistency. +- **Bookmarks and Reading Lists**: personal or collaborative content management. + +## Key Features + +| Feature | Description | +|---------|-------------| +| **CRDT-based sync** | Causal-Length Set, Delete-Wins, Add-Wins, and Grow-Only Set algorithms | +| **Block-Level LWW** | Line-level merge for text/markdown columns, concurrent edits to different lines are preserved | +| **Built-in networking** | Embedded network layer (libcurl or native), single function call to sync | +| **Row-Level Security** | Server-enforced RLS: each client syncs only the rows it is authorized to see | +| **Multi-platform** | Linux, macOS, Windows, iOS, Android, WASM | diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/jwt-claims.md b/sqlite-cloud/sqlite-ai/sqlite-sync/jwt-claims.md new file mode 100644 index 0000000..b907036 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/jwt-claims.md @@ -0,0 +1,114 @@ +--- +title: "JWT Claims Reference" +description: "JWT claim requirements and role/grant expectations for PostgreSQL and Supabase CloudSync backends." +category: platform +status: publish +slug: sqlite-sync-jwt-claims +--- + +## HS256 Claims + +Use this mode when CloudSync validates JWTs with `jwtSecret`. + +| Claim | Required? | Notes | +| --- | --- | --- | +| `sub` | Depends | Commonly used by application-specific RLS policies | +| `email` | No | Optional app-specific claim | +| `role` | Yes | Required for PostgreSQL JWT-authenticated requests because CloudSync uses it for `SET LOCAL ROLE` | +| `iss` | No | Optional in HS256 mode | +| `aud` | Depends | Required only when `jwtExpectedAudiences` is configured | +| `iat` | No | Optional issued-at timestamp | +| `exp` | Yes | Required and validated by CloudSync | + +## JWKS Claims + +Use this mode when CloudSync validates JWTs with `jwtAllowedIssuers` and optional `jwksUri`. + +| Claim | Required? | Notes | +| --- | --- | --- | +| `sub` | Depends | Commonly used by application-specific RLS policies | +| `email` | No | Optional app-specific claim | +| `role` | Yes | Required for PostgreSQL JWT-authenticated requests because CloudSync uses it for `SET LOCAL ROLE` | +| `iss` | Yes | Required for JWKS or issuer-based validation | +| `aud` | Depends | Required only when `jwtExpectedAudiences` is configured | +| `iat` | No | Optional issued-at timestamp | +| `exp` | Yes | Required and validated by CloudSync | +| Header `kid` | Yes | Required in the JWT header so CloudSync can select the verification key from the JWKS | + +## PostgreSQL Role Requirement + +For PostgreSQL JWT authentication, the `role` claim must name a real database role that CloudSync can switch into with `SET LOCAL ROLE`. + +That role should: + +- already exist in PostgreSQL +- have the schema, table, and sequence privileges your sync operations need +- be grantable by the connection-string user + +If the JWT contains a `role` that does not exist, or the connection user cannot switch into it, PostgreSQL sync operations will fail even if the JWT itself is otherwise valid. + +### Creating the Role + +```sql +CREATE ROLE rls_role NOLOGIN; +GRANT rls_role TO postgres; +``` + +### Required Grants + +`cloudsync_payload_apply` running as a non-superuser touches several internal CloudSync objects during apply — not just your user table. If any grant is missing on an internal object, the per-PK savepoint silently rolls back the write and the caller sees a non-zero column-change count with no rows landing. + +Recommended setup: + +```sql +GRANT USAGE ON SCHEMA public TO rls_role; +GRANT USAGE ON SCHEMA auth TO rls_role; + +ALTER DEFAULT PRIVILEGES IN SCHEMA public + GRANT SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER + ON TABLES TO rls_role; + +ALTER DEFAULT PRIVILEGES IN SCHEMA public + GRANT USAGE, SELECT, UPDATE ON SEQUENCES TO rls_role; + +ALTER DEFAULT PRIVILEGES IN SCHEMA public + GRANT EXECUTE ON FUNCTIONS TO rls_role; +``` + +If the extension is already installed, backfill existing objects with one-time grants and keep the default-privileges block for future objects. + +## How CloudSync Passes JWT Claims to PostgreSQL + +CloudSync validates the JWT and passes all claims to PostgreSQL via `request.jwt.claims`. It also executes `SET LOCAL ROLE` from the JWT `role` claim. + +That means RLS policies can read claims with expressions such as: + +```sql +current_setting('request.jwt.claims')::jsonb->>'sub' +current_setting('request.jwt.claims')::jsonb->>'role' +``` + +## Optional Helper Functions + +If you want shorter policy expressions, create convenience wrappers: + +```sql +CREATE SCHEMA IF NOT EXISTS auth; + +CREATE OR REPLACE FUNCTION auth.session() +RETURNS jsonb AS $$ + SELECT current_setting('request.jwt.claims', true)::jsonb; +$$ LANGUAGE SQL STABLE; + +CREATE OR REPLACE FUNCTION auth.user_id() +RETURNS text AS $$ + SELECT auth.session()->>'sub'; +$$ LANGUAGE SQL STABLE; + +CREATE OR REPLACE FUNCTION auth.role() +RETURNS text AS $$ + SELECT auth.session()->>'role'; +$$ LANGUAGE SQL STABLE; +``` + +For RLS behavior and troubleshooting, see the [RLS reference](/docs/sqlite-sync-rls-reference). diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/postgresql-quick-start.md b/sqlite-cloud/sqlite-ai/sqlite-sync/postgresql-quick-start.md new file mode 100644 index 0000000..d187ac7 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/postgresql-quick-start.md @@ -0,0 +1,163 @@ +--- +title: "Self-Hosted PostgreSQL Quick Start" +description: "Enable CloudSync on your own PostgreSQL instance and connect SQLite Sync clients to it." +category: platform +status: publish +slug: sqlite-sync-postgresql-quick-start +--- + +This guide helps you enable CloudSync on a **self-hosted PostgreSQL database**. CloudSync adds offline-first synchronization capabilities to your PostgreSQL database. + +## Step 1: Deploy PostgreSQL with CloudSync + +You can enable CloudSync in one of two ways: + +- Use the published Docker image if you run PostgreSQL in Docker +- Install the released extension files into an existing native PostgreSQL installation + +### Option A: Docker + +Use the published PostgreSQL image that already includes the CloudSync extension: + +- `sqlitecloud/sqlite-sync-postgres:15` +- `sqlitecloud/sqlite-sync-postgres:17` + +Example using Docker Compose: + +```yaml +services: + db: + image: sqlitecloud/sqlite-sync-postgres:17 + container_name: cloudsync-postgres + environment: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: your-secure-password + POSTGRES_DB: postgres + ports: + - "5432:5432" + volumes: + - pg_data:/var/lib/postgresql/data + - ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro + +volumes: + pg_data: +``` + +Create `init.sql`: + +```sql +CREATE EXTENSION IF NOT EXISTS cloudsync; +``` + +Run: + +```bash +docker compose up -d +``` + +### Option B: Existing PostgreSQL Without Docker + +If you already run PostgreSQL directly on a VM or bare metal, download the release tarball that matches your operating system, CPU architecture, and PostgreSQL major version. + +Extract the archive, then copy the extension files into PostgreSQL's extension directories. The tarball ships `cloudsync.control`, a `cloudsync--.sql` install script for the current release, and any `cloudsync----.sql` upgrade scripts needed so existing installations can run `ALTER EXTENSION cloudsync UPDATE`. + +```bash +cp cloudsync.so "$(pg_config --pkglibdir)/" +cp cloudsync.control cloudsync--*.sql "$(pg_config --sharedir)/extension/" +``` + +Then connect to PostgreSQL and enable the extension: + +```sql +CREATE EXTENSION IF NOT EXISTS cloudsync; +``` + +## Step 2: Verify the Extension + +If you are using Docker: + +```bash +docker compose exec db psql -U postgres -d postgres -c "SELECT cloudsync_version();" +``` + +If you are using an existing PostgreSQL installation without Docker: + +```bash +psql -U postgres -d postgres -c "SELECT cloudsync_version();" +``` + +If the extension is installed correctly, PostgreSQL returns the CloudSync version string. + +### Upgrading a later release + +CloudSync uses the first two components of its semver as the PostgreSQL extension version. How you upgrade depends on which component changed: + +- **PATCH release**: pull the new Docker image or replace the extension files on disk and restart PostgreSQL. No SQL-level upgrade is needed. `SELECT cloudsync_version();` confirms the new semver. +- **MINOR or MAJOR release**: pull the new artifacts as above, then run once per database: + + ```sql + ALTER EXTENSION cloudsync UPDATE; + ``` + +You can check the current state at any time: + +```sql +SELECT name, default_version, installed_version +FROM pg_available_extensions +WHERE name = 'cloudsync'; +``` + +## Step 3: Register Your Database in the CloudSync Dashboard + +In the [CloudSync dashboard](https://dashboard.sqlitecloud.io/), create a new workspace with the **PostgreSQL** provider, then add a project with your PostgreSQL connection string: + +```text +postgresql://user:password@host:5432/database +``` + +## Step 4: Enable CloudSync on Tables + +In the dashboard, go to the **Database Setup** tab, select the tables you want to sync, and click **Deploy Changes**. + +## Step 5: Set Up Authentication + +On the **Client Integration** tab you'll find your **Database ID** and authentication settings. + +### Quick Test with API Key + +The fastest way to test CloudSync without per-user access control. + +With API key authentication, CloudSync uses the database role resolved from the API-key-authenticated connection when available; otherwise it falls back to the role from the connection string. + +```sql +SELECT cloudsync_network_init(''); +SELECT cloudsync_network_set_apikey(':'); +SELECT cloudsync_network_sync(); +``` + +### Using JWT Tokens + +1. Set **Row Level Security** to **Yes, enforce RLS** +2. Under **Authentication (JWT)**, click **Configure authentication** and choose: + - **HMAC Secret (HS256):** + - Enter your JWT secret (or generate one: `openssl rand -base64 32`) + - Optionally add **Expected audiences** + - **JWKS Issuer Validation:** + - Enter the issuer base URL from your token's `iss` claim + - By default, CloudSync uses OIDC discovery to resolve `jwks_uri` + - Optionally set an **Explicit JWKS URI** + - Optionally add **Expected audiences** +3. For claim details and RLS examples, see: + - [JWT Claims Reference](/docs/sqlite-sync-jwt-claims) + - [RLS Reference](/docs/sqlite-sync-rls-reference) +4. In your client code: + + ```sql + SELECT cloudsync_network_init(''); + SELECT cloudsync_network_set_token(''); + SELECT cloudsync_network_sync(); + ``` + +## Example App + +For a complete Expo walkthrough using a self-hosted PostgreSQL backend, see the [Todo App PostgreSQL example](https://github.com/sqliteai/sqlite-sync/blob/main/docs/postgresql/examples/todo-app-postgres.md). diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/quick-starts/android.mdx b/sqlite-cloud/sqlite-ai/sqlite-sync/quick-starts/android.mdx new file mode 100644 index 0000000..dfe332b --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/quick-starts/android.mdx @@ -0,0 +1,192 @@ +--- +title: "Android Quick Start Guide" +description: SQLite Sync is a multi-platform extension that brings a true local-first experience to your applications with minimal effort. +category: platform +status: publish +slug: sqlite-sync-quick-start-android +--- + +import Callout from "@commons-components/Information/Callout.astro"; + +This guide shows how to integrate sqlite-sync extension into your Android application. + +### 1. Add Dependencies + +You can add sqlite-sync as a dependency to your Android project. + +
    +Groovy DSL + +```groovy +repositories { + google() + mavenCentral() + maven { url 'https://jitpack.io' } +} +dependencies { + // ... + // Use requery's SQLite instead of Android's built-in SQLite to support loading custom extensions + implementation 'com.github.requery:sqlite-android:3.49.0' + // Both packages below are identical - use either one + implementation 'ai.sqlite:sync:0.8.39' // Maven Central + // implementation 'com.github.sqliteai:sqlite-sync:0.8.39' // JitPack (alternative) +} +``` + +
    + +
    +Kotlin DSL + +```kotlin +repositories { + google() + mavenCentral() + maven(url = "https://jitpack.io") +} +dependencies { + // ... + // Use requery's SQLite instead of Android's built-in SQLite to support loading custom extensions + implementation("com.github.requery:sqlite-android:3.49.0") + // Both packages below are identical - use either one + implementation("ai.sqlite:sync:0.8.39") // Maven Central + // implementation("com.github.sqliteai:sqlite-sync:0.8.39") // JitPack (alternative) +} +``` + +
    + +### 2. Update AndroidManifest.xml + +Add `android:extractNativeLibs="true"` to your `` tag: + +```xml + +``` + +### 3. Basic Integration + +Here’s a complete example showing how to load the extension, create a table, initialize CloudSync, and perform network sync. + + + Replace the following placeholders with your actual values: + - `database_name` - Your database name + - `table_name` - Your table name + - `` - Your SQLiteCloud connection string + - `` - Your SQLiteCloud API key + + +```kotlin +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.lifecycle.lifecycleScope +import io.requery.android.database.sqlite.SQLiteCustomExtension +import io.requery.android.database.sqlite.SQLiteDatabase +import io.requery.android.database.sqlite.SQLiteDatabaseConfiguration +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +class MainActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + // --- Create extension configuration --- + val cloudsyncExtension = SQLiteCustomExtension(applicationInfo.nativeLibraryDir + "/cloudsync", null) + + // --- Configure database with extension --- + val config = SQLiteDatabaseConfiguration( + cacheDir.path + "/database_name.db", + SQLiteDatabase.CREATE_IF_NECESSARY or SQLiteDatabase.OPEN_READWRITE, + emptyList(), + emptyList(), + listOf(cloudsyncExtension) + ) + + // --- Open database --- + val db = SQLiteDatabase.openDatabase(config, null, null) + val tableName = "table_name" + + lifecycleScope.launch { + withContext(Dispatchers.IO) { + // --- Check CloudSync version --- + val version = db.rawQuery("SELECT cloudsync_version();", null).use { cursor -> + if (cursor.moveToFirst()) cursor.getString(0) else null + } + + if (version == null) { + println("CLOUDSYNC-TEST: Failed to load SQLite Sync extension") + return@withContext + } + + println("CLOUDSYNC-TEST: SQLite Sync loaded successfully. Version: $version") + + try { + // --- Create test table --- + val createTableSQL = """ + CREATE TABLE IF NOT EXISTS $tableName ( + id TEXT PRIMARY KEY NOT NULL, + value TEXT NOT NULL DEFAULT '', + created_at TEXT DEFAULT CURRENT_TIMESTAMP + ); + """.trimIndent() + db.execSQL(createTableSQL) + + // --- Initialize CloudSync for table --- + val initResult = db.rawQuery("SELECT cloudsync_init('$tableName');", null).use { it.moveToFirst() } + + // --- Insert sample data --- + db.execSQL(""" + INSERT INTO $tableName (id, value) VALUES + (cloudsync_uuid(), 'test1'), + (cloudsync_uuid(), 'test2'); + """.trimIndent()) + + // --- Initialize network connection --- + db.rawQuery( + "SELECT cloudsync_network_init('');", + null + ).use { it.moveToFirst() } + + // --- Set API key --- + db.rawQuery( + "SELECT cloudsync_network_set_apikey('');", + null + ).use { it.moveToFirst() } + + // --- Run network sync multiple times --- + // Note: cloudsync_network_sync() returns > 0 if data was sent/received. + // It should ideally be called periodically to ensure both sending local + // changes and receiving remote changes work reliably. + repeat(2) { attempt -> + try { + val syncResult = db.rawQuery("SELECT cloudsync_network_sync();", null).use { cursor -> + if (cursor.moveToFirst()) cursor.getInt(0) else 0 + } + println("CLOUDSYNC-TEST: Network sync attempt ${attempt + 1}: result = $syncResult") + } catch (e: Exception) { + println("CLOUDSYNC-TEST: Sync attempt ${attempt + 1} failed: ${e.message}") + } + } + } catch (e: Exception) { + println("CLOUDSYNC-TEST: Error - ${e.message}") + } finally { + // --- Terminate CloudSync --- + db.rawQuery("SELECT cloudsync_terminate();", null).use { it.moveToFirst() } + + // Close the database + db.close() + } + } + } + } +} +``` + + + CloudSync functions must be executed with `SELECT`. In Android, use + `rawQuery()` to call them, and always call `moveToFirst()` (or `moveToNext()`) + on the cursor to ensure the query actually executes. + diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/quick-starts/ios.md b/sqlite-cloud/sqlite-ai/sqlite-sync/quick-starts/ios.md new file mode 100644 index 0000000..0128f78 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/quick-starts/ios.md @@ -0,0 +1,207 @@ +--- +title: "iOS Quick Start Guide" +description: SQLite Sync is a multi-platform extension that brings a true local-first experience to your applications with minimal effort. +category: platform +status: publish +slug: sqlite-sync-quick-start-ios +--- + +This guide will walk you through setting up SQLite in Swift to load CloudsSync extensions. + +## 1. Create a New Swift Project + +1. Open Xcode +2. Create a new project +3. Select **Multiplatform** → **App** + +## 2. Download and Add CloudSync Framework + +1. Download the latest version of `cloudsync-apple-xcframework` from here + +2. In Xcode, click on your project name in the source tree (top left with the Xcode logo) + +3. In the new tab that opens, navigate to the left column under the **Targets** section and click on the first target + +4. You should now be in the **General** tab. Scroll down to **"Frameworks, Libraries, and Embedded Content"** + +5. Click the **+** button → **Add Other...** → **Add Files...** + +6. Select the downloaded `CloudSync.xcframework` folder + +7. Switch to the **Build Phases** tab and verify that `CloudSync.xcframework` appears under **Embedded Frameworks** + +## 3. Handle Security Permissions (macOS) + +When you return to the main ContentView file, you may encounter an Apple security error: + +1. Click **Done** when the security dialog appears +2. Open **System Settings** → **Privacy & Security** +3. Scroll to the bottom and find the message "Mac blocked CloudSync" +4. Click **Allow Anyway** +5. Close and reopen ContentView in Xcode +6. The same error should appear but now with a third button **Open Anyway** - click it +7. If errors persist, try reopening and closing ContentView multiple times or repeat the security steps above + +## 4. Set Up SQLite with Extension Loading + +You need a version of SQLite that supports loading extensions. You have two options: + +### Option A: Download SQLite Amalgamation (Recommended) + +1. Download the amalgamation from here +2. Create a new folder called **SQLite** in your Swift project in Xcode +3. Copy `sqlite3.c` and `sqlite3.h` into this folder by dragging them in +4. Enable all targets and confirm + +### Option B: Use CocoaPods + +## 5. Configure Objective-C Bridging Header + +1. When you add the SQLite files, a popup will appear asking **"Would you like to configure an Objective-C bridging header?"** +2. Click **Create Bridging Header** +3. In the newly created bridging header file, import the SQLite headers: + ```objc + #import "sqlite3.h" + ``` + +## 6. Test the Setup + +To verify that the extension loads correctly in your Swift project, replace your ContentView.swift content with this test code: + +```swift +import SwiftUI + +struct ContentView: View { + @State private var statusLines: [String] = [] + private var statusText: String { statusLines.joined(separator: "\n") } + + var body: some View { + VStack(spacing: 12) { + Image(systemName: "globe") + .imageScale(.large) + .foregroundStyle(.tint) + Text("Hello, world!") + + Divider() + + Text("Status") + .font(.headline) + + ScrollView { + Text(statusText.isEmpty ? "No status yet." : statusText) + .font(.system(.footnote, design: .monospaced)) + .frame(maxWidth: .infinity, alignment: .leading) + .textSelection(.enabled) + .padding(.vertical, 4) + } + .frame(maxHeight: 260) + } + .padding() + .task { + log("Starting...") + var db: OpaquePointer? + + // Open an in-memory database just for demonstrating status updates. + // Replace with your own URL/path if needed. + var rc = sqlite3_open(":memory:", &db) + if rc != SQLITE_OK { + let msg = db.flatMap { sqlite3_errmsg($0) }.map { String(cString: $0) } ?? "Unknown error" + log("sqlite3_open failed (\(rc)): \(msg)") + if let db { sqlite3_close(db) } + return + } + log("Database opened.") + + // Enable loadable extensions + rc = sqlite3_enable_load_extension(db, 1) + log("sqlite3_enable_load_extension rc=\(rc)") + + // Locate the extension in the bundle (adjust as needed) + let vendorBundle = Bundle(identifier: "ai.sqlite.cloudsync") + let candidatePaths: [String?] = [ + vendorBundle?.path(forResource: "CloudSync", ofType: "dylib"), + vendorBundle?.path(forResource: "CloudSync", ofType: ""), + Bundle.main.path(forResource: "CloudSync", ofType: "dylib"), + Bundle.main.path(forResource: "CloudSync", ofType: "") + ] + let cloudsyncPath = candidatePaths.compactMap { $0 }.first + log("cloudsyncPath: \(cloudsyncPath ?? "Not found")") + + var loaded = false + if let path = cloudsyncPath { + var errMsg: UnsafeMutablePointer? = nil + rc = sqlite3_load_extension(db, path, nil, &errMsg) + if rc != SQLITE_OK { + let message = errMsg.map { String(cString: $0) } ?? String(cString: sqlite3_errmsg(db)) + if let e = errMsg { sqlite3_free(e) } + log("sqlite3_load_extension failed rc=\(rc): \(message)") + } else { + loaded = true + log("sqlite3_load_extension succeeded.") + } + + // Optionally disable further extension loading + _ = sqlite3_enable_load_extension(db, 0) + } else { + log("Skipping load: extension file not found in bundle.") + } + + // Run SELECT cloudsync_version() and log the result + if loaded { + let sql = "SELECT cloudsync_version()" + log("Running query: \(sql)") + var stmt: OpaquePointer? + rc = sqlite3_prepare_v2(db, sql, -1, &stmt, nil) + if rc != SQLITE_OK { + let msg = String(cString: sqlite3_errmsg(db)) + log("sqlite3_prepare_v2 failed (\(rc)): \(msg)") + } else { + defer { sqlite3_finalize(stmt) } + rc = sqlite3_step(stmt) + if rc == SQLITE_ROW { + if let cstr = sqlite3_column_text(stmt, 0) { + let version = String(cString: cstr) + log("cloudsync_version(): \(version)") + } else { + log("cloudsync_version(): (null)") + } + } else if rc == SQLITE_DONE { + log("cloudsync_version() returned no rows") + } else { + let msg = String(cString: sqlite3_errmsg(db)) + log("sqlite3_step failed (\(rc)): \(msg)") + } + } + } else { + log("Extension not loaded; skipping cloudsync_version() query.") + } + + if let db { sqlite3_close(db) } + log("Done.") + } + } + + @MainActor + private func log(_ line: String) { + statusLines.append(line) + } +} + +#Preview { + ContentView() +} +``` + +## Expected Results + +When you run the test app, you should see status messages in the UI indicating: + +- Database connection success +- Extension loading status +- CloudSync version information (if successfully loaded) + +This confirms that CloudSync is properly integrated and functional in your Swift project. + +## Usage Example + +Check out the Swift Multiplatform app for a complete implementation of using the SQLite CloudSync extension to sync data across devices. diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/quick-starts/linux.md b/sqlite-cloud/sqlite-ai/sqlite-sync/quick-starts/linux.md new file mode 100644 index 0000000..516e07e --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/quick-starts/linux.md @@ -0,0 +1,66 @@ +--- +title: Linux Quick Start +description: SQLite Sync is a multi-platform extension that brings a true local-first experience to your applications with minimal effort. +category: platform +status: publish +slug: sqlite-sync-quick-start-linux +--- + +SQLite on Linux supports dynamic extension loading via `.so` shared libraries. + +This guide walks through how to load an extension named `cloudsync.so` on common Linux distributions via SQLite3 Command Line. + +--- + +## 1. Install SQLite (Per Distribution) + +### Ubuntu / Debian + +```bash +sudo apt install sqlite3 +``` + +### Fedora + +```bash +sudo dnf install sqlite +``` + +### Arch Linux + +```bash +pacman -Sy sqlite3 +``` + +### Alpine Linux + +```bash +apk add sqlite +``` + +## 2. Download the Extension + +Go to sqlite-sync releases and download the extension. + +> For Alpine Linux: ensure to download the extension specifically for `musl-x86_64` or `musl-arm64` targets. + +## 3. Load Extension from CLI + +```bash +sqlite3 +``` + +```sql +.load ./cloudsync.so +SELECT cloudsync_version(); +``` + +--- + +## Troubleshooting + +| Problem | Solution | +| -------------------------------------------- | ----------------------------------------------------------------- | +| `no such file or directory` | Ensure path to `.so` is correct and matches your platform. | +| `incompatible architecture` | Download extension for your Linux system (e.g., x86_64 vs arm64). | +| `Failed to load extension: symbol not found` | Download the extension for `musl-x86_64` or `musl-arm64` targets | diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/quick-starts/macos.md b/sqlite-cloud/sqlite-ai/sqlite-sync/quick-starts/macos.md new file mode 100644 index 0000000..66a8553 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/quick-starts/macos.md @@ -0,0 +1,107 @@ +--- +title: "MacOS Quick Start Guide" +description: SQLite Sync is a multi-platform extension that brings a true local-first experience to your applications with minimal effort. +category: platform +status: publish +slug: sqlite-sync-quick-start-macos +--- + +This guide explains how to install SQLite on macOS with support for loading extensions. + +## macOS and xcframework + +On recent versions of macOS, the recommended way to load a SQLite extension is through the .xcframework approach, the same method used on iOS. + +## macOS and dylib + +On macOS, dynamic libraries (`.dylib`) can be loaded at runtime using SQLite’s `sqlite3_load_extension` API. + +### Step 1: Add Bridging Header (if using Swift only) + +Create a `bridging-header.h` file: + +```c +#include +``` + +Set it in your Xcode project under **Build Settings → Objective-C Bridging Header**. + +### Step 2: Swift Code to Load Extension + +```swift +import Foundation +import SQLite3 + +let dbPath = ":memory:" // or a real file path +var db: OpaquePointer? + +if sqlite3_open(dbPath, &db) != SQLITE_OK { + fatalError("Failed to open database") +} + +// Enable loading extensions +if sqlite3_enable_load_extension(db, 1) != SQLITE_OK { + let err = String(cString: sqlite3_errmsg(db)) + fatalError("Enable extension loading failed: \(err)") +} + +// Load the extension +let extensionPath = Bundle.main.path(forResource: "my_extension", ofType: "dylib")! +if sqlite3_load_extension(db, extensionPath, nil, nil) != SQLITE_OK { + let err = String(cString: sqlite3_errmsg(db)) + fatalError("Extension loading failed: \(err)") +} + +print("Extension loaded successfully.") +``` + +> ⚠️ Gatekeeper may block unsigned `.dylib` files. You might need to codesign or use `spctl --add`. + +## Python on macOS + +The default Python on macOS doesn't support loading SQLite extensions. +Install Python from the official package or use Homebrew Python instead: + +```bash +brew install python +``` + +Verify that you are using the Homebrew-installed `python3` by running: + +```bash +which python3 + +# /opt/homebrew/bin/python3 +``` + +After installing Python with Homebrew, the `python` command now uses the Homebrew version. +You can now load SQLite extensions in Python as shown here. + +```python +import sqlite3 +import os + +# Path to your compiled extension (.dylib for macOS/iOS) +EXTENSION_PATH = os.path.abspath("cloudsync") + +# Connect to SQLite and enable extension loading +conn = sqlite3.connect(":memory:") +conn.enable_load_extension(True) + +# Load the extension +try: + conn.load_extension(EXTENSION_PATH) + print("Extension loaded successfully.") +except sqlite3.OperationalError as e: + print(f"Failed to load extension: {e}") + +conn.enable_load_extension(False) + +# Optionally test it (e.g., call a custom SQL function) +cursor = conn.execute("SELECT cloudsync_version();") +print(cursor.fetchone()) +``` + +## Usage Example + +Check out the Swift Multiplatform app for a complete implementation of using the SQLite CloudSync extension to sync data across devices. diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/quick-starts/react-native-expo.md b/sqlite-cloud/sqlite-ai/sqlite-sync/quick-starts/react-native-expo.md new file mode 100644 index 0000000..fe9c73e --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/quick-starts/react-native-expo.md @@ -0,0 +1,169 @@ +--- +title: "React Native - Expo Quick Start Guide" +description: SQLite Sync is a multi-platform extension that brings a true local-first experience to your applications with minimal effort. +category: platform +status: publish +slug: sqlite-sync-quick-start-expo +--- + +This guide shows how to integrate CloudSync extensions in Expo and React Native applications using OP-SQLite. + +## Getting Started + +Before setting up SQLite extensions, you'll need to create and initialize your project: + +### Create a New Expo Project + +```bash +# Create a new project +npx create-expo-app MyApp + +# Or use our pre-configured template with SQLite extensions +npx create-expo-app MyApp --template @sqliteai/todoapp +``` + +### Initialize for Native Code + +Since SQLite extensions require native code, you must initialize your project: + +```bash +cd MyApp +npx expo prebuild +``` + +> **Important**: This setup requires native code generation. Run `npx expo prebuild` after any changes to native dependencies or extension files. + +## Android Setup + +### Step 1: Download Android Extension + +1. Go to sqlite-sync releases +2. Download your preferred .zip architecture releases: + - arm64-v8a - Modern 64-bit ARM devices (recommended for most users) + - x86_64 - 64-bit x86 emulators and Intel-based devices + +### Step 2: Place Extension Files + +Extract the `.so` files in the following directory structure: + +``` +/android + /app + /src + /main + /jniLibs + /arm64-v8a + cloudsync.so + /x86_64 + cloudsync.so +``` + +> **Note:** Create the `jniLibs` directory structure if it doesn't exist. + +## iOS Setup + +### Step 1: Download iOS Extension + +1. Go to sqlite-sync releases +2. Download the `cloudsync-apple-xcframework-*.zip` +3. Extract `CloudSync.xcframework` + +### Step 2: Add Framework to Project + +1. Place the framework in your project: + + ``` + /ios + /[app-name] + /Frameworks + /CloudSync.xcframework + ``` + +2. **Open Xcode:** + + - Open Existing Project → Select your Expo app's `ios` folder + - Click on your app name (top left, with Xcode logo) + +3. **Configure Target:** + + - Go to **Targets** → **[app-name]** → **General** tab + - Scroll down to **"Frameworks, Libraries, and Embedded Content"** + - Click **"+"** → **"Add Other…"** → **"Add Files…"** + - Select `/ios/[app-name]/Frameworks/CloudSync.xcframework` + +4. **Set Embed Options:** + + - Ensure the **"Embed"** column shows either: + - **"Embed & Sign"** (recommended) + - **"Embed Without Signing"** + +5. **Verify Build Phases:** + + - Go to **"Build Phases"** tab + - Check that **"Embed Frameworks"** section contains **CloudSync** + +6. Close Xcode + +## Install OP-SQLite + +### For React Native: + +```bash +npm install @op-engineering/op-sqlite +npx pod-install +``` + +### For Expo: + +```bash +npx expo install @op-engineering/op-sqlite +npx expo prebuild +``` + +## Implementation + +### Basic Setup + +```javascript +import { getDylibPath, open } from "@op-engineering/op-sqlite"; +import { Platform } from "react-native"; + +// Open database connection +const db = open({ name: "to-do-app" }); +``` + +### Load Extension + +```javascript +const loadCloudSyncExtension = async () => { + let extensionPath; + + console.log("Loading CloudSync extension..."); + + try { + if (Platform.OS === "ios") { + extensionPath = getDylibPath("ai.sqlite.cloudsync", "CloudSync"); + } else { + extensionPath = "cloudsync"; + } + + // Load the extension + db.loadExtension(extensionPath); + + // Verify extension loaded successfully + const version = await db.execute("SELECT cloudsync_version();"); + console.log( + `CloudSync extension loaded successfully, version: ${version.rows[0]["cloudsync_version()"]}` + ); + + return true; + } catch (error) { + console.error("Error loading CloudSync extension:", error); + return false; + } +}; +``` + +## Usage Example + +Check out the Expo to-do-app for comprehensive usage examples and best practices. diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/quick-starts/wasm.md b/sqlite-cloud/sqlite-ai/sqlite-sync/quick-starts/wasm.md new file mode 100644 index 0000000..18c84d4 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/quick-starts/wasm.md @@ -0,0 +1,100 @@ +--- +title: "WASM Quick Start Guide" +description: SQLite Sync is a multi-platform extension that brings a true local-first experience to your applications with minimal effort. +category: platform +status: publish +slug: sqlite-sync-quick-start-wasm +--- + +1. Install the WebAssembly (WASM) version of SQLite with the SQLite Sync extension enabled from npm: + + ```bash + npm install @sqliteai/sqlite-wasm + ``` + +2. Create an HTML file that imports the SQLite WASM module using an import map and references the JavaScript loader: + + ```html + + + + + + SQLite WASM Extension Example + + +

    SQLite WASM with SQLite Sync Example

    +

    Open the directory in the terminal and type: npx serve .

    +

    Check the browser console for output.

    + + + + + + ``` + +3. Create the JavaScript file (load_extension.js) that initializes the SQLite WASM worker and verifies the extension is loaded: + + ```javascript + /** + * This example uses the package `@sqliteai/sqlite-wasm`. + * This version of SQLite WASM is bundled with SQLite Sync and SQLite Vector extensions. + * Extensions cannot be loaded at runtime in the browser environment. + * + * Run: `npx serve .` + */ + + import { sqlite3Worker1Promiser } from '@sqliteai/sqlite-wasm'; + + const log = console.log; + const error = console.error; + + const initializeSQLite = async () => { + try { + log('Loading and initializing SQLite3 module with sqlite-sync extension...'); + + const promiser = await new Promise((resolve) => { + const _promiser = sqlite3Worker1Promiser({ + onready: () => resolve(_promiser), + }); + }); + + const configResponse = await promiser('config-get', {}); + log('Running SQLite3 version', configResponse.result.version.libVersion); + + const openResponse = await promiser('open', { + filename: 'file:mydb.sqlite3', + }); + const { dbId } = openResponse; + + await promiser('exec', { + dbId, + sql: 'SELECT cloudsync_version();', // or vector_version() + callback: (result) => { + if (!result.row) { + return; + } + log('Include SQLite Sync version: ', result.row[0]); + } + }); + + } catch (err) { + if (!(err instanceof Error)) { + err = new Error(err.result.message); + } + error(err.name, err.message); + } + }; + + initializeSQLite(); + ``` + +## Usage Example + +Check out the React/Vite app for a complete implementation of using the SQLite CloudSync extension to sync data across devices. diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/quick-starts/windows.md b/sqlite-cloud/sqlite-ai/sqlite-sync/quick-starts/windows.md new file mode 100644 index 0000000..1397ad9 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/quick-starts/windows.md @@ -0,0 +1,227 @@ +--- +title: Windows Quick Start +description: SQLite Sync is a multi-platform extension that brings a true local-first experience to your applications with minimal effort. +category: platform +status: publish +slug: sqlite-sync-quick-start-windows +--- + +This guide explains how to install SQLite on Windows with support for loading extensions. + +## Using SQLite with Python + +1. **Download Python** + + Get the latest Python for Windows from python.org. + +2. **Install Python** + + - Run the installer. + - Make sure to check **"Add Python to PATH"**. + - SQLite comes bundled with Python, no extra steps needed. + +3. **Check your installation** + Open Command Prompt and run: + + ```bash + python --version + python -c "import sqlite3; print('SQLite version:', sqlite3.sqlite_version)" + ``` + +4. **Download the Extension** + + Go to sqlite-sync releases and download the extension. + +5. **Load Extension** + ```python + import sqlite3 + import os + + # Path to your compiled extension (.dll for Windows) + EXTENSION_PATH = os.path.abspath("cloudsync") + + # Connect to SQLite and enable extension loading + conn = sqlite3.connect(":memory:") + conn.enable_load_extension(True) + + # Load the extension + try: + conn.load_extension(EXTENSION_PATH) + print("Extension loaded successfully.") + except sqlite3.OperationalError as e: + print(f"Failed to load extension: {e}") + + conn.enable_load_extension(False) + + # Optionally test it (e.g., call a custom SQL function) + cursor = conn.execute("SELECT cloudsync_version();") + print(cursor.fetchone()) + ``` + +## Using SQLite with C# + +This guide shows how to load a native SQLite extension (e.g., **`cloudsync.dll`**) from a C# app on **Windows** using **`Microsoft.Data.Sqlite`**. + +### Prerequisites + +- Windows x64 +- .NET 6+ SDK +- NuGet package manager +- The native extension file: `cloudsync.dll` (x64 build) - download from sqlite-sync releases + +> **Important:** Your app, `e_sqlite3.dll` (bundled by `Microsoft.Data.Sqlite`), and `cloudsync.dll` must all be the **same architecture** (typically x64). + +--- + +### 1. Install the SQLite package + +Install the `Microsoft.Data.Sqlite` NuGet package: + +```bash +dotnet add package Microsoft.Data.Sqlite +``` + +### 2. Set up your project structure + +Place `cloudsync.dll` in your project and configure it to copy to the output folder. + +Example directory structure: + +``` +MyApp/ + Program.cs + Native/ + cloudsync.dll + MyApp.csproj +``` + +Configure your `MyApp.csproj` file: + +```xml + + + Exe + net8.0 + enable + enable + + + + + + + + + + PreserveNewest + + + +``` + +### 3. Load the extension in your code + +Create your `Program.cs` file to initialize SQLite and load the extension: + +```csharp +using System; +using Microsoft.Data.Sqlite; + +class Program +{ + static void Main() + { + // Configure the database connection + var cs = new SqliteConnectionStringBuilder + { + DataSource = "example.db", + Mode = SqliteOpenMode.ReadWriteCreate + }.ToString(); + + using var conn = new SqliteConnection(cs); + conn.Open(); + + // Enable extension loading + conn.EnableExtensions(); + + // Load the native extension (DLL must be next to the EXE or on PATH) + // You can pass an absolute path if you prefer + conn.LoadExtension("cloudsync"); + + // Verify SQLite is working + using var cmd = conn.CreateCommand(); + cmd.CommandText = "SELECT sqlite_version();"; + Console.WriteLine("SQLite version: " + cmd.ExecuteScalar()); + + // Verify the extension is loaded + cmd.CommandText = "SELECT cloudsync_version();"; + Console.WriteLine("cloudsync_version(): " + cmd.ExecuteScalar()); + } +} +``` + +### 4. Run your application + +Build and run your application: + +```bash +dotnet build +dotnet run +``` + +You should see output similar to: + +``` +SQLite version: 3.45.0 +cloudsync_version(): 1.0.0 +``` + +#### Extension search locations + +SQLite searches for extensions in this order: + +1. Process working directory +2. Application base directory (where your .exe lives) +3. PATH environment variable directories +4. Full path provided to `LoadExtension(...)` + +> **Tip:** For most apps, simply copying the DLL to the output folder (next to your .exe) is sufficient. + +--- + +### Common issues and solutions + +**SqliteException: not authorized** + +- **Cause:** Extension loading not enabled +- **Fix:** Call `conn.EnableExtensions()` before loading + +**SqliteException: The specified module could not be found** + +- **Cause:** DLL not in search path or missing dependencies +- **Fix:** Place DLL next to .exe, use absolute path, or ensure dependencies are available + +**BadImageFormatException** + +- **Cause:** Architecture mismatch (e.g., mixing x86 and x64) +- **Fix:** Ensure app, `e_sqlite3.dll`, and `cloudsync.dll` are all the same architecture + +**EntryPointNotFoundException** + +- **Cause:** DLL is not a valid SQLite extension +- **Fix:** Verify the extension exports `sqlite3_extension_init` + +**Windows "blocked" DLL** + +- **Cause:** Downloaded DLL is blocked by Windows +- **Fix:** Right-click → Properties → Check "Unblock" → OK + +--- + +### Deployment + +When publishing your app, ensure the extension is included: + +```bash +dotnet publish -c Release -r win-x64 --self-contained false +``` diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/rls.md b/sqlite-cloud/sqlite-ai/sqlite-sync/rls.md new file mode 100644 index 0000000..0c8d240 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/rls.md @@ -0,0 +1,95 @@ +--- +title: "RLS Reference" +description: "Behavior, setup, and troubleshooting for using CloudSync with PostgreSQL Row Level Security." +category: platform +status: publish +slug: sqlite-sync-rls-reference +--- + +CloudSync is fully compatible with PostgreSQL Row Level Security. Standard RLS policies work out of the box. + +## How It Works + +### Column-batch merge + +CloudSync resolves CRDT conflicts at the column level. Before writing to the target table, CloudSync buffers all winning column values for the same primary key and flushes them as a single SQL statement. This ensures the database sees a complete row with all columns present. + +### UPDATE vs INSERT selection + +When flushing a batch, CloudSync chooses the statement type based on whether the row already exists locally: + +- **New row**: `INSERT ... ON CONFLICT DO UPDATE` +- **Existing row**: `UPDATE ... SET ... WHERE pk = ...` + +### Per-PK savepoint isolation + +Each primary key's flush is wrapped in its own savepoint. When RLS denies a write, CloudSync rolls back only that savepoint and continues with the next primary key. Allowed rows commit normally; denied rows are skipped. + +## Quick Setup + +Given a table with an ownership column: + +```sql +CREATE TABLE documents ( + id TEXT PRIMARY KEY, + user_id UUID, + title TEXT, + content TEXT +); + +SELECT cloudsync_init('documents'); +``` + +Enable RLS and create standard policies: + +```sql +ALTER TABLE documents ENABLE ROW LEVEL SECURITY; + +CREATE POLICY "select_own" ON documents FOR SELECT + USING (auth.uid() = user_id); + +CREATE POLICY "insert_own" ON documents FOR INSERT + WITH CHECK (auth.uid() = user_id); + +CREATE POLICY "update_own" ON documents FOR UPDATE + USING (auth.uid() = user_id) + WITH CHECK (auth.uid() = user_id); + +CREATE POLICY "delete_own" ON documents FOR DELETE + USING (auth.uid() = user_id); +``` + +When you authenticate PostgreSQL requests with JWTs, CloudSync also executes `SET LOCAL ROLE` using the JWT `role` claim. See the [JWT Claims Reference](/docs/sqlite-sync-jwt-claims). + +## Supabase Notes + +When using Supabase: + +1. `auth.uid()` returns the authenticated user's UUID from the JWT claims. +2. Ensure the JWT token is set before sync operations. +3. The Supabase service role bypasses RLS entirely, so use the `authenticated` role when you want user-context enforcement. + +## Troubleshooting + +### "new row violates row-level security policy" + +Insert operations fail when the ownership column value does not match the authenticated user. + +Verify that: + +- the JWT or session variable is set correctly before calling `cloudsync_payload_apply` +- the ownership column in the synced data matches the authenticated user +- your RLS policies reference the correct ownership column + +### Apply reports a count, but rows are missing + +If `cloudsync_payload_apply` returns a non-zero column-change count but rows do not land, the calling role is usually missing grants on one of CloudSync's internal objects. + +Apply the grant set from the [JWT Claims Reference](/docs/sqlite-sync-jwt-claims) and inspect server logs for `permission denied` entries around `cloudsync_payload_apply` if you need the exact missing object. + +### Debugging + +```sql +SELECT auth.uid(); +SELECT id, user_id FROM documents WHERE id = 'problematic-pk'; +``` diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/row-level-security.md b/sqlite-cloud/sqlite-ai/sqlite-sync/row-level-security.md new file mode 100644 index 0000000..c0c4e53 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/row-level-security.md @@ -0,0 +1,55 @@ +--- +title: "SQLite-Sync Row-Level Security" +description: "Use SQLite-Sync with SQLite Cloud Row-Level Security for per-user and per-tenant data isolation." +category: platform +status: publish +slug: sqlite-sync-row-level-security +--- + +SQLite Sync supports **Row-Level Security (RLS)** through the underlying [SQLite Cloud](https://sqlitecloud.io/) infrastructure. RLS allows you to use a **single shared cloud database** while each client only sees and modifies its own data. Policies are enforced on the server, so the security boundary is at the database level, not in application code. + +## How It Works + +- Control not just who can read or write a table, but **which specific rows** they can access. +- Each device syncs only the rows it is authorized to see: no full dataset download, no client-side filtering. + +For example: + +- User A can only see and edit their own data. +- User B can access a different set of rows, even within the same shared table. + +## Benefits + +- **Single database, multiple tenants**: one cloud database serves all users. RLS policies partition data per user or role, eliminating the need to provision separate databases. +- **Efficient sync**: each client downloads only its authorized rows, reducing bandwidth and local storage. +- **Server-enforced security**: policies are evaluated on the server during sync. A compromised or modified client cannot bypass access controls. +- **Simplified development**: no need to implement permission logic in your application. Define policies once in the database and they apply everywhere. + +## Authentication + +RLS requires token-based authentication. Use `cloudsync_network_set_token()` instead of `cloudsync_network_set_apikey()`: + +```sql +SELECT cloudsync_network_init('your-managed-database-id'); +SELECT cloudsync_network_set_token('your_auth_token'); +SELECT cloudsync_network_sync(); +``` + +For more information on access tokens, see the [Access Tokens documentation](https://docs.sqlitecloud.io/docs/access-tokens). + +## Schema Considerations + +When using RLS with multi-tenant schemas, UNIQUE constraints must be globally unique across all tenants in the cloud database. For columns that should only be unique within a tenant, use composite UNIQUE constraints: + +```sql +CREATE TABLE users ( + id TEXT PRIMARY KEY, + tenant_id TEXT NOT NULL DEFAULT '', + email TEXT NOT NULL DEFAULT '', + UNIQUE(tenant_id, email) +); +``` + +For more schema guidelines, see [Database Schema Recommendations](/docs/sqlite-sync-best-practices). + +For full RLS documentation, see the [SQLite Cloud RLS documentation](https://docs.sqlitecloud.io/docs/rls). diff --git a/sqlite-cloud/sqlite-ai/sqlite-sync/supabase-self-hosted-quick-start.md b/sqlite-cloud/sqlite-ai/sqlite-sync/supabase-self-hosted-quick-start.md new file mode 100644 index 0000000..1eec64c --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-sync/supabase-self-hosted-quick-start.md @@ -0,0 +1,133 @@ +--- +title: "Self-Hosted Supabase Quick Start" +description: "Enable CloudSync on a self-hosted Supabase deployment and connect SQLite Sync clients to it." +category: platform +status: publish +slug: sqlite-sync-supabase-self-hosted-quick-start +--- + +This guide helps you enable CloudSync on a **fresh or existing** self-hosted Supabase instance. CloudSync adds offline-first synchronization capabilities to your PostgreSQL database. + +## Step 1: Use the CloudSync Supabase Image + +When deploying or updating your Supabase instance, use the published CloudSync Supabase image instead of the standard Supabase Postgres image. + +### For New Deployments + +Follow [Supabase's Installing Supabase](https://supabase.com/docs/guides/self-hosting/docker#installing-supabase) guide to set up the initial files and `.env` configuration. Then, before the first `docker compose up -d`, update your `docker-compose.yml` to use the CloudSync-enabled Postgres image: + +```yaml +db: + image: sqlitecloud/sqlite-sync-supabase:17 + # or sqlitecloud/sqlite-sync-supabase:15 +``` + +Use the CloudSync image tag that matches your Supabase PostgreSQL major version. + +### Add the CloudSync Init Script + +Create the init SQL: + +```bash +mkdir -p volumes/db +cat > volumes/db/cloudsync.sql << 'EOF' +CREATE EXTENSION IF NOT EXISTS cloudsync; +EOF +``` + +Add a volume mount to the `db` service in `docker-compose.yml`: + +```yaml +services: + db: + volumes: + - ./volumes/db/cloudsync.sql:/docker-entrypoint-initdb.d/init-scripts/100-cloudsync.sql:Z +``` + +Then start Supabase: + +```bash +docker compose pull +docker compose up -d +``` + +### For Existing Deployments + +Follow [Supabase's Updating](https://supabase.com/docs/guides/self-hosting/docker#updating) guide. When updating the Postgres image, replace the default image with the matching CloudSync image. + +If Postgres has already been initialized and you are adding CloudSync afterward, the init script will not run automatically. Connect to the database and run: + +```sql +CREATE EXTENSION IF NOT EXISTS cloudsync; +``` + +## Step 2: Verify the Extension + +```bash +docker compose exec db psql -U supabase_admin -d postgres -c "SELECT cloudsync_version();" +``` + +If the extension is installed correctly, PostgreSQL returns the CloudSync version string. + +### Upgrading a later release + +CloudSync uses the first two components of its semver as the PostgreSQL extension version. For patch releases, pull the new image and restart the `db` service. For minor or major releases, restart and then run: + +```sql +ALTER EXTENSION cloudsync UPDATE; +``` + +You can inspect the current extension state with: + +```sql +SELECT name, default_version, installed_version +FROM pg_available_extensions +WHERE name = 'cloudsync'; +``` + +## Step 3: Register Your Database in the CloudSync Dashboard + +In the [CloudSync dashboard](https://dashboard.sqlitecloud.io/), create a new workspace with the **Supabase (Self-hosted)** provider, then add a project with your PostgreSQL connection string: + +```text +postgresql://user:password@host:5432/database +``` + +## Step 4: Enable CloudSync on Tables + +In the dashboard, go to the **Database Setup** tab, select the tables you want to sync, and click **Deploy Changes**. + +## Step 5: Set Up Authentication + +On the **Client Integration** tab you'll find your **Database ID** and authentication settings. + +### Quick Test with API Key + +The fastest way to test CloudSync without per-user access control. + +With API key authentication, CloudSync uses the database role resolved from the API-key-authenticated connection when available; otherwise it falls back to the role from the connection string. + +```sql +SELECT cloudsync_network_init(''); +SELECT cloudsync_network_set_apikey(':'); +SELECT cloudsync_network_sync(); +``` + +### Using JWT Tokens + +1. Set **Row Level Security** to **Yes, enforce RLS** +2. Under **Authentication (JWT)**, click **Configure authentication** +3. For claim details and RLS examples, see: + - [JWT Claims Reference](/docs/sqlite-sync-jwt-claims) + - [RLS Reference](/docs/sqlite-sync-rls-reference) +4. In your client code: + + ```sql + SELECT cloudsync_network_init(''); + SELECT cloudsync_network_set_token(''); + SELECT cloudsync_network_sync(); + ``` + +## Example App + +For a complete web example using a self-hosted Supabase backend with JWT auth and RLS, see the [Sport Tracker Supabase example](https://github.com/sqliteai/sqlite-sync/blob/main/docs/postgresql/examples/sport-tracker-app-supabase.md). diff --git a/sqlite-cloud/sqlite-ai/sqlite-vector-api-reference.md b/sqlite-cloud/sqlite-ai/sqlite-vector-api-reference.md new file mode 100644 index 0000000..2ea2f2c --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-vector-api-reference.md @@ -0,0 +1,313 @@ +--- +title: "SQLite-Vector API Reference" +description: "Reference for SQLite-Vector functions, vector types, quantization, and scan APIs." +category: platform +status: publish +slug: sqlite-vector-api-reference +--- + +This extension enables efficient vector operations directly inside SQLite databases, making it ideal for on-device and edge AI applications. It supports various vector types and SIMD-accelerated distance functions. + +### Getting started + +* All vectors must have a fixed dimension per column, set during `vector_init`. +* Only tables explicitly initialized using `vector_init` are eligible for vector search. +* You **must run `vector_quantize()`** before using `vector_quantize_scan()`. +* You can preload quantization at database open using `vector_quantize_preload()`. + +--- + +## `vector_version()` + +**Returns:** `TEXT` + +**Description:** +Returns the current version of the SQLite Vector Extension. + +**Example:** + +```sql +SELECT vector_version(); +-- e.g., '1.0.0' +``` + +--- + +## `vector_backend()` + +**Returns:** `TEXT` + +**Description:** +Returns the active backend used for vector computation. This indicates the SIMD or hardware acceleration available on the current system. + +**Possible Values:** + +* `CPU` – Generic fallback +* `SSE2` – SIMD on Intel/AMD +* `AVX2` – Advanced SIMD on modern x86 CPUs +* `NEON` – SIMD on ARM (e.g., mobile) + +**Example:** + +```sql +SELECT vector_backend(); +-- e.g., 'AVX2' +``` + +--- + +## `vector_init(table, column, options)` + +**Returns:** `NULL` + +**Description:** +Initializes the vector extension for a given table and column. This is **mandatory** before performing any vector search or quantization. +`vector_init` must be called in every database connection that needs to perform vector operations. + +The target table must have a **`rowid`** (an integer primary key, either explicit or implicit). +If the table was created using `WITHOUT ROWID`, it must have **exactly one primary key column of type `INTEGER`**. +This ensures that each vector can be uniquely identified and efficiently referenced during search and quantization. + +**Parameters:** + +* `table` (TEXT): Name of the table containing vector data. +* `column` (TEXT): Name of the column containing the vector embeddings (stored as BLOBs). +* `options` (TEXT): Comma-separated key=value string. + +**Options:** + +* `dimension` (required): Integer specifying the length of each vector. +* `type`: Vector data type. Options: + + * `FLOAT32` (default) + * `FLOAT16` + * `FLOATB16` + * `INT8` + * `UINT8` + * `1BIT` +* `distance`: Distance function to use. Options: + + * `L2` (default) + * `SQUARED_L2` + * `COSINE` + * `DOT` + * `L1` + * `HAMMING` + +**Example:** + +```sql +SELECT vector_init('documents', 'embedding', 'dimension=384,type=FLOAT32,distance=cosine'); +``` + +--- + +## `vector_quantize(table, column, options)` + +**Returns:** `INTEGER` + +**Description:** +Returns the total number of successfully quantized rows. + +Performs quantization on the specified table and column. This precomputes internal data structures to support fast approximate nearest neighbor (ANN) search. +Read more about quantization [here](https://github.com/sqliteai/sqlite-vector/blob/main/QUANTIZATION.md). + +If a quantization already exists for the specified table and column, it is replaced. If it was previously loaded into memory using `vector_quantize_preload`, the data is automatically reloaded. `vector_quantize` should be called once after data insertion. If called multiple times, the previous quantized data is replaced. The resulting quantization is shared across all database connections, so they do not need to call it again. + +**Parameters:** + +* `table` (TEXT): Name of the table. +* `column` (TEXT): Name of the column containing vector data. +* `options` (TEXT, optional): Comma-separated key=value string. + +**Available options:** + +* `max_memory`: Max memory to use for quantization (default: 30MB) +* `qtype`: Quantization type: `UINT8`, `INT8` or `1BIT` + +**Example:** + +```sql +SELECT vector_quantize('documents', 'embedding', 'max_memory=50MB'); +SELECT vector_quantize('documents', 'embedding', 'qtype=BIT'); +``` + +--- + +## `vector_quantize_memory(table, column)` + +**Returns:** `INTEGER` + +**Description:** +Returns the amount of memory (in bytes) required to preload quantized data for the specified table and column. + +**Example:** + +```sql +SELECT vector_quantize_memory('documents', 'embedding'); +-- e.g., 28490112 +``` + +--- + +## `vector_quantize_preload(table, column)` + +**Returns:** `NULL` + +**Description:** +Loads the quantized representation for the specified table and column into memory. Should be used at startup to ensure optimal query performance. +`vector_quantize_preload` should be called once after `vector_quantize`. The preloaded data is also shared across all database connections, so they do not need to call it again. + +**Example:** + +```sql +SELECT vector_quantize_preload('documents', 'embedding'); +``` + +--- + +## `vector_quantize_cleanup(table, column)` + +**Returns:** `NULL` + +**Description:** +Releases memory previously allocated by a `vector_quantize_preload` call and removes all quantization entries associated with the specified table and column. +Use this function when quantization is no longer required. In some cases, running VACUUM may be necessary to reclaim the freed space from the database. + +If the data changes and you invoke `vector_quantize`, the existing quantization data is automatically replaced. In that case, calling this function is unnecessary. + +**Example:** + +```sql +SELECT vector_quantize_cleanup('documents', 'embedding'); +``` + +--- + +## `vector_as_f32(value)` + +## `vector_as_f16(value)` + +## `vector_as_bf16(value)` + +## `vector_as_i8(value)` + +## `vector_as_u8(value)` + +## `vector_as_bit(value)` + +**Returns:** `BLOB` + +**Description:** +Encodes a vector into the required internal BLOB format to ensure correct storage and compatibility with the system’s vector representation. +A real conversion is performed ONLY in case of JSON input. When input is a BLOB, it is assumed to be already properly formatted. + +Functions in the `vector_as_` family should be used in all `INSERT`, `UPDATE`, and `DELETE` statements to properly format vector values. However, they are *not* required when specifying input vectors for the `vector_full_scan` or `vector_quantize_scan` virtual tables. + +**Parameters:** + +* `value` (TEXT or BLOB): + + * If `TEXT`, it must be a JSON array (e.g., `"[0.1, 0.2, 0.3]"`). + * If `BLOB`, no check is performed; the user must ensure the format matches the specified type and dimension. + +* `dimension` (INT, optional): Enforce a stricter sanity check, ensuring the input vector has the expected dimensionality. + +**Usage by format:** + +```sql +-- Insert a Float32 vector using JSON +INSERT INTO documents(embedding) VALUES(vector_as_f32('[0.1, 0.2, 0.3]')); + +-- Insert a UInt8 vector using raw BLOB (ensure correct formatting!) +INSERT INTO compressed_vectors(embedding) VALUES(vector_as_u8(X'010203')); +``` + +--- + +## 🔍 `vector_full_scan(table, column, vector [, k])` + +**Returns:** `Virtual Table (rowid, distance)` + +**Description:** +Performs a brute-force nearest neighbor search using the given vector. Despite its brute-force nature, this function is highly optimized and useful for small datasets (rows < 1000000) or validation. +Since this interface only returns rowid and distance, if you need to access additional columns from the original table, you must use a SELF JOIN. + +**Parameters:** + +* `table` (TEXT): Name of the target table. +* `column` (TEXT): Column containing vectors. +* `vector` (BLOB or JSON): The query vector. +* `k` (INTEGER, optional): Number of nearest neighbors to return. When provided, the module collects the top-k results sorted by distance. When omitted, the module operates in **streaming mode** — rows are returned progressively as they are scanned, enabling standard SQL clauses such as `WHERE` and `LIMIT` to control filtering and result count. + +**Examples:** + +```sql +-- Top-k mode: return the 5 nearest neighbors, sorted by distance +SELECT rowid, distance +FROM vector_full_scan('documents', 'embedding', vector_as_f32('[0.1, 0.2, 0.3]'), 5); +``` + +```sql +-- Streaming mode: progressively scan all rows, apply SQL filters +SELECT rowid, distance +FROM vector_full_scan('documents', 'embedding', vector_as_f32('[0.1, 0.2, 0.3]')) +LIMIT 5; +``` + +```sql +-- Streaming mode with JOIN and filtering +SELECT + v.rowid, + row_number() OVER (ORDER BY v.distance) AS rank_number, + v.distance +FROM vector_full_scan('documents', 'embedding', vector_as_f32('[0.1, 0.2, 0.3]')) AS v + JOIN documents ON documents.rowid = v.rowid +WHERE documents.category = 'science' +LIMIT 10; +``` + +--- + +## ⚡ `vector_quantize_scan(table, column, vector [, k])` + +**Returns:** `Virtual Table (rowid, distance)` + +**Description:** +Performs a fast approximate nearest neighbor search using the pre-quantized data. This is the **recommended query method** for large datasets due to its excellent speed/recall/memory trade-off. Since this interface only returns rowid and distance, if you need to access additional columns from the original table, you must use a SELF JOIN. + +You **must run `vector_quantize()`** before using `vector_quantize_scan()` and when data initialized for vectors changes. + +**Parameters:** + +* `table` (TEXT): Name of the target table. +* `column` (TEXT): Column containing vectors. +* `vector` (BLOB or JSON): The query vector. +* `k` (INTEGER, optional): Number of nearest neighbors to return. When provided, the module collects the top-k results sorted by distance. When omitted, the module operates in **streaming mode** — rows are returned progressively, enabling standard SQL clauses such as `WHERE` and `LIMIT`. + +**Performance Highlights:** + +* Handles **1M vectors** of dimension 768 in a few milliseconds. +* Uses **<50MB** of RAM. +* Achieves **>0.95 recall**. + +**Examples:** + +```sql +-- Top-k mode: return the 10 nearest neighbors, sorted by distance +SELECT rowid, distance +FROM vector_quantize_scan('documents', 'embedding', vector_as_f32('[0.1, 0.2, 0.3]'), 10); +``` + +```sql +-- Streaming mode: progressively scan using quantized data +SELECT rowid, distance +FROM vector_quantize_scan('documents', 'embedding', vector_as_f32('[0.1, 0.2, 0.3]')) +LIMIT 10; +``` + +**Usage Notes:** + +* In **top-k mode** (with `k`), results are sorted by distance. The query planner knows the output is pre-sorted, so no additional `ORDER BY` is needed. +* In **streaming mode** (without `k`), rows are returned in scan order. Use `ORDER BY distance` and `LIMIT` as needed. +* Streaming mode is ideal for combining vector similarity with additional SQL-level filters or progressive result consumption. diff --git a/sqlite-cloud/sqlite-ai/sqlite-vector-examples.md b/sqlite-cloud/sqlite-ai/sqlite-vector-examples.md new file mode 100644 index 0000000..e8f9cb9 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-vector-examples.md @@ -0,0 +1,48 @@ +--- +title: "SQLite-Vector Examples" +description: "SQLite-Vector examples for inserting, quantizing, preloading, and searching vectors." +category: platform +status: publish +slug: sqlite-vector-examples +--- + +## Example Usage + +```sql +-- Create a regular SQLite table +CREATE TABLE images ( + id INTEGER PRIMARY KEY, + embedding BLOB, -- store Float32/UInt8/etc. + label TEXT +); + +-- Insert a BLOB vector (Float32, 384 dimensions) using bindings +INSERT INTO images (embedding, label) VALUES (?, 'cat'); + +-- Insert a JSON vector (Float32, 384 dimensions) +INSERT INTO images (embedding, label) VALUES (vector_as_f32('[0.3, 1.0, 0.9, 3.2, 1.4,...]'), 'dog'); + +-- Initialize the vector. By default, the distance function is L2. +-- To use a different metric, specify one of the following options: +-- distance=L1, distance=COSINE, distance=DOT, distance=SQUARED_L2, or distance=HAMMING. +SELECT vector_init('images', 'embedding', 'type=FLOAT32,dimension=384'); + +-- Quantize vector +SELECT vector_quantize('images', 'embedding'); + +-- Optional preload quantized version in memory (for a 4x/5x speedup) +SELECT vector_quantize_preload('images', 'embedding'); + +-- Run a nearest neighbor query on the quantized version (returns top 20 closest vectors) +SELECT e.id, v.distance FROM images AS e + JOIN vector_quantize_scan('images', 'embedding', ?, 20) AS v + ON e.id = v.rowid; + +-- Streaming mode: omit k to get rows progressively, use SQL to filter and limit +SELECT e.id, v.distance FROM images AS e + JOIN vector_quantize_scan('images', 'embedding', ?) AS v + ON e.id = v.rowid + WHERE e.label = 'cat' + LIMIT 10; +``` + diff --git a/sqlite-cloud/sqlite-ai/sqlite-vector-getting-started.md b/sqlite-cloud/sqlite-ai/sqlite-vector-getting-started.md new file mode 100644 index 0000000..29e0053 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-vector-getting-started.md @@ -0,0 +1,48 @@ +--- +title: "SQLite-Vector Getting Started" +description: "Run nearest-neighbor search from ordinary SQLite tables." +category: platform +status: publish +slug: sqlite-vector-getting-started +--- + +## Getting Started + +```sql +-- Create a regular SQLite table +CREATE TABLE images ( + id INTEGER PRIMARY KEY, + embedding BLOB, -- store Float32/UInt8/etc. + label TEXT +); + +-- Insert a BLOB vector (Float32, 384 dimensions) using bindings +INSERT INTO images (embedding, label) VALUES (?, 'cat'); + +-- Insert a JSON vector (Float32, 384 dimensions) +INSERT INTO images (embedding, label) VALUES (vector_as_f32('[0.3, 1.0, 0.9, 3.2, 1.4,...]'), 'dog'); + +-- Initialize the vector. By default, the distance function is L2. +-- To use a different metric, specify one of the following options: +-- distance=L1, distance=COSINE, distance=DOT, distance=SQUARED_L2, or distance=HAMMING. +SELECT vector_init('images', 'embedding', 'type=FLOAT32,dimension=384'); + +-- Quantize vector +SELECT vector_quantize('images', 'embedding'); + +-- Optional preload quantized version in memory (for a 4x/5x speedup) +SELECT vector_quantize_preload('images', 'embedding'); + +-- Run a nearest neighbor query on the quantized version (returns top 20 closest vectors) +SELECT e.id, v.distance FROM images AS e + JOIN vector_quantize_scan('images', 'embedding', ?, 20) AS v + ON e.id = v.rowid; + +-- Streaming mode: omit k to get rows progressively, use SQL to filter and limit +SELECT e.id, v.distance FROM images AS e + JOIN vector_quantize_scan('images', 'embedding', ?) AS v + ON e.id = v.rowid + WHERE e.label = 'cat' + LIMIT 10; +``` + diff --git a/sqlite-cloud/sqlite-ai/sqlite-vector-quantization.md b/sqlite-cloud/sqlite-ai/sqlite-vector-quantization.md new file mode 100644 index 0000000..2b02633 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-vector-quantization.md @@ -0,0 +1,84 @@ +--- +title: "SQLite-Vector Quantization" +description: "Guide to SQLite-Vector quantization for high-performance vector search." +category: platform +status: publish +slug: sqlite-vector-quantization +--- + +### Vector Quantization for High Performance + +`sqlite-vector` supports **vector quantization**, a powerful technique to significantly accelerate vector search while reducing memory usage. You can quantize your vectors with: + +```sql +SELECT vector_quantize('my_table', 'my_column'); +``` + +To further boost performance, quantized vectors can be **preloaded in memory** using: + +```sql +SELECT vector_quantize_preload('my_table', 'my_column'); +``` + +This can result in a **4×–5× speedup** on nearest neighbor queries while keeping memory usage low. + +#### What is Quantization? + +Quantization compresses high-dimensional float vectors (e.g., `FLOAT32`) into compact representations using lower-precision formats (e.g., `UINT8`). This drastically reduces the size of the data—often by a factor of 4 to 8—making it practical to load large datasets entirely in memory, even on edge devices. + +#### Why is it Important? + +* **Faster Searches**: With preloaded quantized vectors, distance computations are up to 5× faster. +* **Lower Memory Footprint**: Quantized vectors use significantly less RAM, allowing millions of vectors to fit in memory. +* **Edge-ready**: The reduced size and in-memory access make this ideal for mobile, embedded, and on-device AI applications. + +#### Estimate Memory Usage + +Before preloading quantized vectors, you can **estimate the memory required** using: + +```sql +SELECT vector_quantize_memory('my_table', 'my_column'); +``` + +This gives you an approximate number of bytes needed to load the quantized vectors into memory. + +#### Accuracy You Can Trust + +Despite the compression, our quantization algorithms are finely tuned to maintain high accuracy. You can expect **recall rates greater than 0.95**, ensuring that approximate searches closely match exact results in quality. + +#### Measuring Recall in SQLite-Vector + +You can evaluate the recall of quantized search compared to exact search using a single SQL query. For example, assuming a table `vec_examples` with an `embedding` column, use: + +```sql +WITH +exact_knn AS ( + SELECT e.rowid + FROM vec_examples AS e + JOIN vector_full_scan('vec_examples', 'embedding', ?1, ?2) AS v + ON e.rowid = v.rowid +), +approx_knn AS ( + SELECT e.rowid + FROM vec_examples AS e + JOIN vector_quantize_scan('vec_examples', 'embedding', ?1, ?2) AS v + ON e.rowid = v.rowid +), +matches AS ( + SELECT COUNT(*) AS match_count + FROM exact_knn + WHERE rowid IN (SELECT rowid FROM approx_knn) +), +total AS ( + SELECT COUNT(*) AS total_count + FROM exact_knn +) +SELECT + (SELECT match_count FROM matches) AS match_count, + (SELECT total_count FROM total) AS total_count, + CAST((SELECT match_count FROM matches) AS FLOAT) / + CAST((SELECT total_count FROM total) AS FLOAT) AS recall; +``` + +Where `?1` is the input vector (as a BLOB) and `?2` is the number of nearest neighbors `k`. +This query compares exact and quantized results and computes the recall ratio, helping you validate the quality of quantized search. diff --git a/sqlite-cloud/sqlite-ai/sqlite-vector.mdx b/sqlite-cloud/sqlite-ai/sqlite-vector.mdx new file mode 100644 index 0000000..25c0af1 --- /dev/null +++ b/sqlite-cloud/sqlite-ai/sqlite-vector.mdx @@ -0,0 +1,43 @@ +--- +title: "SQLite-Vector" +description: "Production-grade vector search inside SQLite for local, edge, and embedded AI applications." +category: platform +status: publish +slug: sqlite-vector +--- + +**SQLite Vector** is a cross-platform, ultra-efficient SQLite extension that brings vector search capabilities to your embedded database. It works seamlessly on **iOS, Android, Windows, Linux, and macOS**, using just **30MB of memory** by default. With support for **Float32, Float16, BFloat16, Int8, UInt8 and 1Bit**, and **highly optimized distance functions**, it's the ideal solution for **Edge AI** applications. + +
    + + {"Installed by default in SQLite Cloud"} + + + {"GitHub: https://github.com/sqliteai/sqlite-vector"} + +
    + +## Highlights + +* **No virtual tables required** – store vectors directly as `BLOB`s in ordinary tables +* **Blazing fast** – optimized C implementation with SIMD acceleration +* **Low memory footprint** – defaults to just 30MB of RAM usage +* **Zero preindexing needed** – no long preprocessing or index-building phases +* **Works offline** – perfect for on-device, privacy-preserving AI workloads +* **Plug-and-play** – drop into existing SQLite workflows with minimal effort +* **Cross-platform** – works out of the box on all major OSes + + +## Why Use SQLite-Vector? + +| Feature | SQLite-Vector | Traditional Solutions | +| ---------------------------- | ------------- | ------------------------------------------ | +| Works with ordinary tables | ✅ | ❌ (usually require special virtual tables) | +| Doesn't need preindexing | ✅ | ❌ (can take hours for large datasets) | +| Doesn't need external server | ✅ | ❌ (often needs Redis/FAISS/Weaviate/etc.) | +| Memory-efficient | ✅ | ❌ | +| Easy to use SQL | ✅ | ❌ (often complex JOINs, subqueries) | +| Offline/Edge ready | ✅ | ❌ | +| Cross-platform | ✅ | ❌ | + +Unlike other vector databases or extensions that require complex setup, SQLite-Vector **just works** with your existing database schema and tools. diff --git a/sqlite-cloud/test-wrapper-multi.mdx b/sqlite-cloud/test-wrapper-multi.mdx new file mode 100644 index 0000000..3ad8132 --- /dev/null +++ b/sqlite-cloud/test-wrapper-multi.mdx @@ -0,0 +1,19 @@ +--- +title: Multi Code Component Examples +description: Multi Code Component Examples +slug: wrapper-multicode +category: getting-started +status: draft +--- +import ReactCodeExample from "@docs-website-assets/code-examples/ReactCodeExample.astro"; + + + + + + + + + + + diff --git a/sqlite-cloud/tutorials/tutorial-geopoly.mdx b/sqlite-cloud/tutorials/tutorial-geopoly.mdx new file mode 100644 index 0000000..0c75a9e --- /dev/null +++ b/sqlite-cloud/tutorials/tutorial-geopoly.mdx @@ -0,0 +1,827 @@ +--- +title: Using SQLite Extensions - Geopoly +description: Build a local attractions finder app using SQLite Cloud, SQLite's built-in Geopoly extension, Mapbox, and React. +category: getting-started +status: publish +slug: tutorial-geopoly +--- + +In this tutorial you will build a local attractions finder map-plication using GeoJSON data, a SQLite Cloud database, Mapbox GL JS (JavaScript Graphics Library), React, and SQLite's built-in Geopoly extension. + +**Time to complete: 15-20 mins.** + +If you get stuck in the tutorial or prefer to play with the finished product, check out the example app on GitHub. + +--- + +**1. Initialize your app** + - Create a new directory `sqlc-geopoly-demo`. From this directory, bootstrap a Node.js project. + +```bash +mkdir sqlc-geopoly-demo +cd sqlc-geopoly-demo +npm init -y +``` + +**2. Curate your GeoJSON data** + + - We will leverage the Overpass API (an open-source, read-only API for fetching OpenStreetMap data) to query NY attractions. + + - Visit Overpass Turbo, the Overpass GUI. Copy and paste in the below query, which: + - defines New York as the area of interest; + - fetches nodes in the specified area that are tagged with the keys `amenity`, `historic`, `tourism`, `leisure`, etc.; and + - outputs the data. + +```c +[out:json][timeout:25]; + +area[name="New York"]->.newyork; + +( + node["amenity"="events_venue"](area.newyork); + node["amenity"="exhibition_centre"](area.newyork); + node["amenity"="music_venue"](area.newyork); + node["amenity"="social_centre"](area.newyork); + node["amenity"="marketplace"](area.newyork); + node["building"="museum"](area.newyork); + node["historic"="building"](area.newyork); + node["tourism"="attraction"](area.newyork); + node["leisure"="park"](area.newyork); + node["natural"="beach"](area.newyork); + node["shop"="coffee"](area.newyork); + node["sport"="yoga"](area.newyork); +); + +out body; +>; +out skel qt; +``` + + - Run the query. + + - Click Export. Under Data, copy the GeoJSON. + + - Back in your project dir, create `data/geodata.json`. Paste the formatted GeoJSON into the file. It should look similar to the following: + +```json +{ + "type": "FeatureCollection", + "generator": "overpass-turbo", + "copyright": "The data included in this document is from www.openstreetmap.org. The data is made available under ODbL.", + "timestamp": "2024-08-05T23:56:57Z", + "features": [ + { + "type": "Feature", + "properties": { + "@id": "node/43058007", + "ele": "190", + "gnis:feature_id": "968527", + "leisure": "park", + "name": "Kibler Park" + }, + "geometry": { + "type": "Point", + "coordinates": [-78.6723302, 43.1655945] + }, + "id": "node/43058007" + }, + ..., + { + "type": "Feature", + "properties": { + "@id": "node/12093603396", + "amenity": "events_venue", + "name": "Azteca Venue Party Center" + }, + "geometry": { + "type": "Point", + "coordinates": [-74.1244477, 40.6338683] + }, + "id": "node/12093603396" + } + ] +} +``` + - For this tutorial, we'll use the NY geodata. Once you have the app up-and-running, you can run your own Overpass queries to customize the geodata per your needs. See **Additional Guidance on Overpass** at the end of this tutorial. + +**3. Create a new SQLite Cloud database** + + - If you haven't already, sign up for a SQLite Cloud account and create a new project. + + - In your account dashboard's left nav, click Databases, then Create Database. Name your new database `geopoly-demo`. + +**4. Create a Mapbox account** + + - Sign up for an Individual Mapbox account. (We'll stay on the free tier.) + +**5. Set your environment variables** + + - In your project dir, create a `.env` file. + - This app will use `react-scripts`, which leverages Create React App under-the-hood. Create React App offers built-in support for env vars. You will not need to manually configure `webpack` or another bundler, but all vars will need to be prefixed with `REACT_APP_`. + + - Add 2 env vars to the file: + - `REACT_APP_CONNECTION_STRING`. Copy and paste your connection string from your SQLite Cloud account dashboard. + - `REACT_APP_MAPBOX_TOKEN`. In your Mapbox account dashboard's nav, click Tokens. Copy and paste your default public token. + + - Install the SQLite Cloud JS SDK and `dotenv` package as dependencies: + +```bash +npm i @sqlitecloud/drivers +npm i -D dotenv +``` + +**6. Create your database tables** + + - In your project dir, create `src/helpers/createDatabase.js`. Copy and paste in the following code: + +```js +import { Database } from '@sqlitecloud/drivers'; +import 'dotenv/config'; +import geodata from '../../data/geodata.json' assert { type: 'json' }; + +async function createDatabase() { + // open a connection to your `geopoly-demo` database + const db = new Database(process.env.REACT_APP_CONNECTION_STRING); + + const db_name = 'geopoly-demo'; + await db.sql`USE DATABASE ${db_name};`; + + // create a table with 2 columns: `rowid` and `_shape` + await db.sql`CREATE VIRTUAL TABLE polygons USING geopoly()`; + + // create a table with 5 columns: `id`, `name`, `lng`, `lat`, and `coordinates` + await db.sql`CREATE TABLE attractions (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, lng REAL NOT NULL, lat REAL NOT NULL, coordinates TEXT NOT NULL)`; + + // populate the `attractions` table using the GeoJSON FeatureCollection in `geodata.json` + for (const feature of geodata['features']) { + const { name } = feature.properties; + const { coordinates } = feature.geometry; + const [lng, lat] = coordinates; + + await db.sql`INSERT INTO attractions(name, lng, lat, coordinates) VALUES(${name}, ${lng}, ${lat}, ${JSON.stringify( + coordinates + )})`; + } + + db.close(); + + console.log('Geodata inserted!'); +} + +createDatabase(); +``` + + - Add the following to your `package.json`: + +```json +"scripts": { + "create-tables": "node src/helpers/createDatabase.js" +}, +"type": "module", +``` + + - Run `npm run create-tables`. + + - The time it will take for the command to finish creating the tables and inserting the geodata will depend on the size of your FeatureCollection. The NY Overpass query returns ~2000 Point features, so row insertion takes a couple of minutes. + + - To see the inserted NY attractions geodata, in your SQLite Cloud account dashboard's left nav, click Console. In the database dropdown, select `geopoly-demo`. Copy, paste in, and run the following query: + +```sql +SELECT * FROM attractions ORDER BY id DESC; +``` + +**7. Set up the frontend** + + - In your project dir, create `public/index.html`. Copy and paste in the following code: + +```html + + + + + + + Local Attractions Finder + + + +
    + + +``` + + - In the `src` dir, add 3 files: `index.css` (for app styling), `index.js` (the app entrypoint file), and `App.js` (the app's sole component). Copy and paste in the following code for each file: + +`index.css` +```css +@import url('https://fonts.googleapis.com/css2?family=Inter+Tight:wght@100..900&display=swap'); + +* { + box-sizing: border-box; +} + +body { + margin: 0; + padding: 0; + font: 400 15px/22px 'Inter Tight', sans-serif; + -webkit-font-smoothing: antialiased; +} + +.legend { + padding: 10px; + background-color: #23374b; + color: #fff; + font-family: monospace; +} + +.sidebar { + position: absolute; + width: 25%; + height: 100%; + overflow: hidden; +} + +.map-container { + position: absolute; + left: 25%; + width: 75%; + top: 0; + bottom: 0; +} + +.heading { + padding: 0 10px; + border-bottom: 1px solid #eee; +} + +.listings { + height: 72%; + overflow: auto; + padding-bottom: 15px; +} + +.listings .item { + padding: 10px; + border-bottom: 1px solid #eee; +} + +.listings .item.active { + background-color: #cfe1f8; +} + +.listings .item:last-child { + border-bottom: none; +} + +.listings .item .title { + color: #5a5877; + font-weight: 700; + text-decoration: none; +} + +.listings .item.active .title, +.listings .item .title:hover { + color: #000; +} + +::-webkit-scrollbar { + width: 5px; +} + +::-webkit-scrollbar-track { + background: none; +} + +::-webkit-scrollbar-thumb { + background: #23374b; +} + +.mapboxgl-popup { + padding-bottom: 20px; +} + +.mapboxgl-popup-close-button { + display: none; +} + +.mapboxgl-popup-content { + padding: 0; +} + +.mapboxgl-popup-content h3 { + background: #cfe1f8; + color: #000; + margin: 0; + padding: 10px; + border-radius: 3px 3px 0 0; + font-weight: 700; + margin-top: -15px; +} + +.mapboxgl-popup-content h4 { + margin: 0; + padding: 10px; + font-weight: 400; +} + +.marker { + border: none; + cursor: pointer; + width: 32px; + height: 40px; + background-image: url('https://docs.mapbox.com/mapbox-gl-js/assets/custom_marker.png'); +} + +.mapboxgl-ctrl-geocoder { + border: 0; + border-radius: 0; + position: relative; + top: 0; + width: 800px; + margin-top: 0; +} + +.mapboxgl-ctrl-geocoder > div { + min-width: 100%; + margin-left: 0; +} +``` + + - NOTE: To simplify this tutorial, `.marker.background-image` uses a custom Mapbox marker for the pins marking attractions on the map. The example app on GitHub uses a custom marker image included in the repo's `images` dir (excluded here). + +`index.js` +```js +import React from 'react'; +import { createRoot } from 'react-dom/client'; +import 'mapbox-gl/dist/mapbox-gl.css'; +import './index.css'; +import App from './App.js'; + +const container = document.querySelector('#root'); +const root = createRoot(container); +root.render( + + + +); +``` + +`App.js` +```js +import { useState, useEffect, useRef } from 'react'; +import mapboxgl from 'mapbox-gl'; +import '@mapbox/mapbox-gl-geocoder/dist/mapbox-gl-geocoder.css'; +import MapboxGeocoder from '@mapbox/mapbox-gl-geocoder'; +import { point, distance } from '@turf/turf'; +import { Database } from '@sqlitecloud/drivers'; +import { getBbox } from './helpers/getBbox.js'; + +mapboxgl.accessToken = process.env.REACT_APP_MAPBOX_TOKEN; + +function App() { + const mapContainerRef = useRef(); + const mapRef = useRef(); + + const [lng, setLng] = useState(-73.9654897); + const [lat, setLat] = useState(40.7824635); + const [zoom, setZoom] = useState(12); + + const [places, setPlaces] = useState([]); + const [geometry, setGeometry] = useState([]); + + const units = 'miles'; + + async function queryGeopoly(searchedLng, searchedLat) { + // open a connection to your `geopoly-demo` database + const db = new Database(process.env.REACT_APP_CONNECTION_STRING); + + const db_name = 'geopoly-demo'; + + const radius = 0.05; // must be a positive number + const sides = 50; // 3-1000 + + // generate a new polygon to be added to your `polygons` table + const polygonCoords = + await db.sql`USE DATABASE ${db_name}; INSERT INTO polygons(_shape) VALUES(geopoly_regular(${searchedLng}, ${searchedLat}, ${radius}, ${sides})) RETURNING geopoly_json(_shape);`; + + // point-in-polygon query to get all attractions in the generated polygon's area + const attractionsInPolygon = + await db.sql`USE DATABASE ${db_name}; SELECT name, coordinates FROM attractions WHERE geopoly_contains_point(${polygonCoords[0]['geopoly_json(_shape)']}, lng, lat);`; + + db.close(); + + // remove unnamed attractions + const namedAttractions = attractionsInPolygon.filter( + (attraction) => attraction.name !== null + ); + + const attractionFeatures = namedAttractions.map((attraction, index) => { + const attractionCoordinates = JSON.parse(attraction['coordinates']); + + const attractionFeature = { + type: 'Feature', + geometry: { + type: 'Point', + coordinates: attractionCoordinates, + }, + properties: { + id: index, + title: attraction['name'], + // use Turf.js to calculate the distance between the searched location and the current attraction + distance: distance( + point([searchedLng, searchedLat]), + point(attractionCoordinates), + { + units, // either miles or kilometers + } + ), + }, + }; + + // apply clickable markers for all attractions + const marker = document.createElement('div'); + marker.key = `marker-${attractionFeature.properties.id}`; + marker.id = `marker-${attractionFeature.properties.id}`; + marker.className = 'marker'; + + marker.addEventListener('click', (e) => { + handleClick(attractionFeature); + }); + + new mapboxgl.Marker(marker) + .setLngLat(attractionCoordinates) + .addTo(mapRef.current); + + return attractionFeature; + }); + + // upsort attractions nearest the user's searched location + attractionFeatures.sort((a, b) => { + if (a.properties.distance > b.properties.distance) { + return 1; + } + if (a.properties.distance < b.properties.distance) { + return -1; + } + return 0; + }); + + setPlaces(attractionFeatures); + + // use a helper function (defined in the next step) to fit/ zoom the map view to the searched location and its nearest attraction + if (attractionFeatures[0]) { + const bbox = getBbox(attractionFeatures, searchedLng, searchedLat); + mapRef.current.fitBounds(bbox, { + padding: 100, + }); + + new mapboxgl.Popup({ closeOnClick: false }) + .setLngLat(attractionFeatures[0].geometry.coordinates) + .setHTML( + `

    ${ + attractionFeatures[0].properties.title + }

    ${attractionFeatures[0].properties.distance.toFixed( + 2 + )} ${units} away

    ` + ) + .addTo(mapRef.current); + } + + // update the `geometry` state to hold the returned Polygon and attraction Point features + setGeometry([ + { + type: 'Feature', + geometry: { + type: 'Polygon', + coordinates: [JSON.parse(polygonCoords[0]['geopoly_json(_shape)'])], + }, + }, + ...attractionFeatures, + ]); + } + + function drawFeatureCollection() { + const sourceId = 'newyork'; + + if (!mapRef.current.getSource(sourceId)) { + mapRef.current.addSource(sourceId, { + type: 'geojson', + data: { + type: 'FeatureCollection', + features: geometry, + }, + }); + + mapRef.current.addLayer({ + id: 'polygon', + type: 'fill', + source: sourceId, + paint: { + 'fill-color': '#888888', + 'fill-opacity': 0.4, + }, + filter: ['==', '$type', 'Polygon'], + }); + + mapRef.current.addLayer({ + id: 'outline', + type: 'line', + source: sourceId, + layout: {}, + paint: { + 'line-color': '#000', + 'line-width': 1, + }, + }); + } else { + mapRef.current.getSource(sourceId).setData({ + type: 'FeatureCollection', + features: geometry, + }); + } + } + + function handleClick(feature) { + const center = feature.geometry.coordinates; + const { id, title, distance } = feature.properties; + + mapRef.current.flyTo({ + center, + zoom: 15, + }); + + const popUps = document.getElementsByClassName('mapboxgl-popup'); + if (popUps[0]) { + popUps[0].remove(); + } + + new mapboxgl.Popup({ closeOnClick: false }) + .setLngLat(center) + .setHTML(`

    ${title}

    ${distance.toFixed(2)} ${units} away

    `) + .addTo(mapRef.current); + + const activeItem = document.getElementsByClassName('active'); + if (activeItem[0]) { + activeItem[0].classList.remove('active'); + } + + const listing = document.getElementById(`listing-${id}`); + listing.classList.add('active'); + } + + useEffect(() => { + // create, style, and center the map + mapRef.current = new mapboxgl.Map({ + container: mapContainerRef.current, + style: 'mapbox://styles/mapbox/streets-v12', + center: [lng, lat], + zoom, + }); + + // apply 3 controls to the top right of the map + // an address search input + const geocoder = new MapboxGeocoder({ + accessToken: mapboxgl.accessToken, + mapboxgl, + zoom: 12, + }); + + // toggle fullscreen mode + const fullscreenCtrl = new mapboxgl.FullscreenControl({ + container: mapContainerRef.current, + }); + + // locate the user on the map + const geolocateCtrl = new mapboxgl.GeolocateControl({ + fitBoundsOptions: { + maxZoom: 12, + }, + positionOptions: { + enableHighAccuracy: true, + }, + trackUserLocation: true, + }); + + mapRef.current.addControl(geocoder); + mapRef.current.addControl(fullscreenCtrl); + mapRef.current.addControl(geolocateCtrl); + + // track the map center coordinates and zoom level (displayed on the top left of the app) + function updateCoordinates() { + const { lng, lat } = mapRef.current.getCenter(); + setLng(lng.toFixed(4)); + setLat(lat.toFixed(4)); + setZoom(mapRef.current.getZoom().toFixed(2)); + } + + mapRef.current.on('move', updateCoordinates); + + // call the `queryGeopoly` function when the user clicks a geocoder result + geocoder.on('result', (e) => { + const existingMarkers = document.getElementsByClassName('marker'); + while (existingMarkers[0]) { + existingMarkers[0].remove(); + } + + const popUps = document.getElementsByClassName('mapboxgl-popup'); + while (popUps[0]) { + popUps[0].remove(); + } + + const [lng, lat] = e.result.geometry.coordinates; + queryGeopoly(lng, lat); + }); + + return () => { + mapRef.current.removeControl(geocoder); + mapRef.current.removeControl(fullscreenCtrl); + mapRef.current.removeControl(geolocateCtrl); + mapRef.current.off('move', updateCoordinates); + mapRef.current.remove(); + }; + }, []); // eslint-disable-line react-hooks/exhaustive-deps + + // triggered by a `geometry` state update + useEffect(() => { + if (geometry.length !== 0) { + // draw the returned Polygon, its outline, and attraction Points on the map + drawFeatureCollection(); + } + }, [geometry]); // eslint-disable-line react-hooks/exhaustive-deps + + return ( + <> +
    +
    +

    Center Lat: {lat}

    +

    Center Long: {lng}

    +

    Current Zoom: {zoom}

    +
    +
    +

    Attractions Nearby:

    +
    + +
    + {places.map((place, index) => ( +
    + handleClick(place)}> + {place.properties.title} + +
    + {place.properties.distance.toFixed(2)} {units} away +
    +
    + ))} +
    +
    +
    + + ); +} + +export default App; +``` + +**8. Create a helper function** + + - Create `src/helpers/getBbox.js`. Copy and paste in the following code: + +```js +export function getBbox(sortedEvents, locationLng, locationLat) { + const lons = [ + sortedEvents[0].geometry.coordinates[0], + locationLng, + ]; + const lats = [ + sortedEvents[0].geometry.coordinates[1], + locationLat, + ]; + const sortedLons = lons.sort((a, b) => { + if (a > b) { + return 1; + } + if (a.distance < b.distance) { + return -1; + } + return 0; + }); + const sortedLats = lats.sort((a, b) => { + if (a > b) { + return 1; + } + if (a.distance < b.distance) { + return -1; + } + return 0; + }); + + // return a bounding box, defined by a southwest coordinate pair and northeast coordinate pair + return [ + [sortedLons[0], sortedLats[0]], + [sortedLons[1], sortedLats[1]], + ]; +} +``` + +**9. Run your app!** + + - Replace your `package.json` code with the following, which includes all dependencies needed to run the app: + +```json +{ + "name": "sqlc-geopoly-demo", + "version": "1.0.0", + "private": true, + "description": "", + "main": "index.js", + "scripts": { + "start": "react-scripts start", + "build": "react-scripts build", + "create-tables": "node src/helpers/createDatabase.js" + }, + "eslintConfig": { + "extends": [ + "react-app" + ] + }, + "browserslist": [ + "defaults", + "not ie 11" + ], + "author": "", + "license": "ISC", + "type": "module", + "dependencies": { + "@mapbox/mapbox-gl-geocoder": "^5.0.2", + "@sqlitecloud/drivers": "^1.0.193", + "@turf/turf": "^7.0.0", + "mapbox-gl": "^3.5.2", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-scripts": "^5.0.1" + }, + "devDependencies": { + "@babel/plugin-proposal-private-property-in-object": "^7.21.11", + "dotenv": "^16.4.5" + } +} +``` + + - From your project dir, install the dependencies and start your local dev server. + +```bash +npm i +npm start +``` + + - Visit `http://localhost:3000/` (adjust the port as-needed) in your browser to view the app. + +**10. Find attractions!** + + - On app load, the map is centered on Central Park, NY. + + - In the geocoder (i.e. search input) at the top right of the map, enter "Empire" and click on the "Empire State Building" result. You can also search coordinates (see reverse geocoding). + + - When you select a geocoder result: + - a polygon is generated by Geopoly, added to your `polygons` table, and displayed on the map; and + + - all attractions in your `attractions` table inside the polygon area are listed in the left sidebar AND marked on the map. NOTE: the sidebar upsorts attractions nearest your searched location, in this case the "Empire State Building". + + - To see the inserted polygon data, in your SQLite Cloud account dashboard's left nav, click Console. In the database dropdown, select `geopoly-demo`. Copy, paste in, and run the following query. + + - The `geopoly_json` function parses the `_shape` column's `[object ArrayBuffer]` data into an array of coordinate pairs representing the polygon's vertices: `[[-73.9355,40.7485],[-73.9359,40.7547], ...,[-73.9359,40.7422],[-73.9355,40.7485]]`. The array should contain (1 + # of polygon sides) coordinate pairs. The polygon is closed, so the first and last pairs both represent the same vertex. + +```sql +SELECT rowid, geopoly_json(_shape) FROM polygons; +``` + + - The map zooms in to the nearest attraction to your searched location and highlights its corresponding top listing in the sidebar. + + - You can click on any attraction listing or marker to fly/ zoom to and center on that attraction on the map. + + - Turf.js uses the Haversine formula to account for global curvature when calculating the distance between your searched location and each attraction. However, you should still expect discrepancies between this app's calculated distances vs, say, Google or Apple Maps. + +And that’s it! You’ve successfully built a local attractions finder app that utilizes Geopoly to write geodata to and read from a SQLite Cloud database. + +### Additional Guidance on Overpass: + + - To fetch other attractions or any other kind of location data in NY or another area of interest to you, refer to OpenStreetMap's Map features documentation. As a starting point, modify the area or key-value pairs in the NY query. + + - NOTE: The app works only with Point features (represented in the Map features tables' `Element` columns by an icon with a single dot). Be sure to query only nodes and the key-value pairs that can return Point data. For example, don't use most of the values available for the Boundary key. + + - To implement more complex or granular Point queries, refer to the Overpass QL documentation. + + - If you run a custom Overpass query: + - Add to or replace the FeatureCollection in `geodata.json`. + - In your SQLite Cloud account dashboard's left nav, click Databases. In the `geopoly-demo` row, click the down chevron and then Delete Database. + - Create Database with the same name. + - From your project dir, run `npm run create-tables`. Your database tables will be re-created, and the `attractions` table will be populated with your updated geodata. + + - If you queried and stored attractions near your location, then after the app's initial load, click on the GeolocateControl icon at the top right of the map and allow the browser to quickly center the map on your location. Search away! \ No newline at end of file diff --git a/sqlite-cloud/write-data.mdx b/sqlite-cloud/write-data.mdx index 64d5acf..02fdcd3 100644 --- a/sqlite-cloud/write-data.mdx +++ b/sqlite-cloud/write-data.mdx @@ -3,48 +3,49 @@ title: Writing data to your database description: Learn how to write data to your SQLite Cloud cluster. category: getting-started status: publish +slug: write-data --- +import VideoPlayer from '@commons-components/Video/VideoPlayer.astro'; +import studioInsert from '@docs-website-assets/introduction/video/dashboard_studio.mp4'; After you've created a database in SQLite Cloud, you can start writing data to it. You can write data to your cluster using the SQLite Cloud UI, API, or client libraries. +--- + ## Writing data with the SQLite Cloud UI -Navigate to the console tab in the left-hand navigation. From here, you can run SQL commands against your cluster. Use the optional dropdown menus to select a database and table. +Navigate to the Studio tab from the left-hand navigation. From here, you can run SQL commands directly on your cluster. +If needed, use the dropdown menus to select the database and table where you want to insert or update data. + +Alternatively, you can also interact directly with the table view to add new records or update existing ones without writing SQL manually. + -![Dashboard Projects](@docs-website-assets/introduction/dashboard_console.png) + ### Example ```sql -- If you haven't selected a database yet, run the USE DATABASE command -USE DATABASE mydatabase.sqlite; +USE DATABASE .sqlite; -- Create your table -CREATE TABLE sports_cars (sc_id INTEGER PRIMARY KEY, sc_name TEXT NOT NULL, sc_year INTEGER NOT NULL, image BLOB); +CREATE TABLE sports_cars (sc_id INTEGER PRIMARY KEY, sc_make TEXT NOT NULL, sc_year INTEGER NOT NULL); -- Insert data into your table -INSERT INTO sports_cars (sc_name, sc_year, image) VALUES ('Ferrari', 2021, 'https://example.com/ferrari.jpg'); +INSERT INTO sports_cars (sc_make, sc_year) VALUES ('Ferrari', 2021); ``` -## Writing data with the Weblite API -You can use the SQLite Cloud API to write data to your cluster. - -To upload a local SQLite database via weblite, make a POST request to the `/v2/weblite/.sqlite` endpoint. - -```bash -curl -X 'POST' \ - 'https://.sqlite.cloud:8090/v2/weblite/.sqlite' \ - -H 'accept: application/json' \ - -H 'Authorization: Bearer sqlitecloud://.sqlite.cloud:8860?apikey=.sqlite.cloud:8090/v2/weblite/sql' \ + 'https://.sqlite.cloud/v2/weblite/sql' \ -H 'accept: application/json' \ -H 'Authorization: Bearer sqlitecloud://.sqlite.cloud:8860?apikey=' \ - -d '' + -d '' ``` +--- + ## Writing data with client libraries To write data to your cluster using a client library, use the INSERT INTO SQL command. @@ -52,11 +53,12 @@ To write data to your cluster using a client library, use the INSERT INTO SQL co import { Database } from '@sqlitecloud/drivers'; const db = new Database('sqlitecloud://.sqlite.cloud:?apikey=') -db.exec('USE DATABASE mydatabase.sqlite;') -db.exec('CREATE TABLE sports_cars (sc_id INTEGER PRIMARY KEY, sc_name TEXT NOT NULL, sc_year INTEGER NOT NULL, image BLOB);') +db.exec('USE DATABASE .sqlite;') +db.exec('CREATE TABLE sports_cars (sc_id INTEGER PRIMARY KEY, sc_make TEXT NOT NULL, sc_year INTEGER NOT NULL);') db.commit() -const insertData = async () => await db.sql`INSERT INTO sports_cars (sc_name, sc_year, image) VALUES ('Ferrari', 2021, 'https://example.com/ferrari.jpg');`; +const insertData = async () => await db.sql('INSERT INTO sports_cars (sc_make, sc_year) VALUES (?, ?)', 'Ferrari', 2021); insertData().then((res) => console.log(res)); // "OK" ``` + diff --git a/sqlite/json1.md b/sqlite/json1.md index 5ebf204..5085945 100644 --- a/sqlite/json1.md +++ b/sqlite/json1.md @@ -10,8 +10,8 @@ status: publish ## 1. Overview By default, SQLite supports twenty-nine functions and two operators for -dealing with JSON values. There are also two [table-valued -functions](https://sqlite.org/vtab.html#tabfunc2) that can be used to +dealing with JSON values. There are also two table-valued +functions that can be used to decompose a JSON string. There are 25 scalar functions and operators: @@ -52,7 +52,7 @@ There are four [aggregate SQL functions](lang_aggfunc.html): 3. [json_group_object](#jgroupobject)(*label*,*value*) 4. [jsonb_group_object](#jgroupobjectb)(name,*value*) -The two [table-valued functions](https://sqlite.org/vtab.html#tabfunc2) +The two table-valued functions are: 1. [json_each](#jeach)(*json*) @@ -91,11 +91,11 @@ function will usually throw an error. (Exceptions to this rule are [json_valid()](json1#jvalid), [json_quote()](json1#jquote), and [json_error_position()](json1#jerr).) -These routines understand all [rfc-8259 JSON -syntax](https://www.rfc-editor.org/rfc/rfc8259.txt) and also [JSON5 -extensions](https://spec.json5.org/). JSON text generated by these -routines always strictly conforms to the [canonical JSON -definition](https://json.org) and does not contain any JSON5 or other +These routines understand all rfc-8259 JSON +syntax and also JSON5 +extensions. JSON text generated by these +routines always strictly conforms to the canonical JSON +definition and does not contain any JSON5 or other extensions. The ability to read and understand JSON5 was added in version 3.42.0 (2023-05-16). Prior versions of SQLite would only read canonical JSON. @@ -126,7 +126,7 @@ JSONB is a binary representation of JSON used by SQLite and is intended for internal use by SQLite only. Applications should not use JSONB outside of SQLite nor try to reverse-engineer the JSONB format. -The "JSONB" name is inspired by [PostgreSQL](https://postgresql.org), +The "JSONB" name is inspired by PostgreSQL, but the on-disk format for SQLite's JSONB is not the same as PostgreSQL's. The two formats have the same name, but are not binary compatible. The PostgreSQL JSONB format claims to offer O(1) lookup of @@ -240,19 +240,19 @@ The current implementation of this JSON library uses a recursive descent parser. In order to avoid using excess stack space, any JSON input that has more than 1000 levels of nesting is considered invalid. Limits on nesting depth are allowed for compatible implementations of JSON by -[RFC-8259 section 9](https://tools.ietf.org/html/rfc8259#section-9). +RFC-8259 section 9. ## 3.6. JSON5 Extensions Beginning in version 3.42.0 (2023-05-16), these routines will read and -interpret input JSON text that includes [JSON5](https://spec.json5.org/) +interpret input JSON text that includes JSON5 extensions. However, JSON text generated by these routines will always -be strictly conforming to the [canonical definition of -JSON](https://json.org). +be strictly conforming to the canonical definition of +JSON. -Here is a synopsis of JSON5 extensions (adapted from the [JSON5 -specification](https://spec.json5.org/#introduction)): +Here is a synopsis of JSON5 extensions (adapted from the JSON5 +specification): - Object keys may be unquoted identifiers. - Objects may have a single trailing comma. @@ -699,7 +699,7 @@ is returned in the binary JSONB format. ## 4.14. The json_patch() function The json_patch(T,P) SQL function runs the -[RFC-7396](https://tools.ietf.org/html/rfc7396) MergePatch algorithm to +RFC-7396 MergePatch algorithm to apply patch P against input T. The patched copy of T is returned. MergePatch can add, modify, or delete elements of a JSON Object, and so @@ -919,8 +919,8 @@ the same except that they return their result in the binary ## 4.22. The json_each() and json_tree() table-valued functions -The json_each(X) and json_tree(X) [table-valued -functions](https://www.sqlite.org/vtab.html#tabfunc2) walk the JSON +The json_each(X) and json_tree(X) table-valued +functions walk the JSON value provided as their first argument and return one row for each element. The json_each(X) function only walks the immediate children of the top-level array or object, or just the top-level element itself if