{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Metadata Store & Schema Registry\n",
    "\n",
    "Store and retrieve schemas, metadata, coercion rules, and validation rules. Use the in-memory store for development; use Postgres, MongoDB, Redis, or SQLite for production.\n",
    "\n",
    "[![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/optophi/pycharter/blob/main/docs/notebooks/05_metadata_store.ipynb)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. In-Memory Store (Development)\n",
    "\n",
    "Store and retrieve schemas and metadata without a database."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from pycharter import InMemoryMetadataStore\n",
    "\n",
    "store = InMemoryMetadataStore()\n",
    "store.connect()\n",
    "\n",
    "schema = {\n",
    "    \"type\": \"object\",\n",
    "    \"properties\": {\n",
    "        \"id\": {\"type\": \"string\"},\n",
    "        \"name\": {\"type\": \"string\"},\n",
    "        \"email\": {\"type\": \"string\", \"format\": \"email\"},\n",
    "    },\n",
    "    \"required\": [\"id\", \"name\"],\n",
    "}\n",
    "\n",
    "schema_id = store.store_schema(\"user\", schema, version=\"1.0.0\")\n",
    "print(\"Stored schema ID:\", schema_id)\n",
    "\n",
    "retrieved = store.get_schema(schema_id)\n",
    "print(\"Retrieved properties:\", list(retrieved.get(\"properties\", {}).keys()))\n",
    "\n",
    "store.store_metadata(\n",
    "    schema_id=schema_id,\n",
    "    metadata={\"description\": \"User schema\", \"owner\": \"data-team\", \"domain\": \"identity\"},\n",
    ")\n",
    "print(\"Stored metadata\")\n",
    "\n",
    "schemas = store.list_schemas()\n",
    "print(\"Total schemas:\", len(schemas))\n",
    "\n",
    "store.disconnect()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. Store Coercion and Validation Rules\n",
    "\n",
    "Store rules separately from the schema for independent updates."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "store = InMemoryMetadataStore()\n",
    "store.connect()\n",
    "\n",
    "schema_id = store.store_schema(\n",
    "    \"product\",\n",
    "    {\n",
    "        \"type\": \"object\",\n",
    "        \"properties\": {\"product_id\": {\"type\": \"string\"}, \"price\": {\"type\": \"number\"}},\n",
    "    },\n",
    "    version=\"1.0.0\",\n",
    ")\n",
    "\n",
    "store.store_coercion_rules(schema_id, {\"rules\": {\"price\": \"coerce_to_float\"}}, version=\"1.0.0\")\n",
    "store.store_validation_rules(\n",
    "    schema_id,\n",
    "    {\"rules\": {\"price\": {\"min_value\": {\"threshold\": 0}, \"max_value\": {\"threshold\": 10000}}}},\n",
    "    version=\"1.0.0\",\n",
    ")\n",
    "print(\"Stored coercion and validation rules\")\n",
    "\n",
    "coercion = store.get_coercion_rules(schema_id, version=\"1.0.0\")\n",
    "validation = store.get_validation_rules(schema_id, version=\"1.0.0\")\n",
    "print(\"Coercion fields:\", list(coercion.get(\"rules\", {}).keys()) if coercion else [])\n",
    "print(\"Validation fields:\", list(validation.get(\"rules\", {}).keys()) if validation else [])\n",
    "\n",
    "store.disconnect()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. Version Management\n",
    "\n",
    "Store multiple versions of the same schema (e.g. v1.0.0 and v2.0.0)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "store = InMemoryMetadataStore()\n",
    "store.connect()\n",
    "\n",
    "schema_v1 = {\"type\": \"object\", \"properties\": {\"id\": {\"type\": \"string\"}, \"name\": {\"type\": \"string\"}}}\n",
    "id_v1 = store.store_schema(\"user\", schema_v1, version=\"1.0.0\")\n",
    "\n",
    "schema_v2 = {\n",
    "    \"type\": \"object\",\n",
    "    \"properties\": {\"id\": {\"type\": \"string\"}, \"name\": {\"type\": \"string\"}, \"email\": {\"type\": \"string\"}},\n",
    "}\n",
    "id_v2 = store.store_schema(\"user\", schema_v2, version=\"2.0.0\")\n",
    "\n",
    "print(\"v1.0.0 ID:\", id_v1, \"->\", list(store.get_schema(id_v1)[\"properties\"].keys()))\n",
    "print(\"v2.0.0 ID:\", id_v2, \"->\", list(store.get_schema(id_v2)[\"properties\"].keys()))\n",
    "\n",
    "store.disconnect()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4. Production Backends\n",
    "\n",
    "Use Postgres, MongoDB, Redis, or SQLite for persistent storage. Install optional deps and connect:\n",
    "\n",
    "- **Postgres**: `pip install psycopg2-binary` → `PostgresMetadataStore('postgresql://...')`\n",
    "- **MongoDB**: `pip install pymongo` → `MongoDBMetadataStore('mongodb://...')`\n",
    "- **Redis**: `pip install redis` → `RedisMetadataStore('redis://...')`\n",
    "- **SQLite**: `SQLiteMetadataStore('sqlite:///path.db')` (no extra deps)\n",
    "\n",
    "CLI: `pycharter db init postgresql://user:pass@localhost/db` to initialize the DB."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# from pycharter import PostgresMetadataStore\n",
    "# store = PostgresMetadataStore('postgresql://user:pass@localhost/mydb')\n",
    "# store.connect()\n",
    "# schema_id = store.store_schema('user', schema, version='1.0.0')\n",
    "print(\"Use PostgresMetadataStore, MongoDBMetadataStore, RedisMetadataStore, or SQLiteMetadataStore for production.\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "name": "python",
   "version": "3.10.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
