Skip to content

Commit

Permalink
Merge pull request #121 from singlestore-labs/bharath-templates
Browse files Browse the repository at this point in the history
Add Create DashApp and create Singlestore Cloud Functions template to spaces
  • Loading branch information
bharathts07 authored Nov 13, 2024
2 parents ed421af + 246cbef commit 69c6699
Show file tree
Hide file tree
Showing 4 changed files with 642 additions and 0 deletions.
13 changes: 13 additions & 0 deletions notebooks/cloud-functions-template/meta.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[meta]
authors=["singlestore"]
title="Publish your first SingleStore Cloud function"
description="""\
Learn how to connect to SingleStoreDB and perform basic\
CRUD operations and finally deploy these functions as callable API endpoints.
"""
icon="browser"
difficulty="beginner"
tags=["starter", "notebooks", "python"]
lesson_areas=[]
destinations=["spaces"]
minimum_tier="free-shared"
268 changes: 268 additions & 0 deletions notebooks/cloud-functions-template/notebook.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "8ba141c2-e0c2-4723-b782-c924bc7b294c",
"metadata": {},
"source": [
"<div id=\"singlestore-header\" style=\"display: flex; background-color: rgba(235, 249, 245, 0.25); padding: 5px;\">\n",
" <div id=\"icon-image\" style=\"width: 90px; height: 90px;\">\n",
" <img width=\"100%\" height=\"100%\" src=\"https://raw.githubusercontent.com/singlestore-labs/spaces-notebooks/master/common/images/header-icons/browser.png\" />\n",
" </div>\n",
" <div id=\"text\" style=\"padding: 5px; margin-left: 10px;\">\n",
" <div id=\"badge\" style=\"display: inline-block; background-color: rgba(0, 0, 0, 0.15); border-radius: 4px; padding: 4px 8px; align-items: center; margin-top: 6px; margin-bottom: -2px; font-size: 80%\">SingleStore Notebooks</div>\n",
" <h1 style=\"font-weight: 500; margin: 8px 0 0 4px;\">Publish your first SingleStore Cloud function</h1>\n",
" </div>\n",
"</div>"
]
},
{
"cell_type": "markdown",
"id": "cd7deb95-c7bb-48eb-9cab-ed508b3be5ff",
"metadata": {},
"source": [
"<div class=\"alert alert-block alert-warning\">\n",
" <b class=\"fa fa-solid fa-exclamation-circle\"></b>\n",
" <div>\n",
" <p><b>Note</b></p>\n",
" <p>This notebook can be run on a Free Starter Workspace. To create a Free Starter Workspace navigate to <tt>Start</tt> using the left nav. You can also use your existing Standard or Premium workspace with this Notebook.</p>\n",
" </div>\n",
"</div>"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "a5564913-7ff8-41bf-b64b-b67971c63fae",
"source": [
"This Jupyter notebook will help you build your first Cloud Function, showcasing how to leverage the ultra-fast queries of SingleStore to build a responsive API server using FastAPI"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "1e394195-29b4-403c-9abf-5d7731349eb6",
"source": [
"## Create some simple tables\n",
"\n",
"This setup establishes a basic relational structure to store some items information."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "a17bdd3a-16b3-4e19-8a56-6566a169eccb",
"outputs": [],
"source": [
"%%sql\n",
"DROP TABLE IF EXISTS items;\n",
"\n",
"CREATE TABLE IF NOT EXISTS\n",
"items (\n",
" id INT PRIMARY KEY,\n",
" name VARCHAR(255),\n",
" price FLOAT\n",
");"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "af6e2618-de97-4397-b0d2-23e4a4df1d83",
"source": [
"## Create a Connection Pool\n",
"\n",
"To run multiple simultaneous queries, we use sqlalchemy to create a pool of sql connections to the workspace you have selected. We also define a method to execute queries and transactions using a connection from this pool."
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "f485e71b-2b05-4696-b22a-cf046fd83090",
"outputs": [],
"source": [
"from sqlalchemy import create_engine, text\n",
"import requests\n",
"\n",
"ca_cert_url = \"https://portal.singlestore.com/static/ca/singlestore_bundle.pem\"\n",
"ca_cert_path = \"/tmp/singlestore_bundle.pem\"\n",
"\n",
"response = requests.get(ca_cert_url)\n",
"with open(ca_cert_path, \"wb\") as f:\n",
" f.write(response.content)\n",
"\n",
"engine = create_engine(\n",
" f\"{connection_url}?ssl_ca={ca_cert_path}\",\n",
" pool_size=10, # Maximum number of connections in the pool is 10\n",
" max_overflow=5, # Allow up to 5 additional connections (temporary overflow)\n",
" pool_timeout=30 # Wait up to 30 seconds for a connection from the pool\n",
")\n",
"\n",
"def execute_query(query: str):\n",
" with engine.connect() as connection:\n",
" return connection.execute(text(query))\n",
"\n",
"def execute_transaction(transactional_query: str):\n",
" with engine.connect() as connection:\n",
" transaction = connection.begin()\n",
" try:\n",
" result = connection.execute(text(transactional_query))\n",
" transaction.commit()\n",
" return result\n",
" except Exception as e:\n",
" transaction.rollback()\n",
" raise e"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "ee9058a9-34a5-46fc-8b12-d30cbb8c3340",
"source": [
"## Setup Environment\n",
"\n",
"Lets setup the environment ro run a FastAPI app defining the Data Model and an executor to run the different requests in different threads simultaneously"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "66df8f0c-70c6-4f06-9e64-ef06961cca3a",
"outputs": [],
"source": [
"from fastapi import FastAPI, HTTPException\n",
"from pydantic import BaseModel\n",
"from singlestoredb import connect\n",
"from concurrent.futures import ThreadPoolExecutor\n",
"import asyncio\n",
"\n",
"# Define the Type of the Data\n",
"class Item(BaseModel):\n",
" id: int\n",
" name: str\n",
" price: float\n",
"\n",
"# Create an executor that can execute queries on multiple threads simultaneously\n",
"executor = ThreadPoolExecutor()\n",
"def run_in_thread(fn, *args):\n",
" loop = asyncio.get_event_loop()\n",
" return loop.run_in_executor(executor, fn, *args)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "96760949-5ab2-474d-80ca-d23b5dcc52f7",
"source": [
"## Define FastAPI App\n",
"\n",
"Next, we will be defining a FastAPI app that can insert, query and delete data from your table"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "3087dbe6-57ce-4410-a42f-5b0fe90add90",
"outputs": [],
"source": [
"app = FastAPI()\n",
"\n",
"# Get all items\n",
"@app.get(\"/items\", response_model=list[Item])\n",
"async def get_items():\n",
" def get_items_query():\n",
" result = execute_query(\"SELECT * FROM items;\")\n",
" rows = result.fetchall()\n",
" return [{\"id\": row[0], \"name\": row[1], \"price\": row[2]} for row in rows]\n",
"\n",
" try:\n",
" return await run_in_thread(get_items_query)\n",
" except Exception as e:\n",
"\n",
" raise HTTPException(status_code=500, detail=f\"Error fetching all items: {str(e)}\")\n",
"\n",
"# Insert an item\n",
"@app.post(\"/items\", response_model=dict)\n",
"async def create_item(item: Item):\n",
" def insert_item_query():\n",
" result = execute_transaction(f\"INSERT INTO items (id, name, price) VALUES ({item.id}, '{item.name}', {item.price})\")\n",
" return {\"message\": f\"Item with id {item.id} inserted successfully\"}\n",
"\n",
" try:\n",
" return await run_in_thread(insert_item_query)\n",
" except Exception as e:\n",
" raise HTTPException(status_code=500, detail=f\"Error while inserting item with id {item.id}: {str(e)}\")\n",
"\n",
"# Get item by id\n",
"@app.get(\"/items/{item_id}\", response_model=Item)\n",
"async def get_item(item_id: int):\n",
" def get_item_query():\n",
" result = execute_query(f\"SELECT * FROM items WHERE id={item_id}\")\n",
" row = result.fetchone()\n",
" if not row:\n",
" raise HTTPException(status_code=404, detail=\"Item not found\")\n",
" return {\"id\": row[0], \"name\": row[1], \"price\": row[2]}\n",
"\n",
" try:\n",
" return await run_in_thread(get_item_query)\n",
" except HTTPException as e:\n",
" raise e\n",
" except Exception as e:\n",
" raise HTTPException(status_code=500, detail=f\"Error fetching item with id {item_id}: {str(e)}\")\n",
"\n",
"# Delete item by id\n",
"@app.delete(\"/items/{item_id}\", response_model=dict)\n",
"async def delete_item(item_id: int):\n",
" def delete_item_query():\n",
" result = execute_transaction(f\"DELETE FROM items WHERE id={item_id}\")\n",
" return {\"message\": f\"number of rows deleted: {result.rowcount}\"}\n",
"\n",
" try:\n",
" return await run_in_thread(delete_item_query)\n",
" except Exception as e:\n",
" raise HTTPException(status_code=500, detail=f\"Error deleting item with id {item_id}: {str(e)}\")"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "c3d9ed07-4b55-4d17-aabb-e11b399109d1",
"source": [
"## Start the FastAPI server\n",
"\n",
"The link at which the cloud function will be available interactively will be displayed."
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "ff002c7d-9f1c-40e5-b82a-c9176251dc99",
"outputs": [],
"source": [
"import singlestoredb.apps as apps\n",
"connection_info = await apps.run_function_app(app)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "fabe76b7-e6a0-43a0-8d9e-aa79bd7d3021",
"source": [
"## Publish Cloud Function\n",
"\n",
"After validating the Cloud Function interactively, you can publish it and use it as an API server for your data!"
]
},
{
"cell_type": "markdown",
"id": "386f804b-f3a9-4452-9575-b87c917bbbf8",
"metadata": {},
"source": [
"<div id=\"singlestore-footer\" style=\"background-color: rgba(194, 193, 199, 0.25); height:2px; margin-bottom:10px\"></div>\n",
"<div><img src=\"https://raw.githubusercontent.com/singlestore-labs/spaces-notebooks/master/common/images/singlestore-logo-grey.png\" style=\"padding: 0px; margin: 0px; height: 24px\"/></div>"
]
}
],
"nbformat": 4,
"nbformat_minor": 5
}
13 changes: 13 additions & 0 deletions notebooks/create-dash-app/meta.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[meta]
authors=["singlestore"]
title="Publish your first SingleStore DashApp"
description="""\
Learn how to connect to SingleStoreDB\
and publish an interactive Dashboard.
"""
icon="browser"
difficulty="beginner"
tags=["starter", "notebooks", "python"]
lesson_areas=[]
destinations=["spaces"]
minimum_tier="free-shared"
Loading

0 comments on commit 69c6699

Please sign in to comment.