From 9879dd0ca060dfa2a2ad5621d4e10fe22fc22b43 Mon Sep 17 00:00:00 2001 From: Micah Sandusky Date: Wed, 21 Aug 2024 10:02:39 -0600 Subject: [PATCH] # This is a combination of 5 commits. # This is the 1st commit message: add a query notebook that points at the copy of the points table # This is the commit message #2: add what the point data table linking could look like, including what adding an object might look like # This is the commit message #3: Example of how the realtionship might look # This is the commit message #4: attempt at having many-to-many with observers # This is the commit message #5: assuming we don't need back populate on instrument relationships --- notebooks/prime/query_examples.ipynb | 283 +++++++++++++++++++++++++++ 1 file changed, 283 insertions(+) create mode 100644 notebooks/prime/query_examples.ipynb diff --git a/notebooks/prime/query_examples.ipynb b/notebooks/prime/query_examples.ipynb new file mode 100644 index 0000000..f09a758 --- /dev/null +++ b/notebooks/prime/query_examples.ipynb @@ -0,0 +1,283 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "30e47587-c53d-4fa7-aa39-b233997afec9", + "metadata": {}, + "outputs": [], + "source": [ + "# Imports\n", + "from snowexsql.data import PointData, SingleLocationData, Measurement, Base\n", + "from snowexsql.api import PointMeasurements\n", + "from sqlalchemy import Column, Date, DateTime, Float, Integer, String, Time, Table\n", + "from sqlalchemy.orm import Mapped\n", + "from sqlalchemy.orm import mapped_column\n", + "from typing import List" + ] + }, + { + "cell_type": "markdown", + "id": "ccc0ce03-2e31-49ab-b906-dd0cc9830220", + "metadata": {}, + "source": [ + "## Extend the data model\n", + " * Make a new data model that uses the new `points_prototype` table with the copied over `Points` information" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "c6714db5-db2f-44b2-b5d8-ae253d0c39d2", + "metadata": {}, + "outputs": [], + "source": [ + "# points_prototype\n", + "\n", + "\n", + "class PointDataOriginal(SingleLocationData, Measurement, Base):\n", + " \"\"\"\n", + " Class representing the points table. This table holds all point data.\n", + " Here a single data entry is a single coordinate pair with a single value\n", + " e.g. snow depths\n", + " \"\"\"\n", + " __tablename__ = 'points_original'\n", + " __table_args__ = {\"schema\": \"public\"}\n", + "\n", + " version_number = Column(Integer)\n", + " equipment = Column(String(50))\n", + " value = Column(Float)\n", + "\n", + " __mapper_args__ = {\n", + " 'polymorphic_identity': 'Points',\n", + " }\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "d3bc5746-2eb8-4f0c-8192-fd0556b47ab3", + "metadata": {}, + "source": [ + "## Make a new api class\n", + " * Extend the API class and use the new points prototype data model " + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "c832fcaa-55a5-46f6-bd4a-1f370d6670d3", + "metadata": {}, + "outputs": [], + "source": [ + "class PointsMeasurementsOriginal(PointMeasurements):\n", + " \"\"\"\n", + " Extend the points api class for the new data model\n", + " \"\"\"\n", + " DB_NAME = \"snow:hackweek@35.86.115.212/snowex\"\n", + " MODEL = PointDataOriginal\n", + " " + ] + }, + { + "cell_type": "markdown", + "id": "646d7faf-6934-4054-aec9-11d3c2d682e0", + "metadata": {}, + "source": [ + "## Use our new api class" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6d207811-aa91-44aa-88d8-2dc86d9bcdac", + "metadata": {}, + "outputs": [], + "source": [ + "PointsMeasurementsOriginal().all_instruments" + ] + }, + { + "cell_type": "markdown", + "id": "d26d0853-67c8-4bc4-915a-edc86c01d37c", + "metadata": {}, + "source": [ + "## make a new table class that includes foreign keys" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "85ccfd8c-1a41-4569-86ad-c6342a9add0f", + "metadata": {}, + "outputs": [], + "source": [ + "# points_prototype\n", + "from sqlalchemy import Column, Date, DateTime, Float, Integer, String, Time, ForeignKey\n", + "from sqlalchemy.orm import relationship, sessionmaker\n", + "\n", + "\n", + "# Create a association table for the many-to-many relationship\n", + "point_observers = Table(\n", + " \"point_observers\",\n", + " Base.metadata,\n", + " Column(\"point_id\", ForeignKey(\"points_prototype.id\"), primary_key=True),\n", + " Column(\"observer_id\", ForeignKey(\"observers.id\"), primary_key=True),\n", + " extend_existing=True\n", + ")\n", + "\n", + "\n", + "# Create an Observer table class\n", + "class Observer(Base):\n", + " __tablename__ = 'observers'\n", + " __table_args__ = {\"schema\": \"public\"}\n", + " # this seems important\n", + " __mapper_args__ = {\n", + " 'polymorphic_identity': 'Observer',\n", + " }\n", + " # id is mapped column for many-to-many \n", + " id: Mapped[int] = mapped_column(primary_key=True)\n", + " # Name of the instrument\n", + " first_name = Column(String(255))\n", + " last_name = Column(String(255))\n", + " email = Column(String(255))\n", + "\n", + "\n", + "# Create an instruments table class\n", + "class Instument(Base):\n", + " __tablename__ = 'instrument'\n", + " __table_args__ = {\"schema\": \"public\"}\n", + " # this seems important\n", + " __mapper_args__ = {\n", + " 'polymorphic_identity': 'Instrument',\n", + " }\n", + " # auto created id\n", + " id = Column(Integer, primary_key=True)\n", + " # Name of the instrument\n", + " name = Column(String(50), nullable=False)\n", + "\n", + " # Link each table that use instrument (bi-directional)\n", + " # points = relationship('PointDataPrototype', back_populates='instrument')\n", + "\n", + "\n", + "# Create a new points table class that links to \n", + "class PointDataPrototype(SingleLocationData, Base):\n", + " __tablename__ = 'points_prototype'\n", + " __table_args__ = {\"schema\": \"public\"}\n", + " # this seems important\n", + " __mapper_args__ = {\n", + " 'polymorphic_identity': 'Points',\n", + " }\n", + "\n", + " version_number = Column(Integer)\n", + " equipment = Column(String(50))\n", + " value = Column(Float)\n", + "\n", + " # bring these in instead of Measurement\n", + " type = Column(String(50))\n", + " units = Column(String(50))\n", + "\n", + " # This should be the foreign key\n", + " # instrument = Column(String(50))\n", + " # Link the instrument id with a foreign key\n", + " instrument_id = Column(Integer, ForeignKey('instrument.id'))\n", + " # Link the Instrument class\n", + " instrument = relationship('Instrument')\n", + "\n", + " # id is a mapped column for many-to-many with observers\n", + " id: Mapped[int] = mapped_column(primary_key=True)\n", + " observers: Mapped[List[Observer]] = relationship(secondary=point_observers)\n", + " \n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "f68aac71-a04e-42a4-ae3f-2d9f2710f2f5", + "metadata": {}, + "outputs": [], + "source": [ + "class PointsMeasurementsPrototype(PointMeasurements):\n", + " \"\"\"\n", + " Extend the points api class for the new data model\n", + " \"\"\"\n", + " DB_NAME = \"snow:hackweek@35.86.115.212/snowex\"\n", + " MODEL = PointDataPrototype" + ] + }, + { + "cell_type": "markdown", + "id": "cc87534b-ee80-47f0-857d-ae2e1ee23a3f", + "metadata": {}, + "source": [ + "## Example of adding a new point, this doens't work yet" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "32397550-4d52-4564-baa4-795b515c0040", + "metadata": {}, + "outputs": [], + "source": [ + "def add_entry(instrument_name, observer_names, **kwargs):\n", + " # Check if the instrument already exists\n", + " instrument = session.query(Instrument).filter_by(name=instrument_name).first()\n", + " # observer = session.query(Observer).filter_by(name=observer_name).first()\n", + " \n", + " if not instrument:\n", + " # If the instrument does not exist, create it\n", + " instrument = Instrument(name=instrument_name)\n", + " session.add(instrument)\n", + " session.commit() # Commit to ensure instrument is saved and has an ID\n", + "\n", + " observer_list = []\n", + " for obs_name in observer_names:\n", + " observer = session.query(Observer).filter_by(last_name=observer_name).first()\n", + " if not observer:\n", + " # If the instrument does not exist, create it\n", + " instrument = Observer(last_name=instrument_name)\n", + " session.add(observer)\n", + " session.commit() # Commit to ensure instrument is saved and has an ID\n", + " observer_list.append(observer)\n", + " \n", + " \n", + " # Now that the instrument exists, create the entry, notice we only need the instrument object\n", + " new_entry = PointDataPrototype(**kwargs, instrument=instrument, observers=observer_list)\n", + " session.add(new_entry)\n", + " session.commit()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "354ae291-30f8-4541-8c3e-80f78f7aee7e", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.4" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}