diff --git a/src/zarr_sqlite/zarr_sqlite.py b/src/zarr_sqlite/zarr_sqlite.py index 42e0074..92bb6f1 100644 --- a/src/zarr_sqlite/zarr_sqlite.py +++ b/src/zarr_sqlite/zarr_sqlite.py @@ -1,11 +1,15 @@ from __future__ import annotations +__version__ = "0.1.0" +schema_version = "1.0" + import asyncio import sqlite3 from pathlib import Path from typing import TYPE_CHECKING, override, cast import urllib.parse import uuid +from datetime import datetime from zarr.abc.store import ( ByteRequest, @@ -16,6 +20,8 @@ ) from zarr.core.buffer import Buffer from zarr.core.common import BytesLike +from zarr import __version__ as zarr_version +from sys import version as py_version if TYPE_CHECKING: from collections.abc import AsyncIterator, Iterable, Sequence @@ -177,9 +183,38 @@ async def _execute( return cur.execute(query, params) async def _create_schema(self) -> None: - await self._execute_write( - "CREATE TABLE IF NOT EXISTS zarr(k TEXT PRIMARY KEY, v BLOB)" - ) + await self._ensure_open() + if self._lock is None: + raise ValueError("Store is not open") + + schema = ["CREATE TABLE IF NOT EXISTS zarr(k TEXT PRIMARY KEY, v BLOB)", + "CREATE TABLE IF NOT EXISTS zarr_versions(name TEXT PRIMARY KEY, version TEXT)"] + + set_version = "INSERT OR REPLACE INTO zarr_versions (name, version) VALUES (?, ?)" + versions = {'sqlitestore_version': __version__, + 'sqlitestore_schema': schema_version, + 'create_zarr_version': zarr_version, + 'create_python_version': py_version, + 'create_datetime': datetime.now().isoformat(sep=' ', timespec='seconds'), + } + async with self._lock: + cursor = self._con.cursor() + for statement in schema: + _ = cursor.execute(statement) + for name, ver in versions.items(): + _ = cursor.execute(set_version, (name, ver)) + self._con.commit() + + def get_versions(self): + """return a dict of version information (non-async)""" + result = {} + with sqlite3.connect(self.database_uri, uri=True, autocommit=False, check_same_thread=False) as con: + cur = con.cursor() + cur.execute("SELECT * from zarr_versions") + for row in cur.fetchall(): + result[row[0]] = row[1] + return result + @override def close(self) -> None: @@ -200,7 +235,8 @@ async def is_empty(self, prefix: str) -> bool: @override async def clear(self) -> None: """Clear the store.""" - await self._execute_write("DROP TABLE IF EXISTS zarr") + await self._execute_write("DROP TABLE IF EXISTS zarr;") + await self._execute_write("DROP TABLE IF exists zarr_versions;") await self._create_schema() @override