tiramisu/tiramisu/storage/sqlite3/storage.py

202 lines
7.1 KiB
Python
Raw Normal View History

2013-08-19 11:01:21 +02:00
# -*- coding: utf-8 -*-
" with sqlite3 engine"
2021-02-24 20:30:04 +01:00
# Copyright (C) 2013-2021 Team tiramisu (see AUTHORS for all contributors)
2013-08-19 11:01:21 +02:00
#
2013-09-22 22:33:09 +02:00
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
2013-08-19 11:01:21 +02:00
#
2013-09-22 22:33:09 +02:00
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
# details.
2013-08-19 11:01:21 +02:00
#
2013-09-22 22:33:09 +02:00
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
2013-08-19 11:01:21 +02:00
# ____________________________________________________________
2019-09-01 09:41:53 +02:00
import sqlite3
import warnings
2019-12-24 15:24:20 +01:00
from os.path import join
from typing import Optional, Dict
2013-08-19 11:01:21 +02:00
2018-09-07 08:42:14 +02:00
from ...i18n import _
from ...error import ConflictError
2019-12-24 15:24:20 +01:00
from ...asyncinit import asyncinit
global CONN
CONN = None
2020-01-22 20:46:18 +01:00
async def init():
global CONN
if CONN is None:
CONN = sqlite3.connect(_gen_filename())
CONN.text_factory = str
session_table = 'CREATE TABLE IF NOT EXISTS session(session_id INTEGER, session TEXT UNIQUE, PRIMARY KEY(session_id))'
settings_table = 'CREATE TABLE IF NOT EXISTS property(path TEXT, tiram_index INTEGER, properties TEXT, session_id INTEGER, PRIMARY KEY(path, tiram_index, session_id), ' \
'FOREIGN KEY(session_id) REFERENCES session(session_id))'
permissives_table = 'CREATE TABLE IF NOT EXISTS permissive(path TEXT, tiram_index INTEGER, permissives TEXT, session_id INTEGER, ' \
'PRIMARY KEY(path, tiram_index, session_id), ' \
'FOREIGN KEY(session_id) REFERENCES session(session_id))'
values_table = 'CREATE TABLE IF NOT EXISTS value(path TEXT, value TEXT, owner TEXT, idx INTEGER, session_id INTEGER, ' \
'PRIMARY KEY (path, idx, session_id), ' \
'FOREIGN KEY(session_id) REFERENCES session(session_id))'
informations_table = 'CREATE TABLE IF NOT EXISTS information(key TEXT, value TEXT, session_id INTEGER, path TEXT, ' \
'PRIMARY KEY (key, session_id), ' \
'FOREIGN KEY(session_id) REFERENCES session(session_id))'
cursor = CONN.cursor()
cursor.execute(session_table)
cursor.execute(values_table)
cursor.execute(informations_table)
cursor.execute(settings_table)
cursor.execute(permissives_table)
CONN.commit()
class Connection:
async def __aenter__(self):
self.connection = CONN.cursor()
return self
async def __aexit__(self,
type,
value,
traceback):
if type is None:
CONN.commit()
else:
CONN.rollback()
self.connection.close()
async def execute(self,
sql: str,
params: Optional[Dict]=None) -> None:
if params is None:
params = tuple()
self.connection.execute(sql, params)
async def select(self,
sql: str,
params: Optional[Dict]=None,
only_one: bool=True) -> 'Row':
if params is None:
params = tuple()
self.connection.execute(sql, params)
if only_one:
return self.connection.fetchone()
else:
return self.connection.fetchall()
class Setting:
2013-09-10 21:04:12 +02:00
""":param extension: database file extension (by default: db)
:param dir_database: root database directory (by default: /tmp)
"""
__slots__ = ('extension',
'dir_database',
'name')
def __init__(self):
self.extension = 'db'
self.dir_database = '/tmp'
self.name = 'tiramisu'
def __setattr__(self, key, value):
2019-02-23 22:52:06 +01:00
if CONN is not None: # pragma: no cover
raise Exception(_('cannot change setting when connexion is already '
'opened'))
super().__setattr__(key, value)
2019-02-23 12:25:20 +01:00
PERSISTENT = True
2017-07-04 19:59:42 +02:00
SETTING = Setting()
2017-07-04 19:59:42 +02:00
def _gen_filename():
return join(SETTING.dir_database, '{0}.{1}'.format(SETTING.name, SETTING.extension))
2020-01-22 20:46:18 +01:00
async def list_sessions():
2019-09-01 09:41:53 +02:00
if not CONN:
warnings.warn_explicit(Warning(_('Cannot list sessions, please connect to database first')),
category=Warning,
filename=__file__,
lineno=63)
return []
2020-01-22 20:46:18 +01:00
cursor = CONN.cursor()
return await _list_sessions(cursor)
2020-01-22 20:46:18 +01:00
async def _list_sessions(cursor):
names = [row[0] for row in cursor.execute("SELECT session FROM session").fetchall()]
return names
async def delete_session(session_id):
2017-07-11 22:31:58 +02:00
cursor = CONN.cursor()
2020-01-22 20:46:18 +01:00
ret = cursor.execute("SELECT session_id FROM session WHERE session = ?",
(session_id,)).fetchone()
if ret is not None:
database_id = ret[0]
await _delete_session(database_id,
cursor)
2018-09-11 20:11:13 +02:00
cursor.close()
2013-08-19 11:01:21 +02:00
2020-01-22 20:46:18 +01:00
async def _delete_session(database_id,
cursor):
cursor.execute("DELETE FROM property WHERE session_id = ?", (database_id,))
cursor.execute("DELETE FROM permissive WHERE session_id = ?", (database_id,))
cursor.execute("DELETE FROM value WHERE session_id = ?", (database_id,))
cursor.execute("DELETE FROM information WHERE session_id = ?", (database_id,))
cursor.execute("DELETE FROM session WHERE session_id = ?", (database_id,))
CONN.commit()
2013-08-19 11:01:21 +02:00
2019-12-24 15:24:20 +01:00
@asyncinit
2019-12-08 08:15:47 +01:00
class Storage:
2019-12-24 15:24:20 +01:00
__slots__ = ('_conn',
'_cursor',
'session_id',
'session_name',
'created')
storage = 'sqlite3'
2013-08-19 11:01:21 +02:00
2019-12-24 15:24:20 +01:00
async def __init__(self,
2020-01-22 20:46:18 +01:00
connection: Connection,
2019-12-24 15:24:20 +01:00
session_id: str,
2020-01-22 20:46:18 +01:00
delete_old_session: bool) -> None:
if not isinstance(session_id, str):
raise ValueError(_('session_id has to be a string'))
2018-09-15 22:44:49 +02:00
self.created = False
2018-09-11 20:11:13 +02:00
self.session_id = None
2020-01-22 20:46:18 +01:00
self.session_name = session_id
select = await connection.select("SELECT session_id FROM session WHERE session = ?", (session_id,))
if select is not None:
if delete_old_session:
self.delete_session()
else:
2018-09-11 20:11:13 +02:00
self.session_id = select[0]
if self.session_id is None:
2020-01-22 20:46:18 +01:00
await connection.execute('INSERT INTO session(session) VALUES (?)',
(session_id,))
self.session_id = connection.connection.lastrowid
2018-09-15 22:44:49 +02:00
self.created = True
2013-08-20 22:45:11 +02:00
2020-01-22 20:46:18 +01:00
async def delete_session(self):
if self.session_id is not None:
await _delete_session(self.session_id,
CONN)
self.session_id = None
2017-07-16 23:11:12 +02:00
2020-01-22 20:46:18 +01:00
async def list_sessions(self):
return await _list_sessions(self._cursor)
2013-08-20 22:45:11 +02:00
2020-01-22 20:46:18 +01:00
def getconnection(self):
return Connection()
2017-07-04 19:59:42 +02:00
def getsession():
pass