# Copyright (C) 2019 Lars Wirzenius # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # 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 Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . import copy import uuid import ick2 class StoreInterface: # pragma: no cover def create(self, token, obj): raise NotImplementedError() def update(self, token, rid, obj, revision): raise NotImplementedError() def show(self, token, rid): raise NotImplementedError() def delete(self, token, rid): raise NotImplementedError() def search(self, token, cond): raise NotImplementedError() class MemoryStore(StoreInterface): def __init__(self): self._objs = {} def search(self, token, cond): return list(self._objs.keys()) def _new_id(self): return str(uuid.uuid4()) def _set(self, rid, rev, obj): self._objs[rid] = (rev, copy.deepcopy(obj)) def create(self, token, obj): rid = self._new_id() rev = self._new_id() self._set(rid, rev, obj) return rid, rev def show(self, token, rid): if rid not in self._objs: raise ick2.NotFound('unknown.type', rid) rev, obj = self._objs[rid] return copy.deepcopy(obj), rev def update(self, token, rid, obj, revision): old_obj, old_rev = self.show(token, rid) if old_rev != revision: raise Conflict(rid, old_rev, revision) new_rev = self._new_id() self._set(rid, new_rev, obj) return new_rev def delete(self, token, rid): del self._objs[rid] class Conflict(Exception): def __init__(self, rid, expected, got): super().__init__( 'Update conflict for {}: expected revision {}, got {}'.format( rid, expected, got))