from typing import (
Self,
ClassVar,
BinaryIO,
TYPE_CHECKING,
)
if TYPE_CHECKING:
from .cache import PfPageCache
from pathlib import Path
from bluebase.core import (
LayoutField,
LayoutMixin,
assignment,
)
from .error import (
PfInvalidPageIdError,
PfFreePageAccessError,
PfFileHeaderDisposeError,
PfPinnedPageDisposeError,
PfFreePageDisposeError,
)
from .type import (
PfPageId,
PfFileId,
)
from .page import (
PfPageView,
PfPageHeader,
PfPage,
)
__all__ = (
'PfFileHeader',
'PfFile',
)
[docs]
class PfFile:
"""
Attributes:
fid:
cache:
stream:
"""
fid: PfFileId
cache: 'PfPageCache'
stream: BinaryIO
def __repr__(self) -> str: # pragma: no cover
return f"PfFile({self.fid!r})"
def __init__(self, fid: PfFileId, cache: 'PfPageCache') -> None:
self.fid = fid
self.stream = Path(fid).open('rb+')
self.cache = cache
[docs]
@classmethod
def new(cls, fid: PfFileId, cache: 'PfPageCache') -> Self:
"""
"""
file = cls(fid, cache)
page = cache.acquire(file, PfFileHeader.PID)
page.recycle()
header = PfFile.get_header(page)
header.set('page_count', 1)
header.set('first_free_pid', int(PfFileHeader.NO_FREE_PAGE))
header.commit()
page.unpin()
return file
[docs]
@classmethod
def open(cls, fid: PfFileId, cache: 'PfPageCache') -> Self:
"""
"""
file = cls(fid, cache)
return file
@property
def page_count(self) -> int:
"""
"""
page, header = PfFile.fetch_header(self)
page_count = header.get('page_count')
page.unpin()
return page_count
@page_count.setter
def page_count(self, count: int) -> None:
page, header = PfFile.fetch_header(self)
header.set('page_count', count)
header.commit()
page.unpin()
@property
def first_free_pid(self) -> PfPageId | None:
"""
"""
page, header = PfFile.fetch_header(self)
pid = header.get('first_free_pid')
page.unpin()
if pid == int(PfFileHeader.NO_FREE_PAGE):
return None
return PfPageId(pid)
@first_free_pid.setter
def first_free_pid(self, pid: PfPageId | None) -> None:
if pid is None:
pid = PfFileHeader.NO_FREE_PAGE
page, header = PfFile.fetch_header(self)
header.set('first_free_pid', int(pid))
header.commit()
page.unpin()
[docs]
def validate_pid(self, pid: PfPageId) -> None:
"""
Raises:
PfInvalidPageIdError:
"""
page_count = self.page_count
if int(pid) < 0 or int(pid) >= page_count:
raise PfInvalidPageIdError(file=self, pid=pid, count=page_count)
[docs]
@assignment
def get_page(self, pid: PfPageId) -> PfPage:
"""
Raises:
PfInvalidPageIdError:
PfFreePageAccessError:
"""
raise NotImplementedError
[docs]
@assignment
def find_next_page(self, pid: PfPageId) -> PfPage | None:
"""
Raises:
PfInvalidPageIdError:
PfFreePageAccessError:
"""
raise NotImplementedError
[docs]
@assignment
def allocate_page(self) -> PfPage:
"""
"""
raise NotImplementedError
[docs]
@assignment
def dispose_page(self, page: PfPage) -> None:
"""
Raises:
PfFileHeaderDisposeError:
PfPinnedPageDisposeError:
PfFreePageDisposeError:
"""
raise NotImplementedError
[docs]
@assignment
def persist(self) -> None:
"""
"""
raise NotImplementedError
[docs]
@assignment
def flush(self) -> None:
"""
"""
raise NotImplementedError