Skip to content

Commit 1980735

Browse files
committed
ref(entities): add replation
1 parent fbeed7f commit 1980735

File tree

6 files changed

+195
-103
lines changed

6 files changed

+195
-103
lines changed

src/tgdb/entities/entity.py

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
from collections import OrderedDict
2+
from collections.abc import Sequence
3+
from dataclasses import dataclass
4+
from itertools import batched, pairwise
5+
from uuid import UUID
6+
7+
from tgdb.entities.number import Number
8+
from tgdb.entities.relation.domain import Domain
9+
from tgdb.entities.relation.scalar import Scalar
10+
from tgdb.entities.relation.schema import Schema
11+
12+
13+
@dataclass(frozen=True)
14+
class PartitionVersion:
15+
number: Number
16+
schema: Schema
17+
migration_id: UUID
18+
19+
20+
class NotIncrementedPartitionVersionError(Exception): ...
21+
22+
23+
class PartitionWithoutVersionsError(Exception): ...
24+
25+
26+
# UUID @ str | bool int
27+
28+
# 00000000000000000000000000000001:0:0:qweqweqweqwe oaksdoaksd qweq
29+
# 00000000000000000000000000000001:0:1:
30+
31+
32+
@dataclass(frozen=True)
33+
class Partition:
34+
"""
35+
:raises tgdb.entities.relation.schema.PartitionWithoutVersionsError:
36+
:raises tgdb.entities.relation.schema.NotIncrementedPartitionVersionError:
37+
"""
38+
39+
number: Number
40+
_version_map: OrderedDict[Number, PartitionVersion]
41+
42+
def __post_init__(self) -> None:
43+
if not self._version_map:
44+
raise PartitionWithoutVersionsError
45+
46+
for number, next_number in pairwise(self._version_map):
47+
if next(number) != next_number:
48+
raise NotIncrementedPartitionVersionError
49+
50+
def last_version(self) -> PartitionVersion:
51+
return self._version_map.keys()
52+
53+
def old_versions(self) -> Sequence[PartitionVersion]:
54+
return self._versions[:-1]
55+
56+
def migrate(
57+
self,
58+
new_version_schema: Schema,
59+
new_version_migration_id: UUID,
60+
) -> None:
61+
new_version = PartitionVersion(
62+
next(self.last_version().number),
63+
new_version_schema,
64+
new_version_migration_id,
65+
)
66+
self._versions.append(new_version)
67+
68+
def remove_old_versions(self, *, count: int) -> None:
69+
if count >= len(self._versions):
70+
raise PartitionWithoutVersionsError
71+
72+
for _ in range(count):
73+
self._versions.pop(0)
74+
75+
@classmethod
76+
def new(cls, number: Number, schema: Schema) -> "Partition":
77+
return Partition(number, [PartitionVersion(Number(0), schema)])
78+
79+
80+
class EntityWithoutPartitionsError(Exception): ...
81+
82+
83+
class DifferentlyIdentifyingPartitionError(Exception): ...
84+
85+
86+
class InvalidPartitionMapError(Exception): ...
87+
88+
89+
class NoPartitionError(Exception): ...
90+
91+
92+
@dataclass(frozen=True)
93+
class Entity:
94+
"""
95+
:raises tgdb.entities.entity.EntityWithoutPartitionsError:
96+
:raises tgdb.entities.entity.InvalidPartitionMapError:
97+
"""
98+
99+
number: Number
100+
_partition_map: dict[Number, Partition]
101+
102+
def __post_init__(self) -> None:
103+
if not self._partition_map:
104+
raise EntityWithoutPartitionsError
105+
106+
for number, partition in self._partition_map.items():
107+
if number != partition.number:
108+
raise InvalidPartitionMapError
109+
110+
@classmethod
111+
def new(cls, number: Number, schema: Schema) -> "Entity":
112+
return Entity(number, {Number(0): Partition.new(Number(0), schema)})
113+
114+
def add_partition(self, schema: Schema) -> None:
115+
new_partition = Partition.new(
116+
next(self._last_partition().number), schema
117+
)
118+
self._partition_map[new_partition.number] = new_partition
119+
120+
def partition_numbers(self) -> tuple[Number, ...]:
121+
return tuple(self._partition_map.keys())
122+
123+
def partition_last_version(
124+
self, partition_number: Number
125+
) -> PartitionVersion | None:
126+
partition = self._partition_map.get(partition_number)
127+
128+
if partition is None:
129+
return None
130+
131+
return partition.last_version()
132+
133+
def partition_old_versions(
134+
self, partition_number: Number
135+
) -> Sequence[PartitionVersion] | None:
136+
partition = self._partition_map.get(partition_number)
137+
138+
if partition is None:
139+
return None
140+
141+
return partition.old_versions()
142+
143+
def migrate_partition(
144+
self,
145+
partition_number: Number,
146+
new_schema: Schema,
147+
migration_id: UUID,
148+
) -> None:
149+
"""
150+
:raises tgdb.entities.entity.NoPartitionError:
151+
:raises tgdb.entities.entity.DifferentlyIdentifyingPartitionError:
152+
"""
153+
154+
partition = self._partition_map.get(partition_number)
155+
156+
if partition is None:
157+
raise NoPartitionError
158+
159+
partition
160+
161+
return partition.old_versions()
162+
163+
def remove_old_versions(self, *, count: int) -> None:
164+
if count >= len(self._versions):
165+
raise PartitionWithoutVersionsError
166+
167+
for _ in range(count):
168+
self._versions.pop(0)
169+
170+
def _last_partition(self) -> Partition:
171+
return self._partition_map[max(self._partition_map)]

src/tgdb/entities/message.py

Lines changed: 0 additions & 7 deletions
This file was deleted.

src/tgdb/entities/number.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from collections.abc import Iterator, Sequence
33
from dataclasses import dataclass
44
from datetime import datetime
5-
from typing import Any, overload
5+
from typing import Any, Self, overload
66
from uuid import UUID
77

88

@@ -20,8 +20,8 @@ def __post_init__(self) -> None:
2020
def __int__(self) -> "int":
2121
return self.int
2222

23-
def __add__(self, other: "Number | int") -> "Number":
24-
return Number(self.int + int(other))
23+
def __next__(self) -> "Number":
24+
return Number(self.int + 1)
2525

26-
def __radd__(self, other: "int") -> "Number":
27-
return Number(self.int + other)
26+
def __lt__(self, other: "Number") -> bool:
27+
return self.int < other.int

src/tgdb/entities/relation/domain.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ def is_nonable(self) -> bool: ...
1616
@abstractmethod
1717
def __contains__(self, scalar: Scalar) -> bool: ...
1818

19+
@abstractmethod
20+
def __eq__(self, other: object) -> bool: ...
21+
22+
@abstractmethod
23+
def __hash__(self) -> int: ...
24+
1925

2026
@dataclass(frozen=True)
2127
class IntDomain(Domain):

src/tgdb/entities/relation/schema.py

Lines changed: 13 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,25 @@
22
from dataclasses import dataclass
33
from typing import Any, overload
44

5-
from tgdb.entities.number import Number
65
from tgdb.entities.relation.domain import Domain
76
from tgdb.entities.relation.scalar import Scalar
87

98

10-
@dataclass(frozen=True, unsafe_hash=False, eq=False)
11-
class SchemaPartitionVersion: # noqa: PLW1641
12-
number: Number
9+
class EmptyRelationSchemaError(Exception): ...
10+
11+
12+
@dataclass(frozen=True)
13+
class Schema:
14+
"""
15+
:raises tgdb.entities.relation.schema.EmptyRelationSchemaError:
16+
"""
17+
1318
domains: tuple[Domain, ...]
1419

20+
def __post_init__(self) -> None:
21+
if not self.domains:
22+
raise EmptyRelationSchemaError
23+
1524
def __contains__(self, tuple_: tuple[Scalar, ...]) -> bool:
1625
if len(self) != len(tuple_):
1726
return False
@@ -21,18 +30,6 @@ def __contains__(self, tuple_: tuple[Scalar, ...]) -> bool:
2130
for domain, scalar in zip(self, tuple_, strict=True)
2231
)
2332

24-
def __eq__(self, other: object) -> bool:
25-
if not isinstance(other, SchemaPartitionVersion):
26-
return False
27-
28-
if len(self) != len(other):
29-
return False
30-
31-
return all(
32-
schema1 == schema2
33-
for schema1, schema2 in zip(self, other, strict=True)
34-
)
35-
3633
def __iter__(self) -> Iterator[Domain]:
3734
return iter(self.domains)
3835

@@ -51,75 +48,3 @@ def __getitem__(
5148

5249
def __len__(self) -> int:
5350
return len(self.domains)
54-
55-
56-
@dataclass(frozen=True, unsafe_hash=False)
57-
class SchemaPartition:
58-
number: int
59-
_versions: list[SchemaPartitionVersion]
60-
61-
def __post_init__(self) -> None:
62-
if not self._versions:
63-
raise SchemaWithoutVersionsError
64-
65-
for version_index in range(len(self._versions) - 1):
66-
version = self._versions[version_index]
67-
next_version = self._versions[version_index]
68-
69-
self._validate_increment(version, next_version)
70-
71-
def last_version(self) -> SchemaPartitionVersion:
72-
return self._versions[-1]
73-
74-
def old_versions(self) -> Sequence[SchemaPartitionVersion]:
75-
return self._versions[:-1]
76-
77-
def add_version(self, domains: tuple[Domain, ...]) -> None:
78-
new_version = SchemaPartitionVersion(
79-
self.last_version().number + 1, domains,
80-
)
81-
self._versions.append(new_version)
82-
83-
def remove_old_versions(self, *, count: int) -> None:
84-
if count >= len(self._versions):
85-
raise SchemaWithoutVersionsError
86-
87-
for _ in range(count):
88-
self._versions.pop(0)
89-
90-
def _validate_increment(
91-
self,
92-
prevous_version: SchemaPartitionVersion,
93-
new_version: SchemaPartitionVersion,
94-
) -> None:
95-
if prevous_version.number + 1 != new_version.number:
96-
raise NotIncrementedSchemaVersionsError
97-
98-
99-
class NotIncrementedSchemaVersionsError(Exception): ...
100-
101-
102-
# | id int | id str |
103-
104-
105-
@dataclass(frozen=True, unsafe_hash=False)
106-
class Schema:
107-
number: Number
108-
_partitions: list[SchemaPartition]
109-
110-
def __post_init__(self) -> None:
111-
if not self._partitions:
112-
raise SchemaWithoutVersionsError
113-
114-
for version_index in range(len(self._partitions) - 1):
115-
version = self._partitions[version_index]
116-
next_version = self._partitions[version_index]
117-
118-
self._validate_increment(version, next_version)
119-
120-
121-
class NotIncrementedSchemaVersionsError(Exception): ...
122-
123-
124-
class SchemaWithoutVersionsError(Exception): ...
125-

src/tgdb/entities/transaction.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
from tgdb.entities.logic_time import LogicTime
88
from tgdb.entities.mark import Mark
9-
from tgdb.entities.message import Message
109
from tgdb.entities.row import RowID, RowVersion
1110

1211

@@ -27,7 +26,6 @@ class ViewedRow:
2726
@dataclass(frozen=True)
2827
class MutatedRow:
2928
row_version: RowVersion
30-
message: Message | None
3129

3230
@property
3331
def id(self) -> RowID:
@@ -37,7 +35,6 @@ def id(self) -> RowID:
3735
@dataclass(frozen=True)
3836
class DeletedRow:
3937
id: RowID
40-
message: Message | None
4138

4239

4340
type TransactionScalarEffect = (

0 commit comments

Comments
 (0)