Coverage for gws-app/gws/plugin/storage_provider/sqlite/__init__.py: 100%
33 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-05 13:35 +0200
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-05 13:35 +0200
1"""SQLite storage provider.
3The ``sqlite`` storage provider keeps saved user entries in an SQLite
4database file, by default ``storage8.sqlite`` in the GWS misc directory.
5The ``storage`` table is created on first use. Each entry is a row keyed
6by category and name, with the serialized data, the UID of the user who
7wrote it, and the creation and update timestamps.
9Example::
11 storage {
12 providers+ {
13 type "sqlite"
14 path "/data/storage.sqlite"
15 }
16 }
17"""
19from typing import Optional
21import gws
22import gws.lib.datetimex as dtx
23import gws.lib.sqlitex
26@gws.ext.config.storageProvider('sqlite')
27class Config(gws.Config):
28 """Storage provider that keeps saved user data in an SQLite file."""
30 path: Optional[str]
31 """Database file."""
34@gws.ext.object.storageProvider('sqlite')
35class Object(gws.StorageProvider):
36 """Storage provider backed by an SQLite database file."""
38 dbPath: str
39 """Path to the database file."""
40 table = 'storage'
41 """Name of the table that holds the entries."""
43 def configure(self):
44 self.dbPath = self.cfg('path', default=f'{gws.c.MISC_DIR}/storage8.sqlite')
46 def list_names(self, category):
47 rs = self._db().select(f'SELECT name FROM {self.table} WHERE category=:category', category=category)
48 return sorted(rec['name'] for rec in rs)
50 def read(self, category, name):
51 rs = self._db().select(f'SELECT * FROM {self.table} WHERE category=:category AND name=:name', category=category, name=name)
52 for rec in rs:
53 rec = dict(rec)
54 rec['created'] = dtx.from_timestamp(rec['created'])
55 rec['updated'] = dtx.from_timestamp(rec['updated'])
56 return gws.StorageRecord(**rec)
58 def write(self, category, name, data, user_uid):
59 self._db().execute(
60 f'''
61 INSERT INTO {self.table} (category, name, user_uid, data, created, updated)
62 VALUES (:category, :name, :user_uid, :data, :created, :updated)
63 ON CONFLICT (category, name) DO UPDATE SET
64 user_uid=excluded.user_uid,
65 data=excluded.data,
66 updated=excluded.updated
67 ''',
68 category=category, name=name, user_uid=user_uid, data=data,
69 created=gws.u.stime(), updated=gws.u.stime()
70 )
72 def delete(self, category, name):
73 self._db().execute(
74 f'DELETE FROM {self.table} WHERE category=:category AND name=:name',
75 category=category, name=name
76 )
78 ##
80 _sqlitex: gws.lib.sqlitex.Object
82 def _db(self):
83 """Return the database object, creating the table if needed."""
84 if getattr(self, '_sqlitex', None) is None:
85 ddl = f'''
86 CREATE TABLE IF NOT EXISTS {self.table} (
87 category TEXT NOT NULL,
88 name TEXT NOT NULL,
89 user_uid TEXT,
90 data TEXT,
91 created INTEGER,
92 updated INTEGER,
93 PRIMARY KEY (category, name)
94 )
95 '''
96 self._sqlitex = gws.lib.sqlitex.Object(self.dbPath, ddl)
97 return self._sqlitex